diff -u --recursive --new-file v2.3.14/linux/CREDITS linux/CREDITS --- v2.3.14/linux/CREDITS Thu Aug 12 11:49:02 1999 +++ linux/CREDITS Mon Aug 23 10:53:03 1999 @@ -713,14 +713,11 @@ S: USA N: Paul Gortmaker -E: gpg109@rsphy1.anu.edu.au -W: http://rsphy1.anu.edu.au/~gpg109 -D: Real Time Clock driver author. -D: 8390 net driver hacker (ne2000, wd8013, smc-ultra, 3c503, etc.) -D: Ethernet-HOWTO and BootPrompt-HOWTO author. -D: Added many new CONFIG options (modules, ramdisk, generic-serial, etc.) -D: Implemented 1st "official" kernel thread (moved user bdflush to kflushd) -D: Various other random hacks, patches and utilities. +E: p_gortmaker@yahoo.com +D: Author of RTC driver & several net drivers, Ethernet & BootPrompt Howto. +D: Made support for modules, ramdisk, generic-serial, etc. optional. +D: Transformed old user space bdflush into 1st kernel thread - kflushd. +D: Many other patches, documentation files, mini kernels, utilities, ... N: John E. Gotts E: jgotts@engin.umich.edu @@ -1056,12 +1053,12 @@ S: Czech Republic N: Fred N. van Kempen -E: waltje@uwalt.nl.mugnet.org +E: waltje@linux.com D: NET-2 D: Drivers D: Kernel cleanups -S: Hoefbladhof 27 -S: 2215 DV Voorhout +S: Korte Heul 95 +S: 1403 ND BUSSUM S: The Netherlands N: Karl Keyte diff -u --recursive --new-file v2.3.14/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.3.14/linux/Documentation/00-INDEX Thu Apr 29 11:53:41 1999 +++ linux/Documentation/00-INDEX Wed Aug 25 15:48:28 1999 @@ -25,12 +25,16 @@ - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) VGA-softcursor.txt - how to change your VGA cursor from a blinking underscore. +arm/ + - directory with info about Linux on the ARM architecture. binfmt_misc.txt - info on the kernel support for extra binary formats. cdrom/ - directory with information on the CD-ROM drivers that Linux has. +cpqarray.txt + - info on using Compaq's SMART2 Intelligent Disk Array Controllers. devices.tex - - TeX source listing of all the nodes in /dev/ with major minor #'s + - LaTeX source listing of all the nodes in /dev/ with major minor #'s devices.txt - plain ASCII listing of all the nodes in /dev/ with major minor #'s digiboard.txt @@ -39,12 +43,16 @@ - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. exception.txt - how Linux v2.2 handles exceptions without verify_area etc. +fb/ + - directory with info on the frame buffer graphics abstraction layer. filesystems/ - directory with info on the various filesystems that Linux supports. ftape.txt - notes about the floppy tape device driver hayes-esp.txt - info on using the Hayes ESP serial driver. +i386/ + - directory with info about Linux on the intel ix86 architecture. ide.txt - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS) initrd.txt @@ -57,10 +65,18 @@ - info on the in-kernel binary support for Java(tm) joystick.txt - info on using joystick devices (and driver) with Linux. +joystick-api.txt + - API specification for applications that will be using the joystick. +joystick-parport.txt + - info on how to hook joysticks/gamepads to the parallel port. kbuild/ - directory with info about the kernel build process +kernel-docs.txt + - listing of various WWW + books that document kernel internals. +kernel-parameters.txt + - summary listing of command line / boot prompt args for the kernel. kmod.txt - - - info on the kernel module loader/unloader (kerneld replacement) + - info on the kernel module loader/unloader (kerneld replacement). locks.txt - info on file locking implementations, flock() vs. fcntl(), etc. logo.gif @@ -79,6 +95,8 @@ - info on boot arguments for the multiple devices driver memory.txt - info on typical Linux memory problems. +mkdev.ida + - script to make /dev entries for Intelligent Disk Array Controllers. modules.txt - short guide on how to make kernel parts into loadable modules mtrr.txt @@ -101,20 +119,26 @@ - info and sample code for using with the PC Watchdog reset card. powerpc/ - directory with info on using Linux with the PowerPC. +proc.txt + - detailed info on Linux's /proc filesystem. ramdisk.txt - short guide on how to set up and use the RAM disk. riscom8.txt - notes on using the RISCom/8 multi-port serial driver. rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. +scsi-generic.txt + - info on the sg driver for generic (non-disk/CD/tape) SCSI devices. scsi.txt - short blurb on using SCSI support as a module. serial-console.txt - how to set up Linux with a serial line console as the default. +sgi-visws.txt + - short blurb on the SGI Visual Workstations. smart-config.txt - description of the Smart Config makefile feature. smp.tex - - TeX document describing implementation of Multiprocessor Linux + - LaTeX document describing implementation of Multiprocessor Linux smp.txt - a few more notes on symmetric multi-processing sound/ @@ -127,6 +151,8 @@ - info on using the Stallion multiport serial driver. svga.txt - short guide on selecting video modes at boot via VGA BIOS. +sx.txt + - info on the Specialix SX/SI multiport serial driver. sysctl/ - directory with info on the /proc/sys/* files sysrq.txt @@ -135,6 +161,8 @@ - how to use name translation to ease use of diskless systems. unicode.txt - info on the Unicode character/font mapping used in Linux. +video4linux/ + - directory with info regarding video/TV/radio cards and linux. watchdog.txt - how to auto-reboot Linux if it has "fallen and can't get up". ;-) xterm-linux.xpm diff -u --recursive --new-file v2.3.14/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.14/linux/Documentation/Changes Fri Aug 6 10:44:11 1999 +++ linux/Documentation/Changes Mon Aug 23 09:56:58 1999 @@ -238,13 +238,12 @@ new /proc/net/dev format. This will also provide support for new features like IPv6. - As of 2.1.102, the IP firewalling code has been replaced; ipfwadm -will no longer work. You need to obtain "ipchains," available from -http://www.rustcorp.com/linux/ipchains/ , and use that instead of -ipfwadm. - - To use masq forwarding you will need to obtain "ipmasqadm," -available from http://juanjox.linuxhq.com/ . + The IP firewalling and NAT code has been replaced again. The +actual modules (including ipfwadm and ipchains backwards-compatibility +modules) are currently distributed separately: see + http://antarctica.penguincomputing.com/~netfilter/ + http://www.samba.org/netfilter/ + http://netfilter.kernenotes.org DHCP clients for 2.0 do not work with the new networking code in the 2.2 kernel. You will need to upgrade your dhcpcd / dhcpclient. diff -u --recursive --new-file v2.3.14/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.14/linux/Documentation/Configure.help Wed Aug 18 10:10:06 1999 +++ linux/Documentation/Configure.help Mon Aug 23 11:15:27 1999 @@ -1379,43 +1379,28 @@ file linux/Documentation/networking/filter.txt for more information. If unsure, say N. -Network firewalls -CONFIG_FIREWALL - A firewall is a computer which protects a local network from the - rest of the world: all traffic to and from computers on the local - net is inspected by the firewall first, and sometimes blocked or - modified. The type of firewall you'll get if you say Y here is - called a "packet filter": it can block network traffic based on - type, origin and destination. By contrast, "proxy-based" firewalls - are more secure but more intrusive and more bothersome to set up; - they inspect the network traffic much more closely, modify it and - have knowledge about the higher level protocols, which packet - filters lack. They also often require changes in the programs - running on the local clients. Proxy-based firewalls don't need - support by the kernel, but they are often combined with packet - filters, which only works if you say Y here. - - If you want to configure your Linux box as a packet filter firewall - for a local network, say Y here. If your local network is TCP/IP - based, you will then also have to say Y to "IP: firewalling", below. - - You also need to say Y here and to "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 to the outside world and avoids the need to allocate - globally valid IP host addresses for the machines on the local net) - and IP transparent proxying (makes the computers on the local - network think they're talking to a remote computer, while in reality - the traffic is redirected by your Linux firewall to a local proxy - server). +Network packet filtering +CONFIG_NETFILTER + Netfilter is a framework for filtering and mangling packets. + Various modules exist for netfilter which replace the previous + masquerading (ipmasqadm), packet filtering (ipchains), transparent + proxying, and portforwarding mechanisms. Enabling this option + makes minor alterations to allow these modules to hook into the + packet stream. More information is available from + http://netfilter.kernelnotes.org (to browse the WWW, you need + to have access to a machine on the Internet that has a program like + lynx or netscape). Make sure to say N to "Fast switching" below if you intend to say Y - here. + here, as Fast switching currently bypasses netfilter. Chances are that you should say Y here for every machine which is run as a router and N for every regular host. If unsure, say N. +Network packet filtering debugging +CONFIG_NETFILTER_DEBUG + Say Y to make sure packets aren't leaking. + SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -1637,32 +1622,6 @@ kernel will try the direct access method and falls back to the BIOS if that doesn't work. If unsure, go with the default. -PCI quirks -CONFIG_PCI_QUIRKS - If you have a broken BIOS, it may fail to set up the PCI bus in a - correct or optimal fashion. Saying Y here will correct that problem. - If your BIOS is fine you can say N here for a very slightly smaller - kernel. If unsure, say Y. - -PCI bridge optimization (experimental) -CONFIG_PCI_OPTIMIZE - This can improve access times for some hardware devices if you have - a really broken BIOS and your computer uses a PCI bus system. Say Y - if you think it might help, but try turning it off if you experience - any problems with the PCI bus. N is the safe answer. - -Backward-compatible /proc/pci -CONFIG_PCI_OLD_PROC - Older kernels supported a /proc/pci file containing brief textual - descriptions of all PCI devices in the system. Several programs - tried to parse this file, so it became almost impossible to add new - fields without breaking compatibility. So a new /proc interface to - PCI (/proc/bus/pci) has been implemented and the old one is - supported for compatibility reasons only; you'll get the old one (in - addition to the new one) if you say Y here and to "/proc filesystem - support", below. If unsure, say Y. If you say N, you'll only get the - new /proc/bus/pci interface. - MCA support CONFIG_MCA MicroChannel Architecture is found in some IBM PS/2 machines and @@ -2609,64 +2568,6 @@ If unsure, say N here. -IP: firewalling -CONFIG_IP_FIREWALL - If you want to configure your Linux box as a packet filter firewall - for a local TCP/IP based network, say Y here. You may want to read - the FIREWALL-HOWTO, available via FTP (user: anonymous) in - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. - - Also, you will need the ipchains tool (available on the WWW at - http://www.rustcorp.com/linux/ipchains/) to allow selective blocking - of Internet traffic based on type, origin and destination. - Note that the Linux firewall code has changed and the old program - called ipfwadm won't work anymore. Please read the IPCHAINS-HOWTO. - - The type of firewall provided by ipchains and this kernel support is - called a "packet filter". The other type of firewall, a - "proxy-based" one, is more secure but more intrusive and more - bothersome to set up; it inspects the network traffic much more - closely, modifies it and has knowledge about the higher level - protocols, which a packet filter lacks. Moreover, proxy-based - firewalls often require changes to the programs running on the local - clients. Proxy-based firewalls don't need support by the kernel, but - they are often combined with a packet filter, which only works if - you say Y here. - - The firewalling code will only work if IP forwarding is enabled in - your kernel. You can do that by saying Y to "/proc filesystem - support" and "Sysctl support" below and executing the line - - echo "1" > /proc/sys/net/ipv4/ip_forward - - at boot time after the /proc filesystem has been mounted. - - You need to say Y to "IP firewalling" in order to be able to use IP - masquerading (masquerading means that 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 to the outside world and avoids the need to allocate - globally valid IP host addresses for the machines on the local net) - and IP packet logging and accounting (keeping track of what is using - all your network bandwidth) and IP transparent proxying (makes the - computers on the local network think they're talking to a remote - computer, while in reality the traffic is redirected by your Linux - firewall to a local proxy server). - - If in doubt, say N here. - -IP: firewall packet netlink device -CONFIG_IP_FIREWALL_NETLINK - If you say Y here, you can use the ipchains tool to copy all or part - of any packet you specify that hits your Linux firewall to optional - user space monitoring software that can then look for attacks and - take actions such as paging the administrator of the site. - - To use this, you need to create a character special file under /dev - with major number 36 and minor number 3 using mknod ("man mknod"), - and you need (to write) a program that reads from that device and - takes appropriate action. - IP: kernel level autoconfiguration CONFIG_IP_PNP This enables automatic configuration of IP addresses of devices and @@ -2736,175 +2637,6 @@ Network), but can be distributed all over the Internet. If you want to do that, say Y here and to "IP: multicast routing" below. -IP: transparent proxying -CONFIG_IP_TRANSPARENT_PROXY - This enables your Linux firewall to transparently redirect any - network traffic originating from the local network and destined - for a remote host to a local server, called a "transparent proxy - server". This makes the local computers think they are talking to - the remote end, while in fact they are connected to the local - proxy. Redirection is activated by defining special input firewall - rules (using the ipchains utility) and/or by doing an appropriate - bind() system call. - -IP: masquerading -CONFIG_IP_MASQUERADE - If one of the computers on your local network for which your Linux - box acts as a firewall wants to send something to the outside, your - box can "masquerade" as that computer, i.e. it forwards the traffic - to the intended outside destination, but makes it look like it came - from the firewall box itself. It works both ways: if the outside - host replies, the Linux firewall will silently forward the traffic - to the corresponding local computer. This way, the computers on your - local net are completely invisible to the outside world, even though - they can reach the outside and can receive replies. This makes it - possible to have the computers on the local network participate on - the Internet even if they don't have officially registered IP - addresses. (This last problem can also be solved by connecting the - Linux box to the Internet using SLiRP [SLiRP is a SLIP/PPP emulator - that works if you have a regular dial up shell account on some UNIX - computer; get it via FTP (user: anonymous) from - ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ].) - - The IP masquerading code will only work if IP forwarding is enabled - in your kernel; you can do this by saying Y to "/proc - filesystem support" and "Sysctl support" below and then executing a - line like - - echo "1" > /proc/sys/net/ipv4/ip_forward - - from a boot time script after the /proc filesystem has been mounted. - - Details on how to set things up are contained in the IP Masquerade - mini-HOWTO, available via FTP (user: anonymous) from - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some - information on the WWW at - http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. - - If you say Y here, then the modules ip_masq_ftp.o (for ftp file - transfers), ip_masq_irc.o (for irc chats), ip_masq_quake.o (you - guessed it), ip_masq_vdolive.o (for VDOLive video connections), - ip_masq_cuseeme.o (for CU-SeeMe broadcasts) and ip_masq_raudio.o - (for RealAudio downloads) will automatically be compiled. They are - needed to make masquerading for these protocols work. Modules are - pieces of code which can be inserted in and removed from the running - kernel whenever you want; read Documentation/modules.txt for - details. - -IP: ICMP masquerading -CONFIG_IP_MASQUERADE_ICMP - The basic masquerade code described for "IP: masquerading" above - only handles TCP or UDP packets (and ICMP errors for existing - connections). This option adds additional support for masquerading - ICMP packets, such as ping or the probes used by the Windows 95 - tracert program. - - If you want this, say Y. - -IP: masquerading special modules support -CONFIG_IP_MASQUERADE_MOD - This provides support for special modules that can modify the - rewriting rules used when masquerading. Please note that this - feature adds a little overhead in the input packet processing chain. - - Examples of such modules are ipautofw (allowing the masquerading of - protocols which don't have their own protocol helpers) and port - forwarding (making an incoming port of a local computer visible - through the masquerading host). - - You will need the user space program "ipmasqadm" to use these - additional modules; you can download it from - http://juanjox.linuxhq.com/ - - All this additional code is still under development and so is - currently marked EXPERIMENTAL. - - If you want to try, for example, PORT FORWARDING, say Y. - -IP: ipautofw masquerade support (Experimental) -CONFIG_IP_MASQUERADE_IPAUTOFW - ipautofw is a program which allows the masquerading of protocols - which do not (as yet) have their own protocol helpers. Information - and source for ipautofw is available via FTP (user: anonymous) from - ftp://ftp.netis.com/pub/members/rlynch/ - - You will also need the ipmasqadm tool available from - http://juanjox.linuxhq.com/ . - - The ipautofw code is still under development and so is currently - marked EXPERIMENTAL. If you want to try it, say Y. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ip_masq_autofw.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. - -IP: ipportfw masquerade support -CONFIG_IP_MASQUERADE_IPPORTFW - Port Forwarding is an addition to IP Masquerading which allows some - forwarding of packets from outside to inside a firewall on given - ports. This could be useful if, for example, you want to run a web - server behind the firewall or masquerading host and that web server - should be accessible from the outside world. An external client - sends a request to port 80 of the firewall, the firewall forwards - this request to the web server, the web server handles the request - and the results are sent through the firewall to the original - client. The client thinks that the firewall machine itself is - running the web server. This can also be used for load balancing if - you have a farm of identical web servers behind the firewall. - - Information about this feature is available from - http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to - browse the WWW, you need to have access to a machine on the Internet - that has a program like lynx or netscape). For general info, please - see ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/ - - You will need the user space program "ipmasqadm" which can be - downloaded from http://juanjox.linuxhq.com/ - - The portfw code is still under development and so is currently - marked EXPERIMENTAL. If you want to try it, say Y. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ip_masq_portfw.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. - -IP: ipmarkfw masquerade support -CONFIG_IP_MASQUERADE_MFW - Firewall Mark Forwarding provides functionality similar to port - forwarding (see "IP: ipportfw masquerade support", above), the - difference being that Firewall Mark Forwarding uses "firewalling - mark" to select which packets must be forwarded (see ipchains(8), - "-m" argument). - - This code is still under development and so is currently marked - EXPERIMENTAL. If you want to try it, say Y. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ip_masq_markfw.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. - -IP: always defragment (required for masquerading) -CONFIG_IP_ALWAYS_DEFRAG - If you say Y here, then all incoming fragments (parts of IP packets - that arose when some host between origin and destination decided - that the packets were too large and cut them into pieces) will be - reassembled (defragmented) before being processed, even if they are - about to be forwarded. - - You must say Y here if you want to enable "IP: masquerading" or "IP: - transparent proxying". - - When using "IP: firewalling" support, you might also want to say Y - here, to have a more reliable firewall (otherwise second and further - fragments must be dealt with by the firewall, which can be tricky). - - Only say Y here if running either a firewall that is the sole link - to your network or a transparent proxy; never ever say Y here for a - normal router or host. - IP: aliasing support CONFIG_IP_ALIAS Sometimes it is useful to give several IP addresses to a single @@ -3081,8 +2813,8 @@ IPv6, see http://playground.sun.com/pub/ipng/html/ipng-main.html (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape); for specific information - about IPv6 under Linux read the HOWTO at http://www.terra.net/ipv6/ - and the file net/ipv6/README in the kernel source. + about IPv6 under Linux read http://www.bieringer.de/linux/IPv6/ and + the file net/ipv6/README in the kernel source. If you want to use IPv6, please upgrade to the newest net-tools as given in Documentation/Changes. You will still be able to do regular @@ -3807,14 +3539,12 @@ able to read from and write to character special files in the /dev directory having major mode 36. So far, the kernel uses it to publish some network related information if you say Y to "Routing - messages", below. It is also used by the firewall code to publish - information about possible attacks if you say Y to "IP: firewall - packet netlink device" further down. You also need to say Y here 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. The ethertap device, which lets user space - programs read and write raw Ethernet frames, also needs the network - link driver. If unsure, say Y. + messages", below. You also need to say Y here 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. The ethertap device, which lets user space programs read and + write raw Ethernet frames, also needs the network link driver. If + unsure, say Y. Routing messages CONFIG_RTNETLINK @@ -3829,6 +3559,198 @@ This is a backward compatibility option, choose Y for now. This option will be removed soon. +Asynchronous Transfer Mode (ATM) +CONFIG_ATM + Kernel support for ATM. Note that you need a set of user-space programs + to actually make use of ATM. See http://lrcwww.epfl.ch/linux-atm/ for + further details. + +Classical IP over ATM +CONFIG_ATM_CLIP + Classical IP over ATM for PVCs and SVCs, supporting InARP and ATMARP. + Typically you will either use LAN Emulation (LANE) or Classical IP to + communicate with other IP hosts on your ATM network. + +Do NOT send ICMP if no neighbour +CONFIG_ATM_CLIP_NO_ICMP + Normally, an ICMP host unreachable message is sent if a neighbour cannot + be reached because there is no VC to it in the kernel's ATMARP table. + This may cause problems when ATMARP table entries are briefly removed + during revalidation. If this configuration option is set to "yes", + packets to such neighbours are silently discarded instead. + +LAN Emulation (LANE) support +CONFIG_ATM_LANE + LAN Emulation emulates services of existing LANs across an ATM network. + Besides operating as a normal ATM end station client, Linux LANE client + can also act as an proxy client bridging packets between ELAN and + Ethernet segments. You need LANE if you want to try MPOA. + +Multi-Protocol Over ATM (MPOA) support +CONFIG_ATM_MPOA + Multi-Protocol Over ATM allows ATM edge devices such as routers, + bridges and ATM attached hosts establish direct ATM VCs across + subnetwork boundaries. These shortcut connections bypass routers + enhancing overall network performance. + + +Application REQUested IP over ATM +CONFIG_AREQUIPA + Arequipa is a mechanism to create ATM connections under application + control for IP traffic. See RFC2170 for details. + +ATM over TCP +CONFIG_ATM_TCP + ATM over TCP driver. Useful mainly for development and for experiments. + +Efficient Networks ENI155P +CONFIG_ATM_ENI + Driver for the Efficient Networks ENI155p series and SMC ATM Power155 + 155 Mbps ATM adapters. Both, the versions with 512kB and 2MB on-board + RAM (Efficient calls them "C" and "S", respectively), and the FPGA and + the ASIC Tonga versions of the board are supported. The driver works + with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) adapters. + +Enable extended debugging +CONFIG_ATM_ENI_DEBUG + Extended debugging records various events and displays that list when + an inconsistency is detected. This mechanism is faster than generally + using printks, but still has some impact on performance. Note that + extended debugging may create certain race conditions itself. Enable + this ONLY if you suspect problems with the driver. + +Fine-tune burst settings +CONFIG_ATM_ENI_TUNE_BURST + In order to obtain good throughput, the ENI NIC can transfer multiple + words of data per PCI bus access cycle. Such a multi-word transfer is + called a burst. + + The default settings for the burst sizes are suitable for most PCI + chipsets. However, in some cases, large bursts may overrun buffers in + the PCI chipset and cause data corruption. In such cases, large bursts + must be disabled and only (slower) small bursts can be used. The burst + sizes can be set independently in the send (TX) and receive (RX) + direction. + + Note that enabling many different burst sizes in the same direction + may increase the cost of setting up a transfer such that the resulting + throughput is lower than when using only the largest available burst + size. + + Also, sometimes larger bursts lead to lower throughput, e.g. on an + Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed when + going from 8W to 16W bursts. + +Enable 16W TX bursts (discouraged) +CONFIG_ATM_ENI_BURST_TX_16W + Burst sixteed words at once in the send direction. This may work with + recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W TX bursts (recommended) +CONFIG_ATM_ENI_BURST_TX_8W + Burst eight words at once in the send direction. This is the default + setting. + +Enable 4W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_4W + Burst four words at once in the send direction. You may want to try this + if you have disabled 8W bursts. Enabling 4W if 8W is also set may or may + not improve throughput. + +Enable 2W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_2W + Burst two words at once in the send direction. You may want to try this + if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W are also + set may or may not improve throughput. + +Enable 16W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_16W + Burst sixteen words at once in the receive direction. This may work with + recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_8W + Burst eight words at once in the receive direction. This may work with + recent PCI chipsets, but is known to fail with older chipsets, such as + the Intel Neptune series. + +Enable 4W RX bursts (recommended) +CONFIG_ATM_ENI_BURST_RX_4W + Burst four words at once in the receive direction. This is the default + setting. Enabling 4W if 8W is also set may or may not improve throughput. + +Enable 2W RX bursts (optional) +CONFIG_ATM_ENI_BURST_RX_2W + Burst two words at once in the receive direction. You may want to try + this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W are + also set may or may not improve throughput. + +ZeitNet ZN1221/ZN1225 +CONFIG_ATM_ZATM + Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM + adapters. + +Enable extended debugging +CONFIG_ATM_ZATM_DEBUG + Extended debugging records various events and displays that list when + an inconsistency is detected. This mechanism is faster than generally + using printks, but still has some impact on performance. Note that + extended debugging may create certain race conditions itself. Enable + this ONLY if you suspect problems with the driver. + +Enable usec resolution timestamps +CONFIG_ATM_ZATM_EXACT_TS + The uPD98401 SAR chip supports a high-resolution timer (approx. 30 MHz) + that is used for very accurate reception timestamps. Because that timer + overflows after 140 seconds, and also to avoid timer drift, time + measurements need to be periodically synchronized with the normal + system time. Enabling this feature will add some general overhead for + timer synchronization and also per-packet overhead for time conversion. + +IDT 77201 (NICStAR) +CONFIG_ATM_NICSTAR + The NICStAR chipset family is used in a large number of ATM NICs for + 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE + series. + +Madge Ambassador (Collage PCI 155 Server) +CONFIG_ATM_AMBASSADOR + This is a driver for ATMizer based ATM card produced by Madge + Networks Ltd. Say Y (or M to compile as a module named ambassador.o) + here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_AMBASSADOR_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + drivers/atm/ambassador.h for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client) +CONFIG_ATM_HORIZON + This is a driver for the Horizon chipset ATM adapter cards once + produced by Madge Networks Ltd. Say Y (or M to compile as a module + named horizon.o) here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_HORIZON_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + drivers/atm/horizon.h for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -5549,7 +5471,7 @@ Card) data transfers, which is fast. *** This option is NOT COMPATIBLE with several important *** - *** networking options: especially CONFIG*FIREWALL. *** + *** networking options: especially CONFIG_NETFILTER. *** *** Say N here if you intend to use Linux as a firewall. *** However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER @@ -10153,6 +10075,15 @@ Leave the default 200 unless you have a joystick not attached to your sound card. +ESS Solo1 based PCI sound cards (eg. SC1938) +CONFIG_SOUND_ESSSOLO1 + Say Y or M if you have a PCI sound card utilizing the ESS Technology + Solo1 chip. To find out if your sound card uses a + Solo1 chip without removing your computer's cover, use + lspci -n and look for the PCI ID 125D:1969. This driver + differs slightly from OSS/Free, so PLEASE READ + Documentation/sound/solo1. + S3 SonicVibes based PCI sound cards CONFIG_SOUND_SONICVIBES Say Y or M if you have a PCI sound card utilizing the S3 @@ -12078,7 +12009,7 @@ It is safe to say N to this -- it is not needed for normal printing or parallel port CD-ROM/disk support. -Kernel httpd acceleration (expirimental) +Kernel httpd acceleration (experimental) CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) webserver build into the kernel. It is limited since it can only @@ -12089,7 +12020,7 @@ Before using this, read the README in /usr/src/linux/net/khttpd ! - The kHTTPd is expirimental. Be careful when using it on a production + The kHTTPd is experimental. Be careful when using it on a production machine. Also note that kHTTPd doesn't support virtual servers yet. diff -u --recursive --new-file v2.3.14/linux/Documentation/atm.txt linux/Documentation/atm.txt --- v2.3.14/linux/Documentation/atm.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/atm.txt Mon Aug 23 09:56:31 1999 @@ -0,0 +1,4 @@ +In order to use anything but the most primitive functions of ATM, +several user-mode programs are required to assist the kernel. These +programs and related material can be found via the ATM on Linux Web +page at http://icawww1.epfl.ch/linux-atm/ diff -u --recursive --new-file v2.3.14/linux/Documentation/computone.txt linux/Documentation/computone.txt --- v2.3.14/linux/Documentation/computone.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/computone.txt Mon Aug 23 10:23:23 1999 @@ -0,0 +1,343 @@ + +Computone Intelliport II/Plus Multiport Serial Driver +----------------------------------------------------- + +Release Notes For Linux Kernel 2.2 and higher. +These notes are for the drivers which have already been integrated into the +kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3. + +Version: 1.2.4 +Date: 08/04/99 +Author: Andrew Manison +Testing: larryg@computone.com +Support: support@computone.com +Fixes and Updates: Doug McNash +Proc Filesystem and Kernel Integration: Mike Warfield + + +This file assumes that you are using the Computone drivers which are +integrated into the kernel sources. For updating the drivers or installing +drivers into kernels which do not already have Computone drivers, please +refer to the instructions in the README.computone file in the driver patch. + + +1. INTRODUCTION + +This driver supports the entire family of Intelliport II/Plus controllers +with the exception of the MicroChannel controllers. It does not support +products previous to the Intelliport II. + +This driver was developed on the v2.0.x Linux tree and has been tested up +to v2.2.9; it will probably not work with earlier v1.X kernels,. + + +2. QUICK INSTALLATION + +Hardware - If you have an ISA card, find a free interrupt and io port. + List those in use with `cat /proc/interrupts` and + `cat /proc/ioports`. Set the card dip switches to a free + address. You may need to configure your BIOS to reserve an + irq for an ISA card. PCI and EISA parameters are set + automagically. Insert card into computer with the power off + before or after drivers installation. + + Note the hardware address from the Computone ISA cards installed into + the system. These are required for editing ip2.h or editing + /etc/config.modules, or for specification on the modprobe + command line. + +Software - + +Module installation: + +a) Obtain driver-kernel patch file +b) Copy to the linux source tree root, Run ip2build (if not patch) +c) Determine free irq/address to use if any (configure BIOS if need be) +d) Run "make config" or "make menuconfig" or "make xconfig" + Select (m) module for CONFIG_COMPUTONE under character + devices. CONFIG_PCI and CONFIG_MODULES also may need to be set. +e) Set address on ISA cards then: + edit /usr/src/linux/drivers/char/ip2/ip2.h if needed + or + edit /etc/conf.modules (or /etc/modules.conf) if needed (module). + or both to match this setting. +f) Run "make dep" +g) Run "make modules" +h) Run "make modules_install" +i) Run "/sbin/depmod -a" +j) install driver using `modprobe ip2 ` (options listed below) +k) run ip2mkdev (either the script below or the binary version) + + +Kernel installation: + +a) Obtain driver-kernel patch file +b) Copy to the linux source tree root, Run ip2build (if not patch) +c) Determine free irq/address to use if any (configure BIOS if need be) +d) Run "make config" or "make menuconfig" or "make xconfig" + Select (y) kernel for CONFIG_COMPUTONE under character + devices. CONFIG_PCI may need to be set if you have PCI bus. +e) Set address on ISA cards then: + edit /usr/src/linux/drivers/char/ip2/ip2.h +f) Run "make dep" +g) Run "make zImage" or whatever target you prefer. +h) mv /usr/src/linux/arch/i386/boot/zImage to /boot. +i) Add new config for this kernel into /etc/lilo.conf, run "lilo" + or copy to a floppy disk and boot from that floppy disk. +j) Reboot using this kernel +k) run ip2mkdev (either the script below or the binary version) + + +3. INSTALLATION + +Previously, the driver sources were packaged with a set of patch files +to update the character drivers' makefile and configuration file, and other +kernel source files. A build script (ip2build) was included which applies +the patches if needed, and build any utilities needed. +What you recieve may be a single patch file in conventional kernel +patch format build script. That form can also be applied by +running patch -p1 < ThePatchFile. Otherwise run ip2build. + +The driver can be installed as a module (recommended) or built into the +kernel. This is selected as for other drivers through the `make config` +command from the root of the Linux source tree. If the driver is built +into the kernel you will need to edit the file ip2.h to match the boards +you are installing. See that file for instructions. If the driver is +installed as a module the configuration can also be specified on the +modprobe command line as follows: + + modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4 + +where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11, +12,15) and addr1-4 are the base addresses for up to four controllers. If +the irqs are not specified the driver uses the default in ip2/ip2.h (which +selects polled mode). If no base addresses are specified the defaults in +ip2.h are used. If you are autoloading the driver module with kerneld or +kmod the base addresses and interrupt number must also be set in ip2/ip2.h +and recompile or just insert and options line in /etc/modules.conf or both. +The options line is equivalent to the command line and takes precidence over +what is in ip2.h. + +/etc/modules.conf sample: + options ip2 io=1,0x328 irq=1,10 + alias char-major-71 ip2 + alias char-major-72 ip2 + alias char-major-73 ip2 + +equivelant ip2.h: +static ip2config_t ip2config = +{ + {1,10,0,0}, + { + 0x0001, // Board 0, ttyF0 - ttyF63 /* PCI card */ + 0x0328, // Board 1, ttyF64 - ttyF127 /* ISA card */ + 0x0000, // Board 2, ttyF128 - ttyF191 /* empty */ + 0x0000 // Board 3, ttyF192 - ttyF255 /* empty */ + } +}; + + +Note: Both io and irq should be updated to reflect YOUR system. An "io" + address of "1/2" indicates a PCI/EISA card in the board table. The + PCI or EISA irq will be assigned automatically. + +Specifying an invalid or in-use irq will default the driver into +running in polled mode for that card. If all irq entries are 0 then +all cards will operate in polled mode. + +If you select the driver as part of the kernel run : + + make depend + make zlilo (or whatever you do to create a bootable kernel) + +If you selected a module run : + + make modules && make modules_install + +The utility ip2mkdev (see 5 and 7 below) creates all the device nodes +required by the driver. For a device to be created it must be configured +in the driver and the board must be installed. Only devices corresponding +to real IntelliPort II ports are created. With multiple boards and expansion +boxes this will leave gaps in the sequence of device names. ip2mkdev uses +Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and +cuf0 - cuf255 for callout devices. + + +4. USING THE DRIVERS + +As noted above, the driver implements the ports in accordance with Linux +conventions, and the devices should be interchangeable with the standard +serial devices. (This is a key point for problem reporting: please make +sure that what you are trying do works on the ttySx/cuax ports first; then +tell us what went wrong with the ip2 ports!) + +Higher speeds can be obtained using the setserial utility which remaps +38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. +Intelliport II installations using the PowerPort expansion module can +use the custom speed setting to select the highest speeds: 153,600 bps, +230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for +custom baud rate configuration is fixed at 921,600 for cards/expantion +modules with ST654's and 115200 for those with Cirrus CD1400's. This +corresponds to the maximum bit rates those chips are capable. +For example if the baud base is 921600 and the baud divisor is 18 then +the custom rate is 921600/18 = 51200 bps. See the setserial man page for +complete details. Of course if stty accepts the higher rates now you can +use that as well as the standard ioctls(). + + +5. ip2mkdev and assorted utilities... + +Several utilities, including the source for a binary ip2mkdev utility are +available under .../drivers/char/ip2. These can be build by changing to +that directory and typing "make" after the kernel has be built. If you do +not wish to compile the binary utilities, the shell script below can be +cut out and run as "ip2mkdev" to create the necessary device files. To +use the ip2mkdev script, you must have procfs enabled and the proc file +system mounted on /proc. + +6. NOTES + +This is a release version of the driver, but it is impossible to test it +in all configurations of Linux. If there is any anomalous behaviour that +does not match the standard serial port's behaviour please let us know. + + +7. ip2mkdev shell script + +===== Cut Here ===== +#!/bin/sh - + +# ip2mkdev +# +# Make or remove devices as needed for Computone Intelliport drivers +# +# First rule! If the dev file exists and you need it, don't mess +# with it. That prevents us from screwing up open ttys, ownership +# and permissions on a running system! +# +# This script will NOT remove devices that no longer exist because +# their board or interface box has been removed. If you want to get +# rid of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*" +# before running this script, which will then recreate all the valid +# devices +# +# =mhw= +# Michael H. Warfield +# mhw@wittsend.com +# +if test ! -f /proc/tty/drivers +then + echo "\ +Unable to check driver status. +Make sure proc file system is mounted." + + exit 255 +fi + +if test ! -f /proc/tty/driver/ip2 +then + echo "\ +Unable to locate ip2 proc file. +Attempting to load driver" + + if insmod ip2 + then + if test ! -f /proc/tty/driver/ip2 + then + echo "\ +Unable to locate ip2 proc file after loading driver. +Driver initialization failure or driver version error. +" + exit 255 + fi + else + echo "Unable to load ip2 driver." + exit 255 + fi +fi + +# Ok... So we got the driver loaded and we can locate the procfs files. +# Next we need our major numbers. + +TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tty/!d' -e 's/.*tty.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` +CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` +BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2` + +echo "\ +TTYMAJOR = $TTYMAJOR +CUAMAJOR = $CUAMAJOR +BRDMAJOR = $BRDMAJOR +" + +# Ok... Now we should know our major numbers, if appropriate... +# Now we need our boards and start the device loops. + +grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest +do + # The test for blank "type" will catch the stats lead-in lines + # if they exist in the file + if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = "" + then + continue + fi + + BOARDNO=`expr "$number" : '\([0-9]\):'` + PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '` + MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '` + + if test "$BOARDNO" = "" -o "$PORTS" = "" + then +# This may be a bug. We should at least get this much information + echo "Unable to process board line" + continue + fi + + if test "$MINORS" = "" + then +# Silently skip this one. This board seems to have no boxes + continue + fi + + echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS" + + if test "$BRDMAJOR" != "" + then + BRDMINOR=`expr $BOARDNO \* 4` + STSMINOR=`expr $BRDMINOR + 1` + if test ! -c /dev/ip2ipl$BOARDNO ; then + mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR + fi + if test ! -c /dev/ip2stat$BOARDNO ; then + mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR + fi + fi + + if test "$TTYMAJOR" != "" + then + PORTNO=$BOARDBASE + + for PORTNO in $MINORS + do + if test ! -c /dev/ttyF$PORTNO ; then + # We got the harware but no device - make it + mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO + fi + done + fi + + if test "$CUAMAJOR" != "" + then + PORTNO=$BOARDBASE + + for PORTNO in $MINORS + do + if test ! -c /dev/cuf$PORTNO ; then + # We got the harware but no device - make it + mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO + fi + done + fi +done + +exit 0 +===== Cut Here ===== diff -u --recursive --new-file v2.3.14/linux/Documentation/fb/00-INDEX linux/Documentation/fb/00-INDEX --- v2.3.14/linux/Documentation/fb/00-INDEX Wed Jun 24 14:44:00 1998 +++ linux/Documentation/fb/00-INDEX Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ Index of files in Documentation/fb. If you think something about frame buffer devices needs an entry here, needs correction or you've written one please mail me. - Geert Uytterhoeven - + Geert Uytterhoeven 00-INDEX - this file diff -u --recursive --new-file v2.3.14/linux/Documentation/fb/framebuffer.txt linux/Documentation/fb/framebuffer.txt --- v2.3.14/linux/Documentation/fb/framebuffer.txt Wed Nov 25 14:53:51 1998 +++ linux/Documentation/fb/framebuffer.txt Thu Aug 19 10:54:10 1999 @@ -1,7 +1,7 @@ The Frame Buffer Device ----------------------- -Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) +Maintained by Geert Uytterhoeven Last revised: November 7, 1998 diff -u --recursive --new-file v2.3.14/linux/Documentation/fb/internals.txt linux/Documentation/fb/internals.txt --- v2.3.14/linux/Documentation/fb/internals.txt Mon Oct 5 13:39:20 1998 +++ linux/Documentation/fb/internals.txt Thu Aug 19 10:54:10 1999 @@ -2,7 +2,7 @@ This is a first start for some documentation about frame buffer device internals. -Geert Uytterhoeven , 21 July 1998 +Geert Uytterhoeven , 21 July 1998 -------------------------------------------------------------------------------- diff -u --recursive --new-file v2.3.14/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.3.14/linux/Documentation/ioctl-number.txt Fri Feb 20 17:54:35 1998 +++ linux/Documentation/ioctl-number.txt Mon Aug 23 09:56:31 1999 @@ -130,3 +130,5 @@ 0xA3 90-9F DoubleTalk driver in development: 0xAB 00-06 Network block device +0xAD 00 Netfilter device in development: + diff -u --recursive --new-file v2.3.14/linux/Documentation/isapnp.txt linux/Documentation/isapnp.txt --- v2.3.14/linux/Documentation/isapnp.txt Sun Aug 15 11:50:35 1999 +++ linux/Documentation/isapnp.txt Mon Aug 23 10:52:02 1999 @@ -90,9 +90,8 @@ --------------------- All ISA PNP configuration registers are accessible via lowlevel -isapnp_cfg_(set|get)_(byte|word|dword) functions. +isapnp_(read|write)_(byte|word|dword) functions. -Before any lowlevel function The function isapnp_cfg_begin() must be called before any lowlevel function. The function isapnp_cfg_end() must be always called after configuration otherwise the access to the ISA PnP configuration functions will be blocked. @@ -129,10 +128,12 @@ return -ENODEV; if (dev->prepare(dev)<0) return -EAGAIN; + if (!(dev->resource[0].flags & IORESOURCE_IO)) + return -ENODEV; if (!dev->ro) { /* override resource */ if (user_port != USER_PORT_AUTO_VALUE) - dev->resource[0].start = user_port; + isapnp_resource_change(&dev->resource[0], user_port, 1); } if (dev->activate(dev)<0) { printk("isapnp configure failed (out of resources?)\n"); diff -u --recursive --new-file v2.3.14/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.3.14/linux/Documentation/isdn/INTERFACE Thu Aug 12 09:42:33 1999 +++ linux/Documentation/isdn/INTERFACE Wed Aug 25 15:18:07 1999 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.13 1999/08/11 20:30:26 armin Exp $ +$Id: INTERFACE,v 1.15 1999/08/25 20:02:13 werner Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -436,6 +436,57 @@ arg = unused. parm = unused. + ISDN_CMD_PROCEED: + + With this command, the HL-driver is told to proceed with a incoming call. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_PROCEED + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 with + PROCEED message + + ISDN_CMD_ALERT: + + With this command, the HL-driver is told to alert a proceeding call. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_ALERT + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 with + ALERT message + + ISDN_CMD_REDIR: + + With this command, the HL-driver is told to redirect a call in proceeding + or alerting state. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_REDIR + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 protocol + setup.screen= screening indicator + setup.phone = redirected to party number + + ISDN_CMD_PROT_IO: + + With this call, the LL-driver invokes protocol specific features through + the LL. + The call is not implicitely bound to a connection. + + Parameter: + driver = driver-Id + command = ISDN_CMD_PROT_IO + arg = The lower 8 Bits define the adressed protocol as defined + in ISDN_PTYPE..., the upper bits are used to differenciate + the protocol specific CMD. + + para = protocol and function specific. See isdnif.h for detail. + + ISDN_CMD_FAXCMD: With this command the HL-driver receives a fax sub-command. @@ -471,34 +522,44 @@ parm = unused. ISDN_STAT_ICALL: + ISDN_STAT_ICALLW: With this call, the HL-driver signals an incoming call to the LL. + If ICALLW is signalled the incoming call is a waiting call without + a available B-chan. Parameter: driver = driver-Id command = ISDN_STAT_ICALL arg = channel-number, locally to the driver. (starting with 0) - parm.setup.phone = Callernumber. - parm.setup.eazmsn = CalledNumber. - parm.setup.si1 = Service Indicator. - parm.setup.si2 = Additional Service Indicator. - parm.setup.plan = octet 3 from Calling party number Information Element. - parm.setup.screen = octet 3a from Calling party number Information Element. + para.setup.phone = Callernumber. + para.setup.eazmsn = CalledNumber. + para.setup.si1 = Service Indicator. + para.setup.si2 = Additional Service Indicator. + para.setup.plan = octet 3 from Calling party number Information Element. + para.setup.screen = octet 3a from Calling party number Information Element. Return: 0 = No device matching this call. 1 = At least one device matching this call (RING on ttyI). HL-driver may send ALERTING on the D-channel in this case. 2 = Call will be rejected. - 3 = Incomplete number. - The CalledNumber would match, if more digits are appended. - This feature is needed for Number-Blocks assigned to - a line. In this case, the LL driver should assemble the - CalledNumber by handling keypad protocol and try again - later with a longer CalledNumber. - HL drivers serving ordinary lines should interpret this - return code like 0 (nothing matches). + 3 = Incoming called party number is currently incomplete. + Additional digits are required. + Used for signalling with PtP connections. + 4 = Call will be held in a proceeding state + (HL driver sends PROCEEDING) + Used when a user space prog needs time to interpret a call + para.setup.eazmsn may be filled with an uus1 message of + 30 octets maximum. Empty string if no uus. + 5 = Call will be actively deflected to another party + Only available in DSS1/EURO protocol + para.setup.phone must be set to destination party number + para.setup.eazmsn may be filled with an uus1 message of + 30 octets maximum. Empty string if no uus. -1 = An error happened. (Invalid parameters for example.) + The keypad support now is included in the dial command. + ISDN_STAT_RUN: @@ -654,19 +715,31 @@ arg = channel-number, locally to the driver. (starting with 0) parm.num = ASCII string containing CAUSE-message. - ISDN_STAT_L1ERR: + ISDN_STAT_DISPLAY: - ***CHANGEI1.21 new status message. - A signal can be sent to the linklevel if an Layer1-error results in - packet-loss on receive or send. The field errcode of the cmd.parm - union describes the error more precisely. + With this call, the HL-driver delivers DISPLAY-messages to the LL. + Currently the LL does not use this messages. Parameter: driver = driver-Id - command = ISDN_STAT_L1ERR + command = ISDN_STAT_DISPLAY arg = channel-number, locally to the driver. (starting with 0) - parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. - ISDN_STAT_L1ERR_RECV: Packet lost while receiving. + para.display= string containing DISPLAY-message. + + ISDN_STAT_PROT: + + With this call, the HL-driver delivers protocol specific infos to the LL. + The call is not implicitely bound to a connection. + + Parameter: + driver = driver-Id + command = ISDN_STAT_PROT + arg = The lower 8 Bits define the adressed protocol as defined + in ISDN_PTYPE..., the upper bits are used to differenciate + the protocol specific STAT. + + para = protocol and function specific. See isdnif.h for detail. + ISDN_STAT_DISCH: With this call, the HL-driver signals the LL to disable or enable the @@ -683,7 +756,20 @@ command = ISDN_STAT_DISCH arg = channel-number, locally to the driver. (starting with 0) parm.num[0] = 0 if channel shall be disabled, else enabled. - + + ISDN_STAT_L1ERR: + + ***CHANGEI1.21 new status message. + A signal can be sent to the linklevel if an Layer1-error results in + packet-loss on receive or send. The field errcode of the cmd.parm + union describes the error more precisely. + + Parameter: + driver = driver-Id + command = ISDN_STAT_L1ERR + arg = channel-number, locally to the driver. (starting with 0) + parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. + ISDN_STAT_L1ERR_RECV: Packet lost while receiving. ISDN_STAT_FAXIND: With this call the HL-driver signals a fax sub-command to the LL. diff -u --recursive --new-file v2.3.14/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.3.14/linux/Documentation/isdn/README.HiSax Thu Aug 12 09:42:33 1999 +++ linux/Documentation/isdn/README.HiSax Wed Aug 25 15:18:07 1999 @@ -55,7 +55,8 @@ ith Kommunikationstechnik GmbH MIC 16 ISA card Traverse Technologie NETjet PCI S0 card Dr. Neuhaus Niccy PnP/PCI -Siemens I-Surf +Siemens I-Surf 1.0 +Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) ACER P10 HST Saphir Berkom Telekom A4T @@ -173,7 +174,7 @@ 27 AVM PnP (Fritz!PnP) irq, io (from isapnp setup) 27 AVM PCI (Fritz!PCI) no parameter 28 Sedlbauer Speed Fax+ irq, io (from isapnp setup) - 29 Siemens I-Surf irq, io, memory (from isapnp setup) + 29 Siemens I-Surf 1.0 irq, io, memory (from isapnp setup) 30 ACER P10 irq, io (from isapnp setup) 31 HST Saphir irq, io 32 Telekom A4T none @@ -276,7 +277,7 @@ 27 AVM PnP (Fritz!PnP) ONLY WORKS AS A MODULE ! 27 AVM PCI (Fritz!PCI) no parameter 28 Sedlbauer Speed Fax+ ONLY WORKS AS A MODULE ! - 29 Siemens I-Surf ONLY WORKS AS A MODULE ! + 29 Siemens I-Surf 1.0 ONLY WORKS AS A MODULE ! 30 ACER P10 ONLY WORKS AS A MODULE ! 31 HST Saphir pa=irq, pb=io 32 Telekom A4T no parameter diff -u --recursive --new-file v2.3.14/linux/Documentation/mkdev.ida linux/Documentation/mkdev.ida --- v2.3.14/linux/Documentation/mkdev.ida Wed Dec 31 16:00:00 1969 +++ linux/Documentation/mkdev.ida Mon Aug 23 10:23:23 1999 @@ -0,0 +1,40 @@ +#!/bin/sh +# Script to create device nodes for SMART array controllers +# Usage: +# mkdev.ida [num controllers] [num log volumes] [num partitions] +# +# With no arguments, the script assumes 1 controller, 16 logical volumes, +# and 16 partitions/volume, which is adequate for most configurations. +# +# If you had 5 controllers and were planning on no more than 4 logical volumes +# each, using a maximum of 8 partitions per volume, you could say: +# +# mkdev.ida 5 4 8 +# +# Of course, this has no real benefit over "mkdev.ida 5" except that it +# doesn't create so many device nodes in /dev/ida. + +NR_CTLR=${1-1} +NR_VOL=${2-16} +NR_PART=${3-16} + +if [ ! -d /dev/ida ]; then + mkdir -p /dev/ida +fi + +C=0; while [ $C -lt $NR_CTLR ]; do + MAJ=`expr $C + 72` + D=0; while [ $D -lt $NR_VOL ]; do + P=0; while [ $P -lt $NR_PART ]; do + MIN=`expr $D \* 16 + $P` + if [ $P -eq 0 ]; then + mknod /dev/ida/c${C}d${D} b $MAJ $MIN + else + mknod /dev/ida/c${C}d${D}p${P} b $MAJ $MIN + fi + P=`expr $P + 1` + done + D=`expr $D + 1` + done + C=`expr $C + 1` +done diff -u --recursive --new-file v2.3.14/linux/Documentation/networking/README.sb1000 linux/Documentation/networking/README.sb1000 --- v2.3.14/linux/Documentation/networking/README.sb1000 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/README.sb1000 Mon Aug 23 10:10:29 1999 @@ -0,0 +1,133 @@ +This is the new release of a module network device driver for General +Instruments (also known as NextLevel) SB1000 cable modem board (also +called internal SURFboard). +I have tested and I am running this module on kernel 2.0.33. +Steven N. Hirsch gave me a diff patch +(sb1000-1.1.2_127.patch to be applied with 'patch -p') that allows +you to compile and run the driver with kernel versions 2.1.x. +Thanks very much Steve! + +Here you'll the following files: + +- README +- Makefile +- sb1000.c the actual device driver +- cmconfig.c an ifconfig-like program to correctly set the SB1000 +- cmping.c a ping-like program to test your connection +- ftptest.c a small program to test your connection speed with FTP + (requires ftplib version >= 3.0) + +The directory ppp/ contains the files I am using to connect to MediaOne +here in Jacksonville, to show how you can use the driver and the cmconfig +program. + +Clemmitt Sigler wrote a very good and useful web page and installation +script (for Adelphia PowerLink users but easy to port to other ISPs) +about this SB1000 driver for Linux. +You can find it here: + http://home.adelphia.net/~siglercm/sb1000.html +Thanks very much Clemmitt! + +To install and run it: +- cd sb1000-1.1.2 +- make +- make install +- configure the SB1000 card using the isapnp tools setting the correct + I/O's and IRQ. You can find more info about the isapnp tools at: + http://www.roestock.demon.co.uk/isapnptools/ + (once you're happy with it, you may want to set the configuration + at boot time in one of the /etc/init.d/ scripts) + IMPORTANT NOTICE: after configuring isapnp, please look in the file + /etc/isapnp.conf for the line beginning with: + (READPORT + if it says: '(READPORT 0x0203)' (which should be the default), then + go to the next step. If instead it says something like: + '(READPORT 0x020b)' or '(READPORT 0x)', then please + follow the instructions at the end of this README file before going + to the next step. +- install the PPP configuration files in the /etc/ppp directory; you + definitely have to change the file ppp@gi-on (the start up file), + setting the correct login name, the phone number for the PPP connection + and the frequency (k stands for kHz, M for MHz) for the cablemodem. + You'll also have to change the last line in the pap-secrets file + writing your login and password there (read the whole file for more + site specific configurations). + You may have to change the firewall file to suit your needs (IPs and + ports allowed to connect). +- start the PPP connection with ppp@gi-on and see what happens; you may + want to set 'pppd' (the last command in the ppp@gi-on file) to debug + mode adding 'debug' at the end of the command ('pppd' prints its info in + the file /var/log/messages and/or /var/log/ppp.log). To make sure 'chat' + s not having problems you may want to add a '-v' (verbose) after the 'chat' + command in 'ppp-on-dialer' and check the results in /var/log/messages) +- if everything is working fine you should see after a few seconds a message + likes this: + cm0: sb1000 at (0x120,0x310), csn 1, S/N 0x2a0d16d8, IRQ 9. + sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net) + and ifconfig -a should show you two new interfaces: ppp0 and cm0. + Typing 'cmconfig cm0' will show you more info about the cablemodem interface. +- please let me know if you see any other message coming from 'cm0' in + your '/var/log/messages' or '/var/log/debug' file, to help me debug the + code +- also let me know if you have any problem; if everything works (hopefully), + let me know which speed you can reach downloading the 5Mb test file using + this driver. +- if everything seems to work fine but your computer locks up after a while + (and typically during a lengthy download through the cablemodem), you may + need to add a short delay in the driver to 'slow down' the SURFboard + because your PC might not be able to keep up with the transfer rate of + the SB1000. To do this, edit the 'Makefile' and look for the 'SB1000_DELAY' + define: uncomment those 'CFLAGS' lines (and comment the default ones) + and try setting the delay to something like 60 microseconds with: + '-DSB1000_DELAY=60'; if it still doesn't work or you like playing with + the driver, you may try other numbers: remember though that the higher + the delay, the slower the driver (which slows down the rest of the PC + too when it is actively used). Thanks to Ed Daiga for this tip! + +This release has a few things fixed and a better handling of the frame errors. + +I also have slightly modified the 'cablemodem' script in the 'ppp' so +you may interested in having a look at it: I basically have added filtering +out broadcast messages (you shouldn't get them with a point-to-point +interface and so far the ones I have received were from hosts trying to +attack my system) and lower debug levels for the driver to avoid seeing +the 'frame error' messages (so far noone has noticed any problem with the +driver even with those messages). + +For questions, infos, etc, feel free to email me at: + fventuri@mediaone.net + +Good luck, +Franco Venturi + +Thanks to Edge for his useful comments and to Steven N. Hirsch +for his patch to run the driver with 2.1.x kernels. +Thanks also to Ed Daiga for his help in finding that adding a delay +in the driver fixes some lock up problems with some slow PCs. +Many thanks to Clemmitt Sigler for his (much needed) web page about the +SB1000 driver for Linux. +An interesting URL for Linux + MediaOne (although with an external modem) +is: http://rlz.ne.mediaone.net/linux/home.shtml +Today, Sep 22 1998, I finished writing a short utility (ftptest.c) to +'measure' your cablemodem speed connection in Linux, downloading to +memory the same file several times. To compile it you need ftplib, version +3 or above. To run it, type: + ftptest URL n +where URL is in the form: ftp://ftp.site.local.isp/pub/testfile +and n is the number of simultaneous FTP connections that you want to run + +--------------------------------------------------------------------------- +IMPORTANT NOTICE: if in your file /etc/isapnp.conf, you found something +like '(READPORT 0x020b)' or '(READPORT 0x)', (anything +different from the default 0x0203), you have to change the READ_DATA_PORT +parameter in the sb1000.c file as follows. + - edit the sb1000.c file, look for: + READ_DATA_PORT + (it should be around line 127 in version 1.1.2) + - change the value of READ_DATA_PORT to the same value found in + /etc/isapnp.conf; for instance, if you found a: '(READPORT 0x020b)', + then in sb1000.c you should have: + static const int READ_DATA_PORT = 0x20b; + - save sb1000.c + - compile and install again the driver + (i.e. do a 'make' and a 'make install'). diff -u --recursive --new-file v2.3.14/linux/Documentation/networking/ip_masq/ip_masq-API-ex.c linux/Documentation/networking/ip_masq/ip_masq-API-ex.c --- v2.3.14/linux/Documentation/networking/ip_masq/ip_masq-API-ex.c Sun Oct 4 10:21:45 1998 +++ linux/Documentation/networking/ip_masq/ip_masq-API-ex.c Wed Dec 31 16:00:00 1969 @@ -1,77 +0,0 @@ -/* - There is only 1 optname (see setsockopt(2)), IP_FW_MASQ_CTL that - must be used. - Funcionality depends on your kernel CONFIG options, here is - an example you can use to create an ``incoming'' tunnel: - - See "user.c" module under ipmasqadm tree for a generic example - */ -#undef __KERNEL__ /* Makefile lazyness ;) */ -#include -#include -#include -#include -#include -#include - -#include /* For __uXX types */ -#include -#include -#include -#include -#include /* For IP_FW_MASQ_CTL */ -#include /* For specific masq defs */ - - -int create_listening_masq(struct ip_masq_ctl *masq, int proto, u_int32_t src_addr, u_int16_t src_port, u_int32_t dst_addr) -{ - int sockfd; - - sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - - if (sockfd<0) { - perror("socket(RAW)"); - return -1; - } - - memset (masq, 0, sizeof (*masq)); - - /* - * Want user tunnel control - */ - masq->m_target = IP_MASQ_TARGET_USER; - - /* - * Want to insert new - */ - masq->m_cmd = IP_MASQ_CMD_INSERT; - - masq->u.user.protocol = proto; - masq->u.user.saddr = src_addr; - masq->u.user.sport = src_port; - masq->u.user.rt_daddr = inet_addr("192.168.21.239"); - - if (setsockopt(sockfd, IPPROTO_IP, - IP_FW_MASQ_CTL, (char *)masq, sizeof(*masq))) { - perror("setsockopt()"); - return -1; - } - /* masq struct now contains tunnel details */ - fprintf(stderr, "PROTO=%d SRC=0x%X:%x - MASQ=0x%X:%x - DST=0x%X:%x\n", - masq->u.user.protocol, - ntohl(masq->u.user.saddr), ntohs(masq->u.user.sport), - ntohl(masq->u.user.maddr), ntohs(masq->u.user.mport), - ntohl(masq->u.user.daddr), ntohs(masq->u.user.dport)); - return 0; -} - -int main(void) { - struct ip_masq_ctl masq_buf; - - return create_listening_masq(&masq_buf, - IPPROTO_TCP, - inet_addr("192.168.1.4"), - htons(23), - inet_addr("192.168.21.3")); -} - diff -u --recursive --new-file v2.3.14/linux/Documentation/networking/wavelan.txt linux/Documentation/networking/wavelan.txt --- v2.3.14/linux/Documentation/networking/wavelan.txt Fri Aug 28 10:45:29 1998 +++ linux/Documentation/networking/wavelan.txt Mon Aug 23 10:23:23 1999 @@ -1,7 +1,11 @@ Sun Jul 2 01:38:33 EST 1995 -See also: http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + As the date above certify, this ``readme'' is mostly +obsolete. Please read release notes and change list in +driver/net/wavelan.p.h, and consult my web page at : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + Jean 1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390. The version of the card that I use (NCR) supports four I/O addresses diff -u --recursive --new-file v2.3.14/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt --- v2.3.14/linux/Documentation/serial-console.txt Wed Apr 1 14:58:54 1998 +++ linux/Documentation/serial-console.txt Thu Aug 19 10:54:10 1999 @@ -87,7 +87,7 @@ 6. Thanks - Thanks to Geert Uytterhoeven + Thanks to Geert Uytterhoeven for porting the patches from 2.1.4x to 2.1.6x for taking care of the integration of these patches into m68k, ppc and alpha. diff -u --recursive --new-file v2.3.14/linux/Documentation/smart-config.txt linux/Documentation/smart-config.txt --- v2.3.14/linux/Documentation/smart-config.txt Thu Jun 4 22:53:50 1998 +++ linux/Documentation/smart-config.txt Thu Aug 19 16:47:23 1999 @@ -1,5 +1,5 @@ Smart CONFIG_* Dependencies -Fri 2 Dec 1997 +1 August 1999 Michael Chastain Werner Almesberger @@ -44,22 +44,21 @@ It now generates these dependencies: drivers/net/foo.c: \ - include/config/foo_autofrob.h \ - include/config/foo_model_two.h + include/config/foo/autofrob.h \ + include/config/foo/model/two.h So drivers/net/foo.c depends only on the CONFIG_* lines that it actually uses. - A new program, split-include.c, runs at the end of make config (also - make oldconfig, make menuconfig, and make xconfig). split-include - reads include/linux/autoconf.h and updates the include/linux/*.h - directory, writing one file per option. It updates only the files - that changed. - - mkdep.c also generates much better warning messages for missing - or unneeded lines. In fact, you can get these - messages without generating dependencies with the new top-level - target 'make checkconfig'. + A new program, split-include.c, runs at the beginning of + compilation (make bzImage or make zImage). split-include reads + include/linux/autoconf.h and updates the include/config/ tree, + writing one file per option. It updates only the files for options + that have changed. + + mkdep.c no longer generates warning messages for missing or unneeded + lines. The new top-level target 'make checkconfig' + checks for these problems. Flag Dependencies @@ -68,12 +67,14 @@ the compilation flags used to build it. The file foo.o has its flags stored in .flags.foo.o. - Suppose the user changes the foo driver from resident to - modular, 'make' will notice that the foo.o was not compiled - with -DMODULE and will recompile foo.c. - - All .a and .o files made from C source or with 'ld' or 'ar' - have flag dependencies. .S files do not have flag dependencies. + Suppose the user changes the foo driver from resident to modular. + 'make' will notice that the current foo.o was not compiled with + -DMODULE and will recompile foo.c. + + All .o files made from C source have flag dependencies. So do .o + files made with ld, and .a files made with ar. However, .o files + made from assembly source do not have flag dependencies (nobody + needs this yet, but it would be good to fix). Per-source-file Flags @@ -92,8 +93,8 @@ version of this patch. Michael Chastain picked it up and continued development. He is - now the principal author and maintainer. Report bugs to him, - or to all three people together. + now the principal author and maintainer. Please report any bugs + to him. Martin von Loewis wrote flag dependencies, with some modifications by Michael Chastain. diff -u --recursive --new-file v2.3.14/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.3.14/linux/Documentation/sound/AWE32 Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/AWE32 Mon Aug 23 10:23:23 1999 @@ -85,7 +85,6 @@ 7) Edit /etc/conf.modules, inserting at the end of the file: -alias sound sb alias midi awe_wave post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 diff -u --recursive --new-file v2.3.14/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16 --- v2.3.14/linux/Documentation/sound/MAD16 Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/MAD16 Mon Aug 23 10:23:23 1999 @@ -32,3 +32,22 @@ options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is + +------------------------------------------------------------------------ +The mad16 module in addition supports the following options: + +option: meaning: default: +joystick=0,1 disabled, enabled disabled +cdtype=0x00,0x02,0x04, disabled, Sony CDU31A, disabled + 0x06,0x08,0x0a Mitsumi, Panasonic, + Secondary IDE, Primary IDE +cdport=0x340,0x320, 0x340 + 0x330,0x360 +cdirq=0,3,5,7,9,10,11 disabled, IRQ3, ... disabled +cddma=0,5,6,7 disabled, DMA5, ... DMA5 for Mitsumi or IDE +cddma=0,1,2,3 disabled, DMA1, ... DMA3 for Sony or Panasonic +opl4=0,1 OPL3, OPL4 OPL3 + +for more details see linux/drivers/sound/mad16.c + +Rui Sousa diff -u --recursive --new-file v2.3.14/linux/Documentation/sound/solo1 linux/Documentation/sound/solo1 --- v2.3.14/linux/Documentation/sound/solo1 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/solo1 Mon Aug 23 11:15:27 1999 @@ -0,0 +1,48 @@ +ALaw/uLaw sample formats +------------------------ + +This driver does not support the ALaw/uLaw sample formats. +ALaw is the default mode when opening a sound device +using OSS/Free. The reason for the lack of support is +that the hardware does not support these formats, and adding +conversion routines to the kernel would lead to very ugly +code in the presence of the mmap interface to the driver. +And since xquake uses mmap, mmap is considered important :-) +and no sane application uses ALaw/uLaw these days anyway. +In short, playing a Sun .au file as follows: + +cat my_file.au > /dev/dsp + +does not work. Instead, you may use the play script from +Chris Bagwell's sox-12.14 package (or later, available from the URL +below) to play many different audio file formats. +The script automatically determines the audio format +and does do audio conversions if necessary. +http://home.sprynet.com/sprynet/cbagwell/projects.html + + +Blocking vs. nonblocking IO +--------------------------- + +Unlike OSS/Free this driver honours the O_NONBLOCK file flag +not only during open, but also during read and write. +This is an effort to make the sound driver interface more +regular. Timidity has problems with this; a patch +is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html. +(Timidity patched will also run on OSS/Free). + + +MIDI UART +--------- + +The driver supports a simple MIDI UART interface, with +no ioctl's supported. + + +MIDI synthesizer +---------------- + +The card has an OPL compatible FM synthesizer. + +Thomas Sailer +sailer@ife.ee.ethz.ch diff -u --recursive --new-file v2.3.14/linux/Documentation/sound/vwsnd linux/Documentation/sound/vwsnd --- v2.3.14/linux/Documentation/sound/vwsnd Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/vwsnd Mon Aug 23 10:23:23 1999 @@ -0,0 +1,293 @@ +vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual +Workstations' onboard audio. + +Copyright 1999 Silicon Graphics, Inc. All rights reserved. + + +At the time of this writing, March 1999, there are two models of +Visual Workstation, the 320 and the 540. This document only describes +those models. Future Visual Workstation models may have different +sound capabilities, and this driver will probably not work on those +boxes. + +The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio +codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also +known as Lithium. This driver programs both both chips. + +============================================================================== +QUICK CONFIGURATION + + # insmod soundcore + # insmod vwsnd + +============================================================================== +I/O CONNECTIONS + +On the Visual Workstation, only three of the AD1843 inputs are hooked +up. The analog line in jacks are connected to the AD1843's AUX1 +input. The CD audio lines are connected to the AD1843's AUX2 input. +The microphone jack is connected to the AD1843's MIC input. The mic +jack is mono, but the signal is delivered to both the left and right +MIC inputs. You can record in stereo from the mic input, but you will +get the same signal on both channels (within the limits of A/D +accuracy). Full scale on the Line input is +/- 2.0 V. Full scale on +the MIC input is 20 dB less, or +/- 0.2 V. + +The AD1843's LOUT1 outputs are connected to the Line Out jacks. The +AD1843's HPOUT outputs are connected to the speaker/headphone jack. +LOUT2 is not connected. Line out's maximum level is +/- 2.0 V peak to +peak. The speaker/headphone out's maximum is +/- 4.0 V peak to peak. + +The AD1843's PCM input channel and one of its output channels (DAC1) +are connected to Lithium. The other output channel (DAC2) is not +connected. + +============================================================================== +CAPABILITIES + +The AD1843 has PCM input and output (Pulse Code Modulation, also known +as wavetable). PCM input and output can be mono or stereo in any of +four formats. The formats are 16 bit signed and 8 bit unsigned, +u-Law, and A-Law format. Any sample rate from 4 KHz to 49 KHz is +available, in 1 Hz increments. + +The AD1843 includes an analog mixer that can mix all three input +signals (line, mic and CD) into the analog outputs. The mixer has a +separate gain control and mute switch for each input. + +There are two outputs, line out and speaker/headphone out. They +always produce the same signal, and the speaker always has 3 dB more +gain than the line out. The speaker/headphone output can be muted, +but this driver does not export that function. + +The hardware can sync audio to the video clock, but this driver does +not have a way to specify syncing to video. + +============================================================================== +PROGRAMMING + +This section explains the API supported by the driver. Also see the +Open Sound Programming Guide at http://www.opensound.com/pguide/ . +This section assumes familiarity with that document. + +The driver has two interfaces, an I/O interface and a mixer interface. +There is no MIDI or sequencer capability. + +============================================================================== +PROGRAMMING PCM I/O + +The I/O interface is usually accessed as /dev/audio or /dev/dsp. +Using the standard Open Sound System (OSS) ioctl calls, the sample +rate, number of channels, and sample format may be set within the +limitations described above. The driver supports triggering. It also +supports getting the input and output pointers with one-sample +accuracy. + +The SNDCTL_DSP_GETCAP ioctl returns these capabilities. + + DSP_CAP_DUPLEX - driver supports full duplex. + + DSP_CAP_TRIGGER - driver supports triggering. + + DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR + and SNDCTL_DSP_GETOPTR are accurate to a few samples. + +Memory mapping (mmap) is not implemented. + +The driver permits subdivided fragment sizes from 64 to 4096 bytes. +The number of fragments can be anything from 3 fragments to however +many fragments fit into 124 kilobytes. It is up to the user to +determine how few/small fragments can be used without introducing +glitches with a given workload. Linux is not realtime, so we can't +promise anything. (sigh...) + +When this driver is switched into or out of mu-Law or A-Law mode on +output, it may produce an audible click. This is unavoidable. To +prevent clicking, use signed 16-bit mode instead, and convert from +mu-Law or A-Law format in software. + +============================================================================== +PROGRAMMING THE MIXER INTERFACE + +The mixer interface is usually accessed as /dev/mixer. It is accessed +through ioctls. The mixer allows the application to control gain or +mute several audio signal paths, and also allows selection of the +recording source. + +Each of the constants described here can be read using the +MIXER_READ(SOUND_MIXER_xxx) ioctl. Those that are not read-only can +also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl. In most +cases, defines constants SOUND_MIXER_READ_xxx and +SOUND_MIXER_WRITE_xxx which work just as well. + +SOUND_MIXER_CAPS Read-only + +This is a mask of optional driver capabilities that are implemented. +This driver's only capability is SOUND_CAP_EXCL_INPUT, which means +that only one recording source can be active at a time. + +SOUND_MIXER_DEVMASK Read-only + +This is a mask of the sound channels. This driver's channels are PCM, +LINE, MIC, CD, and RECLEV. + +SOUND_MIXER_STEREODEVS Read-only + +This is a mask of which sound channels are capable of stereo. All +channels are capable of stereo. (But see caveat on MIC input in I/O +CONNECTIONS section above). + +SOUND_MIXER_OUTMASK Read-only + +This is a mask of channels that route inputs through to outputs. +Those are LINE, MIC, and CD. + +SOUND_MIXER_RECMASK Read-only + +This is a mask of channels that can be recording sources. Those are +PCM, LINE, MIC, CD. + +SOUND_MIXER_PCM Default: 0x5757 (0 dB) + +This is the gain control for PCM output. The left and right channel +gain are controlled independently. This gain control has 64 levels, +which range from -82.5 dB to +12.0 dB in 1.5 dB steps. Those 64 +levels are mapped onto 100 levels at the ioctl, see below. + +SOUND_MIXER_LINE Default: 0x4a4a (0 dB) + +This is the gain control for mixing the Line In source into the +outputs. The left and right channel gain are controlled +independently. This gain control has 32 levels, which range from +-34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto +100 levels at the ioctl, see below. + +SOUND_MIXER_MIC Default: 0x4a4a (0 dB) + +This is the gain control for mixing the MIC source into the outputs. +The left and right channel gain are controlled independently. This +gain control has 32 levels, which range from -34.5 dB to +12.0 dB in +1.5 dB steps. Those 32 levels are mapped onto 100 levels at the +ioctl, see below. + +SOUND_MIXER_CD Default: 0x4a4a (0 dB) + +This is the gain control for mixing the CD audio source into the +outputs. The left and right channel gain are controlled +independently. This gain control has 32 levels, which range from +-34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto +100 levels at the ioctl, see below. + +SOUND_MIXER_RECLEV Default: 0 (0 dB) + +This is the gain control for PCM input (RECording LEVel). The left +and right channel gain are controlled independently. This gain +control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB +steps. Those 16 levels are mapped onto 100 levels at the ioctl, see +below. + +SOUND_MIXER_RECSRC Default: SOUND_MASK_LINE + +This is a mask of currently selected PCM input sources (RECording +SouRCes). Because the AD1843 can only have a single recording source +at a time, only one bit at a time can be set in this mask. The +allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC, +or SOUND_MASK_CD. Selecting SOUND_MASK_PCM sets up internal +resampling which is useful for loopback testing and for hardware +sample rate conversion. But software sample rate conversion is +probably faster, so I don't know how useful that is. + +SOUND_MIXER_OUTSRC DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD + +This is a mask of sources that are currently passed through to the +outputs. Those sources whose bits are not set are muted. + +============================================================================== +GAIN CONTROL + +There are five gain controls listed above. Each has 16, 32, or 64 +steps. Each control has 1.5 dB of gain per step. Each control is +stereo. + +The OSS defines the argument to a channel gain ioctl as having two +components, left and right, each of which ranges from 0 to 100. The +two components are packed into the same word, with the left side gain +in the least significant byte, and the right side gain in the second +least significant byte. In C, we would say this. + + #include + + ... + + assert(leftgain >= 0 && leftgain <= 100); + assert(rightgain >= 0 && rightgain <= 100); + arg = leftgain | rightgain << 8; + +So each OSS gain control has 101 steps. But the hardware has 16, 32, +or 64 steps. The hardware steps are spread across the 101 OSS steps +nearly evenly. The conversion formulas are like this, given N equals +16, 32, or 64. + + int round = N/2 - 1; + OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1); + hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100; + +Here is a snippet of C code that will return the left and right gain +of any channel in dB. Pass it one of the predefined gain_desc_t +structures to access any of the five channels' gains. + + typedef struct gain_desc { + float min_gain; + float gain_step; + int nbits; + int chan; + } gain_desc_t; + + const gain_desc_t gain_pcm = { -82.5, 1.5, 6, SOUND_MIXER_PCM }; + const gain_desc_t gain_line = { -34.5, 1.5, 5, SOUND_MIXER_LINE }; + const gain_desc_t gain_mic = { -34.5, 1.5, 5, SOUND_MIXER_MIC }; + const gain_desc_t gain_cd = { -34.5, 1.5, 5, SOUND_MIXER_CD }; + const gain_desc_t gain_reclev = { 0.0, 1.5, 4, SOUND_MIXER_RECLEV }; + + int get_gain_dB(int fd, const gain_desc_t *gp, + float *left, float *right) + { + int word; + int lg, rg; + int mask = (1 << gp->nbits) - 1; + + if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0) + return -1; /* fail */ + lg = word & 0xFF; + rg = word >> 8 & 0xFF; + lg = (lg * mask + mask / 2) / 100; + rg = (rg * mask + mask / 2) / 100; + *left = gp->min_gain + gp->gain_step * lg; + *right = gp->min_gain + gp->gain_step * rg; + return 0; + } + +And here is the corresponding routine to set a channel's gain in dB. + + int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right) + { + float max_gain = + gp->min_gain + (1 << gp->nbits) * gp->gain_step; + float round = gp->gain_step / 2; + int mask = (1 << gp->nbits) - 1; + int word; + int lg, rg; + + if (left < gp->min_gain || right < gp->min_gain) + return EINVAL; + lg = (left - gp->min_gain + round) / gp->gain_step; + rg = (right - gp->min_gain + round) / gp->gain_step; + if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits)) + return EINVAL; + lg = (100 * lg + mask / 2) / mask; + rg = (100 * rg + mask / 2) / mask; + word = lg | rg << 8; + + return ioctl(fd, MIXER_WRITE(gp->chan), &word); + } + diff -u --recursive --new-file v2.3.14/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.14/linux/MAINTAINERS Sun Aug 15 11:50:35 1999 +++ linux/MAINTAINERS Mon Aug 23 10:23:23 1999 @@ -89,10 +89,9 @@ 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker -M: gpg109@rsphy1.anu.edu.au +M: p_gortmaker@yahoo.com L: linux-net@vger.rutgers.edu S: Maintained -W: http://rsphy1.anu.edu.au/~gpg109/ne2000.html AD1816 SOUND DRIVER P: Thorsten Knabe @@ -182,6 +181,16 @@ L: linux-fbdev@vuser.vu.union.edu S: Maintained +COMPUTONE INTELLIPORT MULTIPORT CARD +P: Doug McNash +P: Michael H. Warfield +M: Doug McNash +M: Michael H. Warfield +W: http://www.computone.com/ +W: http://www.wittsend.com/computone.html +L: linux-computone@lazuli.wittsend.com +S: Supported + CONFIGURE, MENUCONFIG, XCONFIG P: Michael Elizabeth Chastain M: mec@shout.net @@ -410,12 +419,6 @@ L: linux-kernel@vger.rutgers.edu S: Maintained -IP FIREWALL -P: Paul Russell -M: Paul.Russell@rustcorp.com.au -W: http://www.rustcorp.com/linux/ipchains -S: Supported - IP MASQUERADING: P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar @@ -549,6 +552,15 @@ L: linware@sh.cvut.cz S: Maintained +NETFILTER +P: Rusty Russell +M: Rusty.Russell@rustcorp.com.au +W: http://www.samba.org/netfilter/ +W: http://netfilter.kernelnotes.org +W: http://antarctica.penguincomputing.com/~netfilter/ +L: netfilter@lists.samba.org +S: Supported + NETROM NETWORK LAYER P: Tomi Manninen M: Tomi.Manninen@hut.fi @@ -682,7 +694,7 @@ REAL TIME CLOCK DRIVER P: Paul Gortmaker -M: gpg109@rsphy1.anu.edu.au +M: p_gortmaker@yahoo.com L: linux-kernel@vger.rutgers.edu S: Maintained @@ -869,7 +881,8 @@ WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS P: Jean Tourrilhes -M: jt@hplb.hpl.hp.com +M: jt@hpl.hp.com +W: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ S: Maintained WD7000 SCSI DRIVER diff -u --recursive --new-file v2.3.14/linux/Makefile linux/Makefile --- v2.3.14/linux/Makefile Wed Aug 18 09:45:10 1999 +++ linux/Makefile Mon Aug 23 09:56:31 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 14 +SUBLEVEL = 15 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -126,6 +126,10 @@ DRIVERS := $(DRIVERS) drivers/net/net.a +ifdef CONFIG_ATM +DRIVERS := $(DRIVERS) drivers/atm/atm.a +endif + ifeq ($(CONFIG_SCSI),y) DRIVERS := $(DRIVERS) drivers/scsi/scsi.a endif @@ -162,7 +166,7 @@ DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a endif -ifdef CONFIG_PNP +ifeq ($(CONFIG_PNP),y) DRIVERS := $(DRIVERS) drivers/pnp/pnp.a endif @@ -325,6 +329,7 @@ if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \ if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \ if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \ + if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \ if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \ diff -u --recursive --new-file v2.3.14/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.14/linux/arch/alpha/config.in Thu Aug 5 18:44:28 1999 +++ linux/arch/alpha/config.in Mon Aug 23 10:59:10 1999 @@ -173,13 +173,6 @@ bool 'Symmetric multi-processing support' CONFIG_SMP fi -if [ "$CONFIG_PCI" = "y" ]; then - bool 'PCI quirks' CONFIG_PCI_QUIRKS - if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE - fi - bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC -fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -216,6 +209,9 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi endmenu fi diff -u --recursive --new-file v2.3.14/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.14/linux/arch/alpha/kernel/Makefile Mon Jul 12 07:49:36 1999 +++ linux/arch/alpha/kernel/Makefile Wed Aug 25 16:01:27 1999 @@ -16,7 +16,7 @@ O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - bios32.o ptrace.o time.o fpreg.o + bios32.o ptrace.o time.o fpreg.o semaphore.o OX_OBJS := alpha_ksyms.o diff -u --recursive --new-file v2.3.14/linux/arch/alpha/kernel/semaphore.c linux/arch/alpha/kernel/semaphore.c --- v2.3.14/linux/arch/alpha/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/semaphore.c Wed Aug 25 16:01:10 1999 @@ -0,0 +1,129 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.14/linux/arch/alpha/lib/io.c linux/arch/alpha/lib/io.c --- v2.3.14/linux/arch/alpha/lib/io.c Mon Aug 16 10:33:58 1999 +++ linux/arch/alpha/lib/io.c Thu Aug 19 08:28:03 1999 @@ -90,7 +90,7 @@ __writeb(b, addr); } -void ___raw_writeb(unsigned short b, unsigned long addr) +void ___raw_writew(unsigned short b, unsigned long addr) { __writew(b, addr); } @@ -487,7 +487,7 @@ if (count >= 2 && (to & 1) == ((long)from & 1)) { count -= 2; do { - __raw_writeb(*(const u16 *)from, to); + __raw_writew(*(const u16 *)from, to); count -= 2; to += 2; from += 2; @@ -518,7 +518,7 @@ /* Handle any initial odd halfword */ if (count >= 2 && (to & 2)) { - __raw_writeb(c, to); + __raw_writew(c, to); to += 2; count -= 2; } @@ -551,7 +551,7 @@ /* The tail is half-word aligned if we have count >= 2 */ if (count >= 2) { - __raw_writeb(c, to); + __raw_writew(c, to); to += 2; count -= 2; } diff -u --recursive --new-file v2.3.14/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.3.14/linux/arch/i386/boot/bootsect.S Wed Aug 18 10:03:05 1999 +++ linux/arch/i386/boot/bootsect.S Thu Aug 19 10:54:13 1999 @@ -106,12 +106,12 @@ seg fs lds si,(bx) ! ds:si is source - mov cl,#6 ! copy 12 bytes + mov cl,#3 ! copy 12 bytes cld push di rep - movsw + movsd pop di pop ds @@ -125,7 +125,7 @@ ! load the setup-sectors directly after the bootblock. ! Note that 'es' is already set up. -! Also cx is 0 from rep movsw above. +! Also cx is 0 from rep movsd above. load_setup: xor ah,ah ! reset FDC diff -u --recursive --new-file v2.3.14/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c --- v2.3.14/linux/arch/i386/boot/compressed/misc.c Wed Jun 24 14:30:08 1998 +++ linux/arch/i386/boot/compressed/misc.c Thu Aug 19 10:49:13 1999 @@ -104,7 +104,7 @@ #define LOW_BUFFER_START 0x2000 #define LOW_BUFFER_END 0x90000 #define LOW_BUFFER_SIZE ( LOW_BUFFER_END - LOW_BUFFER_START ) -#define HEAP_SIZE 0x2000 +#define HEAP_SIZE 0x3000 static int high_loaded =0; static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; diff -u --recursive --new-file v2.3.14/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.14/linux/arch/i386/boot/setup.S Mon Jul 5 20:04:47 1999 +++ linux/arch/i386/boot/setup.S Thu Aug 19 10:54:13 1999 @@ -188,9 +188,9 @@ xor bh,bh mov bl,[497] ! get setup sects from boot sector sub bx,#4 ! LILO loads 4 sectors of setup - shl bx,#8 ! convert to words + shl bx,#7 ! convert to dwords (1sect=2^7 dwords) mov cx,bx - shr bx,#3 ! convert to segment + shr bx,#2 ! convert to segment add bx,#SYSSEG seg cs mov start_sys_seg,bx @@ -203,7 +203,7 @@ mov ax,#SYSSEG mov ds,ax rep - movsw + movsd mov ax,cs ! aka #SETUPSEG mov ds,ax @@ -485,9 +485,9 @@ add bx,#0x100 sub di,di sub si,si - mov cx,#0x800 + mov cx,#0x400 rep - movsw + movsd cmp bx,bp ! we assume start_sys_seg > 0x200, ! so we will perhaps read one page more then ! needed, but never overwrite INITSEG because diff -u --recursive --new-file v2.3.14/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.14/linux/arch/i386/config.in Wed Aug 18 11:18:11 1999 +++ linux/arch/i386/config.in Mon Aug 23 10:59:10 1999 @@ -67,11 +67,6 @@ if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then define_bool CONFIG_PCI_DIRECT y fi - bool ' PCI quirks' CONFIG_PCI_QUIRKS - if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE - fi - bool ' Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC fi bool 'MCA support' CONFIG_MCA bool 'SGI Visual Workstation support' CONFIG_VISWS @@ -136,6 +131,9 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi endmenu fi diff -u --recursive --new-file v2.3.14/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.14/linux/arch/i386/defconfig Sun Aug 15 16:02:03 1999 +++ linux/arch/i386/defconfig Mon Aug 23 10:59:10 1999 @@ -44,8 +44,6 @@ CONFIG_PCI_GOANY=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y -CONFIG_PCI_QUIRKS=y -CONFIG_PCI_OLD_PROC=y # CONFIG_MCA is not set # CONFIG_VISWS is not set CONFIG_X86_IO_APIC=y @@ -123,8 +121,9 @@ # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -140,7 +139,6 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set CONFIG_SKB_LARGE=y # @@ -227,6 +225,7 @@ # CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) @@ -258,6 +257,7 @@ # Token ring devices # # CONFIG_TR is not set +# CONFIG_NET_FC is not set # # Wan interfaces diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.3.14/linux/arch/i386/kernel/Makefile Wed Aug 18 11:11:15 1999 +++ linux/arch/i386/kernel/Makefile Wed Aug 25 14:14:55 1999 @@ -13,7 +13,7 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \ +O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o OX_OBJS := i386_ksyms.o MX_OBJS := diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.3.14/linux/arch/i386/kernel/bios32.c Wed Aug 18 11:24:23 1999 +++ linux/arch/i386/kernel/bios32.c Mon Aug 23 10:59:10 1999 @@ -75,6 +75,8 @@ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj] * * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj] + * + * August 1999 : New resource management and configuration access stuff. [mj] */ #include @@ -85,6 +87,7 @@ #include #include #include +#include #include #include @@ -93,8 +96,6 @@ #include #include -#include - #undef DEBUG #ifdef DEBUG @@ -103,72 +104,6 @@ #define DBG(x...) #endif -/* - * This interrupt-safe spinlock protects all accesses to PCI - * configuration space. - */ - -spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; - -/* - * Generic PCI access -- indirect calls according to detected HW. - */ - -struct pci_access { - int pci_present; - int (*read_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char *); - int (*read_config_word)(unsigned char, unsigned char, unsigned char, unsigned short *); - int (*read_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int *); - int (*write_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char); - int (*write_config_word)(unsigned char, unsigned char, unsigned char, unsigned short); - int (*write_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int); -}; - -static int pci_stub(void) -{ - return PCIBIOS_FUNC_NOT_SUPPORTED; -} - -static struct pci_access pci_access_none = { - 0, /* No PCI present */ - (void *) pci_stub, - (void *) pci_stub, - (void *) pci_stub, - (void *) pci_stub, - (void *) pci_stub, - (void *) pci_stub -}; - -static struct pci_access *access_pci = &pci_access_none; - -int pcibios_present(void) -{ - return access_pci->pci_present; -} - -#define PCI_byte_BAD 0 -#define PCI_word_BAD (pos & 1) -#define PCI_dword_BAD (pos & 3) - -#define PCI_STUB(rw,size,type) \ -int pcibios_##rw##_config_##size (u8 bus, u8 dfn, u8 pos, type value) \ -{ \ - int res; \ - unsigned long flags; \ - if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ - spin_lock_irqsave(&pci_lock, flags); \ - res = access_pci->rw##_config_##size(bus, dfn, pos, value); \ - spin_unlock_irqrestore(&pci_lock, flags); \ - return res; \ -} - -PCI_STUB(read, byte, u8 *) -PCI_STUB(read, word, u16 *) -PCI_STUB(read, dword, u32 *) -PCI_STUB(write, byte, u8) -PCI_STUB(write, word, u16) -PCI_STUB(write, dword, u32) - #define PCI_PROBE_BIOS 1 #define PCI_PROBE_CONF1 2 #define PCI_PROBE_CONF2 4 @@ -176,6 +111,7 @@ #define PCI_BIOS_SORT 0x200 #define PCI_NO_CHECKS 0x400 #define PCI_NO_PEER_FIXUP 0x800 +#define PCI_ASSIGN_ROMS 0x1000 static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; @@ -189,60 +125,53 @@ * Functions for accessing PCI configuration space with type 1 accesses */ -#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) +#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) -static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); *value = inb(0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_read_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short *value) +static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); *value = inw(0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); *value = inl(0xCFC); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); outb(value, 0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); outw(value, 0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL; } -static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) { - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(CONFIG_CMD(dev,where), 0xCF8); outl(value, 0xCFC); return PCIBIOS_SUCCESSFUL; } #undef CONFIG_CMD -static struct pci_access pci_direct_conf1 = { - 1, +static struct pci_ops pci_direct_conf1 = { pci_conf1_read_config_byte, pci_conf1_read_config_word, pci_conf1_read_config_dword, @@ -255,86 +184,65 @@ * Functions for accessing PCI configuration space with type 2 accesses */ -#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) -#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) +#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) +#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) +#define SET(dev) if (dev->devfn) return PCIBIOS_DEVICE_NOT_FOUND; \ + outb(FUNC(dev->devfn), 0xCF8); \ + outb(dev->bus->number, 0xCFA); -static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - *value = inb(IOADDR(device_fn,where)); + SET(dev); + *value = inb(IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } -static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - *value = inw(IOADDR(device_fn,where)); + SET(dev); + *value = inw(IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } -static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - *value = inl (IOADDR(device_fn,where)); + SET(dev); + *value = inl (IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } -static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - outb (value, IOADDR(device_fn,where)); + SET(dev); + outb (value, IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } -static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - outw (value, IOADDR(device_fn,where)); + SET(dev); + outw (value, IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } -static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value) { - if (device_fn & 0x80) - return PCIBIOS_DEVICE_NOT_FOUND; - outb (FUNC(device_fn), 0xCF8); - outb (bus, 0xCFA); - outl (value, IOADDR(device_fn,where)); + SET(dev); + outl (value, IOADDR(dev->devfn,where)); outb (0, 0xCF8); return PCIBIOS_SUCCESSFUL; } +#undef SET #undef IOADDR #undef FUNC -static struct pci_access pci_direct_conf2 = { - 1, +static struct pci_ops pci_direct_conf2 = { pci_conf2_read_config_byte, pci_conf2_read_config_word, pci_conf2_read_config_dword, @@ -353,9 +261,11 @@ * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -int __init pci_sanity_check(struct pci_access *a) +static int __init pci_sanity_check(struct pci_ops *o) { - u16 dfn, x; + u16 x; + struct pci_bus bus; /* Fake bus and device */ + struct pci_dev dev; #ifdef CONFIG_VISWS return 1; /* Lithium PCI Bridges are non-standard */ @@ -363,17 +273,19 @@ if (pci_probe & PCI_NO_CHECKS) return 1; - for(dfn=0; dfn < 0x100; dfn++) - if ((!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) && + bus.number = 0; + dev.bus = &bus; + for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++) + if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) && (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || - (!a->read_config_word(0, dfn, PCI_VENDOR_ID, &x) && + (!o->read_word(&dev, PCI_VENDOR_ID, &x) && (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) return 1; DBG("PCI: Sanity check failed\n"); return 0; } -static struct pci_access * __init pci_check_direct(void) +static struct pci_ops * __init pci_check_direct(void) { unsigned int tmp; unsigned long flags; @@ -497,7 +409,7 @@ unsigned long entry; /* %edx */ unsigned long flags; - spin_lock_irqsave(&pci_lock, flags); + __save_flags(flags); __cli(); __asm__("lcall (%%edi)" : "=a" (return_code), "=b" (address), @@ -506,7 +418,7 @@ : "0" (service), "1" (0), "D" (&bios32_indirect)); - spin_unlock_irqrestore(&pci_lock, flags); + __restore_flags(flags); switch (return_code) { case 0: @@ -603,7 +515,7 @@ #endif static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, unsigned char *device_fn) + unsigned short index, unsigned char *bus, unsigned char *device_fn) { unsigned short bx; unsigned short ret; @@ -624,11 +536,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_read_config_byte(unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char *value) +static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -643,11 +554,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_read_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short *value) +static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -662,11 +572,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_read_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int *value) +static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -681,11 +590,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_write_config_byte (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char value) +static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -700,11 +608,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_write_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short value) +static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -719,11 +626,10 @@ return (int) (ret & 0xff00) >> 8; } -static int pci_bios_write_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int value) +static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value) { unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; + unsigned long bx = (dev->bus->number << 8) | dev->devfn; __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" @@ -742,8 +648,7 @@ * Function table for BIOS32 access */ -static struct pci_access pci_bios_access = { - 1, +static struct pci_ops pci_bios_access = { pci_bios_read_config_byte, pci_bios_read_config_word, pci_bios_read_config_dword, @@ -756,7 +661,7 @@ * Try to find PCI BIOS. */ -static struct pci_access * __init pci_find_bios(void) +static struct pci_ops * __init pci_find_bios(void) { union bios32 *check; unsigned char sum; @@ -855,26 +760,15 @@ #endif /* - * Several BIOS'es forget to assign addresses to I/O ranges. - * We try to fix it here, expecting there are free addresses - * starting with 0x5800. Ugly, but until we come with better - * resource management, it's the only simple solution. + * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it. */ -static int pci_last_io_addr __initdata = 0x5800; - static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx) { - unsigned short cmd; unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx; - unsigned int size, addr, try; - unsigned int bus = dev->bus->number; - unsigned int devfn = dev->devfn; + struct resource *r = &dev->resource[idx]; + unsigned int size = r->end - r->start + 1; - if (!pci_last_io_addr) { - printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn); - return; - } if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { /* @@ -888,38 +782,53 @@ */ return; } - pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); - pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - pcibios_write_config_dword(bus, devfn, reg, ~0); - pcibios_read_config_dword(bus, devfn, reg, &size); - size = (~(size & PCI_BASE_ADDRESS_IO_MASK) & 0xffff) + 1; - addr = 0; - if (!size || size > 0x100) - printk("PCI: Unable to handle I/O allocation for %02x:%02x (%04x), tell \n", bus, devfn, size); - else { - do { - addr = (pci_last_io_addr + size - 1) & ~(size-1); - pci_last_io_addr = addr + size; - } while (check_region(addr, size)); - printk("PCI: Assigning I/O space %04x-%04x to device %02x:%02x\n", addr, addr+size-1, bus, devfn); - pcibios_write_config_dword(bus, devfn, reg, addr | PCI_BASE_ADDRESS_SPACE_IO); - pcibios_read_config_dword(bus, devfn, reg, &try); - if ((try & PCI_BASE_ADDRESS_IO_MASK) != addr) { - addr = 0; - printk("PCI: Address setup failed, got %04x\n", try); - } else { - struct resource *res = dev->resource + idx; - res->start = addr; - res->end = addr + size - 1; - res->flags |= PCI_BASE_ADDRESS_IO_MASK; + /* + * We need to avoid collisions with `mirrored' VGA ports and other strange + * ISA hardware, so we always want the addresses kilobyte aligned. + */ + if (!size || size > 256) { + printk(KERN_ERR "PCI: Cannot assign I/O space to device %s, %d bytes are too much.\n", dev->name, size); + return; + } else { + u32 try; + + if (allocate_resource(&ioport_resource, r, size, 0x1000, ~0, 1024)) { + printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name); + return; + } + printk("PCI: Assigning I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name); + pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO); + pci_read_config_dword(dev, reg, &try); + if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { + r->start = 0; + pci_write_config_dword(dev, reg, 0); + printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try); } } - if (!addr) { - pcibios_write_config_dword(bus, devfn, reg, 0); - dev->resource[idx].start = 0; - dev->resource[idx].flags = 0; +} + +/* + * Assign address to expansion ROM. This is a highly experimental feature + * and you must enable it by "pci=rom". It's even not guaranteed to work + * with all cards since the PCI specs allow address decoders to be shared + * between the ROM space and one of the standard regions (sigh!). + */ +static void __init pcibios_fixup_rom_addr(struct pci_dev *dev) +{ + int reg = (dev->hdr_type == 1) ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; + struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; + unsigned long rom_size = r->end - r->start + 1; + + if (allocate_resource(&iomem_resource, r, rom_size, 0xf0000000, ~0, rom_size) < 0) { + printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n", + dev->name, rom_size); + r->start = 0; + r->end = rom_size - 1; + } else { + DBG("PCI: Assigned address %08lx to expansion ROM of %s (0x%lx bytes)\n", r->start, dev->name, rom_size); + pci_write_config_dword(dev, reg, r->start | PCI_ROM_ADDRESS_ENABLE); + r->flags |= PCI_ROM_ADDRESS_ENABLE; } - pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); } /* @@ -934,18 +843,25 @@ struct pci_dev *d, *e, **z; int mirror = PCI_DEVFN(16,0); int seen_host_bridge = 0; + int i; DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); for(d=b->devices; d && d->devfn < mirror; d=d->sibling) { if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) seen_host_bridge++; - for(e=d->next; e; e=e->sibling) - if (e->devfn == d->devfn + mirror && - e->vendor == d->vendor && - e->device == d->device && - e->class == d->class && - !memcmp(e->resource, d->resource, sizeof(e->resource))) - break; + for(e=d->next; e; e=e->sibling) { + if (e->devfn != d->devfn + mirror || + e->vendor != d->vendor || + e->device != d->device || + e->class != d->class) + continue; + for(i=0; iresource[i].start != d->resource[i].start || + e->resource[i].end != d->resource[i].end || + e->resource[i].flags != d->resource[i].flags) + continue; + break; + } if (!e) return; } @@ -971,12 +887,13 @@ */ static void __init pcibios_fixup_peer_bridges(void) { - struct pci_bus *b = &pci_root; - int i, n, cnt=-1; + struct pci_bus *b = pci_root; + int n, cnt=-1; struct pci_dev *d; + struct pci_ops *ops = pci_root->ops; #ifdef CONFIG_VISWS - pci_scan_peer_bridge(1); + pci_scan_bus(1, ops, NULL); return; #endif @@ -986,7 +903,7 @@ * since it reads bogus values for non-existent busses and * chipsets supporting multiple primary busses use conf1 anyway. */ - if (access_pci == &pci_direct_conf2) + if (ops == &pci_direct_conf2) return; #endif @@ -997,26 +914,31 @@ while (n <= 0xff) { int found = 0; u16 l; - for(i=0; i<256; i += 8) - if (!pcibios_read_config_word(n, i, PCI_VENDOR_ID, &l) && + struct pci_bus bus; + struct pci_dev dev; + bus.number = n; + bus.ops = ops; + dev.bus = &bus; + for(dev.devfn=0; dev.devfn<256; dev.devfn += 8) + if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { #ifdef CONFIG_PCI_BIOS if (pci_bios_present) { int err, idx = 0; u8 bios_bus, bios_dfn; u16 d; - pcibios_read_config_word(n, i, PCI_DEVICE_ID, &d); - DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, i, l, d); + pci_read_config_word(&dev, PCI_DEVICE_ID, &d); + DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, dev.devfn, l, d); while (!(err = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) && - (bios_bus != n || bios_dfn != i)) + (bios_bus != n || bios_dfn != dev.devfn)) idx++; if (err) break; } #endif - DBG("Found device at %02x:%02x\n", n, i); + DBG("Found device at %02x:%02x\n", n, dev.devfn); found++; - if (!pcibios_read_config_word(n, i, PCI_CLASS_DEVICE, &l) && + if (!pci_read_config_word(&dev, PCI_CLASS_DEVICE, &l) && l == PCI_CLASS_BRIDGE_HOST) cnt++; } @@ -1024,7 +946,7 @@ break; if (found) { printk("PCI: Discovered primary peer bus %02x\n", n); - b = pci_scan_peer_bridge(n); + b = pci_scan_bus(n, ops, NULL); n = b->subordinate; } n++; @@ -1042,6 +964,7 @@ */ int pxb, reg; u8 busno, suba, subb; + printk("PCI: Searching for i450NX host bridges on %s\n", d->name); reg = 0xd0; for(pxb=0; pxb<2; pxb++) { pci_read_config_byte(d, reg++, &busno); @@ -1049,13 +972,40 @@ pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_peer_bridge(busno); /* Bus A */ + pci_scan_bus(busno, pci_root->ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_peer_bridge(suba+1); /* Bus B */ + pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */ } pci_probe |= PCI_NO_PEER_FIXUP; } +static void __init pci_fixup_i440bx(struct pci_dev *d) +{ +#if 0 /* Temporarily disabled FIXME */ + /* + * i440BX/ZX -- Occupy the AGP bridge windows. + */ + u16 a, b; + u8 u, v; + pci_read_config_byte(d, 0x1c, &u); + pci_read_config_byte(d, 0x1d, &v); + if (v >= u) { + a = u<<8; + b = ((v-u)<<8) + 0x100; + occupy_region(a, a+b, b, 1, &d->dev); + } + for (u = 0; u < 2; u++) { + pci_read_config_word(d, 0x20+(u*4), &a); + pci_read_config_word(d, 0x22+(u*4), &b); + if (b >= a) { + u32 m = a<<16; + u32 n = ((b-a)<<16) + 0x100000; + occupy_mem_region(m, m+n, n, 1, &d->dev); + } + } +#endif +} + static void __init pci_fixup_umc_ide(struct pci_dev *d) { /* @@ -1064,34 +1014,36 @@ */ int i; + printk("PCI: Fixing base address flags for device %s\n", d->name); for(i=0; i<4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } -struct dev_ex { - u16 vendor, device; - void (*handler)(struct pci_dev *); - char *comment; +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, pci_fixup_i440bx }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, + { 0 } }; -static struct dev_ex __initdata dev_ex_table[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx, "Scanning peer host bridges" }, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide, "Working around UM8886BF bugs" } -}; +/* + * Allocate resources for all PCI devices. We need to do that before + * we try to fix up anything. + */ -static void __init pcibios_scan_buglist(struct pci_bus *b) +static void __init pcibios_claim_resources(void) { - struct pci_dev *d; - int i; + struct pci_dev *dev; + int idx; - for(d=b->devices; d; d=d->sibling) - for(i=0; ivendor == d->vendor && e->device == d->device) { - printk("PCI: %02x:%02x [%04x/%04x]: %s\n", - b->number, d->devfn, d->vendor, d->device, e->comment); - e->handler(d); - } + for (dev=pci_devices; dev; dev=dev->next) + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + if (!r->start) + continue; + if (request_resource((r->flags & PCI_BASE_ADDRESS_SPACE_IO) ? &ioport_resource : &iomem_resource, r) < 0) + printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); + /* We probably should disable the region, shouldn't we? */ } } @@ -1117,14 +1069,12 @@ */ has_io = has_mem = 0; for(i=0; i<6; i++) { - struct resource *res = dev->resource + i; - unsigned long a = res->flags; - if (a & PCI_BASE_ADDRESS_SPACE_IO) { - unsigned long addr = res->start; + struct resource *r = &dev->resource[i]; + if (r->flags & PCI_BASE_ADDRESS_SPACE_IO) { has_io = 1; - if (!addr || addr == PCI_BASE_ADDRESS_IO_MASK) + if (!r->start || r->start == PCI_BASE_ADDRESS_IO_MASK) pcibios_fixup_io_addr(dev, i); - } else if (a & PCI_BASE_ADDRESS_MEM_MASK) + } else if (r->start) has_mem = 1; } /* @@ -1139,18 +1089,21 @@ ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)) { pci_read_config_word(dev, PCI_COMMAND, &cmd); if (has_io && !(cmd & PCI_COMMAND_IO)) { - printk("PCI: Enabling I/O for device %02x:%02x\n", - dev->bus->number, dev->devfn); + printk("PCI: Enabling I/O for device %s\n", dev->name); cmd |= PCI_COMMAND_IO; pci_write_config_word(dev, PCI_COMMAND, cmd); } if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { - printk("PCI: Enabling memory for device %02x:%02x\n", - dev->bus->number, dev->devfn); + printk("PCI: Enabling memory for device %s\n", dev->name); cmd |= PCI_COMMAND_MEMORY; pci_write_config_word(dev, PCI_COMMAND, cmd); } } + /* + * Assign address to expansion ROM if requested. + */ + if ((pci_probe & PCI_ASSIGN_ROMS) && dev->resource[PCI_ROM_RESOURCE].end) + pcibios_fixup_rom_addr(dev); #if defined(CONFIG_X86_IO_APIC) /* * Recalculate IRQ numbers if we use the I/O APIC @@ -1191,38 +1144,27 @@ } /* - * Arch-dependent fixups. + * Called after each bus is probed, but before its children + * are examined. */ -void __init pcibios_fixup(void) -{ - if (!(pci_probe & PCI_NO_PEER_FIXUP)) - pcibios_fixup_peer_bridges(); - pcibios_fixup_devices(); - -#ifdef CONFIG_PCI_BIOS - if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) - pcibios_sort(); -#endif -} - void __init pcibios_fixup_bus(struct pci_bus *b) { pcibios_fixup_ghosts(b); - pcibios_scan_buglist(b); } /* * Initialization. Try all known PCI access methods. Note that we support * using both PCI BIOS and direct access: in such cases, we use I/O ports * to access config space, but we still keep BIOS order of cards to be - * compatible with 2.0.X. This should go away in 2.3. + * compatible with 2.0.X. This should go away some day. */ void __init pcibios_init(void) { - struct pci_access *bios = NULL; - struct pci_access *dir = NULL; + struct pci_ops *bios = NULL; + struct pci_ops *dir = NULL; + struct pci_ops *ops; #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) { @@ -1235,9 +1177,26 @@ dir = pci_check_direct(); #endif if (dir) - access_pci = dir; + ops = dir; else if (bios) - access_pci = bios; + ops = bios; + else { + printk("PCI: No PCI bus detected\n"); + return; + } + + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, ops, NULL); + + if (!(pci_probe & PCI_NO_PEER_FIXUP)) + pcibios_fixup_peer_bridges(); + pcibios_claim_resources(); + pcibios_fixup_devices(); + +#ifdef CONFIG_PCI_BIOS + if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) + pcibios_sort(); +#endif } char * __init pcibios_setup(char *str) @@ -1245,13 +1204,6 @@ if (!strcmp(str, "off")) { pci_probe = 0; return NULL; - } else if (!strncmp(str, "io=", 3)) { - char *p; - unsigned int x = simple_strtoul(str+3, &p, 16); - if (p && *p) - return str; - pci_last_io_addr = x; - return NULL; } #ifdef CONFIG_PCI_BIOS else if (!strcmp(str, "bios")) { @@ -1277,6 +1229,9 @@ #endif else if (!strcmp(str, "nopeer")) { pci_probe |= PCI_NO_PEER_FIXUP; + return NULL; + } else if (!strcmp(str, "rom")) { + pci_probe |= PCI_ASSIGN_ROMS; return NULL; } return str; diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.14/linux/arch/i386/kernel/i386_ksyms.c Tue Jun 29 09:59:26 1999 +++ linux/arch/i386/kernel/i386_ksyms.c Mon Aug 23 10:23:23 1999 @@ -76,7 +76,6 @@ #ifdef __SMP__ EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_invalidate_needed); EXPORT_SYMBOL(cpu_number_map); EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); @@ -111,6 +110,7 @@ EXPORT_SYMBOL(mca_mark_as_used); EXPORT_SYMBOL(mca_mark_as_unused); EXPORT_SYMBOL(mca_find_unused_adapter); +EXPORT_SYMBOL(mca_is_adapter_used); #endif #ifdef CONFIG_VT diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.3.14/linux/arch/i386/kernel/i8259.c Wed Aug 18 11:23:31 1999 +++ linux/arch/i386/kernel/i8259.c Wed Aug 18 21:58:26 1999 @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.14/linux/arch/i386/kernel/irq.c Wed Aug 18 11:17:37 1999 +++ linux/arch/i386/kernel/irq.c Mon Aug 23 13:44:03 1999 @@ -20,7 +20,6 @@ * Naturally it's not a 1:1 relation, but there are similarities. */ -#include #include #include #include @@ -149,7 +148,10 @@ static inline void check_smp_invalidate(int cpu) { if (test_bit(cpu, &smp_invalidate_needed)) { + struct mm_struct *mm = current->mm; clear_bit(cpu, &smp_invalidate_needed); + if (mm) + atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); local_flush_tlb(); } } @@ -617,25 +619,33 @@ void free_irq(unsigned int irq, void *dev_id) { - struct irqaction * action, **p; + struct irqaction **p; unsigned long flags; if (irq >= NR_IRQS) return; spin_lock_irqsave(&irq_controller_lock,flags); - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; + p = &irq_desc[irq].action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; - /* Found it - now remove it from the list of entries */ - *p = action->next; - if (!irq_desc[irq].action) { + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (irq_desc[irq].action) + break; irq_desc[irq].status |= IRQ_DISABLED; irq_desc[irq].handler->shutdown(irq); + break; } + printk("Trying to free free IRQ%d\n",irq); + break; } - printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&irq_controller_lock,flags); } diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c --- v2.3.14/linux/arch/i386/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/semaphore.c Wed Aug 25 14:25:57 1999 @@ -0,0 +1,223 @@ +/* + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + */ +#include + +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to aquire the semaphore, while the "sleeping" + * variable is a count of such aquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + wake_up(&sem->wait); + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + retval = -EINTR; + if (signal_pending(current)) { + sem->sleepers = 0; + if (atomic_add_negative(sleepers, &sem->count)) + break; + wake_up(&sem->wait); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + wake_up(&sem->wait); + retval = 0; + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +int __down_trylock(struct semaphore * sem) +{ + int retval, sleepers; + + spin_lock_irq(&semaphore_lock); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irq(&semaphore_lock); + return 1; +} + + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * %ecx contains the semaphore pointer on entry. Save the C-clobbered + * registers (%eax, %edx and %ecx) except %eax when used as a return + * value.. + */ +asm( +".align 4\n" +".globl __down_failed\n" +"__down_failed:\n\t" + "pushl %eax\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "popl %eax\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __down_failed_interruptible\n" +"__down_failed_interruptible:\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down_interruptible\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __down_failed_trylock\n" +"__down_failed_trylock:\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down_trylock\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __up_wakeup\n" +"__up_wakeup:\n\t" + "pushl %eax\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __up\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "popl %eax\n\t" + "ret" +); diff -u --recursive --new-file v2.3.14/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.14/linux/arch/i386/kernel/setup.c Wed Aug 18 11:25:12 1999 +++ linux/arch/i386/kernel/setup.c Wed Aug 25 15:49:00 1999 @@ -584,6 +584,19 @@ break; } break; + case 6: /* An Athlon. We can trust the BIOS probably */ + { + + u32 ecx, edx, dummy; + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size = ecx>>16; + break; + } + } return r; } @@ -805,6 +818,11 @@ "K5", "K5", NULL, NULL, "K6", "K6", "K6-2", "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, + { X86_VENDOR_AMD, 6, + { "Athlon", "Athlon", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_UMC, 4, { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, @@ -1116,11 +1134,11 @@ struct tss_struct * t = &init_tss[nr]; if (test_and_set_bit(nr,&cpu_initialized)) { - printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); + printk("CPU#%d already initialized!\n", nr); for (;;) __sti(); } cpus_initialized++; - printk("INITIALIZING CPU#%d\n", nr); + printk("Initializing CPU#%d\n", nr); if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); diff -u --recursive --new-file v2.3.14/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.3.14/linux/arch/i386/lib/Makefile Sun Dec 27 10:33:13 1998 +++ linux/arch/i386/lib/Makefile Wed Aug 25 14:15:04 1999 @@ -6,7 +6,7 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \ +L_OBJS = checksum.o old-checksum.o delay.o \ usercopy.o getuser.o putuser.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.14/linux/arch/i386/lib/semaphore.S linux/arch/i386/lib/semaphore.S --- v2.3.14/linux/arch/i386/lib/semaphore.S Wed Feb 17 09:34:13 1999 +++ linux/arch/i386/lib/semaphore.S Wed Dec 31 16:00:00 1969 @@ -1,51 +0,0 @@ -/* - * linux/arch/i386/lib/semaphore.S - * - * Copyright (C) 1996 Linus Torvalds - */ - -#include - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - */ -ENTRY(__down_failed) - pushl %eax /* save %eax */ - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down) - popl %ecx /* restore %ecx (count on __down not changing it) */ - popl %edx /* restore %edx */ - popl %eax /* restore %eax */ - ret - -/* Don't save/restore %eax, because that will be our return value */ -ENTRY(__down_failed_interruptible) - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down_interruptible) - popl %ecx /* restore %ecx (count on __down_interruptible not changing it) */ - popl %edx /* restore %edx */ - ret - -/* Don't save/restore %eax, because that will be our return value */ -ENTRY(__down_failed_trylock) - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down_trylock) - popl %ecx /* restore %ecx (count on __down_trylock not changing it) */ - popl %edx /* restore %edx */ - ret - -ENTRY(__up_wakeup) - pushl %eax /* save %eax */ - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__up) - popl %ecx /* restore %ecx (count on __up not changing it) */ - popl %edx /* restore %edx */ - popl %eax /* restore %eax */ - ret diff -u --recursive --new-file v2.3.14/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.14/linux/arch/i386/mm/init.c Wed Aug 4 22:53:14 1999 +++ linux/arch/i386/mm/init.c Wed Aug 25 14:54:07 1999 @@ -389,9 +389,10 @@ * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. * They seem to have done something stupid with the floppy * controller as well.. - * The amount of available base memory is in WORD 40:13. + * The amount of available base memory is in WORD 40:13. Except + * when it isn't. */ - endbase = PAGE_OFFSET + ((*(unsigned short *)__va(0x413) * 1024) & PAGE_MASK); + endbase = PAGE_OFFSET + 0x9f000; while (start_low_mem < endbase) { clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); start_low_mem += PAGE_SIZE; diff -u --recursive --new-file v2.3.14/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c --- v2.3.14/linux/arch/m68k/amiga/chipram.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/chipram.c Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ /* ** linux/amiga/chipram.c ** -** Modified 03-May-94 by Geert Uytterhoeven -** (Geert.Uytterhoeven@cs.kuleuven.ac.be) +** Modified 03-May-94 by Geert Uytterhoeven ** - 64-bit aligned allocations for full AGA compatibility */ diff -u --recursive --new-file v2.3.14/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.3.14/linux/arch/m68k/config.in Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/config.in Mon Aug 23 10:59:10 1999 @@ -48,9 +48,6 @@ bool 'Sun3x support' CONFIG_SUN3X define_bool CONFIG_SUN3 n -if [ "$CONFIG_PCI" = "y" ]; then - bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC -fi bool 'Q40/Q60 support' CONFIG_Q40 comment 'Processor type' diff -u --recursive --new-file v2.3.14/linux/arch/m68k/tools/amiga/dmesg.c linux/arch/m68k/tools/amiga/dmesg.c --- v2.3.14/linux/arch/m68k/tools/amiga/dmesg.c Wed Sep 25 00:47:40 1996 +++ linux/arch/m68k/tools/amiga/dmesg.c Thu Aug 19 10:54:10 1999 @@ -3,8 +3,7 @@ * in Chip RAM with the kernel command * line option `debug=mem'. * - * © Copyright 1996 by Geert Uytterhoeven - * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * © Copyright 1996 by Geert Uytterhoeven * * * Usage: diff -u --recursive --new-file v2.3.14/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.3.14/linux/arch/mips/config.in Thu Aug 5 18:44:28 1999 +++ linux/arch/mips/config.in Mon Aug 23 10:59:10 1999 @@ -63,14 +63,6 @@ mainmenu_option next_comment comment 'General setup' -if [ "$CONFIG_PCI" = "y" ]; then - bool ' PCI quirks' CONFIG_PCI_QUIRKS - if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE - fi - bool ' Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC -fi - if [ "$CONFIG_DECSTATION" = "y" ]; then define_bool CONFIG_CPU_LITTLE_ENDIAN y else diff -u --recursive --new-file v2.3.14/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.14/linux/arch/ppc/config.in Thu Aug 5 18:44:28 1999 +++ linux/arch/ppc/config.in Mon Aug 23 10:59:10 1999 @@ -50,12 +50,6 @@ define_bool CONFIG_PCI y fi -bool 'PCI quirks' CONFIG_PCI_QUIRKS -if [ "$CONFIG_PCI_QUIRKS" = "y" ]; then - bool ' PCI bridge optimization' CONFIG_PCI_OPTIMIZE -fi - -bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC bool 'Networking support' CONFIG_NET bool 'Sysctl support' CONFIG_SYSCTL bool 'System V IPC' CONFIG_SYSVIPC @@ -139,6 +133,9 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi endmenu fi diff -u --recursive --new-file v2.3.14/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.3.14/linux/arch/sparc/config.in Tue Jun 29 09:22:08 1999 +++ linux/arch/sparc/config.in Mon Aug 23 09:56:31 1999 @@ -170,6 +170,9 @@ # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then # fi + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi endmenu fi diff -u --recursive --new-file v2.3.14/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.14/linux/arch/sparc64/config.in Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc64/config.in Mon Aug 23 10:59:10 1999 @@ -50,9 +50,6 @@ source drivers/sbus/audio/Config.in tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS -if [ "$CONFIG_PCI" = "y" ]; then - bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC -fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT diff -u --recursive --new-file v2.3.14/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.14/linux/drivers/Makefile Mon Aug 9 16:11:33 1999 +++ linux/drivers/Makefile Mon Aug 23 09:56:31 1999 @@ -11,7 +11,7 @@ MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \ macintosh video dio zorro fc4 usb \ - nubus tc ap1000 + nubus tc ap1000 atm ifdef CONFIG_DIO SUB_DIRS += dio @@ -104,6 +104,11 @@ ifeq ($(CONFIG_ISDN),m) MOD_SUB_DIRS += isdn endif +endif + +ifdef CONFIG_ATM +SUB_DIRS += atm +MOD_SUB_DIRS += atm endif ifeq ($(CONFIG_AP1000),y) diff -u --recursive --new-file v2.3.14/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.3.14/linux/drivers/atm/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/Config.in Mon Aug 23 09:56:31 1999 @@ -0,0 +1,45 @@ +# +# ATM device configuration +# +comment 'ATM drivers' +if [ "$CONFIG_INET" = "y" ]; then + tristate 'ATM over TCP' CONFIG_ATM_TCP y +fi +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI y + if [ ! "$CONFIG_ATM_ENI" = "n" ]; then + bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG n + bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST n + if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then + bool ' Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W n + bool ' Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W y + bool ' Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W n + bool ' Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W n + bool ' Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W n + bool ' Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W n + bool ' Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W y + bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W n + fi + fi + tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM y + if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then + bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG n + bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS y + fi +# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y +# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then +# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n +# fi + tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR + if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then + bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI + fi + tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR + if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG + fi + tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON y + if [ "$CONFIG_ATM_HORIZON" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG + fi +fi diff -u --recursive --new-file v2.3.14/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.14/linux/drivers/atm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/Makefile Mon Aug 23 09:56:31 1999 @@ -0,0 +1,79 @@ +# File: drivers/atm/Makefile +# +# Makefile for the Linux network (ATM) device drivers. +# + +L_TARGET := atm.a +L_OBJS := atmdev_init.o +M_OBJS := +MOD_LIST_NAME := ATM_MODULES + +include ../../.config + +ifeq ($(CONFIG_ATM_ENI),y) +L_OBJS += eni.o +LX_OBJS += suni.o +else + ifeq ($(CONFIG_ATM_ENI),m) + M_OBJS += eni.o + MX_OBJS += suni.o + endif +endif + +ifeq ($(CONFIG_ATM_ZATM),y) +L_OBJS += zatm.o uPD98402.o +else + ifeq ($(CONFIG_ATM_ZATM),m) + M_OBJS += zatm.o uPD98402.o + endif +endif + +ifeq ($(CONFIG_ATM_TNETA1570),y) +L_OBJS += tneta1570.o suni.o +endif + +ifeq ($(CONFIG_ATM_FORE200),y) +L_OBJS += fore200.o +endif + +ifeq ($(CONFIG_ATM_NICSTAR),y) +L_OBJS += nicstar.o + ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) + LX_OBJS += suni.o + endif +else + ifeq ($(CONFIG_ATM_NICSTAR),m) + M_OBJS += nicstar.o + ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) + MX_OBJS += suni.o + endif + endif +endif + +ifeq ($(CONFIG_ATM_HORIZON),y) +L_OBJS += horizon.o +else + ifeq ($(CONFIG_ATM_HORIZON),m) + M_OBJS += horizon.o + endif +endif + +ifeq ($(CONFIG_ATM_AMBASSADOR),y) +L_OBJS += ambassador.o +else + ifeq ($(CONFIG_ATM_AMBASSADOR),m) + M_OBJS += ambassador.o + endif +endif + +ifeq ($(CONFIG_ATM_TCP),y) +L_OBJS += atmtcp.o +else + ifeq ($(CONFIG_ATM_TCP),m) + M_OBJS += atmtcp.o + endif +endif + +EXTRA_CFLAGS=-g + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.14/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.3.14/linux/drivers/atm/ambassador.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/ambassador.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,2652 @@ +/* + Madge Ambassador ATM Adapter driver. + Copyright (C) 1995-1999 Madge Networks Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian + system and in the file COPYING in the Linux kernel source. +*/ + +/* + IMPORTANT NOTE: Madge Networks does not license the microcode for + this driver under the GPL. See the .data file for the licence. +*/ + +/* * dedicated to the memory of Graham Gordon 1971-1998 * */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ambassador.h" + +#define maintainer_string "Giuliano Procida at Madge Networks " +#define description_string "Madge ATM Ambassador driver" +#define version_string "1.1" + +static inline void __init show_version (void) { + printk ("%s version %s\n", description_string, version_string); +} + +/* + + Theory of Operation + + I Hardware, detection, initialisation and shutdown. + + 1. Supported Hardware + + This driver is for the PCI ATMizer-based Ambassador card (except + very early versions). It is not suitable for the similar EISA "TR7" + card. Commercially, both cards are known as Collage Server ATM + adapters. + + The loader supports image transfer to the card, image start and few + other miscellaneous commands. + + Only AAL5 is supported with vpi = 0 and vci in the range 0 to 1023. + + The cards are big-endian. + + 2. Detection + + Standard PCI stuff, the early cards are detected and rejected. + + 3. Initialisation + + The cards are reset and the self-test results are checked. The + microcode image is then transferred and started. This waits for a + pointer to a descriptor containing details of the host-based queues + and buffers and various parameters etc. Once they are processed + normal operations may begin. The BIA is read using a microcode + command. + + 4. Shutdown + + This may be accomplished either by a card reset or via the microcode + shutdown command. Further investigation required. + + 5. Persistent state + + The card reset does not affect PCI configuration (good) or the + contents of several other "shared run-time registers" (bad) which + include doorbell and interrupt control as well as EEPROM and PCI + control. The driver must be careful when modifying these registers + not to touch bits it does not use and to undo any changes at exit. + + II Driver software + + 0. Generalities + + The adapter is quite intelligent (fast) and has a simple interface + (few features). VPI is always zero, 1024 VCIs are supported. There + is limited cell rate support. UBR channels can be kept and ABR + (explicit rate, bu not EFCI) is supported. There is no CBR or VBR + support. + + 1. Driver <-> Adapter Communication + + Apart from the basic loader commands, the driver communicates + through three entities: the command queue (CQ), the transmit queue + pair (TXQ) and the receive queue pairs (RXQ). These three entities + are set up by the host and passed to the microcode just after it has + been started. + + All queues are host-based circular queues. They are contiguous and + (due to hardware limitations) have some restrictions as to their + locations in (bus) memory. They are of the "full means the same as + empty so don't do that" variety since the adapter uses pointers + internally. + + The queue pairs work as follows: one queue is for supply to the + adapter, items in it are pending and are owned by the adapter; the + other is the for return from the adapter, items in it have been + dealt with by the adapter. The host adds items to the supply (TX + descriptors and free RX buffer descriptors) and removes items from + the return (TX and RX completions). The adapter deals with out of + order completions. + + Interrupts (card to host) and the doorbell (host to card) are used + for signalling. + + 1. CQ + + This is to communicate "open VC", "close VC", "get stats" etc. to + the adapter. At most one command is retired every millisecond by the + card. There is no out of order completion or notification. The + driver needs to check the return code of the command, waiting as + appropriate. + + 2. TXQ + + TX supply items are of variable length (scatter gather support) and + so the queue items are (more or less) pointers to the real thing. + Each TX supply item contains a unique, host-supplied handle (the skb + bus address seems most sensible as this works for Alphas as well, + there is no need to do any endian conversions on the handles). + + TX return items consist of just the handles above. + + 3. RXQ (up to 4 of these with different lengths and buffer sizes) + + RX supply items consist of a unique, host-supplied handle (the skb + bus address again) and a pointer to the buffer data area. + + RX return items consist of the handle above, the VC, length and a + status word. This just screams "oh so easy" doesn't it? + + Note on RX pool sizes: + + Each pool should have enough buffers to handle a back-to-back stream + of minimum sized frames on a single VC. For example: + + frame spacing = 3us (about right) + + delay = IRQ lat + RX handling + RX buffer replenish = 20 (us) (a guess) + + min number of buffers for one VC = 1 + delay/spacing (buffers) + + delay/spacing = latency = (20+2)/3 = 7 (buffers) (rounding up) + + The 20us delay assumes that there is no need to touch disk; if we + need touch disk to get buffers we are going to drop frames anyway. + + In fact, each pool should have enough buffers to support the + simultaneous reassembly of a separate frame on each VC and cope with + the case in which large frames arrive with round robin cell arrivals + on each VC. + + Only one frame can complete at each cell arrival, so if "n" VCs are + open, the worst case is to have them all complete frames together + followed by all starting new frames together. + + min number of buffers = n + delay/spacing + + These are the extreme requirements, however, they are "n+k" for some + "k" so we have only the constant to choose. This is the argument + rx_lats which current defaults at 3. + + Actually, "n ? n+k : 0" is better and this is what is implemented. + + 4. Driver locking + + Simple spinlocks are used around the TX and RX queue mechanisms. + Anyone with a faster, working method is welcome to implement it. + + The adapter command queue is protected with a spinlock. We always + wait for commands to complete. + + A more complex form of locking is used around parts of the VC open + and close functions. There are three reasons for a lock: 1. we need + to do atomic rate reservation and release (not used yet), 2. Opening + sometimes involves two adapter commands which must not be separated + by another command on the same VC, 3. the changes in RX pool size + must be atomic. The lock needs to work over context switches, so we + use a semaphore. + + III Hardware Features and Microcode Bugs + + 1. Byte Ordering + + *%^"$&%^$*&^"$(%^$#&^%$(&#%$*(&^#%!"!"!*! + + 2. Memory access + + All structures that are not accessed using DMA must be 4-byte + aligned (not a problem) and must not cross 4MB boundaries. + + There is a DMA memory hole at E0000000-E00000FF (groan). + + TX fragments (DMA read) must not cross 4MB boundaries (would be 16MB + but for a hardware bug). + + RX buffers (DMA write) must not cross 16MB boundaries and must + include spare trailing bytes up to the next 4-byte boundary; they + will be written with rubbish. + + The PLX likes to prefetch; if reading up to 4 u32 past the end of + each TX fragment is not a problem, then TX can be made to go a + little faster by passing a flag at init that disables a prefetch + workaround. We do not pass this flag. + + Now we: + . Note that skb_alloc rounds up size to a 16byte boundary. + . Ensure all areas must not traverse 4MB boundaries. + . Ensure all areas must not start at a E00000xx bus address. + (I cannot be certain, but this may always hold with Linux) + . Make all failures cause a loud message. + . Discard non-conforming SKBs (causes TX failure or RX fill delay). + . Discard non-conforming TX fragment descriptors (the TX fails). + In the future we could: + . Allow RX areas that traverse 4MB (but not 16MB) boundaries. + . Segment TX areas into some/more fragments, when necessary. + . Relax checks for non-DMA items (ignore hole). + . Give scatter-gather (iovec) requirements using ???. (?) + + 3. VC close is broken (only for new microcode) + + The VC close adapter microcode command fails to do anything if any + frames have been received on the VC but none have been transmitted. + Frames continue to be reassembled and passed (with IRQ) to the + driver. + + IV To Do List + + . Fix bugs! + + . Timer code may be broken. + + . Deal with buggy VC close (somehow) in microcode 12. + + . Handle interrupted and/or non-blocking writes - is this a job for + the protocol layer? + + . Add code to break up TX fragments when they span 4MB boundaries. + + . Add SUNI phy layer (need to know where SUNI lives on card). + + . Implement a tx_alloc fn to (a) satisfy TX alignment etc. and (b) + leave extra headroom space for Ambassador TX descriptors. + + . Understand these elements of struct atm_vcc: recvq (proto?), + sleep, callback, listenq, backlog_quota, reply and user_back. + + . Adjust TX/RX skb allocation to favour IP with LANE/CLIP (configurable). + + . Impose a TX-pending limit (2?) on each VC, help avoid TX q overflow. + + . Decide whether RX buffer recycling is or can be made completely safe; + turn it back on. It looks like Werner is going to axe this. + + . Implement QoS changes on open VCs (involves extracting parts of VC open + and close into separate functions and using them to make changes). + + . Hack on command queue so that someone can issue multiple commands and wait + on the last one (OR only "no-op" or "wait" commands are waited for). + + . Eliminate need for while-schedule around do_command. + +*/ + +/********** microcode **********/ + +#ifdef AMB_NEW_MICROCODE +#define UCODE(x) "atmsar12" "." #x +#else +#define UCODE(x) "atmsar11" "." #x +#endif + +static const u32 __initdata ucode_start = +#include UCODE(start) +; + +static const region __initdata ucode_regions[] = { +#include UCODE(regions) + { 0, 0 } +}; + +static const u32 __initdata ucode_data[] = { +#include UCODE(data) + 0xdeadbeef +}; + +/********** globals **********/ + +static amb_dev * amb_devs = NULL; +static struct timer_list housekeeping; + +static unsigned short debug = 0; +static unsigned int cmds = 8; +static unsigned int txs = 32; +static unsigned int rxs[NUM_RX_POOLS] = { 64, 64, 64, 64 }; +static unsigned int rxs_bs[NUM_RX_POOLS] = { 2500, 5000, 10000, 20000 }; +static unsigned int rx_lats = 7; +static unsigned char pci_lat = 0; + +/********** access to adapter **********/ + +static inline void wr_mem (const amb_dev * dev, u32 * addr, u32 data) { + u32 be = cpu_to_be32 (data); + PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x b[%08x]", addr, data, be); +#ifdef AMB_MMIO + dev->membase[addr - (u32 *) 0] = be; +#else + outl (be, dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); +#endif +} + +static inline u32 rd_mem (const amb_dev * dev, u32 * addr) { +#ifdef AMB_MMIO + u32 be = dev->membase[addr - (u32 *) 0]; +#else + u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); +#endif + u32 data = be32_to_cpu (be); + PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be); + return data; +} + +/********** dump routines **********/ + +static inline void dump_registers (const amb_dev * dev) { +#ifdef DEBUG_AMBASSADOR + // u32 * i; + // PRINTD (DBG_REGS, "mailboxes: "); + // for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i) + // PRINTD (DBG_REGS, "%08x ", rd_mem (dev, i)); + PRINTD (DBG_REGS, "doorb %08x", rd_mem (dev, (u32 *) 0x60)); + PRINTD (DBG_REGS, "irqev %08x", rd_mem (dev, (u32 *) 0x64)); + PRINTD (DBG_REGS, "irqen %08x", rd_mem (dev, (u32 *) 0x68)); + PRINTD (DBG_REGS, "reset %08x", rd_mem (dev, (u32 *) 0x6c)); +#else + (void) dev; +#endif + return; +} + +static inline void dump_loader_block (volatile loader_block * lb) { +#ifdef DEBUG_AMBASSADOR + unsigned int i; + PRINTDB (DBG_LOAD, "lb @ %p; res: %d, cmd: %d, pay:", + lb, be32_to_cpu (lb->result), be32_to_cpu (lb->command)); + for (i = 0; i < MAX_COMMAND_DATA; ++i) + PRINTDM (DBG_LOAD, " %08x", be32_to_cpu (lb->payload.data[i])); + PRINTDE (DBG_LOAD, ", vld: %08x", be32_to_cpu (lb->valid)); +#else + (void) lb; +#endif + return; +} + +static inline void dump_command (command * cmd) { +#ifdef DEBUG_AMBASSADOR + unsigned int i; + PRINTDB (DBG_CMD, "cmd @ %p, req: %08x, pars:", + cmd, /*be32_to_cpu*/ (cmd->request)); + for (i = 0; i < 3; ++i) + PRINTDM (DBG_CMD, " %08x", /*be32_to_cpu*/ (cmd->args.par[i])); + PRINTDE (DBG_CMD, ""); +#else + (void) cmd; +#endif + return; +} + +static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) { +#ifdef DEBUG_AMBASSADOR + unsigned int i; + unsigned char * data = skb->data; + PRINTDB (DBG_DATA, "%s(%u) ", prefix, vc); + for (i=0; ilen && i < 256;i++) + PRINTDM (DBG_DATA, "%02x ", data[i]); + PRINTDE (DBG_DATA,""); +#else + (void) prefix; + (void) vc; + (void) skb; +#endif + return; +} + +/********** check memory areas for use by Ambassador **********/ + +/* see limitations under Hardware Features */ + +static inline int check_area (void * start, size_t length) { + // assumes length > 0 + const u32 fourmegmask = (-1)<<22; + const u32 twofivesixmask = (-1)<<8; + const u32 starthole = 0xE0000000; + u32 startaddress = virt_to_bus (start); + u32 lastaddress = startaddress+length-1; + if ((startaddress ^ lastaddress) & fourmegmask || + (startaddress & twofivesixmask) == starthole) { + PRINTK (KERN_ERR, "check_area failure: [%x,%x] - mail maintainer!", + startaddress, lastaddress); + return -1; + } else { + return 0; + } +} + +/********** free an skb (as per ATM device driver documentation) **********/ + +static inline void amb_kfree_skb (struct sk_buff * skb) { + if (ATM_SKB(skb)->vcc->pop) { + ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); + } else { + dev_kfree_skb (skb); + } +} + +/********** TX completion **********/ + +static inline void tx_complete (amb_dev * dev, tx_out * tx) { + tx_simple * tx_descr = bus_to_virt (tx->handle); + struct sk_buff * skb = tx_descr->skb; + + PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx); + + // VC layer stats + ATM_SKB(skb)->vcc->stats->tx++; + + // free the descriptor + kfree (tx_descr); + + // free the skb + amb_kfree_skb (skb); + + dev->stats.tx_ok++; + return; +} + +/********** RX completion **********/ + +static void rx_complete (amb_dev * dev, rx_out * rx) { + struct sk_buff * skb = bus_to_virt (rx->handle); + u16 vc = be16_to_cpu (rx->vc); + // unused: u16 lec_id = be16_to_cpu (rx->lec_id); + u16 status = be16_to_cpu (rx->status); + u16 rx_len = be16_to_cpu (rx->length); + + PRINTD (DBG_FLOW|DBG_RX, "rx_complete %p %p (len=%hu)", dev, rx, rx_len); + + // XXX move this in and add to VC stats ??? + if (!status) { + struct atm_vcc * atm_vcc = dev->rxer[vc]; + dev->stats.rx.ok++; + + if (atm_vcc) { + + if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { + + if (atm_charge (atm_vcc, skb->truesize)) { + + // prepare socket buffer + ATM_SKB(skb)->vcc = atm_vcc; + skb_put (skb, rx_len); + + dump_skb ("<<<", vc, skb); + + // VC layer stats + atm_vcc->stats->rx++; + skb->stamp = xtime; + // end of our responsability + atm_vcc->push (atm_vcc, skb); + return; + + } else { + // someone fix this (message), please! + PRINTD (DBG_INFO|DBG_RX, "dropped thanks to atm_charge (vc %hu)", vc); + // drop stats incremented in atm_charge + } + + } else { + PRINTK (KERN_INFO, "dropped over-size frame"); + // should we count this? + atm_vcc->stats->rx_drop++; + } + + } else { + PRINTD (DBG_WARN|DBG_RX, "got frame but RX closed for channel %hu", vc); + // this is an adapter bug, only in new version of microcode + } + + } else { + dev->stats.rx.error++; + if (status & CRC_ERR) + dev->stats.rx.badcrc++; + if (status & LEN_ERR) + dev->stats.rx.toolong++; + if (status & ABORT_ERR) + dev->stats.rx.aborted++; + if (status & UNUSED_ERR) + dev->stats.rx.unused++; + } + + dev_kfree_skb (skb); + return; +} + +/* + + Note on queue handling. + + Here "give" and "take" refer to queue entries and a queue (pair) + rather than frames to or from the host or adapter. Empty frame + buffers are given to the RX queue pair and returned unused or + containing RX frames. TX frames (well, pointers to TX fragment + lists) are given to the TX queue pair, completions are returned. + +*/ + +/********** command queue **********/ + +// I really don't like this, but it's the best I can do at the moment + +// also, the callers are responsible for byte order as the microcode +// sometimes does 16-bit accesses (yuk yuk yuk) + +static int command_do (amb_dev * dev, command * cmd) { + volatile amb_cq * cq = &dev->cq; + command * my_slot; + unsigned long timeout; + + PRINTD (DBG_FLOW|DBG_CMD, "command_do %p", dev); + + if (test_bit (dead, &dev->flags)) + return 0; + + spin_lock (&cq->lock); + + // if not full... + if (cq->pending < cq->maximum) { + // remember my slot for later + my_slot = cq->in; + PRINTD (DBG_CMD, "command in slot %p", my_slot); + + dump_command (cmd); + + // copy command in + *cq->in = *cmd; + cq->pending++; + cq->in = NEXTQ (cq->in, cq->start, cq->limit); + + // mail the command + wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (cq->in)); + + // prepare to wait for cq->pending milliseconds + // effectively one centisecond on i386 + timeout = (cq->pending*HZ+999)/1000; + + if (cq->pending > cq->high) + cq->high = cq->pending; + spin_unlock (&cq->lock); + + while (timeout) { + // go to sleep + // PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout); + timeout = schedule_timeout (timeout); + // woken up by timeout or signal + } + + // wait for my slot to be reached (all waiters are here or above, until...) + while (cq->out != my_slot) { + PRINTD (DBG_CMD, "wait: command slot (now at %p)", cq->out); + schedule(); + } + + // wait on my slot (... one gets to its slot, and... ) + while (cq->out->request != cpu_to_be32 (SRB_COMPLETE)) { + PRINTD (DBG_CMD, "wait: command slot completion"); + schedule(); + } + + PRINTD (DBG_CMD, "command complete"); + // update queue (... moves the queue along to the next slot) + spin_lock (&cq->lock); + cq->pending--; + // copy command out + *cmd = *cq->out; + cq->out = NEXTQ (cq->out, cq->start, cq->limit); + spin_unlock (&cq->lock); + + return 0; + } else { + spin_unlock (&cq->lock); + return -EAGAIN; + } + +} + +/********** TX queue pair **********/ + +static inline int tx_give (amb_dev * dev, tx_in * tx) { + amb_txq * txq = &dev->txq; + unsigned long flags; + + PRINTD (DBG_FLOW|DBG_TX, "tx_give %p", dev); + + if (test_bit (dead, &dev->flags)) + return 0; + + spin_lock_irqsave (&txq->lock, flags); + + if (txq->pending < txq->maximum) { + PRINTD (DBG_TX, "TX in slot %p", txq->in.ptr); + + *txq->in.ptr = *tx; + txq->pending++; + txq->in.ptr = NEXTQ (txq->in.ptr, txq->in.start, txq->in.limit); + // hand over the TX and ring the bell + wr_mem (dev, &mem->mb.adapter.tx_address, virt_to_bus (txq->in.ptr)); + wr_mem (dev, &mem->doorbell, TX_FRAME); + + if (txq->pending > txq->high) + txq->high = txq->pending; + spin_unlock_irqrestore (&txq->lock, flags); + return 0; + } else { + txq->filled++; + spin_unlock_irqrestore (&txq->lock, flags); + return -EAGAIN; + } +} + +static inline int tx_take (amb_dev * dev) { + amb_txq * txq = &dev->txq; + unsigned long flags; + + PRINTD (DBG_FLOW|DBG_TX, "tx_take %p", dev); + + spin_lock_irqsave (&txq->lock, flags); + + if (txq->pending && txq->out.ptr->handle) { + // deal with TX completion + tx_complete (dev, txq->out.ptr); + // mark unused again + txq->out.ptr->handle = 0; + // remove item + txq->pending--; + txq->out.ptr = NEXTQ (txq->out.ptr, txq->out.start, txq->out.limit); + + spin_unlock_irqrestore (&txq->lock, flags); + return 0; + } else { + + spin_unlock_irqrestore (&dev->lock, flags); + return -1; + } +} + +/********** RX queue pairs **********/ + +static inline int rx_give (amb_dev * dev, rx_in * rx, unsigned char pool) { + amb_rxq * rxq = &dev->rxq[pool]; + unsigned long flags; + + PRINTD (DBG_FLOW|DBG_RX, "rx_give %p[%hu]", dev, pool); + + spin_lock_irqsave (&rxq->lock, flags); + + if (rxq->pending < rxq->maximum) { + PRINTD (DBG_RX, "RX in slot %p", rxq->in.ptr); + + *rxq->in.ptr = *rx; + rxq->pending++; + rxq->in.ptr = NEXTQ (rxq->in.ptr, rxq->in.start, rxq->in.limit); + // hand over the RX buffer + wr_mem (dev, &mem->mb.adapter.rx_address[pool], virt_to_bus (rxq->in.ptr)); + + spin_unlock_irqrestore (&rxq->lock, flags); + return 0; + } else { + spin_unlock_irqrestore (&rxq->lock, flags); + return -1; + } +} + +static inline int rx_take (amb_dev * dev, unsigned char pool) { + amb_rxq * rxq = &dev->rxq[pool]; + unsigned long flags; + + PRINTD (DBG_FLOW|DBG_RX, "rx_take %p[%hu]", dev, pool); + + spin_lock_irqsave (&rxq->lock, flags); + + if (rxq->pending && (rxq->out.ptr->status || rxq->out.ptr->length)) { + // deal with RX completion + rx_complete (dev, rxq->out.ptr); + // mark unused again + rxq->out.ptr->status = 0; + rxq->out.ptr->length = 0; + // remove item + rxq->pending--; + rxq->out.ptr = NEXTQ (rxq->out.ptr, rxq->out.start, rxq->out.limit); + + if (rxq->pending < rxq->low) + rxq->low = rxq->pending; + spin_unlock_irqrestore (&rxq->lock, flags); + return 0; + } else { + if (!rxq->pending && rxq->buffers_wanted) + rxq->emptied++; + spin_unlock_irqrestore (&rxq->lock, flags); + return -1; + } +} + +/********** RX Pool handling **********/ + +/* pre: buffers_wanted = 0, post: pending = 0 */ +static inline void drain_rx_pool (amb_dev * dev, unsigned char pool) { + amb_rxq * rxq = &dev->rxq[pool]; + + PRINTD (DBG_FLOW|DBG_POOL, "drain_rx_pool %p %hu", dev, pool); + + if (test_bit (dead, &dev->flags)) + return; + + /* we are not quite like the fill pool routines as we cannot just + remove one buffer, we have to remove all of them, but we might as + well pretend... */ + if (rxq->pending > rxq->buffers_wanted) { + command cmd; + cmd.request = cpu_to_be32 (SRB_FLUSH_BUFFER_Q); + cmd.args.flush.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT); + while (command_do (dev, &cmd)) + schedule(); + /* the pool may also be emptied via the interrupt handler */ + while (rxq->pending > rxq->buffers_wanted) + if (rx_take (dev, pool)) + schedule(); + } + + return; +} + +#ifdef MODULE +static void drain_rx_pools (amb_dev * dev) { + unsigned char pool; + + PRINTD (DBG_FLOW|DBG_POOL, "drain_rx_pools %p", dev); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + drain_rx_pool (dev, pool); + + return; +} +#endif + +static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority) { + rx_in rx; + amb_rxq * rxq; + + PRINTD (DBG_FLOW|DBG_POOL, "fill_rx_pool %p %hu %x", dev, pool, priority); + + if (test_bit (dead, &dev->flags)) + return; + + rxq = &dev->rxq[pool]; + while (rxq->pending < rxq->maximum && rxq->pending < rxq->buffers_wanted) { + + struct sk_buff * skb = alloc_skb (rxq->buffer_size + RX_FUDGE, priority); + if (!skb) { + PRINTD (DBG_SKB|DBG_POOL, "failed to allocate skb for RX pool %hu", pool); + return; + } + if (check_area (skb->data, skb->truesize)) { + dev_kfree_skb (skb); + return; + } + // cast needed as there is no %? for pointer differences + PRINTD (DBG_SKB, "allocated skb at %p, head %p, area %li", + skb, skb->head, (long) (skb->end - skb->head)); + rx.handle = virt_to_bus (skb); + rx.host_address = cpu_to_be32 (virt_to_bus (skb->data)); + if (rx_give (dev, &rx, pool)) + dev_kfree_skb (skb); + + } + + return; +} + +// top up all RX pools (also called as a bottom half) +static void fill_rx_pools (amb_dev * dev) { + unsigned char pool; + + PRINTD (DBG_FLOW|DBG_POOL, "fill_rx_pools %p", dev); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + fill_rx_pool (dev, pool, GFP_ATOMIC); + + return; +} + +/********** enable host interrupts **********/ + +static inline void interrupts_on (amb_dev * dev) { + wr_mem (dev, &mem->interrupt_control, + rd_mem (dev, &mem->interrupt_control) + | AMB_INTERRUPT_BITS); +} + +/********** disable host interrupts **********/ + +static inline void interrupts_off (amb_dev * dev) { + wr_mem (dev, &mem->interrupt_control, + rd_mem (dev, &mem->interrupt_control) + &~ AMB_INTERRUPT_BITS); +} + +/********** interrupt handling **********/ + +static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) { + amb_dev * dev = amb_devs; + unsigned int irq_ok; + unsigned int irq_ok_old; + (void) pt_regs; + + PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id); + + if (!dev_id) { + PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq); + return; + } + // Did one of our cards generate the interrupt? + while (dev) { + if (dev == dev_id) + break; + dev = dev->prev; + } + if (!dev) { + PRINTD (DBG_IRQ, "irq not for me: %d", irq); + return; + } + if (irq != dev->irq) { + PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq); + return; + } + + // definitely for us + irq_ok = 0; + irq_ok_old = -1; + + // perhaps disable interrupts? (disabled at PIC by Linux) + // interrupts_off (dev); + + while (irq_ok_old != irq_ok && irq_ok < 100) { + unsigned char pool; +#ifdef DEBUG_AMBASSADOR + u32 ints = rd_mem (dev, &mem->interrupt); +#endif + wr_mem (dev, &mem->interrupt, -1); + PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", ints, irq_ok); + irq_ok_old = irq_ok; + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + while (!rx_take (dev, pool)) + ++irq_ok; + while (!tx_take (dev)) + ++irq_ok; + } + + if (irq_ok) { +#if 0 + queue_task (&dev->bh, &tq_immediate); + mark_bh (IMMEDIATE_BH); +#else + fill_rx_pools (dev); +#endif + + PRINTD (DBG_IRQ, "work done: %u", irq_ok); + } else { + PRINTD (DBG_IRQ|DBG_WARN, "no work done"); + } + + // perhaps re-enable interrupts? (re-enabled at PIC by Linux) + // interrupts_on (dev); + PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id); + return; +} + +/********** don't panic... yeah, right **********/ + +#ifdef DEBUG_AMBASSADOR +static void dont_panic (amb_dev * dev) { + amb_cq * cq = &dev->cq; + amb_txq * txq; + amb_rxq * rxq; + command * cmd; + tx_in * tx; + tx_simple * tx_descr; + unsigned char pool; + rx_in * rx; + + unsigned long flags; + save_flags (flags); + cli(); + + PRINTK (KERN_INFO, "don't panic - putting adapter into reset"); + wr_mem (dev, &mem->reset_control, rd_mem (dev, &mem->reset_control) | AMB_RESET); + + PRINTK (KERN_INFO, "marking all commands complete"); + for (cmd = cq->start; cmd < cq->limit; ++cmd) + cmd->request = cpu_to_be32 (SRB_COMPLETE); + + PRINTK (KERN_INFO, "completing all TXs"); + txq = &dev->txq; + tx = txq->in.ptr; + while (txq->pending--) { + if (tx == txq->in.start) + tx = txq->in.limit; + --tx; + tx_descr = bus_to_virt (be32_to_cpu (tx->tx_descr_addr)); + amb_kfree_skb (tx_descr->skb); + kfree (tx_descr); + } + + PRINTK (KERN_INFO, "freeing all RX buffers"); + for (pool = 0; pool < NUM_RX_POOLS; ++pool) { + rxq = &dev->rxq[pool]; + rx = rxq->in.ptr; + while (rxq->pending--) { + if (rx == rxq->in.start) + rx = rxq->in.limit; + --rx; + dev_kfree_skb (bus_to_virt (rx->handle)); + } + } + + PRINTK (KERN_INFO, "don't panic over - close all VCs and rmmod"); + set_bit (dead, &dev->flags); + restore_flags (flags); + return; +} +#endif + +/********** make rate (not quite as much fun as Horizon) **********/ + +static unsigned int make_rate (unsigned int rate, rounding r, + u16 * bits, unsigned int * actual) { + unsigned char exp = 0; /* silence gcc */ + unsigned int man = 0; + + PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate); + + // rates in cells per second, ITU format (nasty 16bit fp) + // given 5-bit e and 9-bit m: + // rate = EITHER (1+m/2^9)*2^e OR 0 + // bits = EITHER 1<<14 | e<<9 | m OR 0 + // (bit 15 is "reserved", bit 14 "non-zero") + // smallest rate is 0 (special representation) + // largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1) + // simple algorithm: + // find position of top bit, this gives e + // remove top bit and shift (rounding if feeling clever) by 9-e + + // XXX fix me to work with larger ints + + // ucode bug: please don't set bit 14! 0 not representable + + if (rate) { + // non-zero rate + + exp = 31; + man = rate; + + // invariant: rate = man*2^(exp-31) + while (!(man & (1<<31))) { + exp = exp - 1; + man = man<<1; + } + + // man has top bit set + // rate = (2^31+(man-2^31))*2^(exp-31) + // rate = (1+(man-2^31)/2^31)*2^exp + man = man<<1; + // rate = (1+man/2^32)*2^exp + + // exp is in the range 0 to 31, man is in the range 0 to 2^32-1 + // time to lose significance... we want m in the range 0 to 2^9-1 + // rounding presents a minor problem... we first decide which way + // we are rounding (based on given rounding direction and the bits + // of the mantissa that are to be discarded). + + switch (r) { + case round_down: { + // just truncate + man = man>>(32-9); + break; + } + case round_up: { + // check all bits that we are discarding + if (man & (-1>>9)) { + man = (man>>(32-9)) + 1; + if (man == (1<<9)) { + // check for round up outside of range + if (exp == 31) { + return -EINVAL; + } else { + man = 0; + exp += 1; + } + } + } else { + man = (man>>(32-9)); + } + break; + } + case round_nearest: { + // check msb that we are discarding + if (man & (1<<(32-9-1))) { + man = (man>>(32-9)) + 1; + // if rounding up would go out of range, just stay at top + if (man == (1<<9)) { + if (exp == 31) { + man -= 1; + } else { + man = 0; + exp += 1; + } + } + } else { + man = (man>>(32-9)); + } + break; + } + } + + } else { + // zero rate + + switch (r) { + case round_up: { + break; + } + case round_down: { + return -EINVAL; + break; + } + case round_nearest: { + break; + } + } + + } + + PRINTD (DBG_QOS, "rate: man=%u, exp=%hu", man, exp); + + if (bits) + *bits = /* (1<<14) | */ (exp<<9) | man; + + if (actual) + *actual = (exp >= 9) + ? (1 << exp) + (man << (exp-9)) + : (1 << exp) + ((man + (1<<(9-exp-1))) >> (9-exp)); + + return 0; +} + +/********** Linux ATM Operations **********/ + +// some are not yet implemented while others do not make sense for +// this device + +/********** Open a VC **********/ + +static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { + int error; + + struct atm_qos * qos; + struct atm_trafprm * txtp; + struct atm_trafprm * rxtp; + u16 tx_rate_bits; + u16 tx_vc_bits = 0; /* silence gcc */ + u16 tx_frame_bits = 0; + // int pcr; + + amb_dev * dev = AMB_DEV(atm_vcc->dev); + amb_vcc * vcc; + unsigned char pool = -1; // compiler warning + + PRINTD (DBG_FLOW|DBG_VCC, "amb_open %x %x", vpi, vci); + + // UNSPEC is deprecated, remove this code eventually +#if defined ATM_VPI_UNSPEC + if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { + PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); + return -EINVAL; + } +#endif + + // deal with possibly wildcarded VCs + error = atm_find_ci (atm_vcc, &vpi, &vci); + if (error) { + PRINTD (DBG_WARN|DBG_VCC, "atm_find_ci failed!"); + return error; + } + PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci); + + if (!(0 <= vpi && vpi < (1<qos; + + if (qos->aal != ATM_AAL5) { + PRINTD (DBG_QOS, "AAL not supported"); + return -EINVAL; + } + + // traffic parameters + + PRINTD (DBG_QOS, "TX:"); + txtp = &qos->txtp; + if (txtp->traffic_class != ATM_NONE) { + switch (txtp->traffic_class) { + case ATM_UBR: { + // we take "the PCR" as a rate-cap + int pcr = atm_pcr_goal (txtp); + if (!pcr) { + // no rate cap + tx_rate_bits = 0; + tx_vc_bits = TX_UBR; + tx_frame_bits = TX_FRAME_NOTCAP; + } else { + rounding r; + if (pcr < 0) { + r = round_down; + pcr = -pcr; + } else { + r = round_up; + } + error = make_rate (pcr, r, &tx_rate_bits, 0); + tx_vc_bits = TX_UBR_CAPPED; + tx_frame_bits = TX_FRAME_CAPPED; + } + break; + } +#if 0 + case ATM_ABR: { + pcr = atm_pcr_goal (txtp); + PRINTD (DBG_QOS, "pcr goal = %d", pcr); + break; + } +#endif + default: { + // PRINTD (DBG_QOS, "request for non-UBR/ABR denied"); + PRINTD (DBG_QOS, "request for non-UBR denied"); + return -EINVAL; + } + } + PRINTD (DBG_QOS, "tx_rate_bits=%hx, tx_vc_bits=%hx", + tx_rate_bits, tx_vc_bits); + } + + PRINTD (DBG_QOS, "RX:"); + rxtp = &qos->rxtp; + if (rxtp->traffic_class == ATM_NONE) { + // do nothing + } else { + // choose an RX pool (arranged in increasing size) + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + if ((unsigned int) rxtp->max_sdu <= dev->rxq[pool].buffer_size) { + PRINTD (DBG_VCC|DBG_QOS|DBG_POOL, "chose pool %hu (max_sdu %u <= %u)", + pool, rxtp->max_sdu, dev->rxq[pool].buffer_size); + break; + } + if (pool == NUM_RX_POOLS) { + PRINTD (DBG_WARN|DBG_VCC|DBG_QOS|DBG_POOL, + "no pool suitable for VC (RX max_sdu %d is too large)", + rxtp->max_sdu); + return -EINVAL; + } + + switch (rxtp->traffic_class) { + case ATM_UBR: { + break; + } +#if 0 + case ATM_ABR: { + pcr = atm_pcr_goal (rxtp); + PRINTD (DBG_QOS, "pcr goal = %d", pcr); + break; + } +#endif + default: { + // PRINTD (DBG_QOS, "request for non-UBR/ABR denied"); + PRINTD (DBG_QOS, "request for non-UBR denied"); + return -EINVAL; + } + } + } + + // get space for our vcc stuff + vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL); + if (!vcc) { + PRINTK (KERN_ERR, "out of memory!"); + return -ENOMEM; + } + atm_vcc->dev_data = (void *) vcc; + + // no failures beyond this point + + // we are not really "immediately before allocating the connection + // identifier in hardware", but it will just have to do! + atm_vcc->flags |= ATM_VF_ADDR; + + if (txtp->traffic_class != ATM_NONE) { + command cmd; + + vcc->tx_frame_bits = tx_frame_bits; + + down (&dev->vcc_sf); + if (dev->rxer[vci]) { + // RXer on the channel already, just modify rate... + cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE); + cmd.args.modify_rate.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.modify_rate.rate = cpu_to_be16 (tx_rate_bits); + while (command_do (dev, &cmd)) + schedule(); + // ... and TX flags, preserving the RX pool + cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); + cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.modify_flags.flags = cpu_to_be16 + ((AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT) | tx_vc_bits); + while (command_do (dev, &cmd)) + schedule(); + } else { + // no RXer on the channel, just open (with pool zero) + cmd.request = cpu_to_be32 (SRB_OPEN_VC); + cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.open.flags = cpu_to_be16 (tx_vc_bits); + cmd.args.open.rate = cpu_to_be16 (tx_rate_bits); + while (command_do (dev, &cmd)) + schedule(); + } + dev->txer[vci].tx_present = 1; + up (&dev->vcc_sf); + } + + if (rxtp->traffic_class != ATM_NONE) { + command cmd; + + vcc->rx_info.pool = pool; + + down (&dev->vcc_sf); + + /* grow RX buffer pool */ + if (!dev->rxq[pool].buffers_wanted) + dev->rxq[pool].buffers_wanted = rx_lats; + dev->rxq[pool].buffers_wanted += 1; + fill_rx_pool (dev, pool, GFP_KERNEL); + + if (dev->txer[vci].tx_present) { + // TXer on the channel already + // switch (from pool zero) to this pool, preserving the TX bits + cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); + cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.modify_flags.flags = cpu_to_be16 + ((pool << SRB_POOL_SHIFT) | dev->txer[vci].tx_vc_bits); + } else { + // no TXer on the channel, open the VC (with no rate info) + cmd.request = cpu_to_be32 (SRB_OPEN_VC); + cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used in the next two (BE nightmare continues) + cmd.args.open.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT); + cmd.args.open.rate = cpu_to_be16 (0); + } + while (command_do (dev, &cmd)) + schedule(); + // this link allows RX frames through + dev->rxer[vci] = atm_vcc; + up (&dev->vcc_sf); + } + + // set elements of vcc + atm_vcc->vpi = vpi; // 0 + atm_vcc->vci = vci; + + // indicate readiness + atm_vcc->flags |= ATM_VF_READY; + + MOD_INC_USE_COUNT; + return 0; +} + +/********** Close a VC **********/ + +static void amb_close (struct atm_vcc * atm_vcc) { + amb_dev * dev = AMB_DEV (atm_vcc->dev); + amb_vcc * vcc = AMB_VCC (atm_vcc); + u16 vci = atm_vcc->vci; + + PRINTD (DBG_VCC|DBG_FLOW, "amb_close"); + + // indicate unreadiness + atm_vcc->flags &= ~ATM_VF_READY; + + // disable TXing + if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { + command cmd; + + down (&dev->vcc_sf); + if (dev->rxer[vci]) { + // RXer still on the channel, just modify rate... XXX not really needed + cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE); + cmd.args.modify_rate.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.modify_rate.rate = cpu_to_be16 (0); + // ... and clear TX rate flags (XXX to stop RM cell output?), preserving RX pool + } else { + // no RXer on the channel, close channel + cmd.request = cpu_to_be32 (SRB_CLOSE_VC); + cmd.args.close.vc = cpu_to_be32 (vci); // vpi 0 + } + dev->txer[vci].tx_present = 0; + while (command_do (dev, &cmd)) + schedule(); + up (&dev->vcc_sf); + } + + // disable RXing + if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { + command cmd; + + // this is (the?) one reason why we need the amb_vcc struct + unsigned char pool = vcc->rx_info.pool; + + down (&dev->vcc_sf); + if (dev->txer[vci].tx_present) { + // TXer still on the channel, just go to pool zero XXX not really needed + cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); + cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 + // only lower 16 bits used (BE nightmare continues) + cmd.args.modify_flags.flags = cpu_to_be16 (dev->txer[vci].tx_vc_bits); + } else { + // no TXer on the channel, close the VC + cmd.request = cpu_to_be32 (SRB_CLOSE_VC); + cmd.args.close.vc = cpu_to_be32 (vci); // vpi 0 + } + // forget the rxer - no more skbs will be pushed + if (atm_vcc != dev->rxer[vci]) + PRINTK (KERN_ERR, "%s vcc=%p rxer[vci]=%p", + "arghhh! we're going to die!", + vcc, dev->rxer[vci]); + dev->rxer[vci] = 0; + while (command_do (dev, &cmd)) + schedule(); + + /* shrink RX buffer pool */ + dev->rxq[pool].buffers_wanted -= 1; + if (dev->rxq[pool].buffers_wanted == rx_lats) { + dev->rxq[pool].buffers_wanted = 0; + drain_rx_pool (dev, pool); + } + + up (&dev->vcc_sf); + } + + // free our structure + kfree (vcc); + + // say the VPI/VCI is free again + atm_vcc->flags &= ~ATM_VF_ADDR; + MOD_DEC_USE_COUNT; +} + +/********** DebugIoctl **********/ + +#if 0 +static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) { + unsigned short newdebug; + if (cmd == AMB_SETDEBUG) { + if (copy_from_user (&newdebug, arg, sizeof(newdebug))) { + // moan + return -EFAULT; + } else { + debug = newdebug; + return 0; + } + } else if (cmd == AMB_DONTPANIC) { + dont_panic (dev); + } else { + // moan + return -EINVAL; + } +} +#endif + +/********** Set socket options for a VC **********/ + +// int amb_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen); + +/********** Set socket options for a VC **********/ + +// int amb_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen); + +/********** Send **********/ + +static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { + amb_dev * dev = AMB_DEV(atm_vcc->dev); + amb_vcc * vcc = AMB_VCC(atm_vcc); + u16 vc = atm_vcc->vci; + unsigned int tx_len = skb->len; + unsigned char * tx_data = skb->data; + tx_simple * tx_descr; + tx_in tx; + + if (test_bit (dead, &dev->flags)) + return -EIO; + + PRINTD (DBG_FLOW|DBG_TX, "amb_send vc %x data %p len %u", + vc, tx_data, tx_len); + + dump_skb (">>>", vc, skb); + + if (!dev->txer[vc].tx_present) { + PRINTK (KERN_ERR, "attempt to send on RX-only VC %x", vc); + return -EBADFD; + } + + // this is a driver private field so we have to set it ourselves, + // despite the fact that we are _required_ to use it to check for a + // pop function + ATM_SKB(skb)->vcc = atm_vcc; + + if (skb->len > (size_t) atm_vcc->qos.txtp.max_sdu) { + PRINTK (KERN_ERR, "sk_buff length greater than agreed max_sdu, dropping..."); + return -EIO; + } + + if (check_area (skb->data, skb->len)) { + atm_vcc->stats->tx_err++; + return -ENOMEM; // ? + } + + // allocate memory for fragments + tx_descr = kmalloc (sizeof(tx_simple), GFP_KERNEL); + if (!tx_descr) { + PRINTK (KERN_ERR, "could not allocate TX descriptor"); + return -ENOMEM; + } + if (check_area (tx_descr, sizeof(tx_simple))) { + kfree (tx_descr); + return -ENOMEM; + } + PRINTD (DBG_TX, "fragment list allocated at %p", tx_descr); + + tx_descr->skb = skb; + + tx_descr->tx_frag.bytes = cpu_to_be32 (tx_len); + tx_descr->tx_frag.address = cpu_to_be32 (virt_to_bus (tx_data)); + + tx_descr->tx_frag_end.handle = virt_to_bus (tx_descr); + tx_descr->tx_frag_end.vc = 0; + tx_descr->tx_frag_end.next_descriptor_length = 0; + tx_descr->tx_frag_end.next_descriptor = 0; +#ifdef AMB_NEW_MICROCODE + tx_descr->tx_frag_end.cpcs_uu = 0; + tx_descr->tx_frag_end.cpi = 0; + tx_descr->tx_frag_end.pad = 0; +#endif + + tx.vc = cpu_to_be16 (vcc->tx_frame_bits | vc); + tx.tx_descr_length = cpu_to_be16 (sizeof(tx_frag)+sizeof(tx_frag_end)); + tx.tx_descr_addr = cpu_to_be32 (virt_to_bus (&tx_descr->tx_frag)); + +#ifdef DEBUG_AMBASSADOR + /* wey-hey! */ + if (vc == 1023) { + unsigned int i; + unsigned short d = 0; + char * s = skb->data; + switch (*s++) { + case 'D': { + for (i = 0; i < 4; ++i) { + d = (d<<4) | ((*s <= '9') ? (*s - '0') : (*s - 'a' + 10)); + ++s; + } + PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d); + break; + } + case 'R': { + if (*s++ == 'e' && *s++ == 's' && *s++ == 'e' && *s++ == 't') + dont_panic (dev); + break; + } + default: { + break; + } + } + } +#endif + + while (tx_give (dev, &tx)) + schedule(); + return 0; +} + +/********** Scatter Gather Send Capability **********/ + +static int amb_sg_send (struct atm_vcc * atm_vcc, + unsigned long start, + unsigned long size) { + PRINTD (DBG_FLOW|DBG_VCC, "amb_sg_send: never"); + return 0; + if (atm_vcc->qos.aal == ATM_AAL5) { + PRINTD (DBG_FLOW|DBG_VCC, "amb_sg_send: yes"); + return 1; + } else { + PRINTD (DBG_FLOW|DBG_VCC, "amb_sg_send: no"); + return 0; + } + PRINTD (DBG_FLOW|DBG_VCC, "amb_sg_send: always"); + return 1; +} + +/********** Send OAM **********/ + +// static int amb_send_oam (struct atm_vcc * atm_vcc, void * cell, int flags); + +/********** Feedback to Driver **********/ + +// void amb_feedback (struct atm_vcc * atm_vcc, struct sk_buff * skb, +// unsigned long start, unsigned long dest, int len); + +/********** Change QoS on a VC **********/ + +// int amb_change_qos (struct atm_vcc * atm_vcc, struct atm_qos * qos, int flags); + +/********** Free RX Socket Buffer **********/ + +#if 0 +static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) { + amb_dev * dev = AMB_DEV (atm_vcc->dev); + amb_vcc * vcc = AMB_VCC (atm_vcc); + unsigned char pool = vcc->rx_info.pool; + rx_in rx; + + // This may be unsafe for various reasons that I cannot really guess + // at. However, I note that the ATM layer calls kfree_skb rather + // than dev_kfree_skb at this point so we are least covered as far + // as buffer locking goes. There may be bugs if pcap clones RX skbs. + + PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)", + skb, atm_vcc, vcc); + + rx.handle = virt_to_bus (skb); + rx.host_address = cpu_to_be32 (virt_to_bus (skb->data)); + + skb->data = skb->head; + skb->tail = skb->head; + skb->len = 0; + + if (!rx_give (dev, &rx, pool)) { + // success + PRINTD (DBG_SKB|DBG_POOL, "recycled skb for pool %hu", pool); + return; + } + + // just do what the ATM layer would have done + kfree_skb (skb); + + return; +} +#endif + +/********** Proc File Output **********/ + +static int amb_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) { + amb_dev * dev = AMB_DEV (atm_dev); + int left = *pos; + unsigned char pool; + + PRINTD (DBG_FLOW, "amb_proc_read"); + + /* more diagnostics here? */ + + if (!left--) { + amb_stats * s = &dev->stats; + return sprintf (page, + "frames: TX OK %lu, RX OK %lu, RX bad %lu " + "(CRC %lu, long %lu, aborted %lu, unused %lu).\n", + s->tx_ok, s->rx.ok, s->rx.error, + s->rx.badcrc, s->rx.toolong, + s->rx.aborted, s->rx.unused); + } + + if (!left--) { + amb_cq * c = &dev->cq; + return sprintf (page, "cmd queue [cur/hi/max]: %u/%u/%u. ", + c->pending, c->high, c->maximum); + } + + if (!left--) { + amb_txq * t = &dev->txq; + return sprintf (page, "TX queue [cur/max high full]: %u/%u %u %u.\n", + t->pending, t->maximum, t->high, t->filled); + } + + if (!left--) { + unsigned int count = sprintf (page, "RX queues [cur/max/req low empty]:"); + for (pool = 0; pool < NUM_RX_POOLS; ++pool) { + amb_rxq * r = &dev->rxq[pool]; + count += sprintf (page+count, " %u/%u/%u %u %u", + r->pending, r->maximum, r->buffers_wanted, r->low, r->emptied); + } + count += sprintf (page+count, ".\n"); + return count; + } + + if (!left--) { + unsigned int count = sprintf (page, "RX buffer sizes:"); + for (pool = 0; pool < NUM_RX_POOLS; ++pool) { + amb_rxq * r = &dev->rxq[pool]; + count += sprintf (page+count, " %u", r->buffer_size); + } + count += sprintf (page+count, ".\n"); + return count; + } + +#if 0 + if (!left--) { + // suni block etc? + } +#endif + + return 0; +} + +/********** Operation Structure **********/ + +static const struct atmdev_ops amb_ops = { + NULL, // no amb_dev_close + amb_open, + amb_close, + NULL, // no amb_ioctl, + NULL, // amb_getsockopt, + NULL, // amb_setsockopt, + amb_send, + amb_sg_send, + NULL, // no send_oam - not in fact used yet + NULL, // no amb_phy_put - not needed in this driver + NULL, // no amb_phy_get - not needed in this driver + NULL, // no feedback - feedback to the driver! + NULL, // no amb_change_qos + NULL, // amb_free_rx_skb not used until checked by someone else + amb_proc_read +}; + +/********** housekeeping **********/ + +static inline void set_timer (struct timer_list * timer, unsigned long delay) { + timer->expires = jiffies + delay; + add_timer (timer); + return; +} + +static void do_housekeeping (unsigned long arg) { + amb_dev * dev = amb_devs; + // data is set to zero at module unload + (void) arg; + + if (housekeeping.data) { + while (dev) { + + // could collect device-specific (not driver/atm-linux) stats here + + // last resort refill once every ten seconds + fill_rx_pools (dev); + + dev = dev->prev; + } + set_timer (&housekeeping, 10*HZ); + } + + return; +} + +/********** creation of communication queues **********/ + +static int create_queues (amb_dev * dev, unsigned int cmds, unsigned int txs, + unsigned int * rxs, unsigned int * rx_buffer_sizes) { + unsigned char pool; + size_t total = 0; + void * memory; + void * limit; + + PRINTD (DBG_FLOW, "create_queues %p", dev); + + total += cmds * sizeof(command); + + total += txs * (sizeof(tx_in) + sizeof(tx_out)); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + total += rxs[pool] * (sizeof(rx_in) + sizeof(rx_out)); + + memory = kmalloc (total, GFP_KERNEL); + if (!memory) { + PRINTK (KERN_ERR, "could not allocate queues"); + return -ENOMEM; + } + if (check_area (memory, total)) { + PRINTK (KERN_ERR, "queues allocated in nasty area"); + kfree (memory); + return -ENOMEM; + } + + limit = memory + total; + PRINTD (DBG_INIT, "queues from %p to %p", memory, limit); + + PRINTD (DBG_CMD, "command queue at %p", memory); + + { + command * cmd = memory; + amb_cq * cq = &dev->cq; + + cq->pending = 0; + cq->high = 0; + cq->maximum = cmds - 1; + + cq->start = cmd; + cq->in = cmd; + cq->out = cmd; + cq->limit = cmd + cmds; + + memory = cq->limit; + } + + PRINTD (DBG_TX, "TX queue pair at %p", memory); + + { + tx_in * in = memory; + tx_out * out; + amb_txq * txq = &dev->txq; + + txq->pending = 0; + txq->high = 0; + txq->filled = 0; + txq->maximum = txs - 1; + + txq->in.start = in; + txq->in.ptr = in; + txq->in.limit = in + txs; + + memory = txq->in.limit; + out = memory; + + txq->out.start = out; + txq->out.ptr = out; + txq->out.limit = out + txs; + + memory = txq->out.limit; + } + + PRINTD (DBG_RX, "RX queue pairs at %p", memory); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) { + rx_in * in = memory; + rx_out * out; + amb_rxq * rxq = &dev->rxq[pool]; + + rxq->buffer_size = rx_buffer_sizes[pool]; + rxq->buffers_wanted = 0; + + rxq->pending = 0; + rxq->low = rxs[pool] - 1; + rxq->emptied = 0; + rxq->maximum = rxs[pool] - 1; + + rxq->in.start = in; + rxq->in.ptr = in; + rxq->in.limit = in + rxs[pool]; + + memory = rxq->in.limit; + out = memory; + + rxq->out.start = out; + rxq->out.ptr = out; + rxq->out.limit = out + rxs[pool]; + + memory = rxq->out.limit; + } + + if (memory == limit) { + return 0; + } else { + PRINTK (KERN_ERR, "bad queue alloc %p != %p (tell maintainer)", memory, limit); + kfree (limit - total); + return -ENOMEM; + } + +} + +/********** destruction of communication queues **********/ + +static void destroy_queues (amb_dev * dev) { + // all queues assumed empty + void * memory = dev->cq.start; + // includes txq.in, txq.out, rxq[].in and rxq[].out + + PRINTD (DBG_FLOW, "destroy_queues %p", dev); + + PRINTD (DBG_INIT, "freeing queues at %p", memory); + kfree (memory); + + return; +} + +/********** basic loader commands and error handling **********/ + +static int do_loader_command (const amb_dev * dev, loader_command cmd, + volatile loader_block * lb) { + + // centisecond timeouts - guessing away here + unsigned int command_timeouts [] = { + [host_memory_test] = 15, + [read_adapter_memory] = 2, + [write_adapter_memory] = 2, + [adapter_start] = 50, + [get_version_number] = 10, + [interrupt_host] = 1, + [flash_erase_sector] = 1, + [adap_download_block] = 1, + [adap_erase_flash] = 1, + [adap_run_in_iram] = 1, + [adap_end_download] = 1 + }; + +#if 0 /* unused */ + unsigned int command_successes [] = { + [host_memory_test] = COMMAND_PASSED_TEST, + [read_adapter_memory] = COMMAND_READ_DATA_OK, + [write_adapter_memory] = COMMAND_WRITE_DATA_OK, + [adapter_start] = COMMAND_COMPLETE, + [get_version_number] = COMMAND_COMPLETE, + [interrupt_host] = COMMAND_COMPLETE, + [flash_erase_sector] = COMMAND_COMPLETE, + [adap_download_block] = COMMAND_COMPLETE, + [adap_erase_flash] = COMMAND_COMPLETE, + [adap_run_in_iram] = COMMAND_COMPLETE, + [adap_end_download] = COMMAND_COMPLETE + }; +#endif + + int decode_loader_error (u32 result) { + int res; + const char * msg; + switch (result) { + case BAD_COMMAND: + res = -EINVAL; + msg = "bad command"; + break; + case COMMAND_IN_PROGRESS: + res = -ETIMEDOUT; + msg = "command in progress"; + break; + case COMMAND_PASSED_TEST: + res = 0; + msg = "command passed test"; + break; + case COMMAND_FAILED_TEST: + res = -EIO; + msg = "command failed test"; + break; + case COMMAND_READ_DATA_OK: + res = 0; + msg = "command read data ok"; + break; + case COMMAND_READ_BAD_ADDRESS: + res = -EINVAL; + msg = "command read bad address"; + break; + case COMMAND_WRITE_DATA_OK: + res = 0; + msg = "command write data ok"; + break; + case COMMAND_WRITE_BAD_ADDRESS: + res = -EINVAL; + msg = "command write bad address"; + break; + case COMMAND_WRITE_FLASH_FAILURE: + res = -EIO; + msg = "command write flash failure"; + break; + case COMMAND_COMPLETE: + res = 0; + msg = "command complete"; + break; + case COMMAND_FLASH_ERASE_FAILURE: + res = -EIO; + msg = "command flash erase failure"; + break; + case COMMAND_WRITE_BAD_DATA: + res = -EINVAL; + msg = "command write bad data"; + break; + default: + res = -EINVAL; + msg = "unknown error"; + PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_error got %d=%x !", + result, result); + break; + } + if (res) + PRINTK (KERN_ERR, "%s", msg); + return res; + } + + unsigned long timeout; + + PRINTD (DBG_FLOW|DBG_LOAD, "do_loader_command"); + + /* do a command + + Set the return value to zero, set the command type and set the + valid entry to the right magic value. The payload is already + correctly byte-ordered so we leave it alone. Hit the doorbell + with the bus address of this structure. + + */ + + lb->result = 0; + lb->command = cpu_to_be32 (cmd); + lb->valid = cpu_to_be32 (DMA_VALID); + // dump_loader_block (lb); + wr_mem (dev, &mem->doorbell, virt_to_bus (lb)); + + timeout = command_timeouts[cmd] * HZ/100; + + while (!lb->result || lb->result == be32_to_cpu (COMMAND_IN_PROGRESS)) + if (timeout) { + timeout = schedule_timeout (timeout); + } else { + PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd); + dump_registers (dev); + dump_loader_block (lb); + return -ETIMEDOUT; + } + + if (cmd == adapter_start) { + // wait for start command to acknowledge... + timeout = HZ/10; + while (rd_mem (dev, &mem->doorbell)) + if (timeout) { + timeout = schedule_timeout (timeout); + } else { + PRINTD (DBG_LOAD|DBG_ERR, "start command did not clear doorbell, res=%08x", + be32_to_cpu (lb->result)); + dump_registers (dev); + return -ETIMEDOUT; + } + return 0; + } else { + return decode_loader_error (be32_to_cpu (lb->result)); + } + +#if 0 + if ((res != COMMAND_PASSED_TEST) && + (res != COMMAND_READ_DATA_OK) && + (res != COMMAND_WRITE_DATA_OK) && + (res != COMMAND_COMPLETE)) { + PRINTD (DBG_LOAD|DBG_ERR"startup cmd %d failed with error %08x", + cmd, res); + dump_registers (dev); + return -EIO; + } +#endif +} + +/* loader: determine loader version */ + +static int get_loader_version (const amb_dev * dev, u32 * version) { + loader_block lb; + int res; + + PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version"); + + res = do_loader_command (dev, get_version_number, &lb); + if (res) + return res; + if (version) + *version = be32_to_cpu (lb.payload.version); + return 0; +} + +/* loader: read or verify memory data blocks */ + +static int loader_write (const amb_dev * dev, const u32 * data, + u32 address, unsigned int count) { + unsigned int i; + loader_block lb; + transfer_block * tb = &lb.payload.transfer; + + PRINTD (DBG_FLOW|DBG_LOAD, "loader_write"); + + if (count > MAX_TRANSFER_DATA) + return -EINVAL; + tb->address = cpu_to_be32 (address); + tb->count = cpu_to_be32 (count); + for (i = 0; i < count; ++i) + tb->data[i] = cpu_to_be32 (data[i]); + return do_loader_command (dev, write_adapter_memory, &lb); +} + +static int loader_verify (const amb_dev * dev, const u32 * data, + u32 address, unsigned int count) { + unsigned int i; + loader_block lb; + transfer_block * tb = &lb.payload.transfer; + int res; + + PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify"); + + if (count > MAX_TRANSFER_DATA) + return -EINVAL; + tb->address = cpu_to_be32 (address); + tb->count = cpu_to_be32 (count); + res = do_loader_command (dev, read_adapter_memory, &lb); + if (!res) + for (i = 0; i < count; ++i) + if (tb->data[i] != cpu_to_be32 (data[i])) { + res = -EINVAL; + break; + } + return res; +} + +static int loader_start (const amb_dev * dev, u32 address) { + loader_block lb; + + PRINTD (DBG_FLOW|DBG_LOAD, "loader_start"); + + lb.payload.start = cpu_to_be32 (address); + return do_loader_command (dev, adapter_start, &lb); +} + +/********** reset card **********/ + +static int amb_reset (amb_dev * dev, int diags) { + u32 word; + + PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset"); + + word = rd_mem (dev, &mem->reset_control); +#if 0 + // clear all interrupts just in case + wr_mem (dev, &mem->interrupt, -1); +#endif + // put card into reset state + wr_mem (dev, &mem->reset_control, word | AMB_RESET); + // wait a short while + udelay (10); + // clear self-test done flag + wr_mem (dev, &mem->mb.loader.ready, 0); + // take card out of reset state + wr_mem (dev, &mem->reset_control, word &~ AMB_RESET); + + if (diags) { + unsigned long timeout; + // 4.2 second wait + timeout = HZ*42/10; + while (timeout) + timeout = schedule_timeout (timeout); + // half second time-out + timeout = HZ/2; + while (!rd_mem (dev, &mem->mb.loader.ready)) + if (timeout) { + timeout = schedule_timeout (timeout); + } else { + PRINTD (DBG_LOAD|DBG_ERR, "reset timed out"); + return -ETIMEDOUT; + } + + // get results of self-test + word = rd_mem (dev, &mem->mb.loader.result); + if (word & SELF_TEST_FAILURE) { + void sf (const char * msg) { + PRINTK (KERN_ERR, "self-test failed: %s", msg); + } + if (word & GPINT_TST_FAILURE) + sf ("interrupt"); + if (word & SUNI_DATA_PATTERN_FAILURE) + sf ("SUNI data pattern"); + if (word & SUNI_DATA_BITS_FAILURE) + sf ("SUNI data bits"); + if (word & SUNI_UTOPIA_FAILURE) + sf ("SUNI UTOPIA interface"); + if (word & SUNI_FIFO_FAILURE) + sf ("SUNI cell buffer FIFO"); + if (word & SRAM_FAILURE) + sf ("bad SRAM"); + // better return value? + return -EIO; + } + + } + return 0; +} + +/********** transfer and start the microcode **********/ + +static int ucode_init (amb_dev * dev) { + unsigned int i = 0; + unsigned int total = 0; + const u32 * pointer = ucode_data; + u32 address; + unsigned int count; + int res; + + PRINTD (DBG_FLOW|DBG_LOAD, "ucode_init"); + + while (address = ucode_regions[i].start, + count = ucode_regions[i].count) { + PRINTD (DBG_LOAD, "starting region (%x, %u)", address, count); + while (count) { + unsigned int words; + if (count <= MAX_TRANSFER_DATA) + words = count; + else + words = MAX_TRANSFER_DATA; + total += words; + res = loader_write (dev, pointer, address, words); + if (res) + return res; + res = loader_verify (dev, pointer, address, words); + if (res) + return res; + count -= words; + address += sizeof(u32) * words; + pointer += words; + } + i += 1; + } + if (*pointer == 0xdeadbeef) { + return loader_start (dev, ucode_start); + } else { + // cast needed as there is no %? for pointer differnces + PRINTD (DBG_LOAD|DBG_ERR, + "offset=%li, *pointer=%x, address=%x, total=%u", + (long) (pointer - ucode_data), *pointer, address, total); + PRINTK (KERN_ERR, "incorrect microcode data"); + return -ENOMEM; + } +} + +/********** give adapter parameters **********/ + +static int amb_talk (amb_dev * dev) { + adap_talk_block a; + unsigned char pool; + unsigned long timeout; + + static inline u32 x (void * addr) { + return cpu_to_be32 (virt_to_bus (addr)); + } + + PRINTD (DBG_FLOW, "amb_talk %p", dev); + + a.command_start = x (dev->cq.start); + a.command_end = x (dev->cq.limit); + a.tx_start = x (dev->txq.in.start); + a.tx_end = x (dev->txq.in.limit); + a.txcom_start = x (dev->txq.out.start); + a.txcom_end = x (dev->txq.out.limit); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) { + // the other "a" items are set up by the adapter + a.rec_struct[pool].buffer_start = x (dev->rxq[pool].in.start); + a.rec_struct[pool].buffer_end = x (dev->rxq[pool].in.limit); + a.rec_struct[pool].rx_start = x (dev->rxq[pool].out.start); + a.rec_struct[pool].rx_end = x (dev->rxq[pool].out.limit); + a.rec_struct[pool].buffer_size = cpu_to_be32 (dev->rxq[pool].buffer_size); + } + +#ifdef AMB_NEW_MICROCODE + // disable fast PLX prefetching + a.init_flags = 0; +#endif + + // pass the structure + wr_mem (dev, &mem->doorbell, virt_to_bus (&a)); + + // 2.2 second wait (must not touch doorbell during 2 second DMA test) + timeout = HZ*22/10; + while (timeout) + timeout = schedule_timeout (timeout); + // give the adapter another half second? + timeout = HZ/2; + while (rd_mem (dev, &mem->doorbell)) + if (timeout) { + timeout = schedule_timeout (timeout); + } else { + PRINTD (DBG_INIT|DBG_ERR, "adapter init timed out"); + return -ETIMEDOUT; + } + + return 0; +} + +// get microcode version +static void amb_ucode_version (amb_dev * dev) { + u32 major; + u32 minor; + command cmd; + cmd.request = cpu_to_be32 (SRB_GET_VERSION); + while (command_do (dev, &cmd)) + schedule(); + major = be32_to_cpu (cmd.args.version.major); + minor = be32_to_cpu (cmd.args.version.minor); + PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor); +} + +// get end station address +static void amb_esi (amb_dev * dev, u8 * esi) { + u32 lower4; + u16 upper2; + command cmd; + + // swap bits within byte to get Ethernet ordering + u8 bit_swap (u8 byte) { + const u8 swap[] = { + 0x0, 0x8, 0x4, 0xc, + 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, + 0x3, 0xb, 0x7, 0xf + }; + return ((swap[byte & 0xf]<<4) | swap[byte>>4]); + } + + cmd.request = cpu_to_be32 (SRB_GET_BIA); + while (command_do (dev, &cmd)) + schedule(); + lower4 = be32_to_cpu (cmd.args.bia.lower4); + upper2 = be32_to_cpu (cmd.args.bia.upper2); + PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2); + + if (esi) { + unsigned int i; + + PRINTDB (DBG_INIT, "ESI:"); + for (i = 0; i < ESI_LEN; ++i) { + if (i < 4) + esi[i] = bit_swap (lower4>>(8*i)); + else + esi[i] = bit_swap (upper2>>(8*(i-4))); + PRINTDM (DBG_INIT, " %02x", esi[i]); + } + + PRINTDE (DBG_INIT, ""); + } + + return; +} + +static int amb_init (amb_dev * dev) { + u32 version; + + /* enable adapter doorbell */ + wr_mem (dev, &mem->interrupt_control, + rd_mem (dev, &mem->interrupt_control) + | AMB_DOORBELL_BITS); + + if (amb_reset (dev, 1)) { + PRINTK (KERN_ERR, "card reset failed!"); + } else if (get_loader_version (dev, &version)) { + PRINTK (KERN_INFO, "failed to get loader version"); + } else { + PRINTK (KERN_INFO, "loader version is %08x", version); + + if (ucode_init (dev)) { + PRINTK (KERN_ERR, "microcode failure"); + } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) { + PRINTK (KERN_ERR, "failed to get memory for queues"); + } else { + + if (amb_talk (dev)) { + PRINTK (KERN_ERR, "adapter did not accept queues"); + } else { + + amb_ucode_version (dev); + return 0; + } /* amb_talk */ + + destroy_queues (dev); + } /* create_queues, ucode_init */ + + } /* get_loader_version, amb_reset */ + + return -1; +} + +static int __init amb_probe (void) { + struct pci_dev * pci_dev; + int devs; + + void do_pci_device (void) { + amb_dev * dev; + + // read resources from PCI configuration space + u32 * membase = bus_to_virt + (pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK); + u32 iobase = pci_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + u8 irq = pci_dev->irq; + + // check IO region + if (check_region (iobase, AMB_EXTENT)) { + PRINTK (KERN_ERR, "IO range already in use!"); + return; + } + + dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); + if (!dev) { + // perhaps we should be nice: deregister all adapters and abort? + PRINTK (KERN_ERR, "out of memory!"); + return; + } + memset (dev, 0, sizeof(amb_dev)); + + // set up known dev items straight away + dev->pci_dev = pci_dev; + + dev->iobase = iobase; + dev->irq = irq; + dev->membase = membase; + + // flags (currently only dead) + dev->flags = 0; + + // Allocate cell rates (fibre) + // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 + // to be really pedantic, this should be ATM_OC3c_PCR + dev->tx_avail = ATM_OC3_PCR; + dev->rx_avail = ATM_OC3_PCR; + +#if 0 + // initialise bottom half + dev->bh.next = 0; + dev->bh.sync = 0; + dev->bh.routine = (void (*)(void *)) fill_rx_pools; + dev->bh.data = dev; +#endif + + // semaphore for txer/rxer modifications - we cannot use a + // spinlock as the critical region needs to process switches + init_MUTEX(&dev->vcc_sf); + // queue manipulation spinlocks; we want atomic reads and + // writes to the queue descriptors (handles IRQ and SMP) + // consider replacing "int pending" -> "atomic_t available" + // => problem related to who gets to move queue pointers + spin_lock_init (&dev->cq.lock); + spin_lock_init (&dev->txq.lock); + { + unsigned char pool; + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + spin_lock_init (&dev->rxq[pool].lock); + } + + // grab (but share) IRQ and install handler + if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) { + PRINTK (KERN_ERR, "request IRQ failed!"); + // free_irq is at "endif" + } else { + + unsigned char lat; + + // reserve IO region + request_region (iobase, AMB_EXTENT, DEV_LABEL); + + PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at IO %x, IRQ %u, MEM %p", + iobase, irq, membase); + + // enable bus master accesses + pci_set_master (pci_dev); + + // frobnicate latency (upwards, usually) + pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); + if (pci_lat) { + PRINTD (DBG_INIT, "%s PCI latency timer from %hu to %hu", + "changing", lat, pci_lat); + pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat); + } else if (lat < MIN_PCI_LATENCY) { + PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu", + "increasing", lat, MIN_PCI_LATENCY); + pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); + } + + if (amb_init (dev)) { + PRINTK (KERN_ERR, "adapter initialisation failure"); + } else if (!(dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, 0))) { + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + } else { + + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); + dev->atm_dev->dev_data = (void *) dev; + + // register our address + amb_esi (dev, dev->atm_dev->esi); + + // 0 bits for vpi, 10 bits for vci + dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; + dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; + + fill_rx_pools (dev); + + /* enable host interrupts */ + interrupts_on (dev); + + // update count and linked list + ++devs; + dev->prev = amb_devs; + amb_devs = dev; + // success + return; + + // not currently reached + atm_dev_deregister (dev->atm_dev); + } /* atm_dev_register, amb_init */ + + release_region (iobase, AMB_EXTENT); + free_irq (irq, dev); + } /* request_region, request_irq */ + + kfree (dev); + } /* kmalloc, end-of-fn */ + + PRINTD (DBG_FLOW, "amb_probe"); + + if (!pci_present()) + return 0; + + devs = 0; + pci_dev = NULL; + while ((pci_dev = pci_find_device + (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, pci_dev) + )) + do_pci_device(); + + pci_dev = NULL; + while ((pci_dev = pci_find_device + (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD, pci_dev) + )) + PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card"); + + return devs; +} + +static void __init amb_check_args (void) { + unsigned char pool; + unsigned int max_rx_size; + +#ifdef DEBUG_AMBASSADOR + PRINTK (KERN_NOTICE, "debug bitmap is %hx", debug &= DBG_MASK); +#else + if (debug) + PRINTK (KERN_NOTICE, "no debugging support"); +#endif + + if (cmds < MIN_QUEUE_SIZE) + PRINTK (KERN_NOTICE, "cmds has been raised to %u", + cmds = MIN_QUEUE_SIZE); + + if (txs < MIN_QUEUE_SIZE) + PRINTK (KERN_NOTICE, "txs has been raised to %u", + txs = MIN_QUEUE_SIZE); + + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + if (rxs[pool] < MIN_QUEUE_SIZE) + PRINTK (KERN_NOTICE, "rxs[%hu] has been raised to %u", + pool, rxs[pool] = MIN_QUEUE_SIZE); + + // buffers sizes should be greater than zero and strictly increasing + max_rx_size = 0; + for (pool = 0; pool < NUM_RX_POOLS; ++pool) + if (rxs_bs[pool] <= max_rx_size) + PRINTK (KERN_NOTICE, "useless pool (rxs_bs[%hu] = %u)", + pool, rxs_bs[pool]); + else + max_rx_size = rxs_bs[pool]; + + if (rx_lats < MIN_RX_BUFFERS) + PRINTK (KERN_NOTICE, "rx_lats has been raised to %u", + rx_lats = MIN_RX_BUFFERS); + + return; +} + +/********** module stuff **********/ + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR(maintainer_string); +MODULE_DESCRIPTION(description_string); +MODULE_PARM(debug, "h"); +MODULE_PARM(cmds, "i"); +MODULE_PARM(txs, "i"); +MODULE_PARM(rxs, __MODULE_STRING(NUM_RX_POOLS) "i"); +MODULE_PARM(rxs_bs, __MODULE_STRING(NUM_RX_POOLS) "i"); +MODULE_PARM(rx_lats, "i"); +MODULE_PARM(pci_lat, "b"); +MODULE_PARM_DESC(debug, "debug bitmap, see .h file"); +MODULE_PARM_DESC(cmds, "number of command queue entries"); +MODULE_PARM_DESC(txs, "number of TX queue entries"); +MODULE_PARM_DESC(rxs, "number of RX queue entries [" __MODULE_STRING(NUM_RX_POOLS) "]"); +MODULE_PARM_DESC(rxs_bs, "size of RX buffers [" __MODULE_STRING(NUM_RX_POOLS) "]"); +MODULE_PARM_DESC(rx_lats, "number of extra buffers to cope with RX latencies"); +MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles"); + +/********** module entry **********/ + +int init_module (void) { + int devs; + + PRINTD (DBG_FLOW|DBG_INIT, "init_module"); + + // sanity check - cast needed as printk does not support %Zu + if (sizeof(amb_mem) != 4*16 + 4*12) { + PRINTK (KERN_ERR, "Fix amb_mem (is %lu words).", + (unsigned long) sizeof(amb_mem)); + return -ENOMEM; + } + + show_version(); + + // check arguments + amb_check_args(); + + // get the juice + devs = amb_probe(); + + if (devs) { + init_timer (&housekeeping); + housekeeping.function = do_housekeeping; + // paranoia + housekeeping.data = 1; + set_timer (&housekeeping, 0); + } else { + PRINTK (KERN_INFO, "no (usable) adapters found"); + } + + return devs ? 0 : -ENODEV; +} + +/********** module exit **********/ + +void cleanup_module (void) { + amb_dev * dev; + + PRINTD (DBG_FLOW|DBG_INIT, "cleanup_module"); + + // paranoia + housekeeping.data = 0; + del_timer (&housekeeping); + + while (amb_devs) { + dev = amb_devs; + amb_devs = dev->prev; + + PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev); + // the drain should not be necessary + drain_rx_pools (dev); + amb_reset (dev, 0); + interrupts_off (dev); + destroy_queues (dev); + atm_dev_deregister (dev->atm_dev); + free_irq (dev->irq, dev); + release_region (dev->iobase, AMB_EXTENT); + kfree (dev); + } + + return; +} + +#else + +/********** monolithic entry **********/ + +int __init amb_detect (void) { + int devs; + + PRINTD (DBG_FLOW|DBG_INIT, "init_module"); + + // sanity check - cast needed as printk does not support %Zu + if (sizeof(amb_mem) != 4*16 + 4*12) { + PRINTK (KERN_ERR, "Fix amb_mem (is %lu words).", + (unsigned long) sizeof(amb_mem)); + return 0; + } + + show_version(); + + // check arguments + amb_check_args(); + + // get the juice + devs = amb_probe(); + + if (devs) { + init_timer (&housekeeping); + housekeeping.function = do_housekeeping; + // paranoia + housekeeping.data = 1; + set_timer (&housekeeping, 0); + } else { + PRINTK (KERN_INFO, "no (usable) adapters found"); + } + + return devs; +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h --- v2.3.14/linux/drivers/atm/ambassador.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/ambassador.h Mon Aug 23 13:44:03 1999 @@ -0,0 +1,689 @@ +/* + Madge Ambassador ATM Adapter driver. + Copyright (C) 1995-1999 Madge Networks Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian + system and in the file COPYING in the Linux kernel source. +*/ + +/* + IMPORTANT NOTE: Madge Networks does not license the microcode for + this driver under the GPL. See the .data file for the licence. +*/ + +#ifndef AMBASSADOR_H +#define AMBASSADOR_H + +#include + +#ifdef CONFIG_ATM_AMBASSADOR_DEBUG +#define DEBUG_AMBASSADOR +#endif + +#define DEV_LABEL "amb" + +#ifndef PCI_VENDOR_ID_MADGE +#define PCI_VENDOR_ID_MADGE 0x10B6 +#endif +#ifndef PCI_VENDOR_ID_MADGE_AMBASSADOR +#define PCI_DEVICE_ID_MADGE_AMBASSADOR 0x1001 +#endif +#ifndef PCI_VENDOR_ID_MADGE_AMBASSADOR_BAD +#define PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD 0x1002 +#endif + +// diagnostic output + +#define PRINTK(severity,format,args...) \ + printk(severity DEV_LABEL ": " format "\n" , ## args) + +#ifdef DEBUG_AMBASSADOR + +#define DBG_ERR 0x0001 +#define DBG_WARN 0x0002 +#define DBG_INFO 0x0004 +#define DBG_INIT 0x0008 +#define DBG_LOAD 0x0010 +#define DBG_VCC 0x0020 +#define DBG_QOS 0x0040 +#define DBG_CMD 0x0080 +#define DBG_TX 0x0100 +#define DBG_RX 0x0200 +#define DBG_SKB 0x0400 +#define DBG_POOL 0x0800 +#define DBG_IRQ 0x1000 +#define DBG_FLOW 0x2000 +#define DBG_REGS 0x4000 +#define DBG_DATA 0x8000 +#define DBG_MASK 0xffff + +/* the ## prevents the annoying double expansion of the macro arguments */ +/* KERN_INFO is used since KERN_DEBUG often does not make it to the console */ +#define PRINTDB(bits,format,args...) \ + ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format , ## args) : 1 ) +#define PRINTDM(bits,format,args...) \ + ( (debug & (bits)) ? printk (format , ## args) : 1 ) +#define PRINTDE(bits,format,args...) \ + ( (debug & (bits)) ? printk (format "\n" , ## args) : 1 ) +#define PRINTD(bits,format,args...) \ + ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format "\n" , ## args) : 1 ) + +#else + +#define PRINTD(bits,format,args...) +#define PRINTDB(bits,format,args...) +#define PRINTDM(bits,format,args...) +#define PRINTDE(bits,format,args...) + +#endif + +#define PRINTDD(bits,format,args...) +#define PRINTDDB(sec,fmt,args...) +#define PRINTDDM(sec,fmt,args...) +#define PRINTDDE(sec,fmt,args...) + +// tunable values (?) + +/* MUST be powers of two -- why ? */ +#define COM_Q_ENTRIES 8 +#define TX_Q_ENTRIES 32 +#define RX_Q_ENTRIES 64 + +// fixed values + +// guessing +#define AMB_EXTENT 0x80 + +// Minimum allowed size for an Ambassador queue +#define MIN_QUEUE_SIZE 2 + +// Ambassador microcode allows 1 to 4 pools, we use 4 (simpler) +#define NUM_RX_POOLS 4 + +// minimum RX buffers required to cope with replenishing delay +#define MIN_RX_BUFFERS 1 + +// RX buffer tailroom to cope with writing too much +#define RX_FUDGE 3 + +// minimum PCI latency we will tolerate (32 IS TOO SMALL) +#define MIN_PCI_LATENCY 64 // 255 + +// VCs supported by card (VPI always 0) +#define NUM_VPI_BITS 0 +#define NUM_VCI_BITS 10 +#define NUM_VCS 1024 + +/* The status field bits defined so far. */ +#define RX_ERR 0x8000 // always present if there is an error (hmm) +#define CRC_ERR 0x4000 // AAL5 CRC error +#define LEN_ERR 0x2000 // overlength frame +#define ABORT_ERR 0x1000 // zero length field in received frame +#define UNUSED_ERR 0x0800 // buffer returned unused + +// Adaptor commands + +#define SRB_OPEN_VC 0 +/* par_0: dwordswap(VC_number) */ +/* par_1: dwordswap(flags<<16) or wordswap(flags)*/ +/* flags: */ + +/* LANE: 0x0004 */ +/* NOT_UBR: 0x0008 */ +/* ABR: 0x0010 */ + +/* RxPool0: 0x0000 */ +/* RxPool1: 0x0020 */ +/* RxPool2: 0x0040 */ +/* RxPool3: 0x0060 */ + +/* par_2: dwordswap(fp_rate<<16) or wordswap(fp_rate) */ + +#define SRB_CLOSE_VC 1 +/* par_0: dwordswap(VC_number) */ + +#define SRB_GET_BIA 2 +/* returns */ +/* par_0: dwordswap(half BIA) */ +/* par_1: dwordswap(half BIA) */ + +#define SRB_GET_SUNI_STATS 3 +/* par_0: dwordswap(physical_host_address) */ + +#define SRB_SET_BITS_8 4 +#define SRB_SET_BITS_16 5 +#define SRB_SET_BITS_32 6 +#define SRB_CLEAR_BITS_8 7 +#define SRB_CLEAR_BITS_16 8 +#define SRB_CLEAR_BITS_32 9 +/* par_0: dwordswap(ATMizer address) */ +/* par_1: dwordswap(mask) */ + +#define SRB_SET_8 10 +#define SRB_SET_16 11 +#define SRB_SET_32 12 +/* par_0: dwordswap(ATMizer address) */ +/* par_1: dwordswap(data) */ + +#define SRB_GET_32 13 +/* par_0: dwordswap(ATMizer address) */ +/* returns */ +/* par_1: dwordswap(ATMizer data) */ + +#define SRB_GET_VERSION 14 +/* returns */ +/* par_0: dwordswap(Major Version) */ +/* par_1: dwordswap(Minor Version) */ + +#define SRB_FLUSH_BUFFER_Q 15 +/* Only flags to define which buffer pool; all others must be zero */ +/* par_0: dwordswap(flags<<16) or wordswap(flags)*/ + +#define SRB_GET_DMA_SPEEDS 16 +/* returns */ +/* par_0: dwordswap(Read speed (bytes/sec)) */ +/* par_1: dwordswap(Write speed (bytes/sec)) */ + +#define SRB_MODIFY_VC_RATE 17 +/* par_0: dwordswap(VC_number) */ +/* par_1: dwordswap(fp_rate<<16) or wordswap(fp_rate) */ + +#define SRB_MODIFY_VC_FLAGS 18 +/* par_0: dwordswap(VC_number) */ +/* par_1: dwordswap(flags<<16) or wordswap(flags)*/ + +/* flags: */ + +/* LANE: 0x0004 */ +/* NOT_UBR: 0x0008 */ +/* ABR: 0x0010 */ + +/* RxPool0: 0x0000 */ +/* RxPool1: 0x0020 */ +/* RxPool2: 0x0040 */ +/* RxPool3: 0x0060 */ + +#define SRB_POOL_SHIFT 5 + +#define SRB_STOP_TASKING 19 +#define SRB_START_TASKING 20 +#define SRB_SHUT_DOWN 21 +#define MAX_SRB 21 + +#define SRB_COMPLETE 0xffffffff + +#define TX_FRAME 0x80000000 + +// number of types of SRB MUST be a power of two -- why? +#define NUM_OF_SRB 32 + +// number of bits of period info for rate +#define MAX_RATE_BITS 6 + +#define TX_UBR 0x0000 +#define TX_UBR_CAPPED 0x0008 +#define TX_ABR 0x0018 +#define TX_FRAME_NOTCAP 0x0000 +#define TX_FRAME_CAPPED 0x8000 + +#define FP_155_RATE 0x24b1 +#define FP_25_RATE 0x1f9d + +#define AMB_RESET 0x40 + +/* #define VERSION_NUMBER 0x01000000 // initial release */ +/* #define VERSION_NUMBER 0x01010000 // fixed startup probs PLX MB0 not cleared */ +/* #define VERSION_NUMBER 0x01020000 // changed SUNI reset timings; allowed r/w onchip */ + +/* #define VERSION_NUMBER 0x01030000 // clear local doorbell int reg on reset */ +/* #define VERSION_NUMBER 0x01040000 // PLX bug work around version PLUS */ +/* remove race conditions on basic interface */ +/* indicate to the host that diagnostics */ +/* have finished; if failed, how and what */ +/* failed */ +/* fix host memory test to fix PLX bug */ +/* allow flash upgrade and BIA upgrade directly */ +/* */ +#define VERSION_NUMBER 0x01050025 /* Jason's first hacked version. */ +/* Change in download algorithm */ + +#define DMA_VALID 0xb728e149 /* completely random */ + +#define FLASH_BASE 0xa0c00000 +#define FLASH_SIZE 0x00020000 /* 128K */ +#define BIA_BASE (FLASH_BASE+0x0001c000) /* Flash Sector 7 */ +#define BIA_ADDRESS ((void *)0xa0c1c000) +#define PLX_BASE 0xe0000000 + +typedef enum { + host_memory_test = 1, + read_adapter_memory, + write_adapter_memory, + adapter_start, + get_version_number, + interrupt_host, + flash_erase_sector, + adap_download_block = 0x20, + adap_erase_flash, + adap_run_in_iram, + adap_end_download +} loader_command; + +#define BAD_COMMAND (-1) +#define COMMAND_IN_PROGRESS 1 +#define COMMAND_PASSED_TEST 2 +#define COMMAND_FAILED_TEST 3 +#define COMMAND_READ_DATA_OK 4 +#define COMMAND_READ_BAD_ADDRESS 5 +#define COMMAND_WRITE_DATA_OK 6 +#define COMMAND_WRITE_BAD_ADDRESS 7 +#define COMMAND_WRITE_FLASH_FAILURE 8 +#define COMMAND_COMPLETE 9 +#define COMMAND_FLASH_ERASE_FAILURE 10 +#define COMMAND_WRITE_BAD_DATA 11 + +/* bit fields for mailbox[0] return values */ + +#define GPINT_TST_FAILURE 0x00000001 +#define SUNI_DATA_PATTERN_FAILURE 0x00000002 +#define SUNI_DATA_BITS_FAILURE 0x00000004 +#define SUNI_UTOPIA_FAILURE 0x00000008 +#define SUNI_FIFO_FAILURE 0x00000010 +#define SRAM_FAILURE 0x00000020 +#define SELF_TEST_FAILURE 0x0000003f + +/* mailbox[1] = 0 in progress, -1 on completion */ +/* mailbox[2] = current test 00 00 test(8 bit) phase(8 bit) */ +/* mailbox[3] = last failure, 00 00 test(8 bit) phase(8 bit) */ +/* mailbox[4],mailbox[5],mailbox[6] random failure values */ + +/* PLX/etc. memory map including command structure */ + +/* These registers may also be memory mapped in PCI memory */ + +#define UNUSED_LOADER_MAILBOXES 6 + +typedef struct { + u32 stuff[16]; + union { + struct { + u32 result; + u32 ready; + u32 stuff[UNUSED_LOADER_MAILBOXES]; + } loader; + struct { + u32 cmd_address; + u32 tx_address; + u32 rx_address[NUM_RX_POOLS]; + u32 gen_counter; + u32 spare; + } adapter; + } mb; + u32 doorbell; + u32 interrupt; + u32 interrupt_control; + u32 reset_control; +} amb_mem; + +#define mem ((amb_mem *)0) + +/* IRQ (card to host) and doorbell (host to card) enable bits */ +#define AMB_INTERRUPT_BITS 0x00030000 +#define AMB_DOORBELL_BITS 0x00000300 + +/* loader commands */ + +#define MAX_COMMAND_DATA 13 +#define MAX_TRANSFER_DATA 11 + +typedef struct { + u32 address; + u32 count; + u32 data[MAX_TRANSFER_DATA]; +} transfer_block; + +typedef struct { + u32 result; + u32 command; + union { + transfer_block transfer; + u32 version; + u32 start; + u32 data[MAX_COMMAND_DATA]; + } payload; + u32 valid; +} loader_block; + +/* command queue */ + +/* Again all data are BIG ENDIAN */ + +typedef struct { + union { + struct { + u32 vc; + u32 flags; + u32 rate; + } open; + struct { + u32 vc; + u32 rate; + } modify_rate; + struct { + u32 vc; + u32 flags; + } modify_flags; + struct { + u32 vc; + } close; + struct { + u32 lower4; + u32 upper2; + } bia; + struct { + u32 address; + } suni; + struct { + u32 major; + u32 minor; + } version; + struct { + u32 read; + u32 write; + } speed; + struct { + u32 flags; + } flush; + struct { + u32 address; + u32 data; + } memory; + u32 par[3]; + } args; + u32 request; +} command; + +/* transmit queues and associated structures */ + +/* The hosts transmit structure. All BIG ENDIAN; host address + restricted to first 1GByte, but address passed to the card must + have the top MS bit or'ed in. -- check this */ + +/* TX is described by 1+ tx_frags followed by a tx_frag_end */ + +typedef struct { + u32 bytes; + u32 address; +} tx_frag; + +/* apart from handle the fields here are for the adapter to play with + and should be set to zero */ + +typedef struct { + u32 handle; + // really? what about a BE host? + u16 vc; + u16 next_descriptor_length; + u32 next_descriptor; +#ifdef AMB_NEW_MICROCODE + // BE host? + u8 cpcs_uu; + u8 cpi; + u16 pad; +#endif +} tx_frag_end; + +typedef struct { + tx_frag tx_frag; + tx_frag_end tx_frag_end; + struct sk_buff * skb; +} tx_simple; + +#if 0 +typedef union { + tx_frag fragment; + tx_frag_end end_of_list; +} tx_descr; +#endif + +/* this "points" to the sequence of fragments and trailer */ + +typedef struct { + // what about a BE host? + u16 vc; + u16 tx_descr_length; + u32 tx_descr_addr; +} tx_in; + +/* handle is the handle from tx_in */ + +typedef struct { + u32 handle; +} tx_out; + +/* receive frame structure */ + +/* All BIG ENDIAN; handle is as passed from host; length is zero for + aborted frames, and frames with errors. Header is actually VC + number, lec-id is NOT yet supported. */ + +typedef struct { + u32 handle; + // what about a BE host? + u16 vc; + u16 lec_id; // unused + u16 status; + u16 length; +} rx_out; + +/* buffer supply structure */ + +typedef struct { + u32 handle; + u32 host_address; +} rx_in; + +/* This first structure is the area in host memory where the adapter + writes its pointer values. These pointer values are BIG ENDIAN and + reside in the same 4MB 'page' as this structure. The host gives the + adapter the address of this block by sending a doorbell interrupt + to the adapter after downloading the code and setting it going. The + addresses have the top 10 bits set to 1010000010b -- really? + + The host must initialise these before handing the block to the + adapter. */ + +typedef struct { + u32 command_start; /* SRB commands completions */ + u32 command_end; /* SRB commands completions */ + u32 tx_start; + u32 tx_end; + u32 txcom_start; /* tx completions */ + u32 txcom_end; /* tx completions */ + struct { + u32 buffer_start; + u32 buffer_end; + u32 buffer_q_get; + u32 buffer_q_end; + u32 buffer_aptr; + u32 rx_start; /* rx completions */ + u32 rx_end; + u32 rx_ptr; + u32 buffer_size; /* size of host buffer */ + } rec_struct[NUM_RX_POOLS]; +#ifdef AMB_NEW_MICROCODE + // BE? + u16 init_flags; + u16 talk_block_spare; +#endif +} adap_talk_block; + +/* This structure must be kept in line with the vcr image in sarmain.h + + This is the structure in the host filled in by the adapter by + GET_SUNI_STATS */ + +typedef struct { + // what about a BE host? + u8 racp_chcs; + u8 racp_uhcs; + u16 spare; + u32 racp_rcell; + u32 tacp_tcell; + u32 flags; + u32 dropped_cells; + u32 dropped_frames; +} suni_stats; + +typedef enum { + dead +} amb_flags; + +#define NEXTQ(current,start,limit) \ + ( (current)+1 < (limit) ? (current)+1 : (start) ) + +typedef struct { + spinlock_t lock; + unsigned int pending; + unsigned int high; + unsigned int maximum; // size - 1 (q implementation) + command * start; + command * in; + command * out; + command * limit; +} amb_cq; + +typedef struct { + spinlock_t lock; + unsigned int pending; + unsigned int high; + unsigned int filled; + unsigned int maximum; // size - 1 (q implementation) + struct { + tx_in * start; + tx_in * ptr; + tx_in * limit; + } in; + struct { + tx_out * start; + tx_out * ptr; + tx_out * limit; + } out; +} amb_txq; + +typedef struct { + spinlock_t lock; + unsigned int pending; + unsigned int low; + unsigned int emptied; + unsigned int maximum; // size - 1 (q implementation) + struct { + rx_in * start; + rx_in * ptr; + rx_in * limit; + } in; + struct { + rx_out * start; + rx_out * ptr; + rx_out * limit; + } out; + unsigned int buffers_wanted; + unsigned int buffer_size; +} amb_rxq; + +typedef struct { + unsigned long tx_ok; + struct { + unsigned long ok; + unsigned long error; + unsigned long badcrc; + unsigned long toolong; + unsigned long aborted; + unsigned long unused; + } rx; +} amb_stats; + +// a single struct pointed to by atm_vcc->dev_data + +typedef struct { + u8 tx_vc_bits:7; + u8 tx_present:1; +} amb_tx_info; + +typedef struct { + unsigned char pool; +} amb_rx_info; + +typedef struct { + amb_rx_info rx_info; + u16 tx_frame_bits; + unsigned int tx_rate; + unsigned int rx_rate; +} amb_vcc; + +struct amb_dev { + u8 irq; + u8 flags; + u32 iobase; + u32 * membase; + +#if 0 + struct tq_struct bh; +#endif + + amb_cq cq; + amb_txq txq; + amb_rxq rxq[NUM_RX_POOLS]; + + struct semaphore vcc_sf; + amb_tx_info txer[NUM_VCS]; + struct atm_vcc * rxer[NUM_VCS]; + unsigned int tx_avail; + unsigned int rx_avail; + + amb_stats stats; + + struct atm_dev * atm_dev; + struct pci_dev * pci_dev; + struct amb_dev * prev; +}; + +typedef struct amb_dev amb_dev; + +#define AMB_DEV(atm_dev) ((amb_dev *) (atm_dev)->dev_data) +#define AMB_VCC(atm_vcc) ((amb_vcc *) (atm_vcc)->dev_data) + +/* the microcode */ + +typedef struct { + u32 start; + unsigned int count; +} region; + +extern const region ucode_regions[]; +extern const u32 ucode_data[]; +extern const u32 ucode_start; + +/* rate rounding */ + +typedef enum { + round_up, + round_down, + round_nearest +} rounding; + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.14/linux/drivers/atm/atmdev_init.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/atmdev_init.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,60 @@ +/* drivers/atm/atmdev_init.c - ATM device driver initialization */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + +#include +#include + + +#ifdef CONFIG_ATM_ENI +extern int eni_detect(void); +#endif +#ifdef CONFIG_ATM_ZATM +extern int zatm_detect(void); +#endif +#ifdef CONFIG_ATM_TNETA1570 +extern int tneta1570_detect(void); +#endif +#ifdef CONFIG_ATM_FORE200 +extern int fore200_detect(void); +#endif +#ifdef CONFIG_ATM_NICSTAR +extern int nicstar_detect(void); +#endif +#ifdef CONFIG_ATM_AMBASSADOR +extern int amb_detect(void); +#endif +#ifdef CONFIG_ATM_HORIZON +extern int hrz_detect(void); +#endif + + +__initfunc(int atmdev_init(void)) +{ + int devs; + + devs = 0; +#ifdef CONFIG_ATM_ENI + devs += eni_detect(); +#endif +#ifdef CONFIG_ATM_ZATM + devs += zatm_detect(); +#endif +#ifdef CONFIG_ATM_TNETA1570 + devs += tneta1570_detect(); +#endif +#ifdef CONFIG_ATM_FORE200 + devs += fore200_detect(); +#endif +#ifdef CONFIG_ATM_NICSTAR + devs += nicstar_detect(); +#endif +#ifdef CONFIG_ATM_AMBASSADOR + devs += amb_detect(); +#endif +#ifdef CONFIG_ATM_HORIZON + devs += hrz_detect(); +#endif + return devs; +} diff -u --recursive --new-file v2.3.14/linux/drivers/atm/atmsar11.data linux/drivers/atm/atmsar11.data --- v2.3.14/linux/drivers/atm/atmsar11.data Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/atmsar11.data Mon Aug 23 09:56:31 1999 @@ -0,0 +1,2063 @@ +/* + Madge Ambassador ATM Adapter microcode. + Copyright (C) 1995-1999 Madge Networks Ltd. + + This is provided here for your convenience only. + + No restrictions are placed on its use, so long as this file remains + unchanged. + + You may not make, use or re-distribute modified versions of this code. +*/ + + 0x401a6800, + 0x00000000, + 0x335b007c, + 0x13600005, + 0x335b1000, + 0x3c1aa0c0, + 0x375a0180, + 0x03400008, + 0x00000000, + 0x1760fffb, + 0x335b4000, + 0x401a7000, + 0x13600003, + 0x241b0fc0, + 0xaf9b4500, + 0x25080008, + 0x03400008, + 0x42000010, + 0x8f810c90, + 0x32220002, + 0x10400003, + 0x3c03a0d1, + 0x2463f810, + 0x0060f809, + 0x24210001, + 0x1000001a, + 0xaf810c90, + 0x82020011, + 0xaf900c48, + 0x0441000a, + 0x34420080, + 0x967d0002, + 0x96020012, + 0x00000000, + 0x105d0011, + 0x00000000, + 0x04110161, + 0xa6620002, + 0x1000000d, + 0xae62000c, + 0x34848000, + 0xa2020011, + 0x4d01ffff, + 0x00000000, + 0x8f834c00, + 0x00000000, + 0xaf830fec, + 0x00e0f809, + 0x03e03821, + 0x00041400, + 0x0440fff7, + 0x00000000, + 0xaf80460c, + 0x8e100008, + 0x4d01ffff, + 0x00000000, + 0x8f834c00, + 0x4900001d, + 0xaf830fec, + 0x8f820cbc, + 0x8f9d0c4c, + 0x24420001, + 0x97be0000, + 0xaf820cbc, + 0x13c00009, + 0xaca200d8, + 0xa7a00000, + 0x3c0100d1, + 0x003e0825, + 0x9422002c, + 0x0411013f, + 0xa4220002, + 0xac22000c, + 0xac200010, + 0x8f9e0c54, + 0x27bd0002, + 0x17be0002, + 0x8ca200c0, + 0x8f9d0c50, + 0x8f970fc8, + 0xaf9d0c4c, + 0x12e20005, + 0x87804002, + 0x3c02a0d1, + 0x2442f94c, + 0x0040f809, + 0x00000000, + 0x00e0f809, + 0x03e03821, + 0x4500ffdc, + 0x8e11000c, + 0x3c1300d1, + 0x00111102, + 0x2c430400, + 0x1060ffb9, + 0x00021180, + 0x02629821, + 0x8e76003c, + 0x32220008, + 0x1440ffb7, + 0x8e770034, + 0x8e750030, + 0x3c03cfb0, + 0x16c00003, + 0x02d5102b, + 0x041100be, + 0x00000000, + 0x1040ffa6, + 0x00701826, + 0x4d01ffff, + 0x00000000, + 0x8f824c00, + 0xaf974c00, + 0xaf820fec, + 0xac760010, + 0x02609021, + 0x32220002, + 0x10400007, + 0x8f944a00, + 0x9602003a, + 0x34840004, + 0x14400003, + 0xaf820fbc, + 0x3c029000, + 0xaf820fbc, + 0x8e100008, + 0x32943f00, + 0x8e11000c, + 0x2694ff00, + 0x12800073, + 0x3c1300d1, + 0x49010071, + 0x32370008, + 0x16e0006f, + 0x00111102, + 0x2c430400, + 0x1060006c, + 0x0002b980, + 0x00041740, + 0x0440003a, + 0x02779821, + 0x12720023, + 0x26d60030, + 0xae56003c, + 0x8e76003c, + 0x8e770034, + 0x8e750030, + 0x3c03cfb0, + 0x16c00003, + 0x02d5102b, + 0x04110091, + 0x00000000, + 0x10400060, + 0x2e821000, + 0x14400009, + 0x00701826, + 0x4d01ffff, + 0x00000000, + 0x8f824c00, + 0xaf974c00, + 0xac760010, + 0xae420034, + 0x1000ffd0, + 0xaf80460c, + 0x00e0f809, + 0x03e03821, + 0x3c03cfb0, + 0x00701826, + 0xae460034, + 0x4d01ffff, + 0x00000000, + 0x8f824c00, + 0xaf974c00, + 0xaf820fec, + 0xac760010, + 0x1000ffc3, + 0xaf80460c, + 0x02d5102b, + 0x10400042, + 0x3c17cfb0, + 0x2e821000, + 0x14400006, + 0x02f0b826, + 0x4d01ffff, + 0x00000000, + 0xaef60010, + 0x1000ffb8, + 0xaf80460c, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x8f824c00, + 0xaf864c00, + 0xaef60010, + 0xaf820fec, + 0x1000ffae, + 0xaf80460c, + 0x3084fffb, + 0x8e570038, + 0x3242ffc0, + 0x00021182, + 0xa7820fb8, + 0xaf970fb4, + 0x865d002a, + 0x865e0008, + 0xa79d0fba, + 0x279d0f18, + 0x33de0060, + 0x03bee821, + 0x001ef0c2, + 0x03bee821, + 0x8f970c58, + 0x4d01ffff, + 0x00000000, + 0x8f834c00, + 0x8fa2001c, + 0x12e30003, + 0x3c030c40, + 0x3c1ec000, + 0xaf9e0fbc, + 0xac620fb4, + 0x8fa30018, + 0x2442000c, + 0x14430002, + 0xaf80460c, + 0x8fa20014, + 0xae40003c, + 0xafa2001c, + 0x8e76003c, + 0x8e770034, + 0x8e750030, + 0x3c03cfb0, + 0x16c00003, + 0x02d5102b, + 0x0411003c, + 0x00000000, + 0x00701826, + 0x4d01ffff, + 0x00000000, + 0xaca500e4, + 0x10400032, + 0xaf974c00, + 0x1000ff7f, + 0xac760010, + 0x00041740, + 0x04400007, + 0x26d60030, + 0xae56003c, + 0x00e0f809, + 0x03e03821, + 0xaf80460c, + 0x1000ff39, + 0xae460034, + 0x8e570038, + 0x3242ffc0, + 0x00021182, + 0xa7820fb8, + 0xaf970fb4, + 0x8f970c58, + 0x00e0f809, + 0x03e03821, + 0x12e60003, + 0x3c030c40, + 0x3c02c000, + 0xaf820fbc, + 0x865d002a, + 0x865e0008, + 0xa79d0fba, + 0x279d0f18, + 0x33de0060, + 0x03bee821, + 0x001ef0c2, + 0x03bee821, + 0x8fa2001c, + 0x4d01ffff, + 0x00000000, + 0x8f974c00, + 0xac620fb4, + 0x3084fffb, + 0x8fa30018, + 0x2442000c, + 0x14430002, + 0xaf80460c, + 0x8fa20014, + 0xae40003c, + 0xafa2001c, + 0x4d01ffff, + 0x00000000, + 0xaca500e4, + 0x1000ff13, + 0xaf974c00, + 0x00e0f809, + 0x03e03821, + 0x1000ff0f, + 0x00000000, + 0x1040005b, + 0x867e0008, + 0x279d0f18, + 0x33de0060, + 0x03bee821, + 0x001e10c2, + 0x03a2e821, + 0x8fb70008, + 0x8fa2000c, + 0x8ef60004, + 0x12e20028, + 0x86620008, + 0x82030010, + 0x00021740, + 0x04410019, + 0x24630001, + 0x10600017, + 0x3c02d1b0, + 0x00501026, + 0x4d01ffff, + 0x00000000, + 0x8f9e4c00, + 0xac560010, + 0x26d6fffe, + 0x86020010, + 0x3c03cfb0, + 0x34632000, + 0xa662002a, + 0x8ee20000, + 0x26f70008, + 0xae620038, + 0x8fa20020, + 0xafb70008, + 0x2417ffff, + 0x02c2a821, + 0x4d01ffff, + 0x00000000, + 0xaf9e4c00, + 0x03e00008, + 0xae750030, + 0x8ee20000, + 0x26f70008, + 0xae620038, + 0x8fa20020, + 0xafb70008, + 0x2417ffff, + 0xa677002a, + 0x02c2a821, + 0x3c03cfb0, + 0x03e00008, + 0xae750030, + 0x001e18c2, + 0x00651821, + 0x8c6300c8, + 0x8fa20010, + 0x00000000, + 0x0062b023, + 0x1ec00003, + 0x8fa10004, + 0x12c0001b, + 0x0022b023, + 0x2ec30041, + 0x14600002, + 0x3c150040, + 0x24160040, + 0x00161e80, + 0x00031882, + 0x00751825, + 0x4d01ffff, + 0x00000000, + 0x8f954c00, + 0x001eb840, + 0x00771821, + 0xac624d00, + 0x00561021, + 0x14410002, + 0x27830d00, + 0x8fa20000, + 0x02e3b821, + 0xafa20010, + 0x02d71821, + 0xafa3000c, + 0x4d01ffff, + 0x00000000, + 0x8ef60004, + 0x1000ffb5, + 0xaf954c00, + 0x3c16dead, + 0xae76003c, + 0xae600038, + 0x26d5ffff, + 0x00001021, + 0x03e00008, + 0xae750030, + 0x2c430ab2, + 0x10600005, + 0x2c4324b2, + 0x10000004, + 0x24020ab2, + 0x10000002, + 0x240224b1, + 0x1060fffd, + 0x304301ff, + 0x00031840, + 0x3c1da0d1, + 0x27bdd6cc, + 0x007d1821, + 0x94630000, + 0x0002ea42, + 0x00031c00, + 0x27bdfffb, + 0x03e00008, + 0x03a31006, + 0x24030fc0, + 0xaf834500, + 0x10000002, + 0x01206021, + 0x3c0ccfb0, + 0x11e00056, + 0x01896026, + 0x85fe0000, + 0x00000000, + 0x13c00047, + 0x3c02cfb0, + 0x07c0002d, + 0x001e1f80, + 0x04610034, + 0x001e1fc0, + 0x04600009, + 0x3c02d3b0, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x8f864c00, + 0x8f990fec, + 0x1000000b, + 0xaf994c00, + 0x01e27826, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x8f864c00, + 0xaf994c00, + 0xadef2010, + 0x3c02d3b0, + 0x01e27826, + 0x8f820fc0, + 0x8f830fc4, + 0xaf824d00, + 0x8de20004, + 0xa5e00000, + 0xac620000, + 0x8c620000, + 0x24020380, + 0xaf824d00, + 0x8f824d00, + 0x8f820f14, + 0x24630004, + 0x14620002, + 0x2419ffff, + 0x8f830f10, + 0xaca500e4, + 0xaf830fc4, + 0x4d01ffff, + 0x00000000, + 0x8f824c80, + 0x1000001f, + 0xade2003c, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0xa5e00000, + 0x8f864c00, + 0x15800022, + 0xaf8f4540, + 0x10000017, + 0x01e27826, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x8f864c00, + 0xaf994c00, + 0xadef2010, + 0x3c02cfb0, + 0x01e27826, + 0xa5e00000, + 0x4d01ffff, + 0x00000000, + 0x10000007, + 0x8f994c00, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x8f864c00, + 0x8f990fec, + 0x1580000a, + 0xaf8f4500, + 0x00007821, + 0x10000014, + 0xaf190014, + 0x00e0f809, + 0x03e03821, + 0x4d01ffff, + 0x00000000, + 0x1180fff8, + 0x8f864c00, + 0x85220000, + 0x01207821, + 0x0440000a, + 0x8d290008, + 0x130b0004, + 0x000c1602, + 0xaf190014, + 0x8d790014, + 0x0160c021, + 0xaf994c00, + 0xad8e4010, + 0x3042003f, + 0x01c27021, + 0x00041780, + 0x0440018b, + 0x8f824a00, + 0x30818000, + 0x30420004, + 0x1440ff8d, + 0x8d4b0000, + 0x1020000c, + 0x30847fff, + 0x8f820c48, + 0x0120f021, + 0x24430034, + 0x8c5d000c, + 0x24420004, + 0xafdd000c, + 0x1462fffc, + 0x27de0004, + 0xa5210000, + 0x1000ff82, + 0x25080008, + 0x11600058, + 0x00000000, + 0x857d0008, + 0x8d63000c, + 0x9562000a, + 0x8d410004, + 0x07a10026, + 0x00621821, + 0xa563000a, + 0x00031c02, + 0x041101a0, + 0x000318c0, + 0x001d16c0, + 0x0441001f, + 0x27a20080, + 0x00021cc0, + 0x0461000e, + 0x0040e821, + 0x27bd0080, + 0x95620000, + 0x95630002, + 0x3442000c, + 0xad22000c, + 0x24020100, + 0xa5220010, + 0x9562002c, + 0xa5230014, + 0xa5220012, + 0xa5200016, + 0x34028000, + 0xa5220000, + 0xa57d0008, + 0x07a0000c, + 0x8f820c4c, + 0x8f830c50, + 0x2441ffe8, + 0x0023f02b, + 0x13c00002, + 0x00201021, + 0x24420400, + 0x945e0000, + 0x2441fffe, + 0x17c0fff9, + 0xad620010, + 0xa44b0000, + 0x142b001c, + 0xad400000, + 0xad400004, + 0x254a0008, + 0x3142007f, + 0x1440000e, + 0x00041780, + 0x04410003, + 0x8f820fe0, + 0x10000006, + 0x34840001, + 0x34840002, + 0x24420008, + 0x34421000, + 0x38421000, + 0xaf820fe0, + 0x354a0100, + 0x394a0100, + 0x39420080, + 0xaf820fe4, + 0x001d14c0, + 0x04410003, + 0x33a2efff, + 0x1000ff3c, + 0xa5620008, + 0x07a0009f, + 0x33a2fffe, + 0x10000021, + 0xa5620008, + 0x8d620024, + 0x001d1cc0, + 0x04610004, + 0xad420000, + 0x33a3efff, + 0x1000ff31, + 0xa5630008, + 0x07a00005, + 0x33a3fffe, + 0xa5630008, + 0x8d4b0000, + 0x1000ffaa, + 0x00000000, + 0x1000008e, + 0x25080008, + 0x254a0008, + 0x3142007f, + 0x1440000e, + 0x00041780, + 0x04410003, + 0x8f820fe0, + 0x10000006, + 0x34840001, + 0x34840002, + 0x24420008, + 0x34421000, + 0x38421000, + 0xaf820fe0, + 0x354a0100, + 0x394a0100, + 0x39420080, + 0xaf820fe4, + 0x11000003, + 0x8d4b0000, + 0x1000ff93, + 0x2508fff8, + 0x8f820fd8, + 0x8f830fdc, + 0x8f810fd4, + 0x1062001d, + 0x24620008, + 0x4d01ffff, + 0x00000000, + 0x8f8c4c00, + 0x847f0000, + 0x3c1e00d1, + 0x33fd03ff, + 0x001d5980, + 0x017e5821, + 0x857e0008, + 0x001de900, + 0x001e0f00, + 0x03e1f825, + 0x07e00003, + 0xaf820fdc, + 0x879e0ca0, + 0x278b0c98, + 0x07c10042, + 0x3c020840, + 0x3c01f7b0, + 0x8d620020, + 0x00230826, + 0xac220000, + 0x8c620004, + 0x94630002, + 0x2442fff8, + 0x00431021, + 0x1000004e, + 0xad620020, + 0x8f820fd0, + 0x87830ca0, + 0x14220007, + 0x278b0c98, + 0x41000051, + 0x3c018000, + 0xaca100e0, + 0x8ca100c4, + 0x00000000, + 0x1022004c, + 0x0022e823, + 0x8f9f0f0c, + 0x07a10002, + 0xaf810fd4, + 0x03e2e823, + 0x2fa30041, + 0x14600002, + 0x3c1e0040, + 0x241d0040, + 0x001d1e80, + 0x00031882, + 0x007e1825, + 0x4d01ffff, + 0x00000000, + 0x8f8c4c00, + 0xac624cc0, + 0x005d1021, + 0x145f0002, + 0x27830cc0, + 0x8f820f08, + 0x03a3f021, + 0xaf820fd0, + 0xaf9e0fd8, + 0x4d01ffff, + 0x00000000, + 0x1000ffc3, + 0x24620008, + 0x8d63000c, + 0x8d7d0010, + 0xa563000a, + 0x13a00002, + 0x00031c02, + 0xa7a00000, + 0x000318c0, + 0x041100ef, + 0x00681821, + 0x4d01ffff, + 0x00000000, + 0x8f820c44, + 0x8f830c40, + 0xad620010, + 0xa5630004, + 0xa5630006, + 0x10000021, + 0xaf8c4c00, + 0xa57d0000, + 0x8c7d0004, + 0x94630002, + 0xac5d4c40, + 0x27a20008, + 0xad620018, + 0x03a3e821, + 0x27bdfff4, + 0xad7d001c, + 0x27bd0004, + 0xad7d0020, + 0x37c18001, + 0x001e17c0, + 0x0441ffe0, + 0xa5610008, + 0x4d01ffff, + 0x00000000, + 0x8f820c44, + 0x8f830c40, + 0xad620010, + 0xa5630004, + 0xa5630006, + 0x8f820fd8, + 0x8f830fdc, + 0x4d01ffff, + 0x00000000, + 0x1462ff95, + 0x24620008, + 0xaf8c4c00, + 0x87830ca0, + 0x278b0c98, + 0x0461fe97, + 0x00041700, + 0x04400005, + 0x95620000, + 0x11780006, + 0x00000000, + 0xaf0e0010, + 0xa70d0004, + 0x3084fff7, + 0x956d0004, + 0x8d6e0010, + 0x25adffd0, + 0x05a1fe8f, + 0xad22000c, + 0x3c0cffb0, + 0x01896026, + 0x000d1822, + 0x25ad0030, + 0x8d7e0018, + 0x8d61001c, + 0x4d01ffff, + 0x00000000, + 0x103e0036, + 0x8f9d4c00, + 0x3c010840, + 0xac3e4c40, + 0x27de0008, + 0x11a00017, + 0xad7e0018, + 0x000df600, + 0x019e6025, + 0x4d01ffff, + 0x00000000, + 0xad8e4010, + 0x8f8d0c40, + 0x957e0006, + 0x8f8e0c44, + 0x03cdf021, + 0xa57e0006, + 0x000cf782, + 0x000c0e02, + 0x03c1f021, + 0x001e0f80, + 0x000c6200, + 0x000c6202, + 0x01816025, + 0x33de003c, + 0x019e6021, + 0x34010001, + 0x10000008, + 0xa5210000, + 0x957e0006, + 0x4d01ffff, + 0x00000000, + 0x8f8d0c40, + 0x8f8e0c44, + 0x03cdf021, + 0xa57e0006, + 0x4d01ffff, + 0x00000000, + 0x01a3f02b, + 0x17c00008, + 0x0003f600, + 0x01a36823, + 0x019e6025, + 0x01896026, + 0x4d01fff7, + 0x00000000, + 0x1000fe58, + 0xaf9d4c00, + 0x8d7e0018, + 0x8d61001c, + 0x00000000, + 0x143effce, + 0x006d1823, + 0x4d01ffff, + 0x00000000, + 0x2c610008, + 0x10200017, + 0x95610008, + 0x00000000, + 0x0001ff80, + 0x07e0000b, + 0x34210002, + 0x006d1821, + 0x00031e00, + 0x01836025, + 0x01896026, + 0x240d002c, + 0xa5610008, + 0x4d01ffff, + 0x00000000, + 0x1000fe40, + 0xaf9d4c00, + 0x3c1f0c40, + 0xaffe4fa8, + 0x3021fffd, + 0xa5610008, + 0x3c0cd3cf, + 0x358ce000, + 0x10000008, + 0x34030002, + 0x3c1f0c40, + 0xaffe4fa8, + 0x11a0fff9, + 0x000df600, + 0x34030003, + 0x019e6025, + 0x01896026, + 0x34840008, + 0x34420002, + 0xad22000c, + 0x95620006, + 0xa5230000, + 0xad220038, + 0x4d01ffff, + 0x00000000, + 0x857e0008, + 0x8f820fa8, + 0x97830fac, + 0xad220004, + 0x33c17fff, + 0xad600010, + 0xa5610008, + 0x1060fe20, + 0xaf9d4c00, + 0xa57e0008, + 0x00031900, + 0x30633ff0, + 0xa5630000, + 0x8f820fb0, + 0x3c030840, + 0xac624c40, + 0x24430008, + 0xad630018, + 0x97830fae, + 0x2442fff4, + 0x00621821, + 0xad63001c, + 0x4d01ffff, + 0x00000000, + 0x8f8d0c40, + 0x8f830c44, + 0xa56d0004, + 0xa56d0006, + 0xad630010, + 0x1000fe0a, + 0xaf9d4c00, + 0x8f820fe0, + 0x00040fc0, + 0x8c430000, + 0x0421001b, + 0x8f9f0fe4, + 0x8c5d0004, + 0xac400004, + 0x1060000e, + 0xac400000, + 0x00000000, + 0x94620028, + 0x00000000, + 0x005f1020, + 0x8c410004, + 0x00000000, + 0x10200003, + 0xac430004, + 0x10000002, + 0xac230024, + 0xac430000, + 0x17a3fff4, + 0x8c630024, + 0x8f820fe0, + 0x3bff0080, + 0x24420008, + 0x34421000, + 0x38421000, + 0xaf820fe0, + 0xaf9f0fe4, + 0x1000fe57, + 0x3084fffe, + 0x10600010, + 0x00000000, + 0x947d0028, + 0x00000000, + 0x03bfe820, + 0x8fa10004, + 0xafa30004, + 0x10200003, + 0x8c5e0004, + 0x10000002, + 0xac230024, + 0xafa30000, + 0x8c610024, + 0x17c3fe48, + 0xac410000, + 0xac400004, + 0xac400000, + 0x1000fe44, + 0x3084fffd, + 0x2c620100, + 0x1440000e, + 0x006a1021, + 0x3143007f, + 0x01431823, + 0x00431823, + 0x3062007f, + 0xa5620028, + 0x00621823, + 0x00031902, + 0x8f820fe0, + 0x2463fff8, + 0x00621821, + 0x34631000, + 0x10000003, + 0x38631000, + 0x34430100, + 0x38630100, + 0x8c620004, + 0x00000000, + 0x10400003, + 0xac6b0004, + 0x03e00008, + 0xac4b0024, + 0x03e00008, + 0xac6b0000, + 0x00000002, + 0xa0d0e000, + 0x00000000, + 0x00001000, + 0x00000006, + 0x00000008, + 0x00000000, + 0x00000008, + 0x00000002, + 0xa0d0d648, + 0x00000000, + 0x00000888, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x24313200, + 0x24313200, + 0x24313200, + 0x00000000, + 0x244d4352, + 0x2420436f, + 0x70797269, + 0x67687420, + 0x28632920, + 0x4d616467, + 0x65204e65, + 0x74776f72, + 0x6b73204c, + 0x74642031, + 0x3939352e, + 0x20416c6c, + 0x20726967, + 0x68747320, + 0x72657365, + 0x72766564, + 0x2e004d61, + 0x64676520, + 0x416d6261, + 0x73736164, + 0x6f722076, + 0x312e3031, + 0x00000000, + 0x00000001, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xfff04000, + 0x00000000, + 0x0c343e2d, + 0x00000000, + 0x3c1ca0d1, + 0x279c5638, + 0x3c1da0d1, + 0x27bddfd0, + 0x3c08a0d1, + 0x2508dfd0, + 0xaf878008, + 0x0c343c13, + 0x00000000, + 0x24040003, + 0x0097000d, + 0x3c08bfc0, + 0x35080230, + 0x8d080000, + 0x00000000, + 0x01000008, + 0x00000000, + 0x27bdffd0, + 0xafbf001c, + 0xafb10018, + 0xafb00014, + 0x3c11fff0, + 0x00008021, + 0x3c180056, + 0x37183b79, + 0x26190200, + 0x17200002, + 0x0319001a, + 0x0007000d, + 0x2401ffff, + 0x17210005, + 0x00000000, + 0x3c018000, + 0x17010002, + 0x00000000, + 0x0006000d, + 0x00001012, + 0x00101840, + 0x3c05a0d1, + 0x24a5d6cc, + 0x00a32021, + 0xa4820000, + 0x26100001, + 0x2a010200, + 0x1420ffea, + 0x00000000, + 0x3c06a0d1, + 0x24c6f9e4, + 0x3c07a0d1, + 0x24e7d648, + 0xace60000, + 0x3c08a0d1, + 0x2508fb14, + 0xace80004, + 0x3c09a0d1, + 0x2529fc94, + 0xace90008, + 0x3c0aa0d1, + 0x254afcd4, + 0xacea000c, + 0x3c0ba0d1, + 0x256bfba8, + 0xaceb0010, + 0x3c0ca0d1, + 0x258cfbc4, + 0xacec0014, + 0x3c0da0d1, + 0x25adfbe0, + 0xaced0018, + 0x3c0ea0d1, + 0x25cefbfc, + 0xacee001c, + 0x3c0fa0d1, + 0x25effc18, + 0xacef0020, + 0x3c18a0d1, + 0x2718fc34, + 0xacf80024, + 0x3c19a0d1, + 0x2739fc50, + 0xacf90028, + 0x3c02a0d1, + 0x2442fc60, + 0xace2002c, + 0x3c03a0d1, + 0x2463fc70, + 0xace30030, + 0x3c04a0d1, + 0x2484fc80, + 0xace40034, + 0x3c05a0d1, + 0x24a5fcb4, + 0xace50038, + 0x3c06a0d1, + 0x24c6fe08, + 0xace6003c, + 0x3c08a0d1, + 0x2508fe90, + 0xace80040, + 0x3c09a0d1, + 0x2529fa38, + 0xace90044, + 0x3c0aa0d1, + 0x254afa74, + 0xacea0048, + 0x24100013, + 0x3c0ba0d1, + 0x256bf9d8, + 0x00106080, + 0x3c0ea0d1, + 0x25ced648, + 0x01cc6821, + 0xadab0000, + 0x26100001, + 0x2a010020, + 0x1420fff6, + 0x00000000, + 0x8f988000, + 0x00000000, + 0xaf000100, + 0x8f828000, + 0x241903ff, + 0xa4590202, + 0x00008021, + 0x8f868000, + 0x24030fff, + 0x00102040, + 0x24c70380, + 0x00e42821, + 0xa4a30000, + 0x26100001, + 0x2a010008, + 0x1420fff7, + 0x00000000, + 0x8f898000, + 0x34089c40, + 0xad2803a0, + 0x8f8b8000, + 0x3c0a00ff, + 0x354affff, + 0xad6a03a4, + 0x00008021, + 0x8f8f8000, + 0x240c0fff, + 0x00106840, + 0x25f80300, + 0x030d7021, + 0xa5cc0000, + 0x26100001, + 0x2a010008, + 0x1420fff7, + 0x00000000, + 0x8f828000, + 0x34199c40, + 0xac590320, + 0x8f848000, + 0x3c0300ff, + 0x3463ffff, + 0xac830324, + 0x8f868000, + 0x240502ff, + 0xa4c50202, + 0x3c08a0c0, + 0x35080180, + 0x3c09a0d1, + 0x2529d5b8, + 0x250a0028, + 0x8d0b0000, + 0x8d0c0004, + 0xad2b0000, + 0xad2c0004, + 0x25080008, + 0x150afffa, + 0x25290008, + 0x40026000, + 0x00000000, + 0xafa20028, + 0x24030022, + 0x3c04a0e0, + 0x34840014, + 0xac830000, + 0x8fa50028, + 0x00000000, + 0x34a61001, + 0x00c01021, + 0xafa60028, + 0x3c07ffbf, + 0x34e7ffff, + 0x00c73824, + 0x00e01021, + 0xafa70028, + 0x40876000, + 0x00000000, + 0x3c080002, + 0x3508d890, + 0x3c09fffe, + 0x35290130, + 0xad280000, + 0x8faa0028, + 0x3c0bf000, + 0x014b5825, + 0x01601021, + 0xafab0028, + 0x01606021, + 0x408c6000, + 0x00000000, + 0x00008021, + 0x00107080, + 0x022e7821, + 0xade00000, + 0x26100001, + 0x2a010400, + 0x1420fffa, + 0x00000000, + 0x24180001, + 0x3c19a0e8, + 0xaf380000, + 0x24020011, + 0x3c03a0f0, + 0x34630017, + 0xa0620000, + 0x3c04f0eb, + 0x34840070, + 0x3c05fff0, + 0x34a54a00, + 0xaca40000, + 0x3c06fceb, + 0x34c60070, + 0xaca60000, + 0x3c07fff0, + 0x34e74700, + 0xace00000, + 0x00008021, + 0x3c08fff0, + 0x35080fc0, + 0x3c09fff0, + 0x35294500, + 0xad280000, + 0x26100001, + 0x2a010004, + 0x1420fff8, + 0x00000000, + 0x00008021, + 0x3c0adead, + 0x00105980, + 0x3c0100d1, + 0x002b0821, + 0xac2a003c, + 0x3c0100d1, + 0x002b0821, + 0xac200030, + 0x3c0100d1, + 0x002b0821, + 0xac200038, + 0x240dffff, + 0x3c0100d1, + 0x002b0821, + 0xac2d0014, + 0x00107100, + 0x3c0100d1, + 0x002b0821, + 0xa42e0000, + 0x3c0100d1, + 0x002b0821, + 0xa4200004, + 0x24180020, + 0x3c0100d1, + 0x002b0821, + 0xa4380008, + 0x3c0100d1, + 0x002b0821, + 0xac200010, + 0x26100001, + 0x2a010400, + 0x1420ffe0, + 0x00000000, + 0x00008021, + 0x001018c0, + 0x3c05a0d1, + 0x24a5e000, + 0x00a32021, + 0xac800000, + 0x3c07a0d1, + 0x24e7e000, + 0x24e80004, + 0x01033021, + 0xacc00000, + 0x26100001, + 0x2a010009, + 0x1420fff3, + 0x00000000, + 0x24090380, + 0x3c0afff0, + 0x354a4d00, + 0xad490000, + 0x3c0ca080, + 0x358c009c, + 0xad800000, + 0x3c0da080, + 0x35ad00a0, + 0xada00000, + 0x3c0e1100, + 0x3c0fa080, + 0x35ef00a8, + 0xadee0000, + 0x41010003, + 0x00000000, + 0x4100ffff, + 0x00000000, + 0x3c18a080, + 0x371800e0, + 0x8f190000, + 0x3c01a0d1, + 0xac39d6c8, + 0x0c343d43, + 0x03202021, + 0x8fb00014, + 0x8fbf001c, + 0x8fb10018, + 0x03e00008, + 0x27bd0030, + 0x0080b821, + 0x3c1cfff0, + 0xa3800c84, + 0xa3800c88, + 0x8f904400, + 0x00002021, + 0xaf800cbc, + 0x240200a8, + 0x27830f00, + 0x2c5d0040, + 0x17a0000c, + 0x3c1dffb0, + 0x03a3e826, + 0xafb74000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4d01ffff, + 0x00000000, + 0x2442ffc0, + 0x24630040, + 0x1000fff3, + 0x26f70040, + 0x1040000d, + 0x00000000, + 0x0002ee00, + 0x3c010040, + 0x03a1e825, + 0x3c01fff0, + 0x03a1e826, + 0x03a3e826, + 0xafb74000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4d01ffff, + 0x00000000, + 0x3c05a080, + 0x8f820f08, + 0x00000000, + 0xaf820fd4, + 0xaf820fd0, + 0xaca200c4, + 0x8f820f10, + 0x00000000, + 0x00021d82, + 0xaf830fc0, + 0x00031d80, + 0x00431023, + 0x3c01a080, + 0x00411025, + 0xaf820fc4, + 0xaf820f10, + 0x8f820f14, + 0x00000000, + 0x00431023, + 0x3c01a080, + 0x00411025, + 0xaf820f14, + 0x24030003, + 0x279d0f18, + 0x24be00c8, + 0x27810d00, + 0x8fa20000, + 0x00000000, + 0xafa20010, + 0xafc20000, + 0xafa10008, + 0xafa1000c, + 0x8fa20014, + 0x00000000, + 0xafa2001c, + 0x27bd0024, + 0x27de0004, + 0x24210040, + 0x1460fff3, + 0x2463ffff, + 0x8f820f00, + 0x00000000, + 0xaf820fc8, + 0xaca200c0, + 0x27820800, + 0x2403000f, + 0xac400000, + 0x24420004, + 0x1460fffd, + 0x2463ffff, + 0x8f830fc0, + 0x00000000, + 0xaf834d00, + 0x8f834d00, + 0x8f830f14, + 0x8f820f10, + 0x2463fffc, + 0xac400000, + 0x1443fffe, + 0x24420004, + 0x24020380, + 0xaf824d00, + 0x279d0f18, + 0x27a10090, + 0x8fa20014, + 0x8fa30018, + 0x00000000, + 0x00621823, + 0x2c7f0040, + 0x17e00009, + 0x3c1f0040, + 0x37ff0800, + 0x03a0f021, + 0x4d01ffff, + 0x00000000, + 0xafe20000, + 0x24420040, + 0x1000fff6, + 0x2463ffc0, + 0x10600006, + 0x37ff0800, + 0x00031e00, + 0x03e3f825, + 0x4d01ffff, + 0x00000000, + 0xafe20000, + 0x27bd0024, + 0x17a1ffe8, + 0x00000000, + 0x00003821, + 0x8fc20014, + 0x8fc30018, + 0x00000000, + 0x00621823, + 0x2c7f0040, + 0x13e00004, + 0x3c1f0040, + 0x00030e00, + 0x10000002, + 0x03e1f825, + 0x24030040, + 0x37ff0800, + 0x241e03e7, + 0x00000821, + 0x4d01ffff, + 0x00000000, + 0xafe20000, + 0x00230821, + 0x4900fffb, + 0x00000000, + 0x87804002, + 0x17c0fff8, + 0x27deffff, + 0x14e00004, + 0x34e74000, + 0x03e7f825, + 0x1000fff0, + 0xaf810c60, + 0xaf810c5c, + 0x3c01a0d1, + 0x8c22d6c8, + 0x00000000, + 0x3c01a080, + 0xac2200e0, + 0x3c01a080, + 0x8c2000e0, + 0xaf800fb4, + 0xa7800fb8, + 0xa7800fba, + 0xa7800fbc, + 0xa7800fbe, + 0x27820cc0, + 0xaf820fdc, + 0xaf820fd8, + 0x3c02a0d1, + 0x2442dacc, + 0xaf820c4c, + 0xaf820c50, + 0x24420400, + 0xaf820c54, + 0x2402001e, + 0x3c03fff0, + 0x247d0040, + 0xac7d0008, + 0x03a01821, + 0x1440fffc, + 0x2442ffff, + 0x3c1dfff0, + 0xac7d0008, + 0x3c02c704, + 0x3442dd7b, + 0xaf820c58, + 0x3c070000, + 0x24e70158, + 0x08343fa9, + 0x00000000, + 0x8e620038, + 0x00000000, + 0x14400005, + 0x8f830c94, + 0x12a00022, + 0x24630001, + 0x10000020, + 0xaf830c94, + 0xaf820fb4, + 0x3262ffc0, + 0x00021182, + 0x8663002a, + 0xa7820fb8, + 0x3c02a000, + 0xaf820fbc, + 0xa7830fba, + 0x867e0008, + 0x279d0f18, + 0x33de0060, + 0x03bee821, + 0x001ef0c2, + 0x03bee821, + 0x8fa2001c, + 0x3c030c40, + 0x4d01ffff, + 0x00000000, + 0x8f974c00, + 0xac620fb4, + 0x8fa30018, + 0x2442000c, + 0x14430003, + 0x00000000, + 0x8fa20014, + 0x00000000, + 0xafa2001c, + 0x4d01ffff, + 0x00000000, + 0xaca500e4, + 0xaf974c00, + 0x03e00008, + 0xae60003c, + 0x3c0da0d1, + 0x25add500, + 0x11a00021, + 0x00000000, + 0x8da90000, + 0x00000000, + 0x1120001d, + 0x00000000, + 0x8daa0004, + 0x8dab0008, + 0x8dac000c, + 0x00094740, + 0x05010004, + 0x00000000, + 0x3c08a0d1, + 0x2508d638, + 0x01485021, + 0x00094780, + 0x05010007, + 0x00000000, + 0x1180000d, + 0x00000000, + 0xad400000, + 0x254a0004, + 0x1000fffb, + 0x258cfffc, + 0x11800007, + 0x00000000, + 0x8d6e0000, + 0x256b0004, + 0xad4e0000, + 0x254a0004, + 0x1000fff9, + 0x258cfffc, + 0x1000ffe1, + 0x25ad0010, + 0x03e00008, + 0x00000000, + 0x3c021040, + 0xac574ff0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4d01ffff, + 0x00000000, + 0x8f820ffc, + 0x00000000, + 0x3042001f, + 0x00021080, + 0x3c17a0d1, + 0x02e2b821, + 0x26f7d648, + 0x8ef70000, + 0x00000000, + 0x02e00008, + 0x00000000, + 0x2402ffff, + 0xaf820ffc, + 0x8f970fc8, + 0x3c021040, + 0xac570ff0, + 0x8f820f04, + 0x26f70010, + 0x16e20004, + 0xaf970fc8, + 0x8f970f00, + 0x00000000, + 0xaf970fc8, + 0x4d01ffff, + 0x00000000, + 0x03e00008, + 0x00000000, + 0x3c1fa0d1, + 0x27fff02c, + 0x1000ffed, + 0x8f970ff0, + 0x3c0200d1, + 0x32f703ff, + 0x0017b980, + 0x02e2b825, + 0xaee0003c, + 0x2402ffff, + 0xaee20030, + 0xaee20014, + 0x97830ff4, + 0x97820ff8, + 0x3c1d0000, + 0x27bd0698, + 0xa6e30008, + 0xa6e20002, + 0xaf9f0fe8, + 0x03a0f809, + 0xa6e2002c, + 0x8f9f0fe8, + 0x1000ffd9, + 0xaee2000c, + 0x8f970ff0, + 0x3c0200d1, + 0x32f703ff, + 0x0017b980, + 0x02e2b825, + 0x97820ff4, + 0x3c030000, + 0x24630698, + 0xa6e20002, + 0xaf9f0fe8, + 0x0060f809, + 0xa6e2002c, + 0x8f9f0fe8, + 0x1000ffca, + 0xaee2000c, + 0x8f970ff0, + 0x3c0200d1, + 0x32f703ff, + 0x0017b980, + 0x02e2b825, + 0x97820ff4, + 0x00000000, + 0x96e30008, + 0xa6e20008, + 0x00431026, + 0x30420060, + 0x1040ffbd, + 0x8ee2003c, + 0xaee0003c, + 0x1040ffba, + 0x3c028800, + 0xaf820fbc, + 0x8ee20038, + 0xaee00038, + 0x30630060, + 0x279d0f18, + 0x03a3e821, + 0x000318c2, + 0x03a3e821, + 0x8fa3001c, + 0x1040ffaf, + 0xaf820fb4, + 0x3c020c40, + 0xac430fb4, + 0x8fa20018, + 0x2463000c, + 0x14430003, + 0x00000000, + 0x8fa30014, + 0x00000000, + 0xafa3001c, + 0x4d01ffff, + 0x00000000, + 0x1000ffa2, + 0x00000000, + 0x8f970ff0, + 0x3c0200d1, + 0xa7970fb8, + 0x0017b980, + 0x32f7ffc0, + 0x02e2b821, + 0xaee00030, + 0x3c02dead, + 0x8ee3003c, + 0xaee2003c, + 0x8ee20038, + 0x1060ff95, + 0xaee00038, + 0x3c038800, + 0xaf830fbc, + 0x86e30008, + 0x27970f18, + 0x30630060, + 0x02e3b821, + 0x000318c2, + 0x02e3b821, + 0x8ee3001c, + 0x1040ff8a, + 0xaf820fb4, + 0x3c020c40, + 0xac430fb4, + 0x8ee20018, + 0x2463000c, + 0x14430003, + 0x00000000, + 0x8ee30014, + 0x00000000, + 0xaee3001c, + 0x4d01ffff, + 0x00000000, + 0x1000ff7d, + 0x00000000, + 0x8f820ff0, + 0x8f970ff4, + 0x90410000, + 0x00000000, + 0x00370825, + 0x1000ff76, + 0xa0410000, + 0x8f820ff0, + 0x8f970ff4, + 0x94410000, + 0x00000000, + 0x00370825, + 0x1000ff6f, + 0xa4410000, + 0x8f820ff0, + 0x8f970ff4, + 0x8c410000, + 0x00000000, + 0x00370825, + 0x1000ff68, + 0xac410000, + 0x8f820ff0, + 0x8f970ff4, + 0x90410000, + 0x02e0b827, + 0x00370824, + 0x1000ff61, + 0xa0410000, + 0x8f820ff0, + 0x8f970ff4, + 0x94410000, + 0x02e0b827, + 0x00370824, + 0x1000ff5a, + 0xa4410000, + 0x8f820ff0, + 0x8f970ff4, + 0x8c410000, + 0x02e0b827, + 0x00370824, + 0x1000ff53, + 0xac410000, + 0x8f820ff0, + 0x8f970ff4, + 0x1000ff4f, + 0xa0570000, + 0x8f820ff0, + 0x8f970ff4, + 0x1000ff4b, + 0xa4570000, + 0x8f820ff0, + 0x8f970ff4, + 0x1000ff47, + 0xac570000, + 0x8f820ff0, + 0x00000000, + 0x8c420000, + 0x1000ff42, + 0xaf820ff4, + 0x3c01a0c2, + 0x8c22c000, + 0x00000000, + 0xaf820ff0, + 0x3c01a0c2, + 0x8c22c004, + 0x1000ff3a, + 0xaf820ff4, + 0x3c01a0d1, + 0x8c22d5ac, + 0x00000000, + 0xaf820ff0, + 0x3c01a0d1, + 0x8c22d5b0, + 0x1000ff32, + 0xaf820ff4, + 0x3c02a0f0, + 0xac400000, + 0x90570153, + 0x00000000, + 0xa3970c80, + 0x90570157, + 0x00000000, + 0xa3970c81, + 0x9057015b, + 0x00000000, + 0xa3970c87, + 0x9057015f, + 0x00000000, + 0xa3970c86, + 0x90570163, + 0x00000000, + 0x32f70007, + 0xa3970c85, + 0x90570193, + 0x00000000, + 0xa3970c8b, + 0x90570197, + 0x00000000, + 0xa3970c8a, + 0x9057019b, + 0x00000000, + 0x32f70007, + 0xa3970c89, + 0x9057000b, + 0x00000000, + 0x32f700e0, + 0x00170942, + 0x90570047, + 0x00000000, + 0x32f70078, + 0x00370825, + 0x90570067, + 0x00000000, + 0x32f7000f, + 0x0017b9c0, + 0x00370825, + 0x905700c7, + 0x00000000, + 0x32f7002f, + 0x0017bac0, + 0x00370825, + 0x90570147, + 0x00000000, + 0x32f7001e, + 0x0017bc00, + 0x00370825, + 0x90570183, + 0x00000000, + 0x32f70060, + 0x0017bc00, + 0x00370825, + 0xaf810c8c, + 0x3c021840, + 0x8f970fc8, + 0x00000000, + 0x8f970ff0, + 0x00000000, + 0xac570c80, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4d01ffff, + 0x00000000, + 0x3c02a0d1, + 0x2442f998, + 0xaf800c90, + 0xaf800c94, + 0x00400008, + 0x00000000, + 0x87970ff0, + 0x3c1300d1, + 0xa6770008, + 0x3c030000, + 0x24630520, + 0xaf9f0fe8, + 0x0060f809, + 0x24020001, + 0x8f9f0fe8, + 0x1040feda, + 0x97970ff0, + 0x27830f18, + 0x00771821, + 0x0017b8c2, + 0x02e3b821, + 0x3c028800, + 0xaf820fbc, + 0x8e620038, + 0xa7800fb8, + 0xaf820fb4, + 0x8ee3001c, + 0x3c020c40, + 0xac430fb4, + 0x8ee20018, + 0x2463000c, + 0x14430004, + 0xaee3001c, + 0x8ee30014, + 0x00000000, + 0xaee3001c, + 0x4d01ffff, + 0x00000000, + 0x1000ffdf, + 0x00000000, + 0x8f820c5c, + 0x8f830c60, + 0xaf820ff0, + 0x1000febe, + 0xaf830ff4, + 0x23890800, + 0x01201821, + 0x2402000f, + 0x206c0040, + 0xac6c0008, + 0x01801821, + 0x1440fffc, + 0x2042ffff, + 0xac690008, + 0x278b0c98, + 0xa5600000, + 0x2403ffff, + 0xad630014, + 0x34020001, + 0x34420020, + 0xa5620008, + 0x278a0e00, + 0x01401021, + 0x00001821, + 0xac400000, + 0x24630004, + 0x2c6c0100, + 0x1580fffc, + 0x24420004, + 0x3c02a0d1, + 0x2442e000, + 0xaf820fe0, + 0x3c1800d1, + 0x01206021, + 0x00006821, + 0x00007821, + 0x00005821, + 0x00004021, + 0x40026000, + 0x00000000, + 0x34424001, + 0x40826000, + 0x3c020000, + 0x244206f8, + 0x00400008, + 0x00000000, diff -u --recursive --new-file v2.3.14/linux/drivers/atm/atmsar11.regions linux/drivers/atm/atmsar11.regions --- v2.3.14/linux/drivers/atm/atmsar11.regions Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/atmsar11.regions Mon Aug 23 09:56:31 1999 @@ -0,0 +1,3 @@ + { 0x00000080, 993, }, + { 0xa0d0d500, 80, }, + { 0xa0d0f000, 978, }, diff -u --recursive --new-file v2.3.14/linux/drivers/atm/atmsar11.start linux/drivers/atm/atmsar11.start --- v2.3.14/linux/drivers/atm/atmsar11.start Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/atmsar11.start Mon Aug 23 09:56:31 1999 @@ -0,0 +1 @@ + 0xa0d0f000 diff -u --recursive --new-file v2.3.14/linux/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c --- v2.3.14/linux/drivers/atm/atmtcp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/atmtcp.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,339 @@ +/* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ + +/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include "../../net/atm/tunable.h" /* @@@ fix this */ +#include "../../net/atm/protocols.h" /* @@@ fix this */ + + +#define PRIV(dev) ((struct atmtcp_dev_data *) ((dev)->dev_data)) + + +struct atmtcp_dev_data { + struct atm_vcc *vcc; /* control VCC; NULL if detached */ + int persist; /* non-zero if persistent */ +}; + + +#define DEV_LABEL "atmtcp" + +#define MAX_VPI_BITS 8 /* simplifies life */ +#define MAX_VCI_BITS 16 + + +static void atmtcp_v_dev_close(struct atm_dev *dev) +{ + MOD_DEC_USE_COUNT; +} + + +static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci) +{ + int error; + + error = atm_find_ci(vcc,&vpi,&vci); + if (error) return error; + vcc->vpi = vpi; + vcc->vci = vci; + if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; + vcc->flags |= ATM_VF_ADDR | ATM_VF_READY; + return 0; +} + + +static void atmtcp_v_close(struct atm_vcc *vcc) +{ + vcc->flags &= ~(ATM_VF_READY | ATM_VF_ADDR); +} + + +static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + struct atm_cirange ci; + struct atm_vcc *vcc; + + if (cmd != ATM_SETCIRANGE) return -EINVAL; + if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT; + if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; + if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; + if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || + ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL; + for (vcc = dev->vccs; vcc; vcc = vcc->next) + if ((vcc->vpi >> ci.vpi_bits) || + (vcc->vci >> ci.vci_bits)) return -EBUSY; + dev->ci_range = ci; + return 0; +} + + +static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ + struct atmtcp_dev_data *dev_data; + struct atm_vcc *out_vcc; + struct sk_buff *new_skb; + struct atmtcp_hdr *hdr; + int size; + + dev_data = PRIV(vcc->dev); + if (dev_data) out_vcc = dev_data->vcc; + if (!dev_data || !out_vcc) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + if (dev_data) return 0; + vcc->stats->tx_err++; + return -ENOLINK; + } + size = skb->len+sizeof(struct atmtcp_hdr); + if (!atm_charge(out_vcc,atm_pdu2truesize(size))) new_skb = NULL; + else { + new_skb = alloc_skb(size,GFP_ATOMIC); + if (!new_skb) + atm_return(out_vcc,atm_pdu2truesize(size)); + } + if (!new_skb) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + vcc->stats->tx_err++; + return -ENOBUFS; + } + hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr)); + hdr->vpi = htons(vcc->vpi); + hdr->vci = htons(vcc->vci); + hdr->length = htonl(skb->len); + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + out_vcc->push(out_vcc,new_skb); + return 0; +} + + +static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page) +{ + struct atmtcp_dev_data *dev_data = PRIV(dev); + + if (*pos) return 0; + if (!dev_data->persist) return sprintf(page,"ephemeral\n"); + return sprintf(page,"persistent, %sconnected\n", + dev_data->vcc ? "" : "dis"); +} + + +static void atmtcp_c_close(struct atm_vcc *vcc) +{ + struct atm_dev *atmtcp_dev; + struct atmtcp_dev_data *dev_data; + + atmtcp_dev = (struct atm_dev *) vcc->dev_data; + dev_data = PRIV(atmtcp_dev); + dev_data->vcc = NULL; + if (dev_data->persist) return; + kfree(dev_data); + shutdown_atm_dev(atmtcp_dev); + vcc->dev_data = NULL; +} + + +static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ + struct atm_dev *dev; + struct atmtcp_hdr *hdr; + struct atm_vcc *out_vcc; + struct sk_buff *new_skb; + + if (!skb->len) return 0; + dev = vcc->dev_data; + hdr = (void *) skb->data; + for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next) + if (out_vcc->vpi == ntohs(hdr->vpi) && + out_vcc->vci == ntohs(hdr->vci) && + out_vcc->qos.rxtp.traffic_class != ATM_NONE) + break; + if (!out_vcc) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + vcc->stats->tx_err++; + return 0; + } + skb_pull(skb,sizeof(struct atmtcp_hdr)); + if (!atm_charge(out_vcc,atm_pdu2truesize(skb->len))) new_skb = NULL; + else { + new_skb = alloc_skb(skb->len,GFP_KERNEL); + if (!new_skb) atm_return(out_vcc,atm_pdu2truesize(skb->len)); + } + if (!new_skb) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -ENOBUFS; + } + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + out_vcc->push(out_vcc,new_skb); + return 0; +} + + +/* + * Device operations for the virtual ATM devices created by ATMTCP. + */ + + +static struct atmdev_ops atmtcp_v_dev_ops = { + atmtcp_v_dev_close, + atmtcp_v_open, + atmtcp_v_close, + atmtcp_v_ioctl, + NULL, /* no getsockopt */ + NULL, /* no setsockopt */ + atmtcp_v_send, + NULL, /* no direct writes */ + NULL, /* no send_oam */ + NULL, /* no phy_put */ + NULL, /* no phy_get */ + NULL, /* no feedback */ + NULL, /* no change_qos */ + NULL, /* no free_rx_skb */ + atmtcp_v_proc /* proc_read */ +}; + + +/* + * Device operations for the ATMTCP control device. + */ + + +static struct atmdev_ops atmtcp_c_dev_ops = { + NULL, /* no dev_close */ + NULL, /* no open */ + atmtcp_c_close, + NULL, /* no ioctl */ + NULL, /* no getsockopt */ + NULL, /* no setsockopt */ + atmtcp_c_send, + NULL, /* no sg_send */ + NULL, /* no send_oam */ + NULL, /* no phy_put */ + NULL, /* no phy_get */ + NULL, /* no feedback */ + NULL, /* no change_qos */ + NULL, /* no free_rx_skb */ + NULL /* no proc_read */ +}; + + +static struct atm_dev atmtcp_control_dev = { + &atmtcp_c_dev_ops, + NULL, /* no PHY */ + "atmtcp", /* type */ + 999, /* dummy device number */ + NULL,NULL, /* pretend not to have any VCCs */ + NULL,NULL, /* no data */ + 0, /* no flags */ + NULL, /* no local address */ + { 0 } /* no ESI, no statistics */ +}; + + +static int atmtcp_create(int itf,int persist,struct atm_dev **result) +{ + struct atmtcp_dev_data *dev_data; + struct atm_dev *dev; + + dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL); + if (!dev_data) return -ENOMEM; + dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,0); + if (!dev) { + kfree(dev_data); + return itf == -1 ? -ENOMEM : -EBUSY; + } + MOD_INC_USE_COUNT; + dev->ci_range.vpi_bits = MAX_VPI_BITS; + dev->ci_range.vci_bits = MAX_VCI_BITS; + PRIV(dev) = dev_data; + PRIV(dev)->vcc = NULL; + PRIV(dev)->persist = persist; + if (result) *result = dev; + return 0; +} + + +int atmtcp_attach(struct atm_vcc *vcc,int itf) +{ + struct atm_dev *dev; + + dev = NULL; + if (itf != -1) dev = atm_find_dev(itf); + if (dev) { + if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE; + if (PRIV(dev)->vcc) return -EBUSY; + } + else { + int error; + + error = atmtcp_create(itf,0,&dev); + if (error) return error; + } + PRIV(dev)->vcc = vcc; + bind_vcc(vcc,&atmtcp_control_dev); + vcc->flags |= ATM_VF_READY | ATM_VF_META; + vcc->dev_data = dev; + (void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */ + vcc->stats = &atmtcp_control_dev.stats.aal5; + return dev->number; +} + + +int atmtcp_create_persistent(int itf) +{ + return atmtcp_create(itf,1,NULL); +} + + +int atmtcp_remove_persistent(int itf) +{ + struct atm_dev *dev; + struct atmtcp_dev_data *dev_data; + + dev = atm_find_dev(itf); + if (!dev) return -ENODEV; + if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE; + dev_data = PRIV(dev); + if (!dev_data->persist) return 0; + dev_data->persist = 0; + if (PRIV(dev)->vcc) return 0; + kfree(dev_data); + shutdown_atm_dev(dev); + return 0; +} + + +#ifdef MODULE + +int init_module(void) +{ + atm_tcp_ops.attach = atmtcp_attach; + atm_tcp_ops.create_persistent = atmtcp_create_persistent; + atm_tcp_ops.remove_persistent = atmtcp_remove_persistent; + return 0; +} + +void cleanup_module(void) +{ +} + +#else + +struct atm_tcp_ops atm_tcp_ops = { + atmtcp_attach, /* attach */ + atmtcp_create_persistent, /* create_persistent */ + atmtcp_remove_persistent /* remove_persistent */ +}; + +#endif + diff -u --recursive --new-file v2.3.14/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.14/linux/drivers/atm/eni.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/eni.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,2264 @@ +/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for xtime */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tonga.h" +#include "midway.h" +#include "suni.h" +#include "eni.h" + +#ifndef __i386__ +#ifndef ioremap_nocache +#define ioremap_nocache(X,Y) ioremap(X,Y) +#endif +#endif + +/* + * TODO: + * + * Show stoppers + * none + * + * Minor + * - OAM support + * - fix bugs listed below + */ + +/* + * KNOWN BUGS: + * + * - may run into JK-JK bug and deadlock + * - should allocate UBR channel first + * - buffer space allocation algorithm is stupid + * (RX: should be maxSDU+maxdelay*rate + * TX: should be maxSDU+min(maxSDU,maxdelay*rate) ) + * - doesn't support OAM cells + * - eni_put_free may hang if not putting memory fragments that _complete_ + * 2^n block (never happens in real life, though) + * - keeps IRQ even if initialization fails + */ + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +#ifndef CONFIG_ATM_ENI_TUNE_BURST +#define CONFIG_ATM_ENI_BURST_TX_8W +#define CONFIG_ATM_ENI_BURST_RX_4W +#endif + + +#ifndef CONFIG_ATM_ENI_DEBUG + + +#define NULLCHECK(x) + +#define EVENT(s,a,b) + + +static void event_dump(void) +{ +} + + +#else + + +/* + * NULL pointer checking + */ + +#define NULLCHECK(x) \ + if ((unsigned long) (x) < 0x30) \ + printk(KERN_CRIT #x "==0x%lx\n",(unsigned long) (x)) + +/* + * Very extensive activity logging. Greatly improves bug detection speed but + * costs a few Mbps if enabled. + */ + +#define EV 64 + +static const char *ev[EV]; +static unsigned long ev_a[EV],ev_b[EV]; +static int ec = 0; + + +static void EVENT(const char *s,unsigned long a,unsigned long b) +{ + ev[ec] = s; + ev_a[ec] = a; + ev_b[ec] = b; + ec = (ec+1) % EV; +} + + +static void event_dump(void) +{ + int n,i; + + for (n = 0; n < EV; n++) { + i = (ec+n) % EV; + printk(KERN_NOTICE); + printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]); + } +} + + +#endif /* CONFIG_ATM_ENI_DEBUG */ + + +/* + * NExx must not be equal at end + * EExx may be equal at end + * xxPJOK verify validity of pointer jumps + * xxPMOK operating on a circular buffer of "c" words + */ + +#define NEPJOK(a0,a1,b) \ + ((a0) < (a1) ? (b) <= (a0) || (b) > (a1) : (b) <= (a0) && (b) > (a1)) +#define EEPJOK(a0,a1,b) \ + ((a0) < (a1) ? (b) < (a0) || (b) >= (a1) : (b) < (a0) && (b) >= (a1)) +#define NEPMOK(a0,d,b,c) NEPJOK(a0,(a0+d) & (c-1),b) +#define EEPMOK(a0,d,b,c) EEPJOK(a0,(a0+d) & (c-1),b) + + +static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0, + backlogged = 0,rx_enqueued = 0,rx_dequeued = 0,pushed = 0,submitted = 0, + putting = 0; + +static struct atm_dev *eni_boards = NULL; + +static u32 *zeroes = NULL; /* aligned "magic" zeroes */ + +/* Read/write registers on card */ +#define eni_in(r) readl(eni_dev->reg+(r)*4) +#define eni_out(v,r) writel((v),eni_dev->reg+(r)*4) + + +/*-------------------------------- utilities --------------------------------*/ + + +static void dump_mem(struct eni_dev *eni_dev) +{ + int i; + + for (i = 0; i < eni_dev->free_len; i++) + printk(KERN_DEBUG " %d: 0x%lx %d\n",i, + eni_dev->free_list[i].start, + 1 << eni_dev->free_list[i].order); +} + + +static void dump(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + + int i; + + eni_dev = ENI_DEV(dev); + printk(KERN_NOTICE "Free memory\n"); + dump_mem(eni_dev); + printk(KERN_NOTICE "TX buffers\n"); + for (i = 0; i < NR_CHAN; i++) + if (eni_dev->tx[i].send) + printk(KERN_NOTICE " TX %d @ 0x%lx: %ld\n",i, + eni_dev->tx[i].send,eni_dev->tx[i].words*4); + printk(KERN_NOTICE "RX buffers\n"); + for (i = 0; i < 1024; i++) + if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx) + printk(KERN_NOTICE " RX %d @ 0x%lx: %ld\n",i, + ENI_VCC(eni_dev->rx_map[i])->recv, + ENI_VCC(eni_dev->rx_map[i])->words*4); + printk(KERN_NOTICE "----\n"); +} + + +static void eni_put_free(struct eni_dev *eni_dev,unsigned long start, + unsigned long size) +{ + struct eni_free *list; + int len,order; + + DPRINTK("init 0x%lx+%ld(0x%lx)\n",start,size,size); + start += eni_dev->base_diff; + list = eni_dev->free_list; + len = eni_dev->free_len; + while (size) { + if (len >= eni_dev->free_list_size) { + printk(KERN_CRIT "eni_put_free overflow (0x%lx,%ld)\n", + start,size); + break; + } + for (order = 0; !((start | size) & (1 << order)); order++); + if (MID_MIN_BUF_SIZE > (1 << order)) { + printk(KERN_CRIT "eni_put_free: order %d too small\n", + order); + break; + } + list[len].start = start; + list[len].order = order; + len++; + start += 1 << order; + size -= 1 << order; + } + eni_dev->free_len = len; + /*dump_mem(eni_dev);*/ +} + + +static unsigned long eni_alloc_mem(struct eni_dev *eni_dev,unsigned long *size) +{ + struct eni_free *list; + unsigned long start; + int len,i,order,best_order,index; + + list = eni_dev->free_list; + len = eni_dev->free_len; + if (*size < MID_MIN_BUF_SIZE) *size = MID_MIN_BUF_SIZE; + if (*size > MID_MAX_BUF_SIZE) return 0; + for (order = 0; (1 << order) < *size; order++); + DPRINTK("trying: %ld->%d\n",*size,order); + best_order = 65; /* we don't have more than 2^64 of anything ... */ + index = 0; /* silence GCC */ + for (i = 0; i < len; i++) + if (list[i].order == order) { + best_order = order; + index = i; + break; + } + else if (best_order > list[i].order && list[i].order > order) { + best_order = list[i].order; + index = i; + } + if (best_order == 65) return 0; + start = list[index].start-eni_dev->base_diff; + list[index] = list[--len]; + eni_dev->free_len = len; + *size = 1 << order; + eni_put_free(eni_dev,start+*size,(1 << best_order)-*size); + DPRINTK("%ld bytes (order %d) at 0x%lx\n",*size,order,start); + memset_io(start,0,*size); /* never leak data */ + /*dump_mem(eni_dev);*/ + return start; +} + + +static void eni_free_mem(struct eni_dev *eni_dev,unsigned long start, + unsigned long size) +{ + struct eni_free *list; + int len,i,order; + + start += eni_dev->base_diff; + list = eni_dev->free_list; + len = eni_dev->free_len; + for (order = -1; size; order++) size >>= 1; + DPRINTK("eni_free_mem: 0x%lx+0x%lx (order %d)\n",start,size,order); + for (i = 0; i < len; i++) + if (list[i].start == (start^(1 << order)) && + list[i].order == order) { + DPRINTK("match[%d]: 0x%lx/0x%lx(0x%x), %d/%d\n",i, + list[i].start,start,1 << order,list[i].order,order); + list[i] = list[--len]; + start &= ~(unsigned long) (1 << order); + order++; + i = -1; + continue; + } + if (len >= eni_dev->free_list_size) { + printk(KERN_ALERT "eni_free_mem overflow (0x%lx,%d)\n",start, + order); + return; + } + list[len].start = start; + list[len].order = order; + eni_dev->free_len = len+1; + /*dump_mem(eni_dev);*/ +} + + +/*----------------------------------- RX ------------------------------------*/ + + +#define ENI_VCC_NOS ((struct atm_vcc *) 1) + + +static void rx_ident_err(struct atm_vcc *vcc) +{ + struct atm_dev *dev; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + + dev = vcc->dev; + eni_dev = ENI_DEV(dev); + /* immediately halt adapter */ + eni_out(eni_in(MID_MC_S) & + ~(MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE),MID_MC_S); + /* dump useful information */ + eni_vcc = ENI_VCC(vcc); + printk(KERN_ALERT DEV_LABEL "(itf %d): driver error - RX ident " + "mismatch\n",dev->number); + printk(KERN_ALERT " VCI %d, rxing %d, words %ld\n",vcc->vci, + eni_vcc->rxing,eni_vcc->words); + printk(KERN_ALERT " host descr 0x%lx, rx pos 0x%lx, descr value " + "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos, + (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4)); + printk(KERN_ALERT " last 0x%p, servicing %d\n",eni_vcc->last, + eni_vcc->servicing); + EVENT("---dump ends here---\n",0,0); + printk(KERN_NOTICE "---recent events---\n"); + event_dump(); + ENI_DEV(dev)->fast = NULL; /* really stop it */ + ENI_DEV(dev)->slow = NULL; + skb_queue_head_init(&ENI_DEV(dev)->rx_queue); +} + + +static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, + unsigned long skip,unsigned long size,unsigned long eff) +{ + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + u32 dma_rd,dma_wr; + u32 dma[RX_DMA_BUF*2]; + unsigned long paddr,here; + int i,j; + + eni_dev = ENI_DEV(vcc->dev); + eni_vcc = ENI_VCC(vcc); + paddr = 0; /* GCC, shut up */ + if (skb) { + paddr = (unsigned long) skb->data; + if (paddr & 3) + printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has " + "mis-aligned RX data (0x%lx)\n",vcc->dev->number, + vcc->vci,paddr); + ENI_PRV_SIZE(skb) = size+skip; + /* PDU plus descriptor */ + ATM_SKB(skb)->vcc = vcc; + } + j = 0; + if ((eff && skip) || 1) { /* @@@ actually, skip is always == 1 ... */ + here = (eni_vcc->descr+skip) & (eni_vcc->words-1); + dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci + << MID_DMA_VCI_SHIFT) | MID_DT_JK; + j++; + } + here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1); + if (!eff) size += skip; + else { + unsigned long words; + + if (!size) { + DPRINTK("strange things happen ...\n"); + EVENT("strange things happen ... (skip=%ld,eff=%ld)\n", + size,eff); + } + words = eff; + if (paddr & 15) { + unsigned long init; + + init = 4-((paddr & 15) >> 2); + if (init > words) init = words; + dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | + (vcc->vci << MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + paddr += init << 2; + words -= init; + } +#ifdef CONFIG_ATM_ENI_BURST_RX_16W /* may work with some PCI chipsets ... */ + if (words & ~15) { + dma[j++] = MID_DT_16W | ((words >> 4) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + paddr += (words & ~15) << 2; + words &= 15; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_8W /* works only with *some* PCI chipsets ... */ + if (words & ~7) { + dma[j++] = MID_DT_8W | ((words >> 3) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + paddr += (words & ~7) << 2; + words &= 7; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_4W /* recommended */ + if (words & ~3) { + dma[j++] = MID_DT_4W | ((words >> 2) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + paddr += (words & ~3) << 2; + words &= 3; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_2W /* probably useless if RX_4W, RX_8W, ... */ + if (words & ~1) { + dma[j++] = MID_DT_2W | ((words >> 1) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + paddr += (words & ~1) << 2; + words &= 1; + } +#endif + if (words) { + dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) + | (vcc->vci << MID_DMA_VCI_SHIFT); + dma[j++] = virt_to_bus((void *) paddr); + } + } + if (size != eff) { + dma[j++] = (here << MID_DMA_COUNT_SHIFT) | + (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; + j++; + } + if (!j || j > 2*RX_DMA_BUF) { + printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); + if (skb) kfree_skb(skb); + return -1; + } + dma[j-2] |= MID_DMA_END; + j = j >> 1; + dma_wr = eni_in(MID_DMA_WR_RX); + dma_rd = eni_in(MID_DMA_RD_RX); + /* + * Can I move the dma_wr pointer by 2j+1 positions without overwriting + * data that hasn't been read (position of dma_rd) yet ? + */ + if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ + printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", + vcc->dev->number); + if (skb) kfree_skb(skb); + return -1; + } + for (i = 0; i < j; i++) { + writel(dma[i*2],eni_dev->rx_dma+dma_wr*8); + writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*8+4); + dma_wr = (dma_wr+1) & (NR_DMA_RX-1); + } + if (skb) { + ENI_PRV_POS(skb) = eni_vcc->descr+size+1; + skb_queue_tail(&eni_dev->rx_queue,skb); +eni_vcc->last = skb; +rx_enqueued++; + } + eni_vcc->descr = here; + eni_out(dma_wr,MID_DMA_WR_RX); + return 0; +} + + +static void discard(struct atm_vcc *vcc,unsigned long size) +{ + struct eni_vcc *eni_vcc; + + eni_vcc = ENI_VCC(vcc); + EVENT("discard (size=%ld)\n",size,0); + while (do_rx_dma(vcc,NULL,1,size,0)) EVENT("BUSY LOOP",0,0); + /* could do a full fallback, but that might be more expensive */ + if (eni_vcc->rxing) ENI_PRV_POS(eni_vcc->last) += size+1; + else eni_vcc->rx_pos = (eni_vcc->rx_pos+size+1) & (eni_vcc->words-1); +} + + +/* + * TODO: should check whether direct copies (without DMA setup, dequeuing on + * interrupt, etc.) aren't much faster for AAL0 + */ + +static int rx_aal0(struct atm_vcc *vcc) +{ + struct eni_vcc *eni_vcc; + unsigned long descr; + unsigned long length; + struct sk_buff *skb; + + DPRINTK(">rx_aal0\n"); + eni_vcc = ENI_VCC(vcc); + descr = readl(eni_vcc->recv+eni_vcc->descr*4); + if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { + rx_ident_err(vcc); + return 1; + } + if (descr & MID_RED_T) { + DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", + vcc->dev->number); + length = 0; + vcc->stats->rx_err++; + } + else { + length = ATM_CELL_SIZE-1; /* no HEC */ + } + if (!length || !atm_charge(vcc,atm_pdu2truesize(length))) skb = NULL; + else { + skb = alloc_skb(length,GFP_ATOMIC); + if (!skb) atm_return(vcc,atm_pdu2truesize(length)); + } + if (!skb) { + discard(vcc,length >> 2); + return 0; + } + skb_put(skb,length); + skb->stamp = eni_vcc->timestamp; + DPRINTK("got len %ld\n",length); + if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1; + eni_vcc->rxing++; + return 0; +} + + +static int rx_aal5(struct atm_vcc *vcc) +{ + struct eni_vcc *eni_vcc; + unsigned long descr; + unsigned long size,eff,length; + struct sk_buff *skb; + + EVENT("rx_aal5\n",0,0); + DPRINTK(">rx_aal5\n"); + eni_vcc = ENI_VCC(vcc); + descr = readl(eni_vcc->recv+eni_vcc->descr*4); + if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { + rx_ident_err(vcc); + return 1; + } + if (descr & (MID_RED_T | MID_RED_CRC_ERR)) { + if (descr & MID_RED_T) { + EVENT("empty cell (descr=0x%lx)\n",descr,0); + DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", + vcc->dev->number); + size = 0; + } + else { + static unsigned long silence = 0; + + if (time_after(jiffies, silence) || silence == 0) { + printk(KERN_WARNING DEV_LABEL "(itf %d): " + "discarding PDU(s) with CRC error\n", + vcc->dev->number); + silence = (jiffies+2*HZ)|1; + } + size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); + EVENT("CRC error (descr=0x%lx,size=%ld)\n",descr, + size); + } + eff = length = 0; + vcc->stats->rx_err++; + } + else { + size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); + DPRINTK("size=%ld\n",size); + length = readl(eni_vcc->recv+(((eni_vcc->descr+size-1) & + (eni_vcc->words-1)))*4) & 0xffff; + /* -trailer(2)+header(1) */ + if (length && length <= (size << 2)-8 && length <= + ATM_MAX_AAL5_PDU) eff = (length+3) >> 2; + else { /* ^ trailer length (8) */ + EVENT("bad PDU (descr=0x08%lx,length=%ld)\n",descr, + length); + printk(KERN_ERR DEV_LABEL "(itf %d): bad AAL5 PDU " + "(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n", + vcc->dev->number,vcc->vci,length,size << 2,descr); + length = eff = 0; + vcc->stats->rx_err++; + } + } + if (!eff || !atm_charge(vcc,atm_pdu2truesize(eff << 2))) skb = NULL; + else { + skb = alloc_skb(eff << 2,GFP_ATOMIC); + if (!skb) { + EVENT("peek reject (eff << 2=%ld)\n",eff << 2,0); + DPRINTK(DEV_LABEL "(itf %d): peek reject for %ld " + "bytes\n",vcc->dev->number,eff << 2); + atm_return(vcc,atm_pdu2truesize(eff << 2)); + } + } + if (!skb) { + discard(vcc,size); + return 0; + } + skb_put(skb,length); + DPRINTK("got len %ld\n",length); + if (do_rx_dma(vcc,skb,1,size,eff)) return 1; + eni_vcc->rxing++; + return 0; +} + + +static inline int rx_vcc(struct atm_vcc *vcc) +{ + unsigned long vci_dsc,tmp; + struct eni_vcc *eni_vcc; + + eni_vcc = ENI_VCC(vcc); + vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*16; + EVENT("rx_vcc(1)\n",0,0); + while (eni_vcc->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) >> + MID_VCI_DESCR_SHIFT)) { + EVENT("rx_vcc(2: host dsc=0x%lx, nic dsc=0x%lx)\n", + eni_vcc->descr,tmp); + DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, + (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >> + MID_VCI_DESCR_SHIFT)); + if (ENI_VCC(vcc)->rx(vcc)) return 1; + } + /* clear IN_SERVICE flag */ + writel(readl(vci_dsc) & ~MID_VCI_IN_SERVICE,vci_dsc); + /* + * If new data has arrived between evaluating the while condition and + * clearing IN_SERVICE, we wouldn't be notified until additional data + * follows. So we have to loop again to be sure. + */ + EVENT("rx_vcc(3)\n",0,0); + while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) + >> MID_VCI_DESCR_SHIFT)) { + EVENT("rx_vcc(4: host dsc=0x%lx, nic dsc=0x%lx)\n", + eni_vcc->descr,tmp); + DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, + (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >> + MID_VCI_DESCR_SHIFT)); + if (ENI_VCC(vcc)->rx(vcc)) return 1; + } + return 0; +} + + +static void poll_rx(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + struct atm_vcc *curr; + + eni_dev = ENI_DEV(dev); + while ((curr = eni_dev->fast)) { + EVENT("poll_rx.fast\n",0,0); + if (rx_vcc(curr)) return; + eni_dev->fast = ENI_VCC(curr)->next; + ENI_VCC(curr)->next = ENI_VCC_NOS; + ENI_VCC(curr)->servicing--; + } + while ((curr = eni_dev->slow)) { + EVENT("poll_rx.slow\n",0,0); + if (rx_vcc(curr)) return; + eni_dev->slow = ENI_VCC(curr)->next; + ENI_VCC(curr)->next = ENI_VCC_NOS; + ENI_VCC(curr)->servicing--; + } +} + + +static void get_service(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + struct atm_vcc *vcc; + unsigned long vci; + + DPRINTK(">get_service\n"); + eni_dev = ENI_DEV(dev); + while (eni_in(MID_SERV_WRITE) != eni_dev->serv_read) { + vci = readl(eni_dev->service+eni_dev->serv_read*4); + eni_dev->serv_read = (eni_dev->serv_read+1) & (NR_SERVICE-1); + vcc = eni_dev->rx_map[vci & 1023]; + if (!vcc) { + printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %ld not " + "found\n",dev->number,vci); + continue; /* nasty but we try to go on anyway */ + /* @@@ nope, doesn't work */ + } + EVENT("getting from service\n",0,0); + if (ENI_VCC(vcc)->next != ENI_VCC_NOS) { + EVENT("double service\n",0,0); + DPRINTK("Grr, servicing VCC %ld twice\n",vci); + continue; + } + ENI_VCC(vcc)->timestamp = xtime; + ENI_VCC(vcc)->next = NULL; + if (vcc->qos.rxtp.traffic_class == ATM_CBR) { + if (eni_dev->fast) + ENI_VCC(eni_dev->last_fast)->next = vcc; + else eni_dev->fast = vcc; + eni_dev->last_fast = vcc; + } + else { + if (eni_dev->slow) + ENI_VCC(eni_dev->last_slow)->next = vcc; + else eni_dev->slow = vcc; + eni_dev->last_slow = vcc; + } +putting++; + ENI_VCC(vcc)->servicing++; + } +} + + +static void dequeue_rx(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + struct atm_vcc *vcc; + struct sk_buff *skb; + unsigned long vci_dsc; + int first; + + eni_dev = ENI_DEV(dev); + first = 1; + while (1) { + skb = skb_dequeue(&eni_dev->rx_queue); + if (!skb) { + if (first) { + DPRINTK(DEV_LABEL "(itf %d): RX but not " + "rxing\n",dev->number); + EVENT("nothing to dequeue\n",0,0); + } + break; + } + EVENT("dequeued (size=%ld,pos=0x%lx)\n",ENI_PRV_SIZE(skb), + ENI_PRV_POS(skb)); +rx_dequeued++; + vcc = ATM_SKB(skb)->vcc; + eni_vcc = ENI_VCC(vcc); + first = 0; + vci_dsc = eni_dev->vci+vcc->vci*16; + if (!EEPMOK(eni_vcc->rx_pos,ENI_PRV_SIZE(skb), + (readl(vci_dsc+4) & MID_VCI_READ) >> MID_VCI_READ_SHIFT, + eni_vcc->words)) { + EVENT("requeuing\n",0,0); + skb_queue_head(&eni_dev->rx_queue,skb); + break; + } + eni_vcc->rxing--; + eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); + if (!skb->len) kfree_skb(skb); + else { + EVENT("pushing (len=%ld)\n",skb->len,0); + if (vcc->qos.aal == ATM_AAL0) + *(unsigned long *) skb->data = + ntohl(*(unsigned long *) skb->data); + memset(skb->cb,0,sizeof(struct eni_skb_prv)); + vcc->push(vcc,skb); + pushed++; + } + vcc->stats->rx++; + } + wake_up(&eni_dev->rx_wait); +} + + +static int open_rx_first(struct atm_vcc *vcc) +{ + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + unsigned long size; + + DPRINTK("open_rx_first\n"); + eni_dev = ENI_DEV(vcc->dev); + eni_vcc = ENI_VCC(vcc); + eni_vcc->rx = NULL; + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */ + if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <= + MID_MAX_BUF_SIZE) + size = MID_MAX_BUF_SIZE; + eni_vcc->recv = eni_alloc_mem(eni_dev,&size); + DPRINTK("rx at 0x%lx\n",eni_vcc->recv); + eni_vcc->words = size >> 2; + if (!eni_vcc->recv) return -ENOBUFS; + eni_vcc->rx = vcc->qos.aal == ATM_AAL5 ? rx_aal5 : rx_aal0; + eni_vcc->descr = 0; + eni_vcc->rx_pos = 0; + eni_vcc->rxing = 0; + eni_vcc->servicing = 0; + eni_vcc->next = ENI_VCC_NOS; + return 0; +} + + +static int open_rx_second(struct atm_vcc *vcc) +{ + unsigned long here; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + unsigned long size; + int order; + + DPRINTK("open_rx_second\n"); + eni_dev = ENI_DEV(vcc->dev); + eni_vcc = ENI_VCC(vcc); + if (!eni_vcc->rx) return 0; + /* set up VCI descriptor */ + here = eni_dev->vci+vcc->vci*16; + DPRINTK("loc 0x%x\n",(unsigned) (eni_vcc->recv-eni_dev->ram)/4); + size = eni_vcc->words >> 8; + for (order = -1; size; order++) size >>= 1; + writel(0,here+4); /* descr, read = 0 */ + writel(0,here+8); /* write, state, count = 0 */ + if (eni_dev->rx_map[vcc->vci]) + printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already " + "in use\n",vcc->dev->number,vcc->vci); + eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */ + writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) << + MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE | + (((eni_vcc->recv-eni_dev->ram) >> (MID_LOC_SKIP+2)) << + MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT),here); + return 0; +} + + +static void close_rx(struct atm_vcc *vcc) +{ + unsigned long here,flags; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + u32 tmp; + + eni_vcc = ENI_VCC(vcc); + if (!eni_vcc->rx) return; + eni_dev = ENI_DEV(vcc->dev); + if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { + here = eni_dev->vci+vcc->vci*16; + /* block receiver */ + writel((readl(here) & ~MID_VCI_MODE) | (MID_MODE_TRASH << + MID_VCI_MODE_SHIFT),here); + /* wait for receiver to become idle */ + udelay(27); + /* discard pending cell */ + writel(readl(here) & ~MID_VCI_IN_SERVICE,here); + /* don't accept any new ones */ + eni_dev->rx_map[vcc->vci] = NULL; + /* wait for RX queue to drain */ + DPRINTK("eni_close: waiting for RX ...\n"); + EVENT("RX closing\n",0,0); + save_flags(flags); + cli(); + while (eni_vcc->rxing || eni_vcc->servicing) { + EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing, + eni_vcc->servicing); + printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing, + eni_vcc->rxing); + sleep_on(&eni_dev->rx_wait); + } + while (eni_vcc->rx_pos != (tmp = + readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>> + MID_VCI_READ_SHIFT) { + EVENT("drain discard (host 0x%lx, nic 0x%lx)\n", + eni_vcc->rx_pos,tmp); + printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n", + eni_vcc->rx_pos,tmp); + sleep_on(&eni_dev->rx_wait); + } + restore_flags(flags); + } + eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2); + eni_vcc->rx = NULL; +} + + +static int start_rx(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + + eni_dev = ENI_DEV(dev); + eni_dev->rx_map = (struct atm_vcc **) get_free_page(GFP_KERNEL); + if (!eni_dev->rx_map) { + printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", + dev->number); + free_page((unsigned long) eni_dev->free_list); + return -ENOMEM; + } + memset(eni_dev->rx_map,0,PAGE_SIZE); + eni_dev->fast = eni_dev->last_fast = NULL; + eni_dev->slow = eni_dev->last_slow = NULL; + init_waitqueue_head(&eni_dev->rx_wait); + skb_queue_head_init(&eni_dev->rx_queue); + eni_dev->serv_read = eni_in(MID_SERV_WRITE); + eni_out(0,MID_DMA_WR_RX); + return 0; +} + + +/*----------------------------------- TX ------------------------------------*/ + + +enum enq_res { enq_ok,enq_next,enq_jam }; + + +static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, + u32 size) +{ + u32 init,words; + + DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size); + EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size); +#if 0 /* don't complain anymore */ + if (paddr & 3) + printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr); + if (size & 3) + printk(KERN_ERR "put_dma: unaligned size (0x%lx)\n",size); +#endif + if (paddr & 3) { + init = 4-(paddr & 3); + if (init > size || size < 7) init = size; + DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size); + dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += init; + size -= init; + } + words = size >> 2; + size &= 3; + if (words && (paddr & 31)) { + init = 8-((paddr & 31) >> 2); + if (init > words) init = words; + DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words); + dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += init << 2; + words -= init; + } +#ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */ + if (words & ~15) { + DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",paddr,words >> 4, + words); + dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) + | (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += (words & ~15) << 2; + words &= 15; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */ + if (words & ~7) { + DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3, + words); + dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) + | (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += (words & ~7) << 2; + words &= 7; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */ + if (words & ~3) { + DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",paddr,words >> 2, + words); + dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) + | (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += (words & ~3) << 2; + words &= 3; + } +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */ + if (words & ~1) { + DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",paddr,words >> 1, + words); + dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) + | (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += (words & ~1) << 2; + words &= 1; + } +#endif + if (words) { + DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words); + dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += words << 2; + } + if (size) { + DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size); + dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); + dma[(*j)++] = virt_to_bus((void *) paddr); + } +} + + +static enum enq_res do_tx(struct sk_buff *skb) +{ + struct atm_vcc *vcc; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + struct eni_tx *tx; + u32 dma_rd,dma_wr; + u32 size; /* in words */ + int aal5,dma_size,i,j; + + DPRINTK(">do_tx\n"); + NULLCHECK(skb); + EVENT("do_tx: skb=0x%lx, %ld bytes\n",(unsigned long) skb,skb->len); + vcc = ATM_SKB(skb)->vcc; + NULLCHECK(vcc); + eni_dev = ENI_DEV(vcc->dev); + NULLCHECK(eni_dev); + eni_vcc = ENI_VCC(vcc); + tx = eni_vcc->tx; + NULLCHECK(tx); +#if 0 /* Enable this for testing with the "align" program */ + { + unsigned int hack = *((char *) skb->data)-'0'; + + if (hack < 8) { + skb->data += hack; + skb->len -= hack; + } + } +#endif +#if 0 /* should work now */ + if ((unsigned long) skb->data & 3) + printk(KERN_ERR DEV_LABEL "(itf %d): VCI %d has mis-aligned " + "TX data\n",vcc->dev->number,vcc->vci); +#endif + /* + * Potential future IP speedup: make hard_header big enough to put + * segmentation descriptor directly into PDU. Saves: 4 slave writes, + * 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-) + */ + + /* check space in buffer */ + if (!(aal5 = vcc->qos.aal == ATM_AAL5)) + size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE; + /* cell without HEC plus segmentation header (includes + four-byte cell header) */ + else { + size = skb->len+4*AAL5_TRAILER+ATM_CELL_PAYLOAD-1; + /* add AAL5 trailer */ + size = ((size-(size % ATM_CELL_PAYLOAD)) >> 2)+TX_DESCR_SIZE; + /* add segmentation header */ + } + /* + * Can I move tx_pos by size bytes without getting closer than TX_GAP + * to the read pointer ? TX_GAP means to leave some space for what + * the manual calls "too close". + */ + if (!NEPMOK(tx->tx_pos,size+TX_GAP, + eni_in(MID_TX_RDPTR(tx->index)),tx->words)) { + DPRINTK(DEV_LABEL "(itf %d): TX full (size %d)\n", + vcc->dev->number,size); + return enq_next; + } + /* check DMA */ + dma_wr = eni_in(MID_DMA_WR_TX); + dma_rd = eni_in(MID_DMA_RD_TX); + dma_size = 3; /* JK for descriptor and final fill, plus final size + mis-alignment fix */ +DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); + if (!ATM_SKB(skb)->iovcnt) dma_size += 5; + else dma_size += 5*ATM_SKB(skb)->iovcnt; + if (dma_size > TX_DMA_BUF) { + printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries " + "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF); + } + DPRINTK("dma_wr is %d, tx_pos is %ld\n",dma_wr,tx->tx_pos); + if (dma_wr != dma_rd && ((dma_rd+NR_DMA_TX-dma_wr) & (NR_DMA_TX-1)) < + dma_size) { + printk(KERN_WARNING DEV_LABEL "(itf %d): TX DMA full\n", + vcc->dev->number); + return enq_jam; + } + /* prepare DMA queue entries */ + j = 0; + eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) << + MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | + MID_DT_JK; + j++; + if (!ATM_SKB(skb)->iovcnt) + if (aal5) + put_dma(tx->index,eni_dev->dma,&j, + (unsigned long) skb->data,skb->len); + else put_dma(tx->index,eni_dev->dma,&j, + (unsigned long) skb->data+4,skb->len-4); + else { +DPRINTK("doing direct send\n"); + for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) + put_dma(tx->index,eni_dev->dma,&j,(unsigned long) + ((struct iovec *) skb->data)[i].iov_base, + ((struct iovec *) skb->data)[i].iov_len); + } + if (skb->len & 3) + put_dma(tx->index,eni_dev->dma,&j, + (unsigned long) zeroes,4-(skb->len & 3)); + /* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */ + eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) << + MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | + MID_DMA_END | MID_DT_JK; + j++; + DPRINTK("DMA at end: %d\n",j); + /* store frame */ + writel((MID_SEG_TX_ID << MID_SEG_ID_SHIFT) | + (aal5 ? MID_SEG_AAL5 : 0) | (tx->prescaler << MID_SEG_PR_SHIFT) | + (tx->resolution << MID_SEG_RATE_SHIFT) | + (size/(ATM_CELL_PAYLOAD/4)),tx->send+tx->tx_pos*4); +/*printk("dsc = 0x%08lx\n",(unsigned long) readl(tx->send+tx->tx_pos*4));*/ + writel((vcc->vci << MID_SEG_VCI_SHIFT) | + (aal5 ? 0 : (skb->data[3] & 0xf)) | + (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? MID_SEG_CLP : 0), + tx->send+((tx->tx_pos+1) & (tx->words-1))*4); + DPRINTK("size: %d, len:%d\n",size,skb->len); + if (aal5) + writel(skb->len,tx->send+ + ((tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1))*4); + j = j >> 1; + for (i = 0; i < j; i++) { + writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*8); + writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*8+4); + dma_wr = (dma_wr+1) & (NR_DMA_TX-1); + } + ENI_PRV_POS(skb) = tx->tx_pos; + ENI_PRV_SIZE(skb) = size; + ENI_VCC(vcc)->txing += size; + tx->tx_pos = (tx->tx_pos+size) & (tx->words-1); + DPRINTK("dma_wr set to %d, tx_pos is now %ld\n",dma_wr,tx->tx_pos); + eni_out(dma_wr,MID_DMA_WR_TX); + skb_queue_tail(&eni_dev->tx_queue,skb); +queued++; + return enq_ok; +} + + +static void poll_tx(struct atm_dev *dev) +{ + struct eni_tx *tx; + struct sk_buff *skb; + enum enq_res res; + int i; + + DPRINTK(">poll_tx\n"); + for (i = NR_CHAN-1; i >= 0; i--) { + tx = &ENI_DEV(dev)->tx[i]; + if (tx->send) + while ((skb = skb_dequeue(&tx->backlog))) { + res = do_tx(skb); + if (res != enq_ok) { + DPRINTK("re-queuing TX PDU\n"); + skb_queue_head(&tx->backlog,skb); +requeued++; + if (res == enq_jam) return; + else break; + } + } + } +} + + +static void dequeue_tx(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + struct atm_vcc *vcc; + struct sk_buff *skb; + struct eni_tx *tx; + + NULLCHECK(dev); + eni_dev = ENI_DEV(dev); + NULLCHECK(eni_dev); + while ((skb = skb_dequeue(&eni_dev->tx_queue))) { + vcc = ATM_SKB(skb)->vcc; + NULLCHECK(vcc); + tx = ENI_VCC(vcc)->tx; + NULLCHECK(ENI_VCC(vcc)->tx); + DPRINTK("dequeue_tx: next 0x%lx curr 0x%x\n",ENI_PRV_POS(skb), + (unsigned) eni_in(MID_TX_DESCRSTART(tx->index))); + if (ENI_VCC(vcc)->txing < tx->words && ENI_PRV_POS(skb) == + eni_in(MID_TX_DESCRSTART(tx->index))) { + skb_queue_head(&eni_dev->tx_queue,skb); + break; + } + ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + vcc->stats->tx++; + wake_up(&eni_dev->tx_wait); +dma_complete++; + } +} + + +static struct eni_tx *alloc_tx(struct eni_dev *eni_dev,int ubr) +{ + int i; + + for (i = !ubr; i < NR_CHAN; i++) + if (!eni_dev->tx[i].send) return eni_dev->tx+i; + return NULL; +} + + +static int comp_tx(struct eni_dev *eni_dev,int *pcr,int reserved,int *pre, + int *res,int unlimited) +{ + static const int pre_div[] = { 4,16,128,2048 }; + /* 2^(((x+2)^2-(x+2))/2+1) */ + + if (unlimited) *pre = *res = 0; + else { + if (*pcr > 0) { + int div; + + for (*pre = 0; *pre < 3; (*pre)++) + if (TS_CLOCK/pre_div[*pre]/64 <= *pcr) break; + div = pre_div[*pre]**pcr; + DPRINTK("min div %d\n",div); + *res = TS_CLOCK/div-1; + } + else { + int div; + + if (!*pcr) *pcr = eni_dev->tx_bw+reserved; + for (*pre = 3; *pre >= 0; (*pre)--) + if (TS_CLOCK/pre_div[*pre]/64 > -*pcr) break; + if (*pre < 3) (*pre)++; /* else fail later */ + div = pre_div[*pre]*-*pcr; + DPRINTK("max div %d\n",div); + *res = (TS_CLOCK+div-1)/div-1; + } + if (*res < 0) *res = 0; + if (*res > MID_SEG_MAX_RATE) *res = MID_SEG_MAX_RATE; + } + *pcr = TS_CLOCK/pre_div[*pre]/(*res+1); + DPRINTK("out pcr: %d (%d:%d)\n",*pcr,*pre,*res); + return 0; +} + + +static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp, + int set_rsv,int set_shp) +{ + struct eni_dev *eni_dev = ENI_DEV(vcc->dev); + struct eni_vcc *eni_vcc = ENI_VCC(vcc); + struct eni_tx *tx; + unsigned long size,mem; + int rate,ubr,unlimited,new_tx; + int pre,res,order; + int error; + + rate = atm_pcr_goal(txtp); + ubr = txtp->traffic_class == ATM_UBR; + unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR || + rate >= ATM_OC3_PCR); + if (!unlimited) { + size = txtp->max_sdu*3; /* @@@ improve */ + if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <= + MID_MAX_BUF_SIZE) + size = MID_MAX_BUF_SIZE; + } + else { + if (eni_dev->ubr) { + eni_vcc->tx = eni_dev->ubr; + txtp->pcr = ATM_OC3_PCR; + return 0; + } + size = UBR_BUFFER; + } + new_tx = !eni_vcc->tx; + mem = 0; /* for gcc */ + if (!new_tx) tx = eni_vcc->tx; + else { + mem = eni_alloc_mem(eni_dev,&size); + if (!mem) return -ENOBUFS; + tx = alloc_tx(eni_dev,unlimited); + if (!tx) { + eni_free_mem(eni_dev,mem,size); + return -EBUSY; + } + DPRINTK("got chan %d\n",tx->index); + tx->reserved = tx->shaping = 0; + tx->send = mem; + tx->words = size >> 2; + skb_queue_head_init(&tx->backlog); + for (order = 0; size > (1 << (order+10)); order++); + eni_out((order << MID_SIZE_SHIFT) | + ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)), + MID_TX_PLACE(tx->index)); + tx->tx_pos = eni_in(MID_TX_DESCRSTART(tx->index)) & + MID_DESCR_START; + } + error = comp_tx(eni_dev,&rate,tx->reserved,&pre,&res,unlimited); + if (!error && txtp->min_pcr > rate) error = -EINVAL; + if (!error && txtp->max_pcr && txtp->max_pcr != ATM_MAX_PCR && + txtp->max_pcr < rate) error = -EINVAL; + if (!error && !ubr && rate > eni_dev->tx_bw+tx->reserved) + error = -EINVAL; + if (!error && set_rsv && !set_shp && rate < tx->shaping) + error = -EINVAL; + if (!error && !set_rsv && rate > tx->reserved && !ubr) + error = -EINVAL; + if (error) { + if (new_tx) { + tx->send = 0; + eni_free_mem(eni_dev,mem,size); + } + return error; + } + txtp->pcr = rate; + if (set_rsv && !ubr) { + eni_dev->tx_bw += tx->reserved; + tx->reserved = rate; + eni_dev->tx_bw -= rate; + } + if (set_shp || (unlimited && new_tx)) { + if (unlimited && new_tx) eni_dev->ubr = tx; + tx->prescaler = pre; + tx->resolution = res; + tx->shaping = rate; + } + if (set_shp) eni_vcc->tx = tx; + DPRINTK("rsv %d shp %d\n",tx->reserved,tx->shaping); + return 0; +} + + +static int open_tx_first(struct atm_vcc *vcc) +{ + ENI_VCC(vcc)->tx = NULL; + if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; + ENI_VCC(vcc)->txing = 0; + return reserve_or_set_tx(vcc,&vcc->qos.txtp,1,1); +} + + +static int open_tx_second(struct atm_vcc *vcc) +{ + return 0; /* nothing to do */ +} + + +static void close_tx(struct atm_vcc *vcc) +{ + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + unsigned long flags; + + eni_vcc = ENI_VCC(vcc); + if (!eni_vcc->tx) return; + eni_dev = ENI_DEV(vcc->dev); + /* wait for TX queue to drain */ + DPRINTK("eni_close: waiting for TX ...\n"); + save_flags(flags); + cli(); + while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) { + DPRINTK("%d TX left\n",eni_vcc->txing); + sleep_on(&eni_dev->tx_wait); + } + /* + * Looping a few times in here is probably far cheaper than keeping + * track of TX completions all the time, so let's poll a bit ... + */ + while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) != + eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index))) + schedule(); + restore_flags(flags); +#if 0 + if (skb_peek(&eni_vcc->tx->backlog)) + printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n"); +#endif + if (eni_vcc->tx != eni_dev->ubr) { + eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2); + eni_vcc->tx->send = 0; + eni_dev->tx_bw += eni_vcc->tx->reserved; + } + eni_vcc->tx = NULL; +} + + +static int start_tx(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; + int i; + + eni_dev = ENI_DEV(dev); + eni_dev->lost = 0; + eni_dev->tx_bw = ATM_OC3_PCR; + init_waitqueue_head(&eni_dev->tx_wait); + eni_dev->ubr = NULL; + skb_queue_head_init(&eni_dev->tx_queue); + eni_out(0,MID_DMA_WR_TX); + for (i = 0; i < NR_CHAN; i++) { + eni_dev->tx[i].send = 0; + eni_dev->tx[i].index = i; + } + return 0; +} + + +/*--------------------------------- common ----------------------------------*/ + + +#if 0 /* may become useful again when tuning things */ + +static void foo(void) +{ +printk(KERN_INFO + "tx_complete=%d,dma_complete=%d,queued=%d,requeued=%d,sub=%d,\n" + "backlogged=%d,rx_enqueued=%d,rx_dequeued=%d,putting=%d,pushed=%d\n", + tx_complete,dma_complete,queued,requeued,submitted,backlogged, + rx_enqueued,rx_dequeued,putting,pushed); +if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost); +} + +#endif + + +static void misc_int(struct atm_dev *dev,unsigned long reason) +{ + struct eni_dev *eni_dev; + + DPRINTK(">misc_int\n"); + eni_dev = ENI_DEV(dev); + if (reason & MID_STAT_OVFL) { + EVENT("stat overflow\n",0,0); + eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH; + } + if (reason & MID_SUNI_INT) { + EVENT("SUNI int\n",0,0); + dev->phy->interrupt(dev); +#if 0 + foo(); +#endif + } + if (reason & MID_DMA_ERR_ACK) { + printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " + "error\n",dev->number); + EVENT("---dump ends here---\n",0,0); + printk(KERN_NOTICE "---recent events---\n"); + event_dump(); + } + if (reason & MID_TX_IDENT_MISM) { + printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident " + "mismatch\n",dev->number); + EVENT("---dump ends here---\n",0,0); + printk(KERN_NOTICE "---recent events---\n"); + event_dump(); + } + if (reason & MID_TX_DMA_OVFL) { + printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " + "overflow\n",dev->number); + EVENT("---dump ends here---\n",0,0); + printk(KERN_NOTICE "---recent events---\n"); + event_dump(); + } +} + + +static void eni_int(int irq,void *dev_id,struct pt_regs *regs) +{ + struct atm_dev *dev; + struct eni_dev *eni_dev; + unsigned long reason; + + DPRINTK(">eni_int\n"); + dev = dev_id; + eni_dev = ENI_DEV(dev); + while ((reason = eni_in(MID_ISA))) { + DPRINTK(DEV_LABEL ": int 0x%lx\n",reason); + if (reason & MID_RX_DMA_COMPLETE) { + EVENT("INT: RX DMA complete, starting dequeue_rx\n", + 0,0); + dequeue_rx(dev); + EVENT("dequeue_rx done, starting poll_rx\n",0,0); + poll_rx(dev); + EVENT("poll_rx done\n",0,0); + /* poll_tx ? */ + } + if (reason & MID_SERVICE) { + EVENT("INT: service, starting get_service\n",0,0); + get_service(dev); + EVENT("get_service done, starting poll_rx\n",0,0); + poll_rx(dev); + EVENT("poll_rx done\n",0,0); + } + if (reason & MID_TX_DMA_COMPLETE) { + EVENT("INT: TX DMA COMPLETE\n",0,0); + dequeue_tx(dev); + } + if (reason & MID_TX_COMPLETE) { + EVENT("INT: TX COMPLETE\n",0,0); +tx_complete++; + wake_up(&eni_dev->tx_wait); + poll_tx(dev); + /* poll_rx ? */ + } + if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK | + MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) { + EVENT("misc interrupt\n",0,0); + misc_int(dev,reason); + } + } +} + + +/*--------------------------------- entries ---------------------------------*/ + + +static const char *media_name[] __initdata = { + "MMF", "SMF", "MMF", "03?", /* 0- 3 */ + "UTP", "05?", "06?", "07?", /* 4- 7 */ + "TAXI","09?", "10?", "11?", /* 8-11 */ + "12?", "13?", "14?", "15?", /* 12-15 */ + "MMF", "SMF", "18?", "19?", /* 16-19 */ + "UTP", "21?", "22?", "23?", /* 20-23 */ + "24?", "25?", "26?", "27?", /* 24-27 */ + "28?", "29?", "30?", "31?" /* 28-31 */ +}; + + +#define SET_SEPROM \ + ({ if (!error && !pci_error) { \ + pci_error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL,tonga); \ + udelay(10); /* 10 usecs */ \ + } }) +#define GET_SEPROM \ + ({ if (!error && !pci_error) { \ + pci_error = pci_read_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL,&tonga); \ + udelay(10); /* 10 usecs */ \ + } }) + + +__initfunc(static int get_esi_asic(struct atm_dev *dev)) +{ + struct eni_dev *eni_dev; + unsigned char tonga; + int error,failed,pci_error; + int address,i,j; + + eni_dev = ENI_DEV(dev); + error = pci_error = 0; + tonga = SEPROM_MAGIC | SEPROM_DATA | SEPROM_CLK; + SET_SEPROM; + for (i = 0; i < ESI_LEN && !error && !pci_error; i++) { + /* start operation */ + tonga |= SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + tonga &= ~SEPROM_DATA; + SET_SEPROM; + tonga &= ~SEPROM_CLK; + SET_SEPROM; + /* send address */ + address = ((i+SEPROM_ESI_BASE) << 1)+1; + for (j = 7; j >= 0; j--) { + tonga = (address >> j) & 1 ? tonga | SEPROM_DATA : + tonga & ~SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + tonga &= ~SEPROM_CLK; + SET_SEPROM; + } + /* get ack */ + tonga |= SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + GET_SEPROM; + failed = tonga & SEPROM_DATA; + tonga &= ~SEPROM_CLK; + SET_SEPROM; + tonga |= SEPROM_DATA; + SET_SEPROM; + if (failed) error = -EIO; + else { + dev->esi[i] = 0; + for (j = 7; j >= 0; j--) { + dev->esi[i] <<= 1; + tonga |= SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + GET_SEPROM; + if (tonga & SEPROM_DATA) dev->esi[i] |= 1; + tonga &= ~SEPROM_CLK; + SET_SEPROM; + tonga |= SEPROM_DATA; + SET_SEPROM; + } + /* get ack */ + tonga |= SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + GET_SEPROM; + if (!(tonga & SEPROM_DATA)) error = -EIO; + tonga &= ~SEPROM_CLK; + SET_SEPROM; + tonga |= SEPROM_DATA; + SET_SEPROM; + } + /* stop operation */ + tonga &= ~SEPROM_DATA; + SET_SEPROM; + tonga |= SEPROM_CLK; + SET_SEPROM; + tonga |= SEPROM_DATA; + SET_SEPROM; + } + if (pci_error) { + printk(KERN_ERR DEV_LABEL "(itf %d): error reading ESI " + "(0x%02x)\n",dev->number,pci_error); + error = -EIO; + } + return error; +} + + +#undef SET_SEPROM +#undef GET_SEPROM + + +__initfunc(static int get_esi_fpga(struct atm_dev *dev,unsigned long base)) +{ + unsigned long mac_base; + int i; + + mac_base = base+EPROM_SIZE-sizeof(struct midway_eprom); + for (i = 0; i < ESI_LEN; i++) dev->esi[i] = readb(mac_base+(i^3)); + return 0; +} + + +__initfunc(static int eni_init(struct atm_dev *dev)) +{ + struct midway_eprom *eprom; + struct eni_dev *eni_dev; + struct pci_dev *pci_dev; + unsigned int real_base,base; + unsigned char revision; + int error,i,last; + + DPRINTK(">eni_init\n"); + dev->ci_range.vpi_bits = 0; + dev->ci_range.vci_bits = NR_VCI_LD; + dev->link_rate = ATM_OC3_PCR; + eni_dev = ENI_DEV(dev); + pci_dev = eni_dev->pci_dev; + real_base = pci_dev->base_address[0] & MEM_VALID; /* strip flags */ + eni_dev->irq = pci_dev->irq; + error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision); + if (error) { + printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n", + dev->number,error); + return -EINVAL; + } + if ((error = pci_write_config_word(pci_dev,PCI_COMMAND, + PCI_COMMAND_MEMORY | + (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { + printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory " + "(0x%02x)\n",dev->number,error); + return error; + } + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", + dev->number,revision,real_base,eni_dev->irq); + if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { + printk("\n"); + printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page " + "mapping\n",dev->number); + return error; + } + eni_dev->base_diff = real_base-base; + /* id may not be present in ASIC Tonga boards - check this @@@ */ + if (!eni_dev->asic) { + eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct + midway_eprom)); + if (readl(&eprom->magic) != ENI155_MAGIC) { + printk("\n"); + printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad " + "magic - expected 0x%x, got 0x%x\n",dev->number, + ENI155_MAGIC,(unsigned) readl(&eprom->magic)); + return -EINVAL; + } + } + eni_dev->phy = base+PHY_BASE; + eni_dev->reg = base+REG_BASE; + eni_dev->ram = base+RAM_BASE; + last = MAP_MAX_SIZE-RAM_BASE; + for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { + writel(0x55555555,eni_dev->ram+i); + if (readl(eni_dev->ram+i) != 0x55555555) last = i; + else { + writel(0xAAAAAAAA,eni_dev->ram+i); + if (readl(eni_dev->ram+i) != 0xAAAAAAAA) last = i; + else writel(i,eni_dev->ram+i); + } + } + for (i = 0; i < last; i += RAM_INCREMENT) + if (readl(eni_dev->ram+i) != i) break; + eni_dev->mem = i; + memset_io(eni_dev->ram,0,eni_dev->mem); + /* TODO: should shrink allocation now */ + printk("mem=%dkB (",eni_dev->mem >> 10); + /* TODO: check for non-SUNI, check for TAXI ? */ + if (!(eni_in(MID_RES_ID_MCON) & 0x200) != !eni_dev->asic) { + printk(")\n"); + printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n", + dev->number,(unsigned) eni_in(MID_RES_ID_MCON)); + return -EINVAL; + } + error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base); + if (error) return error; + for (i = 0; i < ESI_LEN; i++) + printk("%s%02X",i ? "-" : "",dev->esi[i]); + printk(")\n"); + printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number, + eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA", + media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]); + return suni_init(dev); +} + + +__initfunc(static int eni_start(struct atm_dev *dev)) +{ + struct eni_dev *eni_dev; + unsigned long buf,buffer_mem; + int error; + + DPRINTK(">eni_start\n"); + eni_dev = ENI_DEV(dev); + if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) { + printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", + dev->number,eni_dev->irq); + return -EAGAIN; + } + /* @@@ should release IRQ on error */ + if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { + printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" + "master (0x%02x)\n",dev->number,error); + return error; + } + if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, + END_SWAP_DMA))) { + printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " + "(0x%02x)\n",dev->number,error); + return error; + } + /* determine addresses of internal tables */ + eni_dev->vci = eni_dev->ram; + eni_dev->rx_dma = eni_dev->ram+NR_VCI*16; + eni_dev->tx_dma = eni_dev->rx_dma+NR_DMA_RX*8; + eni_dev->service = eni_dev->tx_dma+NR_DMA_TX*8; + buf = eni_dev->service+NR_SERVICE*4; + DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n", + eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma, + eni_dev->service,buf); + /* initialize memory management */ + buffer_mem = eni_dev->mem-(buf-eni_dev->ram); + eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; + eni_dev->free_list = (struct eni_free *) kmalloc( + sizeof(struct eni_free)*(eni_dev->free_list_size+1),GFP_KERNEL); + if (!eni_dev->free_list) { + printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", + dev->number); + return -ENOMEM; + } + eni_dev->free_len = 0; + eni_put_free(eni_dev,buf,buffer_mem); + memset_io(eni_dev->vci,0,16*NR_VCI); /* clear VCI table */ + /* + * byte_addr free (k) + * 0x00000000 512 VCI table + * 0x00004000 496 RX DMA + * 0x00005000 492 TX DMA + * 0x00006000 488 service list + * 0x00007000 484 buffers + * 0x00080000 0 end (512kB) + */ + eni_out(0xffffffff,MID_IE); + error = start_tx(dev); + if (error) return error; + error = start_rx(dev); + if (error) return error; + error = dev->phy->start(dev); + if (error) return error; + eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | + MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, + MID_MC_S); + /* Tonga uses SBus INTReq1 */ + (void) eni_in(MID_ISA); /* clear Midway interrupts */ + return 0; +} + + +static void eni_close(struct atm_vcc *vcc) +{ + DPRINTK(">eni_close\n"); + if (!ENI_VCC(vcc)) return; + vcc->flags &= ~ATM_VF_READY; + close_rx(vcc); + close_tx(vcc); + DPRINTK("eni_close: done waiting\n"); + /* deallocate memory */ + kfree(ENI_VCC(vcc)); + ENI_VCC(vcc) = NULL; + vcc->flags &= ~ATM_VF_ADDR; + /*foo();*/ +} + + +static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci) +{ + struct atm_vcc *walk; + + if (*vpi == ATM_VPI_ANY) *vpi = 0; + if (*vci == ATM_VCI_ANY) { + for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) { + if (vcc->qos.rxtp.traffic_class != ATM_NONE && + ENI_DEV(vcc->dev)->rx_map[*vci]) + continue; + if (vcc->qos.txtp.traffic_class != ATM_NONE) { + for (walk = vcc->dev->vccs; walk; + walk = walk->next) + if ((walk->flags & ATM_VF_ADDR) && + walk->vci == *vci && + walk->qos.txtp.traffic_class != + ATM_NONE) + break; + if (walk) continue; + } + break; + } + return *vci == NR_VCI ? -EADDRINUSE : 0; + } + if (*vci == ATM_VCI_UNSPEC) return 0; + if (vcc->qos.rxtp.traffic_class != ATM_NONE && + ENI_DEV(vcc->dev)->rx_map[*vci]) + return -EADDRINUSE; + if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; + for (walk = vcc->dev->vccs; walk; walk = walk->next) + if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci && + walk->qos.txtp.traffic_class != ATM_NONE) + return -EADDRINUSE; + return 0; +} + + +static int eni_open(struct atm_vcc *vcc,short vpi,int vci) +{ + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + int error; + + DPRINTK(">eni_open\n"); + EVENT("eni_open\n",0,0); + if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL; + eni_dev = ENI_DEV(vcc->dev); + error = get_ci(vcc,&vpi,&vci); + if (error) return error; + vcc->vpi = vpi; + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) + vcc->flags |= ATM_VF_ADDR; + if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) + return -EINVAL; + DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, + vcc->vci); + if (!(vcc->flags & ATM_VF_PARTIAL)) { + eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL); + if (!eni_vcc) return -ENOMEM; + ENI_VCC(vcc) = eni_vcc; + eni_vcc->tx = NULL; /* for eni_close after open_rx */ + if ((error = open_rx_first(vcc))) { + eni_close(vcc); + return error; + } + if ((error = open_tx_first(vcc))) { + eni_close(vcc); + return error; + } + } + if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; + if ((error = open_rx_second(vcc))) { + eni_close(vcc); + return error; + } + if ((error = open_tx_second(vcc))) { + eni_close(vcc); + return error; + } + vcc->flags |= ATM_VF_READY; + /* should power down SUNI while !ref_count @@@ */ + return 0; +} + + +static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) +{ + struct eni_dev *eni_dev = ENI_DEV(vcc->dev); + struct eni_tx *tx = ENI_VCC(vcc)->tx; + struct sk_buff *skb; + unsigned long flags; + int error,rate,rsv,shp; + + if (qos->txtp.traffic_class == ATM_NONE) return 0; + if (tx == eni_dev->ubr) return -EBADFD; + rate = atm_pcr_goal(&qos->txtp); + if (rate < 0) rate = -rate; + rsv = shp = 0; + if ((flgs & ATM_MF_DEC_RSV) && rate && rate < tx->reserved) rsv = 1; + if ((flgs & ATM_MF_INC_RSV) && (!rate || rate > tx->reserved)) rsv = 1; + if ((flgs & ATM_MF_DEC_SHP) && rate && rate < tx->shaping) shp = 1; + if ((flgs & ATM_MF_INC_SHP) && (!rate || rate > tx->shaping)) shp = 1; + if (!rsv && !shp) return 0; + error = reserve_or_set_tx(vcc,&qos->txtp,rsv,shp); + if (error) return error; + if (shp && !(flgs & ATM_MF_IMMED)) return 0; + /* + * Walk through the send buffer and patch the rate information in all + * segmentation buffer descriptors of this VCC. + */ + save_flags(flags); + cli(); + for (skb = eni_dev->tx_queue.next; skb != + (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) { + unsigned long dsc; + + if (ATM_SKB(skb)->vcc != vcc) continue; + dsc = tx->send+ENI_PRV_POS(skb)*4; + writel((readl(dsc) & ~(MID_SEG_RATE | MID_SEG_PR)) | + (tx->prescaler << MID_SEG_PR_SHIFT) | + (tx->resolution << MID_SEG_RATE_SHIFT), dsc); + } + restore_flags(flags); + return 0; +} + + +static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + if (cmd == ENI_MEMDUMP) { + printk(KERN_WARNING "Please use /proc/atm/" DEV_LABEL ":%d " + "instead of obsolete ioctl ENI_MEMDUMP\n",dev->number); + dump(dev); + return 0; + } + if (cmd == ATM_SETCIRANGE) { + struct atm_cirange ci; + + if (copy_from_user(&ci,(void *) arg,sizeof(struct atm_cirange))) + return -EFAULT; + if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && + (ci.vci_bits == NR_VCI_LD || ci.vpi_bits == ATM_CI_MAX)) + return 0; + return -EINVAL; + } + if (!dev->phy->ioctl) return -EINVAL; + return dev->phy->ioctl(dev,cmd,arg); +} + + +static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen) +{ +#ifdef CONFIG_MMU_HACKS + +static const struct atm_buffconst bctx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; +static const struct atm_buffconst bcrx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; + +#else + +static const struct atm_buffconst bctx = { sizeof(int),0,sizeof(int),0,0,0 }; +static const struct atm_buffconst bcrx = { sizeof(int),0,sizeof(int),0,0,0 }; + +#endif + if (level == SOL_AAL && (optname == SO_BCTXOPT || + optname == SO_BCRXOPT)) + return copy_to_user(optval,optname == SO_BCTXOPT ? &bctx : + &bcrx,sizeof(struct atm_buffconst)) ? -EFAULT : 0; + return -EINVAL; +} + + +static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen) +{ + return -EINVAL; +} + + +static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ + unsigned long flags; + + DPRINTK(">eni_send\n"); + if (!ENI_VCC(vcc)->tx) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } + if (!skb) { + printk(KERN_CRIT "!skb in eni_send ?\n"); + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } + if (vcc->qos.aal == ATM_AAL0) { + if (skb->len != ATM_CELL_SIZE-1) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } + *(u32 *) skb->data = htonl(*(u32 *) skb->data); + } +submitted++; + ATM_SKB(skb)->vcc = vcc; + save_flags(flags); + cli(); /* brute force */ + if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) { + skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); + backlogged++; + } + restore_flags(flags); + return 0; +} + + +static int eni_sg_send(struct atm_vcc *vcc,unsigned long start, + unsigned long size) +{ + return vcc->qos.aal == ATM_AAL5 && !((start | size) & 3); + /* don't tolerate misalignment */ +} + + +static void eni_phy_put(struct atm_dev *dev,unsigned char value, + unsigned long addr) +{ + writel(value,ENI_DEV(dev)->phy+addr*4); +} + + + +static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr) +{ + return readl(ENI_DEV(dev)->phy+addr*4); +} + + +static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) +{ + static const char *signal[] = { "LOST","unknown","okay" }; + struct eni_dev *eni_dev = ENI_DEV(dev); + struct atm_vcc *vcc; + int left,i; + + left = *pos; + if (!left) + return sprintf(page,DEV_LABEL "(itf %d) signal %s, %dkB, " + "%d cps remaining\n",dev->number,signal[(int) dev->signal], + eni_dev->mem >> 10,eni_dev->tx_bw); + left--; + if (!left) + return sprintf(page,"Bursts: TX" +#if !defined(CONFIG_ATM_ENI_BURST_TX_16W) && \ + !defined(CONFIG_ATM_ENI_BURST_TX_8W) && \ + !defined(CONFIG_ATM_ENI_BURST_TX_4W) && \ + !defined(CONFIG_ATM_ENI_BURST_TX_2W) + " none" +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_16W + " 16W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_8W + " 8W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_4W + " 4W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_TX_2W + " 2W" +#endif + ", RX" +#if !defined(CONFIG_ATM_ENI_BURST_RX_16W) && \ + !defined(CONFIG_ATM_ENI_BURST_RX_8W) && \ + !defined(CONFIG_ATM_ENI_BURST_RX_4W) && \ + !defined(CONFIG_ATM_ENI_BURST_RX_2W) + " none" +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_16W + " 16W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_8W + " 8W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_4W + " 4W" +#endif +#ifdef CONFIG_ATM_ENI_BURST_RX_2W + " 2W" +#endif +#ifndef CONFIG_ATM_ENI_TUNE_BURST + " (default)" +#endif + "\n"); + for (i = 0; i < NR_CHAN; i++) { + struct eni_tx *tx = eni_dev->tx+i; + + if (!tx->send) continue; + if (--left) continue; + return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx (%6ld bytes), " + "rsv %d cps, shp %d cps%s\n",i, + tx->send-eni_dev->ram, + tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, + tx->reserved,tx->shaping, + tx == eni_dev->ubr ? " (UBR)" : ""); + } + for (vcc = dev->vccs; vcc; vcc = vcc->next) { + struct eni_vcc *eni_vcc = ENI_VCC(vcc); + int length; + + if (--left) continue; + length = sprintf(page,"vcc %4d: ",vcc->vci); + if (eni_vcc->rx) { + length += sprintf(page+length,"0x%06lx-0x%06lx " + "(%6ld bytes)", + eni_vcc->recv-eni_dev->ram, + eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, + eni_vcc->words*4); + if (eni_vcc->tx) length += sprintf(page+length,", "); + } + if (eni_vcc->tx) + length += sprintf(page+length,"tx[%d]", + eni_vcc->tx->index); + page[length] = '\n'; + return length+1; + } + for (i = 0; i < eni_dev->free_len; i++) { + struct eni_free *fe = eni_dev->free_list+i; + unsigned long offset; + + if (--left) continue; + offset = eni_dev->ram+eni_dev->base_diff; + return sprintf(page,"free 0x%06lx-0x%06lx (%6d bytes)\n", + fe->start-offset,fe->start-offset+(1 << fe->order)-1, + 1 << fe->order); + } + return 0; +} + + +static const struct atmdev_ops ops = { + NULL, /* no dev_close */ + eni_open, + eni_close, + eni_ioctl, + eni_getsockopt, + eni_setsockopt, + eni_send, + eni_sg_send, + NULL, /* no send_oam */ + eni_phy_put, + eni_phy_get, + NULL, /* no feedback */ + eni_change_qos, /* no change_qos */ + NULL, /* no free_rx_skb */ + eni_proc_read +}; + + +__initfunc(int eni_detect(void)) +{ + struct atm_dev *dev; + struct eni_dev *eni_dev; + int devs,type; + + eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev), + GFP_KERNEL); + if (!eni_dev) return -ENOMEM; + devs = 0; + for (type = 0; type < 2; type++) { + struct pci_dev *pci_dev; + + pci_dev = NULL; + while ((pci_dev = pci_find_device(PCI_VENDOR_ID_EF,type ? + PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA, + pci_dev))) { + if (!devs) { + zeroes = kmalloc(4,GFP_KERNEL); + if (!zeroes) { + kfree(eni_dev); + return -ENOMEM; + } + } + dev = atm_dev_register(DEV_LABEL,&ops,-1,0); + if (!dev) break; + eni_dev->pci_dev = pci_dev; + ENI_DEV(dev) = eni_dev; + eni_dev->asic = type; + if (eni_init(dev) || eni_start(dev)) { + atm_dev_deregister(dev); + break; + } + eni_dev->more = eni_boards; + eni_boards = dev; + devs++; + eni_dev = (struct eni_dev *) kmalloc(sizeof(struct + eni_dev),GFP_KERNEL); + if (!eni_dev) break; + } + } + kfree(eni_dev); + if (!devs && zeroes) { + kfree(zeroes); + zeroes = NULL; + } + return devs; +} + + +#ifdef MODULE + +int init_module(void) +{ + if (!eni_detect()) { + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); + return -ENXIO; + } + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* + * Well, there's no way to get rid of the driver yet, so we don't + * have to clean up, right ? :-) + */ +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/eni.h linux/drivers/atm/eni.h --- v2.3.14/linux/drivers/atm/eni.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/eni.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,115 @@ +/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef DRIVER_ATM_ENI_H +#define DRIVER_ATM_ENI_H + +#include +#include +#include +#include +#include +#include + +#include "midway.h" + + +#define KERNEL_OFFSET 0xC0000000 /* kernel 0x0 is at phys 0xC0000000 */ +#define DEV_LABEL "eni" + +#define UBR_BUFFER (128*1024) /* UBR buffer size */ + +#define RX_DMA_BUF 8 /* burst and skip a few things */ +#define TX_DMA_BUF 100 /* should be enough for 64 kB */ + + +struct eni_free { + unsigned long start; /* counting in bytes */ + int order; +}; + +struct eni_tx { + unsigned long send; /* base, 0 if unused */ + int prescaler; /* shaping prescaler */ + int resolution; /* shaping divider */ + unsigned long tx_pos; /* current TX write position */ + unsigned long words; /* size of TX queue */ + int index; /* TX channel number */ + int reserved; /* reserved peak cell rate */ + int shaping; /* shaped peak cell rate */ + struct sk_buff_head backlog; /* queue of waiting TX buffers */ +}; + +struct eni_vcc { + int (*rx)(struct atm_vcc *vcc); /* RX function, NULL if none */ + unsigned long recv; /* receive buffer */ + unsigned long words; /* its size in words */ + unsigned long descr; /* next descriptor (RX) */ + unsigned long rx_pos; /* current RX descriptor pos */ + struct eni_tx *tx; /* TXer, NULL if none */ + int rxing; /* number of pending PDUs */ + int servicing; /* number of waiting VCs (0 or 1) */ + int txing; /* number of pending TX cells/PDUs */ + struct timeval timestamp; /* for RX timing */ + struct atm_vcc *next; /* next pending RX */ + struct sk_buff *last; /* last PDU being DMAed (used to carry + discard information) */ +}; + +struct eni_dev { + /*-------------------------------- base pointers into Midway address + space */ + unsigned long phy; /* PHY interface chip registers */ + unsigned long reg; /* register base */ + unsigned long ram; /* RAM base */ + unsigned long vci; /* VCI table */ + unsigned long rx_dma; /* RX DMA queue */ + unsigned long tx_dma; /* TX DMA queue */ + unsigned long service; /* service list */ + /*-------------------------------- TX part */ + struct eni_tx tx[NR_CHAN]; /* TX channels */ + struct eni_tx *ubr; /* UBR channel */ + struct sk_buff_head tx_queue; /* PDUs currently being TX DMAed*/ + wait_queue_head_t tx_wait; /* for close */ + int tx_bw; /* remaining bandwidth */ + u32 dma[TX_DMA_BUF*2]; /* DMA request scratch area */ + /*-------------------------------- RX part */ + u32 serv_read; /* host service read index */ + struct atm_vcc *fast,*last_fast;/* queues of VCCs with pending PDUs */ + struct atm_vcc *slow,*last_slow; + struct atm_vcc **rx_map; /* for fast lookups */ + struct sk_buff_head rx_queue; /* PDUs currently being RX-DMAed */ + wait_queue_head_t rx_wait; /* for close */ + /*-------------------------------- statistics */ + unsigned long lost; /* number of lost cells (RX) */ + /*-------------------------------- memory management */ + unsigned long base_diff; /* virtual-real base address */ + int free_len; /* free list length */ + struct eni_free *free_list; /* free list */ + int free_list_size; /* maximum size of free list */ + /*-------------------------------- ENI links */ + struct atm_dev *more; /* other ENI devices */ + /*-------------------------------- general information */ + int mem; /* RAM on board (in bytes) */ + int asic; /* PCI interface type, 0 for FPGA */ + unsigned char irq; /* IRQ */ + struct pci_dev *pci_dev; /* PCI stuff */ +}; + + +#define ENI_DEV(d) ((struct eni_dev *) (d)->dev_data) +#define ENI_VCC(d) ((struct eni_vcc *) (d)->dev_data) + + +struct eni_skb_prv { + struct atm_skb_data _; /* reserved */ + unsigned long pos; /* position of next descriptor */ + int size; /* PDU size in reassembly buffer */ +}; + +#define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size) +#define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos) + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c --- v2.3.14/linux/drivers/atm/horizon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/horizon.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,3066 @@ +/* + Madge Horizon ATM Adapter driver. + Copyright (C) 1995-1999 Madge Networks Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian + system and in the file COPYING in the Linux kernel source. +*/ + +/* + IMPORTANT NOTE: Madge Networks no longer makes the adapters + supported by this driver and makes no commitment to maintain it. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "horizon.h" + +#define maintainer_string "Giuliano Procida at Madge Networks " +#define description_string "Madge ATM Horizon [Ultra] driver" +#define version_string "1.1" + +static void __init show_version (void) { + printk ("%s version %s\n", description_string, version_string); +} + +/* + + CREDITS + + Driver and documentation by: + + Chris Aston Madge Networks + Giuliano Procida Madge Networks + Simon Benham Madge Networks + Simon Johnson Madge Networks + Various Others Madge Networks + + Some inspiration taken from other drivers by: + + Alexandru Cucos UTBv + Kari Mettinen University of Helsinki + Werner Almesberger EPFL LRC + + Theory of Operation + + I Hardware, detection, initialisation and shutdown. + + 1. Supported Hardware + + This driver should handle all variants of the PCI Madge ATM adapters + with the Horizon chipset. These are all PCI cards supporting PIO, BM + DMA and a form of MMIO (registers only, not internal RAM). + + The driver is only known to work with SONET and UTP Horizon Ultra + cards at 155Mb/s. However, code is in place to deal with both the + original Horizon and 35Mb/s. + + There are two revisions of the Horizon ASIC: the original and the + Ultra. Details of hardware bugs are in section III. + + The ASIC version can be distinguished by chip markings but is NOT + indicated by the PCI revision (all adapters seem to have PCI rev 1). + + I believe that: + + Horizon => Collage 25 PCI Adapter (UTP and STP) + Horizon Ultra => Collage 155 PCI Client (UTP or SONET) + Ambassador x => Collage 155 PCI Server (completely different) + + Horizon (25Mb/s) is fitted with UTP and STP connectors. It seems to + have a Madge B154 plus glue logic serializer. I have also found a + really ancient version of this with slightly different glue. It + comes with the revision 0 (140-025-01) ASIC. + + Horizon Ultra (155Mb/s) is fitted with either a Pulse Medialink + output (UTP) or an HP HFBR 5205 output (SONET). It has either + Madge's SAMBA framer or a SUNI-lite device (early versions). It + comes with the revision 1 (140-027-01) ASIC. + + 2. Detection + + All Horizon-based cards present with the same PCI Vendor and Device + IDs. The standard Linux 2.2 PCI API is used to locate any cards and + to enable bus-mastering (with appropriate latency). + + ATM_LAYER_STATUS in the control register distinguishes between the + two possible physical layers (25 and 155). It is not clear whether + the 155 cards can also operate at 25Mbps. We rely on the fact that a + card operates at 155 if and only if it has the newer Horizon Ultra + ASIC. + + For 155 cards the two possible framers are probed for and then set + up for loop-timing. + + 3. Initialisation + + The card is reset and then put into a know state. The physical layer + is configured for normal operation at the appropriate speed; in the + case of the 155 cards, the framer is initialised with line-based + timing; the internal RAM is zeroed and the allocation of buffers for + RX and TX is made; the Burnt In Address is read and copied to the + ATM ESI; various policy settings for RX (VPI bits, unknown VCs, oam + cells) are made. Ideally all policy items should be configurable at + module load (if not actually on-demand), however, only the vpi vs + vci bit allocation can be specified at insmod. + + 4. Shutdown + + This is in response to module_cleaup. No VCs are in use and the card + should be idle; it is reset. + + II Driver software (as it should be) + + 0. Traffic Parameters + + The traffic classes (not an enumeration) are currently: ATM_NONE (no + traffic), ATM_UBR, ATM_CBR, ATM_VBR and ATM_ABR, ATM_ANYCLASS + (compatible with everything). Together with (perhaps only some of) + the following items they make up the traffic specification. + + struct atm_trafprm { + unsigned char traffic_class; traffic class (ATM_UBR, ...) + int max_pcr; maximum PCR in cells per second + int pcr; desired PCR in cells per second + int min_pcr; minimum PCR in cells per second + int max_cdv; maximum CDV in microseconds + int max_sdu; maximum SDU in bytes + }; + + Note that these denote bandwidth available not bandwidth used; the + possibilities according to ATMF are: + + Real Time (cdv and max CDT given) + + CBR(pcr) pcr bandwidth always available + rtVBR(pcr,scr,mbs) scr bandwidth always available, upto pcr at mbs too + + Non Real Time + + nrtVBR(pcr,scr,mbs) scr bandwidth always available, upto pcr at mbs too + UBR() + ABR(mcr,pcr) mcr bandwidth always available, upto pcr (depending) too + + mbs is max burst size (bucket) + pcr and scr have associated cdvt values + mcr is like scr but has no cdtv + cdtv may differ at each hop + + Some of the above items are qos items (as opposed to traffic + parameters). We have nothing to do with qos. All except ABR can have + their traffic parameters converted to GCRA parameters. The GCRA may + be implemented as a (real-number) leaky bucket. The GCRA can be used + in complicated ways by switches and in simpler ways by end-stations. + It can be used both to filter incoming cells and shape out-going + cells. + + ATM Linux actually supports: + + ATM_NONE() (no traffic in this direction) + ATM_UBR(max_frame_size) + ATM_CBR(max/min_pcr, max_cdv, max_frame_size) + + 0 or ATM_MAX_PCR are used to indicate maximum available PCR + + A traffic specification consists of the AAL type and separate + traffic specifications for either direction. In ATM Linux it is: + + struct atm_qos { + struct atm_trafprm txtp; + struct atm_trafprm rxtp; + unsigned char aal; + }; + + AAL types are: + + ATM_NO_AAL AAL not specified + ATM_AAL0 "raw" ATM cells + ATM_AAL1 AAL1 (CBR) + ATM_AAL2 AAL2 (VBR) + ATM_AAL34 AAL3/4 (data) + ATM_AAL5 AAL5 (data) + ATM_SAAL signaling AAL + + The Horizon has support for AAL frame types: 0, 3/4 and 5. However, + it does not implement AAL 3/4 SAR and it has a different notion of + "raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are + supported by this driver. + + The Horizon has (TX) support for ABR (including UBR), VBR and CBR. + Each TX channel has a bucket (containing up to 31 cell units) and + two timers (PCR and SCR) associated with it that can be used to + govern cell emissions and host notification (in the case of + ABR). The timers may either be disabled or may be set to any of 240 + values (determined by the clock crystal, a fixed (?) per-device + divider, a configurable divider and a configurable timer preload + value). + + At the moment only UBR and CBR are supported by the driver. This is + due to my not understanding ATM Linux VBR or Horizon's VBR support. + + 1. TX (TX channel setup and TX transfer) + + The TX half of the driver owns the TX Horizon registers. The TX + component in the IRQ handler is the BM completion handler. This can + only be entered when tx_busy is true (enforced by hardware). The + other TX component can only be entered when tx_busy is false + (enforced by driver). So TX is single-threaded. + + Apart from a minor optimisation to not re-select the last channel, + the TX send component works as follows: + + Atomic test and set tx_busy until we succeed; we should implement + some sort of timeout so that tx_busy will never be stuck at true. + + If no TX channel is setup for this VC we wait for an idle one (if + necessary) and set it up. + + At this point we have a TX channel ready for use. We wait for enough + buffers to become available then start a TX transmit (set the TX + descriptor, schedule transfer, exit). + + The IRQ component handles TX completion (stats, free buffer, tx_busy + unset, exit). We also re-schedule further transfers for the same + frame if needed. + + TX setup in more detail: + + TX open is a nop, the relevant information is held in the hrz_vcc + (vcc->dev_data) structure and is "cached" on the card. + + TX close gets the TX lock and clears the channel from the "cache". + + 2. RX (Data Available and RX transfer) + + The RX half of the driver owns the RX registers. There are two RX + components in the IRQ handler: the data available handler deals with + fresh data that has arrived on the card, the BM completion handler + is very similar to the TX completion handler. The data available + handler grabs the rx_lock and it is only released once the data has + been discarded or completely transferred to the host. The BM + completion handler only runs when the lock is held; the data + available handler is locked out over the same period. + + Data available on the card triggers an interrupt. If the data is not + suitable for out existing RX channels or we cannot allocate a buffer + it is flushed. Otherwise an RX receive is scheduled. Multiple RX + transfers may be scheduled for the same frame. + + RX setup in more detail: + + RX open... + RX close... + + III Hardware Bugs + + 0. Byte vs Word addressing of adapter RAM. + + A design feature; see the .h file (especially the memory map). + + 1. Bus Master Data Transfers (original Horizon only, fixed in Ultra) + + The host must not start a transmit direction transfer at a + non-four-byte boundary in host memory. Instead the host should + perform a byte, or a two byte, or one byte followed by two byte + transfer in order to start the rest of the transfer on a four byte + boundary. RX is OK. + + Simultaneous transmit and receive direction bus master transfers are + not allowed. + + The simplest solution to these two is to always do PIO (never DMA) + in the TX direction on the original Horizon. More complicated + solutions are likely to hurt my brain. + + 3. Loss of buffer on close VC + + When a VC is being closed, the buffer associated with it is not + returned to the pool. The host must store the reference to this + buffer and when opening a new VC then give it to that new VC. + + The host intervention currently consists of stacking such a buffer + pointer at VC close and checking the stack at VC open. + + 4. Failure to close a VC + + If a VC is currently receiving a frame then closing the VC may fail + and the frame continues to be received. + + The solution is to make sure any received frames are flushed when + ready. This is currently done just before the solution to 3. + + 5. PCI bus (original Horizon only, fixed in Ultra) + + Reading from the data port prior to initialisation will hang the PCI + bus. Just don't do that then! We don't. + + IV To Do List + + . Timer code may be broken. + + . Allow users to specify buffer allocation split for TX and RX. + + . Deal once and for all with buggy VC close. + + . Handle interrupted and/or non-blocking operations. + + . Change some macros to functions and move from .h to .c. + + . Try to limit the number of TX frames each VC may have queued, in + order to reduce the chances of TX buffer exhaustion. + + . Implement VBR (bucket and timers not understood) and ABR (need to + do RM cells manually); also no Linux support for either. + + . Implement QoS changes on open VCs (involves extracting parts of VC open + and close into separate functions and using them to make changes). + +*/ + +/********** globals **********/ + +static hrz_dev * hrz_devs = NULL; +static struct timer_list housekeeping; + +static unsigned short debug = 0; +static unsigned short vpi_bits = 0; +static unsigned short max_tx_size = 9000; +static unsigned short max_rx_size = 9000; +static unsigned char pci_lat = 0; + +/********** access functions **********/ + +/* Read / Write Horizon registers */ +static inline void wr_regl (const hrz_dev * dev, unsigned char reg, u32 data) { + outl (cpu_to_le32 (data), dev->iobase + reg); +} + +static inline u32 rd_regl (const hrz_dev * dev, unsigned char reg) { + return le32_to_cpu (inl (dev->iobase + reg)); +} + +static inline void wr_regw (const hrz_dev * dev, unsigned char reg, u16 data) { + outw (cpu_to_le16 (data), dev->iobase + reg); +} + +static inline u16 rd_regw (const hrz_dev * dev, unsigned char reg) { + return le16_to_cpu (inw (dev->iobase + reg)); +} + +static inline void wrs_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { + outsb (dev->iobase + reg, addr, len); +} + +static inline void rds_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { + insb (dev->iobase + reg, addr, len); +} + +/* Read / Write to a given address in Horizon buffer memory. */ +// Interrupts must be disabled between the address register and data port +// accesses as these must form an atomic operation. + +static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) { + // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr); + wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); + wr_regl (dev, MEMORY_PORT_OFF, data); +} + +static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) { + // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr); + wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); + return rd_regl(dev, MEMORY_PORT_OFF); +} + +static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) { + wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr | 0x80000000); + wr_regl (dev, MEMORY_PORT_OFF, data); +} + +static inline u32 rd_framer (const hrz_dev * dev, u32 addr) { + wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr | 0x80000000); + return rd_regl (dev, MEMORY_PORT_OFF); +} + +/********** specialised access functions **********/ + +/* RX */ + +static inline void FLUSH_RX_CHANNEL (hrz_dev * dev, u16 channel) { + wr_regw (dev, RX_CHANNEL_PORT_OFF, FLUSH_CHANNEL | channel); + return; +} + +static inline void WAIT_FLUSH_RX_COMPLETE (hrz_dev * dev) { + while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & FLUSH_CHANNEL) + ; + return; +} + +static inline void SELECT_RX_CHANNEL (hrz_dev * dev, u16 channel) { + wr_regw (dev, RX_CHANNEL_PORT_OFF, channel); + return; +} + +static inline void WAIT_UPDATE_COMPLETE (hrz_dev * dev) { + while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & RX_CHANNEL_UPDATE_IN_PROGRESS) + ; + return; +} + +/* TX */ + +static inline void SELECT_TX_CHANNEL (hrz_dev * dev, u16 tx_channel) { + wr_regl (dev, TX_CHANNEL_PORT_OFF, tx_channel); + return; +} + +/* Update or query one configuration parameter of a particular channel. */ + +static inline void update_tx_channel_config (hrz_dev * dev, short chan, u8 mode, u16 value) { + wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, + chan * TX_CHANNEL_CONFIG_MULT | mode); + wr_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF, value); + return; +} + +static inline u16 query_tx_channel_config (hrz_dev * dev, short chan, u8 mode) { + wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, + chan * TX_CHANNEL_CONFIG_MULT | mode); + return rd_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF); +} + +/********** dump functions **********/ + +static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) { +#ifdef DEBUG_HORIZON + unsigned int i; + unsigned char * data = skb->data; + PRINTDB (DBG_DATA, "%s(%u) ", prefix, vc); + for (i=0; ilen && i < 256;i++) + PRINTDM (DBG_DATA, "%02x ", data[i]); + PRINTDE (DBG_DATA,""); +#else + (void) prefix; + (void) vc; + (void) skb; +#endif + return; +} + +static inline void dump_regs (hrz_dev * dev) { +#ifdef DEBUG_HORIZON + PRINTD (DBG_REGS, "CONTROL 0: %#x", rd_regl (dev, CONTROL_0_REG)); + PRINTD (DBG_REGS, "RX CONFIG: %#x", rd_regw (dev, RX_CONFIG_OFF)); + PRINTD (DBG_REGS, "TX CONFIG: %#x", rd_regw (dev, TX_CONFIG_OFF)); + PRINTD (DBG_REGS, "TX STATUS: %#x", rd_regw (dev, TX_STATUS_OFF)); + PRINTD (DBG_REGS, "IRQ ENBLE: %#x", rd_regl (dev, INT_ENABLE_REG_OFF)); + PRINTD (DBG_REGS, "IRQ SORCE: %#x", rd_regl (dev, INT_SOURCE_REG_OFF)); +#else + (void) dev; +#endif + return; +} + +static inline void dump_framer (hrz_dev * dev) { +#ifdef DEBUG_HORIZON + unsigned int i; + PRINTDB (DBG_REGS, "framer registers:"); + for (i = 0; i < 0x10; ++i) + PRINTDM (DBG_REGS, " %02x", rd_framer (dev, i)); + PRINTDE (DBG_REGS,""); +#else + (void) dev; +#endif + return; +} + +/********** VPI/VCI <-> (RX) channel conversions **********/ + +/* RX channels are 10 bit integers, these fns are quite paranoid */ + +static inline int channel_to_vpci (const u16 channel, short * vpi, int * vci) { + unsigned short vci_bits = 10 - vpi_bits; + if ((channel & RX_CHANNEL_MASK) == channel) { + *vci = channel & ((~0)<> vci_bits; + return channel ? 0 : -EINVAL; + } + return -EINVAL; +} + +static inline int vpci_to_channel (u16 * channel, const short vpi, const int vci) { + unsigned short vci_bits = 10 - vpi_bits; + if (0 <= vpi && vpi < 1<>RX_Q_ENTRY_CHANNEL_SHIFT) & RX_CHANNEL_MASK; +} + +/* Cell Transmit Rate Values + * + * the cell transmit rate (cells per sec) can be set to a variety of + * different values by specifying two parameters: a timer preload from + * 1 to 16 (stored as 0 to 15) and a clock divider (2 to the power of + * an exponent from 0 to 14; the special value 15 disables the timer). + * + * cellrate = baserate / (preload * 2^divider) + * + * The maximum cell rate that can be specified is therefore just the + * base rate. Halving the preload is equivalent to adding 1 to the + * divider and so values 1 to 8 of the preload are redundant except + * in the case of a maximal divider (14). + * + * Given a desired cell rate, an algorithm to determine the preload + * and divider is: + * + * a) x = baserate / cellrate, want p * 2^d = x (as far as possible) + * b) if x > 16 * 2^14 then set p = 16, d = 14 (min rate), done + * if x <= 16 then set p = x, d = 0 (high rates), done + * c) now have 16 < x <= 2^18, or 1 < x/16 <= 2^14 and we want to + * know n such that 2^(n-1) < x/16 <= 2^n, so slide a bit until + * we find the range (n will be between 1 and 14), set d = n + * d) Also have 8 < x/2^n <= 16, so set p nearest x/2^n + * + * The algorithm used below is a minor variant of the above. + * + * The base rate is derived from the oscillator frequency (Hz) using a + * fixed divider: + * + * baserate = freq / 32 in the case of some Unknown Card + * baserate = freq / 8 in the case of the Horizon 25 + * baserate = freq / 8 in the case of the Horizon Ultra 155 + * + * The Horizon cards have oscillators and base rates as follows: + * + * Card Oscillator Base Rate + * Unknown Card 33 MHz 1.03125 MHz (33 MHz = PCI freq) + * Horizon 25 32 MHz 4 MHz + * Horizon Ultra 155 40 MHz 5 MHz + * + * The following defines give the base rates in Hz. These were + * previously a factor of 100 larger, no doubt someone was using + * cps*100. + */ + +#define BR_UKN 1031250l +#define BR_HRZ 4000000l +#define BR_ULT 5000000l + +// d is an exponent +#define CR_MIND 0 +#define CR_MAXD 14 + +// p ranges from 1 to a power of 2 +#define CR_MAXPEXP 4 + +static int make_rate (const hrz_dev * dev, u32 c, rounding r, + u16 * bits, unsigned int * actual) { + + // note: rounding the rate down means rounding 'p' up + + const unsigned long br = test_bit (ultra, &dev->flags) ? BR_ULT : BR_HRZ; + + u32 div = CR_MIND; + u32 pre; + + // local fn to build the timer bits + inline int set_cr (void) { + // paranoia + if (div > CR_MAXD || (!pre) || pre > 1<> 1; + ++br_exp; + } + // (br >>br_exp) <rx_descs[channel]; + + PRINTD (DBG_FLOW, "hrz_open_rx %x", channel); + + spin_lock_irqsave (&dev->mem_lock, flags); + channel_type = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; + spin_unlock_irqrestore (&dev->mem_lock, flags); + + // very serious error, should never occur + if (channel_type != RX_CHANNEL_DISABLED) { + PRINTD (DBG_ERR|DBG_VCC, "RX channel for VC already open"); + return -EBUSY; // clean up? + } + + // Give back spare buffer + if (dev->noof_spare_buffers) { + buf_ptr = dev->spare_buffers[--dev->noof_spare_buffers]; + PRINTD (DBG_VCC, "using a spare buffer: %u", buf_ptr); + // should never occur + if (buf_ptr == RX_CHANNEL_DISABLED || buf_ptr == RX_CHANNEL_IDLE) { + // but easy to recover from + PRINTD (DBG_ERR|DBG_VCC, "bad spare buffer pointer, using IDLE"); + buf_ptr = RX_CHANNEL_IDLE; + } + } else { + PRINTD (DBG_VCC, "using IDLE buffer pointer"); + } + + // Channel is currently disabled so change its status to idle + + // do we really need to save the flags again? + spin_lock_irqsave (&dev->mem_lock, flags); + + wr_mem (dev, &rx_desc->wr_buf_type, + buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME); + if (buf_ptr != RX_CHANNEL_IDLE) + wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr); + + spin_unlock_irqrestore (&dev->mem_lock, flags); + + // rxer->rate = make_rate (qos->peak_cells); + + PRINTD (DBG_FLOW, "hrz_open_rx ok"); + + return 0; +} + +#if 0 +/********** change vc rate for a given vc **********/ + +static void hrz_change_vc_qos (ATM_RXER * rxer, MAAL_QOS * qos) { + rxer->rate = make_rate (qos->peak_cells); +} +#endif + +/********** free an skb (as per ATM device driver documentation) **********/ + +static inline void hrz_kfree_skb (struct sk_buff * skb) { + if (ATM_SKB(skb)->vcc->pop) { + ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); + } else { + dev_kfree_skb (skb); + } +} + +/********** cancel listen on a VC **********/ + +static void hrz_close_rx (hrz_dev * dev, u16 vc) { + unsigned long flags; + + u32 value; + + u32 r1, r2; + + rx_ch_desc * rx_desc = &memmap->rx_descs[vc]; + + int was_idle = 0; + + spin_lock_irqsave (&dev->mem_lock, flags); + value = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; + spin_unlock_irqrestore (&dev->mem_lock, flags); + + if (value == RX_CHANNEL_DISABLED) { + // I suppose this could happen once we deal with _NONE traffic properly + PRINTD (DBG_VCC, "closing VC: RX channel %u already disabled", vc); + return; + } + if (value == RX_CHANNEL_IDLE) + was_idle = 1; + + spin_lock_irqsave (&dev->mem_lock, flags); + + for (;;) { + wr_mem (dev, &rx_desc->wr_buf_type, RX_CHANNEL_DISABLED); + + if ((rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK) == RX_CHANNEL_DISABLED) + break; + + was_idle = 0; + } + + if (was_idle) { + spin_unlock_irqrestore (&dev->mem_lock, flags); + return; + } + + WAIT_FLUSH_RX_COMPLETE(dev); + + // XXX Is this all really necessary? We can rely on the rx_data_av + // handler to discard frames that remain queued for delivery. If the + // worry is that immediately reopening the channel (perhaps by a + // different process) may cause some data to be mis-delivered then + // there may still be a simpler solution (such as busy-waiting on + // rx_busy once the channel is disabled or before a new one is + // opened - does this leave any holes?). Arguably setting up and + // tearing down the TX and RX halves of each virtual circuit could + // most safely be done within ?x_busy protected regions. + + // OK, current changes are that Simon's marker is disabled and we DO + // look for NULL rxer elsewhere. The code here seems flush frames + // and then remember the last dead cell belonging to the channel + // just disabled - the cell gets relinked at the next vc_open. + // However, when all VCs are closed or only a few opened there are a + // handful of buffers that are unusable. + + // Does anyone feel like documenting spare_buffers properly? + // Does anyone feel like fixing this in a nicer way? + + // Flush any data which is left in the channel + for (;;) { + // Change the rx channel port to something different to the RX + // channel we are trying to close to force Horizon to flush the rx + // channel read and write pointers. + + u16 other = vc^(RX_CHANS/2); + + SELECT_RX_CHANNEL (dev, other); + WAIT_UPDATE_COMPLETE (dev); + + r1 = rd_mem (dev, &rx_desc->rd_buf_type); + + // Select this RX channel. Flush doesn't seem to work unless we + // select an RX channel before hand + + SELECT_RX_CHANNEL (dev, vc); + WAIT_UPDATE_COMPLETE (dev); + + // Attempt to flush a frame on this RX channel + + FLUSH_RX_CHANNEL (dev, vc); + WAIT_FLUSH_RX_COMPLETE (dev); + + // Force Horizon to flush rx channel read and write pointers as before + + SELECT_RX_CHANNEL (dev, other); + WAIT_UPDATE_COMPLETE (dev); + + r2 = rd_mem (dev, &rx_desc->rd_buf_type); + + PRINTD (DBG_VCC|DBG_RX, "r1 = %u, r2 = %u", r1, r2); + + if (r1 == r2) { + dev->spare_buffers[dev->noof_spare_buffers++] = (u16)r1; + break; + } + } + +#if 0 + { + rx_q_entry * wr_ptr = &memmap->rx_q_entries[rd_regw (dev, RX_QUEUE_WR_PTR_OFF)]; + rx_q_entry * rd_ptr = dev->rx_q_entry; + + PRINTD (DBG_VCC|DBG_RX, "rd_ptr = %u, wr_ptr = %u", rd_ptr, wr_ptr); + + while (rd_ptr != wr_ptr) { + u32 x = rd_mem (dev, (HDW *) rd_ptr); + + if (vc == rx_q_entry_to_rx_channel (x)) { + x |= SIMONS_DODGEY_MARKER; + + PRINTD (DBG_RX|DBG_VCC|DBG_WARN, "marking a frame as dodgey"); + + wr_mem (dev, (HDW *) rd_ptr, x); + } + + if (rd_ptr == dev->rx_q_wrap) + rd_ptr = dev->rx_q_reset; + else + rd_ptr++; + } + } +#endif + + spin_unlock_irqrestore (&dev->mem_lock, flags); + + return; +} + +/********** schedule RX transfers **********/ + +// Note on tail recursion: a GCC developer said that it is not likely +// to be fixed soon, so do not define TAILRECUSRIONWORKS unless you +// are sure it does as you may otherwise overflow the kernel stack. + +// giving this fn a return value would help GCC, alledgedly + +static void rx_schedule (hrz_dev * dev, int irq) { + unsigned int rx_bytes; + + int pio_instead; +#ifndef TAILRECURSIONWORKS + do { +#endif + pio_instead = 0; + + // bytes waiting for RX transfer + rx_bytes = dev->rx_bytes; + +#if 0 + spin_count = 0; + while (rd_regl (dev, MASTER_RX_COUNT_REG_OFF)) { + PRINTD (DBG_RX|DBG_WARN, "RX error: other PCI Bus Master RX still in progress!"); + if (++spin_count > 10) { + PRINTD (DBG_RX|DBG_ERR, "spun out waiting PCI Bus Master RX completion"); + wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); + clear_bit (rx_busy, &dev->flags); + hrz_kfree_skb (dev->rx_skb); + return; + } + } +#endif + + // this code follows the TX code but (at the moment) there is only + // one region - the skb itself. I don't know if this will change, + // but it doesn't hurt to have the code here, disabled. + + if (rx_bytes) { + // start next transfer within same region + if (rx_bytes <= MAX_PIO_COUNT) { + PRINTD (DBG_RX|DBG_BUS, "(pio)"); + pio_instead = 1; + } + if (rx_bytes <= MAX_TRANSFER_COUNT) { + PRINTD (DBG_RX|DBG_BUS, "(simple or last multi)"); + dev->rx_bytes = 0; + } else { + PRINTD (DBG_RX|DBG_BUS, "(continuing multi)"); + dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; + rx_bytes = MAX_TRANSFER_COUNT; + } + } else { + // rx_bytes == 0 -- we're between regions + // regions remaining to transfer +#if 0 + unsigned int rx_regions = dev->rx_regions; +#else + unsigned int rx_regions = 0; +#endif + + if (rx_regions) { +#if 0 + // start a new region + dev->rx_addr = dev->rx_iovec->iov_base; + rx_bytes = dev->rx_iovec->iov_len; + ++dev->rx_iovec; + dev->rx_regions = rx_regions - 1; + + if (rx_bytes <= MAX_PIO_COUNT) { + PRINTD (DBG_RX|DBG_BUS, "(pio)"); + pio_instead = 1; + } + if (rx_bytes <= MAX_TRANSFER_COUNT) { + PRINTD (DBG_RX|DBG_BUS, "(full region)"); + dev->rx_bytes = 0; + } else { + PRINTD (DBG_RX|DBG_BUS, "(start multi region)"); + dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; + rx_bytes = MAX_TRANSFER_COUNT; + } +#endif + } else { + // rx_regions == 0 + // that's all folks - end of frame + struct sk_buff * skb = dev->rx_skb; + // dev->rx_iovec = 0; + + FLUSH_RX_CHANNEL (dev, dev->rx_channel); + + dump_skb ("<<<", dev->rx_channel, skb); + + PRINTD (DBG_RX|DBG_SKB, "push %p %u", skb->data, skb->len); + + { + struct atm_vcc * vcc = ATM_SKB(skb)->vcc; + // VC layer stats + vcc->stats->rx++; + skb->stamp = xtime; + // end of our responsability + vcc->push (vcc, skb); + } + } + } + + // note: writing RX_COUNT clears any interrupt condition + if (rx_bytes) { + if (pio_instead) { + if (irq) + wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); + rds_regb (dev, DATA_PORT_OFF, dev->rx_addr, rx_bytes); + } else { + wr_regl (dev, MASTER_RX_ADDR_REG_OFF, virt_to_bus (dev->rx_addr)); + wr_regl (dev, MASTER_RX_COUNT_REG_OFF, rx_bytes); + } + dev->rx_addr += rx_bytes; + } else { + if (irq) + wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); + // allow another RX thread to start + YELLOW_LED_ON(dev); + clear_bit (rx_busy, &dev->flags); + PRINTD (DBG_RX, "cleared rx_busy for dev %p", dev); + } + +#ifdef TAILRECURSIONWORKS + // and we all bless optimised tail calls + if (pio_instead) + rx_schedule (dev, 0); + return; +#else + // grrrrrrr! + irq = 0; + } while (pio_instead); + return; +#endif +} + +/********** handle RX bus master complete events **********/ + +static inline void rx_bus_master_complete_handler (hrz_dev * dev) { + if (test_bit (rx_busy, &dev->flags)) { + rx_schedule (dev, 1); + } else { + PRINTD (DBG_RX|DBG_ERR, "unexpected RX bus master completion"); + // clear interrupt condition on adapter + wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); + } + return; +} + +/********** (queue to) become the next TX thread **********/ + +static inline int tx_hold (hrz_dev * dev) { + while (test_and_set_bit (tx_busy, &dev->flags)) { + PRINTD (DBG_TX, "sleeping at tx lock %p %u", dev, dev->flags); + interruptible_sleep_on (&dev->tx_queue); + PRINTD (DBG_TX, "woken at tx lock %p %u", dev, dev->flags); + if (signal_pending (current)) + return -1; + } + PRINTD (DBG_TX, "set tx_busy for dev %p", dev); + return 0; +} + +/********** allow another TX thread to start **********/ + +static inline void tx_release (hrz_dev * dev) { + clear_bit (tx_busy, &dev->flags); + PRINTD (DBG_TX, "cleared tx_busy for dev %p", dev); + wake_up_interruptible (&dev->tx_queue); +} + +/********** schedule TX transfers **********/ + +static void tx_schedule (hrz_dev * const dev, int irq) { + unsigned int tx_bytes; + + int append_desc = 0; + + int pio_instead; +#ifndef TAILRECURSIONWORKS + do { +#endif + pio_instead = 0; + // bytes in current region waiting for TX transfer + tx_bytes = dev->tx_bytes; + +#if 0 + spin_count = 0; + while (rd_regl (dev, MASTER_TX_COUNT_REG_OFF)) { + PRINTD (DBG_TX|DBG_WARN, "TX error: other PCI Bus Master TX still in progress!"); + if (++spin_count > 10) { + PRINTD (DBG_TX|DBG_ERR, "spun out waiting PCI Bus Master TX completion"); + wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); + tx_release (dev); + hrz_kfree_skb (dev->tx_skb); + return; + } + } +#endif + + if (tx_bytes) { + // start next transfer within same region + if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { + PRINTD (DBG_TX|DBG_BUS, "(pio)"); + pio_instead = 1; + } + if (tx_bytes <= MAX_TRANSFER_COUNT) { + PRINTD (DBG_TX|DBG_BUS, "(simple or last multi)"); + if (!dev->tx_iovec) { + // end of last region + append_desc = 1; + } + dev->tx_bytes = 0; + } else { + PRINTD (DBG_TX|DBG_BUS, "(continuing multi)"); + dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; + tx_bytes = MAX_TRANSFER_COUNT; + } + } else { + // tx_bytes == 0 -- we're between regions + // regions remaining to transfer + unsigned int tx_regions = dev->tx_regions; + + if (tx_regions) { + // start a new region + dev->tx_addr = dev->tx_iovec->iov_base; + tx_bytes = dev->tx_iovec->iov_len; + ++dev->tx_iovec; + dev->tx_regions = tx_regions - 1; + + if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { + PRINTD (DBG_TX|DBG_BUS, "(pio)"); + pio_instead = 1; + } + if (tx_bytes <= MAX_TRANSFER_COUNT) { + PRINTD (DBG_TX|DBG_BUS, "(full region)"); + dev->tx_bytes = 0; + } else { + PRINTD (DBG_TX|DBG_BUS, "(start multi region)"); + dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; + tx_bytes = MAX_TRANSFER_COUNT; + } + } else { + // tx_regions == 0 + // that's all folks - end of frame + struct sk_buff * skb = dev->tx_skb; + dev->tx_iovec = 0; + + // VC layer stats + ATM_SKB(skb)->vcc->stats->tx++; + + // free the skb + hrz_kfree_skb (skb); + } + } + + // note: writing TX_COUNT clears any interrupt condition + if (tx_bytes) { + if (pio_instead) { + if (irq) + wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); + wrs_regb (dev, DATA_PORT_OFF, dev->tx_addr, tx_bytes); + if (append_desc) + wr_regl (dev, TX_DESCRIPTOR_PORT_OFF, cpu_to_be32 (dev->tx_skb->len)); + } else { + wr_regl (dev, MASTER_TX_ADDR_REG_OFF, virt_to_bus (dev->tx_addr)); + if (append_desc) + wr_regl (dev, TX_DESCRIPTOR_REG_OFF, cpu_to_be32 (dev->tx_skb->len)); + wr_regl (dev, MASTER_TX_COUNT_REG_OFF, + append_desc + ? tx_bytes | MASTER_TX_AUTO_APPEND_DESC + : tx_bytes); + } + dev->tx_addr += tx_bytes; + } else { + if (irq) + wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); + YELLOW_LED_ON(dev); + tx_release (dev); + } + +#ifdef TAILRECURSIONWORKS + // and we all bless optimised tail calls + if (pio_instead) + tx_schedule (dev, 0); + return; +#else + // grrrrrrr! + irq = 0; + } while (pio_instead); + return; +#endif +} + +/********** handle TX bus master complete events **********/ + +static inline void tx_bus_master_complete_handler (hrz_dev * dev) { + if (test_bit (tx_busy, &dev->flags)) { + tx_schedule (dev, 1); + } else { + PRINTD (DBG_TX|DBG_ERR, "unexpected TX bus master completion"); + // clear interrupt condition on adapter + wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); + } + return; +} + +/********** move RX Q pointer to next item in circular buffer **********/ + +// called only from IRQ sub-handler +static inline u32 rx_queue_entry_next (hrz_dev * dev) { + u32 rx_queue_entry; + spin_lock (&dev->mem_lock); + rx_queue_entry = rd_mem (dev, &dev->rx_q_entry->entry); + if (dev->rx_q_entry == dev->rx_q_wrap) + dev->rx_q_entry = dev->rx_q_reset; + else + dev->rx_q_entry++; + wr_regw (dev, RX_QUEUE_RD_PTR_OFF, dev->rx_q_entry - dev->rx_q_reset); + spin_unlock (&dev->mem_lock); + return rx_queue_entry; +} + +/********** handle RX disabled by device **********/ + +static inline void rx_disabled_handler (hrz_dev * dev) { + wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE); + // count me please + PRINTK (KERN_WARNING, "RX was disabled!"); +} + +/********** handle RX data received by device **********/ + +// called from IRQ handler +static inline void rx_data_av_handler (hrz_dev * dev) { + u32 rx_queue_entry; + u32 rx_queue_entry_flags; + u16 rx_len; + u16 rx_channel; + + PRINTD (DBG_FLOW, "hrz_data_av_handler"); + + // try to grab rx lock (not possible during RX bus mastering) + if (test_and_set_bit (rx_busy, &dev->flags)) { + PRINTD (DBG_RX, "locked out of rx lock"); + return; + } + PRINTD (DBG_RX, "set rx_busy for dev %p", dev); + // lock is cleared if we fail now, o/w after bus master completion + + YELLOW_LED_OFF(dev); + + rx_queue_entry = rx_queue_entry_next (dev); + + rx_len = rx_q_entry_to_length (rx_queue_entry); + rx_channel = rx_q_entry_to_rx_channel (rx_queue_entry); + + WAIT_FLUSH_RX_COMPLETE (dev); + + SELECT_RX_CHANNEL (dev, rx_channel); + + PRINTD (DBG_RX, "rx_queue_entry is: %#x", rx_queue_entry); + rx_queue_entry_flags = rx_queue_entry & (RX_CRC_32_OK|RX_COMPLETE_FRAME|SIMONS_DODGEY_MARKER); + + if (!rx_len) { + // (at least) bus-mastering breaks if we try to handle a + // zero-length frame, besides AAL5 does not support them + PRINTK (KERN_ERR, "zero-length frame!"); + rx_queue_entry_flags &= ~RX_COMPLETE_FRAME; + } + + if (rx_queue_entry_flags & SIMONS_DODGEY_MARKER) { + PRINTD (DBG_RX|DBG_ERR, "Simon's marker detected!"); + } + if (rx_queue_entry_flags == (RX_CRC_32_OK | RX_COMPLETE_FRAME)) { + struct atm_vcc * atm_vcc; + + PRINTD (DBG_RX, "got a frame on rx_channel %x len %u", rx_channel, rx_len); + + atm_vcc = dev->rxer[rx_channel]; + // if no vcc is assigned to this channel, we should drop the frame + // (is this what SIMONS etc. was trying to achieve?) + + if (atm_vcc) { + + if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { + + if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { + + // If everyone has to call atm_pdu2... why isn't it part of + // atm_charge? B'cos some people already have skb->truesize! + if (atm_charge (atm_vcc, atm_pdu2truesize (rx_len))) { + + struct sk_buff * skb = alloc_skb (rx_len, GFP_ATOMIC); + if (skb) { + // remember this so we can push it later + dev->rx_skb = skb; + // remember this so we can flush it later + dev->rx_channel = rx_channel; + + // prepare socket buffer + skb_put (skb, rx_len); + ATM_SKB(skb)->vcc = atm_vcc; + + // simple transfer + // dev->rx_regions = 0; + // dev->rx_iovec = 0; + dev->rx_bytes = rx_len; + dev->rx_addr = skb->data; + PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)", + skb->data, rx_len); + + // do the business + rx_schedule (dev, 0); + return; + + } else { + PRINTD (DBG_SKB|DBG_WARN, "failed to get skb"); + atm_vcc->stats->rx_drop++; + } + + } else { + // someone fix this (message), please! + PRINTD (DBG_INFO, "dropped thanks to atm_charge"); + // drop stats incremented in atm_charge + } + + } else { + PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel); + // do we count this? + } + + } else { + PRINTK (KERN_WARNING, "dropped over-size frame"); + // do we count this? + } + + } else { + PRINTD (DBG_WARN|DBG_VCC|DBG_RX, "no VCC for this frame (VC closed)"); + // do we count this? + } + + } else { + // Wait update complete ? SPONG + } + + // RX was aborted + YELLOW_LED_ON(dev); + + FLUSH_RX_CHANNEL (dev,rx_channel); + clear_bit (rx_busy, &dev->flags); + + return; +} + +/********** interrupt handler **********/ + +static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) { + hrz_dev * dev = hrz_devs; + u32 int_source; + unsigned int irq_ok; + (void) pt_regs; + + PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id); + + if (!dev_id) { + PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq); + return; + } + // Did one of our cards generate the interrupt? + while (dev) { + if (dev == dev_id) + break; + dev = dev->prev; + } + if (!dev) { + PRINTD (DBG_IRQ, "irq not for me: %d", irq); + return; + } + if (irq != dev->irq) { + PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq); + return; + } + + // definitely for us + irq_ok = 0; + while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF) + & INTERESTING_INTERRUPTS)) { + // In the interests of fairness, the (inline) handlers below are + // called in sequence and without immediate return to the head of + // the while loop. This is only of issue for slow hosts (or when + // debugging messages are on). Really slow hosts may find a fast + // sender keeps them permanently in the IRQ handler. :( + + // (only an issue for slow hosts) RX completion goes before + // rx_data_av as the former implies rx_busy and so the latter + // would just abort. If it reschedules another transfer + // (continuing the same frame) then it will not clear rx_busy. + + // (only an issue for slow hosts) TX completion goes before RX + // data available as it is a much shorter routine - there is the + // chance that any further transfers it schedules will be complete + // by the time of the return to the head of the while loop + + if (int_source & RX_BUS_MASTER_COMPLETE) { + ++irq_ok; + PRINTD (DBG_IRQ|DBG_BUS|DBG_RX, "rx_bus_master_complete asserted"); + rx_bus_master_complete_handler (dev); + } + if (int_source & TX_BUS_MASTER_COMPLETE) { + ++irq_ok; + PRINTD (DBG_IRQ|DBG_BUS|DBG_TX, "tx_bus_master_complete asserted"); + tx_bus_master_complete_handler (dev); + } + if (int_source & RX_DATA_AV) { + ++irq_ok; + PRINTD (DBG_IRQ|DBG_RX, "rx_data_av asserted"); + rx_data_av_handler (dev); + } + } + if (irq_ok) { + PRINTD (DBG_IRQ, "work done: %u", irq_ok); + } else { + PRINTD (DBG_IRQ|DBG_WARN, "spurious interrupt source: %#x", int_source); + } + + PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id); +} + +/********** housekeeping **********/ + +static void set_timer (struct timer_list * timer, unsigned int delay) { + timer->expires = jiffies + delay; + add_timer (timer); + return; +} + +static void do_housekeeping (unsigned long arg) { + // just stats at the moment + hrz_dev * dev = hrz_devs; + (void) arg; + // data is set to zero at module unload + if (housekeeping.data) { + while (dev) { + // collect device-specific (not driver/atm-linux) stats here + dev->tx_cell_count += rd_regw (dev, TX_CELL_COUNT_OFF); + dev->rx_cell_count += rd_regw (dev, RX_CELL_COUNT_OFF); + dev->hec_error_count += rd_regw (dev, HEC_ERROR_COUNT_OFF); + dev->unassigned_cell_count += rd_regw (dev, UNASSIGNED_CELL_COUNT_OFF); + dev = dev->prev; + } + set_timer (&housekeeping, HZ/10); + } + return; +} + +/********** find an idle channel for TX and set it up **********/ + +// called with tx_busy set +static inline short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { + unsigned short idle_channels; + short tx_channel = -1; + unsigned int spin_count; + PRINTD (DBG_FLOW|DBG_TX, "setup_idle_tx_channel %p", dev); + + // better would be to fail immediately, the caller can then decide whether + // to wait or drop (depending on whether this is UBR etc.) + spin_count = 0; + while (!(idle_channels = rd_regw (dev, TX_STATUS_OFF) & IDLE_CHANNELS_MASK)) { + PRINTD (DBG_TX|DBG_WARN, "waiting for idle TX channel"); + // delay a bit here + if (++spin_count > 100) { + PRINTD (DBG_TX|DBG_ERR, "spun out waiting for idle TX channel"); + return -EBUSY; + } + } + + // got an idle channel + { + // tx_idle ensures we look for idle channels in RR order + int chan = dev->tx_idle; + + int keep_going = 1; + while (keep_going) { + if (idle_channels & (1<tx_idle = chan; + } + + // set up the channel we found + { + // Initialise the cell header in the transmit channel descriptor + // a.k.a. prepare the channel and remember that we have done so. + + tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel]; + u16 rd_ptr; + u16 wr_ptr; + u16 channel = vcc->channel; + + unsigned long flags; + spin_lock_irqsave (&dev->mem_lock, flags); + + // Update the transmit channel record. + dev->tx_channel_record[tx_channel] = channel; + + // xBR channel + update_tx_channel_config (dev, tx_channel, RATE_TYPE_ACCESS, + vcc->tx_xbr_bits); + + // Update the PCR counter preload value etc. + update_tx_channel_config (dev, tx_channel, PCR_TIMER_ACCESS, + vcc->tx_pcr_bits); + +#if 0 + if (a vbr channel) { + // SCR timer + update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS, + vcc->tx_scr_bits); + + // Bucket size... + update_tx_channel_config (dev, tx_channel, BUCKET_CAPACITY_ACCESS, + vcc->tx_bucket_bits); + + // ... and fullness + update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS, + vcc->tx_bucket_bits); + } +#endif + + // Initialise the read and write buffer pointers + rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK; + wr_ptr = rd_mem (dev, &tx_desc->wr_buf_type) & BUFFER_PTR_MASK; + + // idle TX channels should have identical pointers + if (rd_ptr != wr_ptr) { + PRINTD (DBG_TX|DBG_ERR, "TX buffer pointers are broken!"); + // spin_unlock... return -E... + // I wonder if gcc would get rid of one of the pointer aliases + } + PRINTD (DBG_TX, "TX buffer pointers are: rd %x, wr %x.", + rd_ptr, wr_ptr); + + switch (vcc->aal) { + case aal0: + PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal0"); + rd_ptr |= CHANNEL_TYPE_RAW_CELLS; + wr_ptr |= CHANNEL_TYPE_RAW_CELLS; + break; + case aal34: + PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal34"); + rd_ptr |= CHANNEL_TYPE_AAL3_4; + wr_ptr |= CHANNEL_TYPE_AAL3_4; + break; + case aal5: + rd_ptr |= CHANNEL_TYPE_AAL5; + wr_ptr |= CHANNEL_TYPE_AAL5; + // Initialise the CRC + wr_mem (dev, &tx_desc->partial_crc, INITIAL_CRC); + break; + } + + wr_mem (dev, &tx_desc->rd_buf_type, rd_ptr); + wr_mem (dev, &tx_desc->wr_buf_type, wr_ptr); + + // Write the Cell Header + // Payload Type, CLP and GFC would go here if non-zero + wr_mem (dev, &tx_desc->cell_header, channel); + + spin_unlock_irqrestore (&dev->mem_lock, flags); + } + + return tx_channel; +} + +/********** send a frame **********/ + +static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { + unsigned int spin_count; + int free_buffers; + hrz_dev * dev = HRZ_DEV(atm_vcc->dev); + hrz_vcc * vcc = HRZ_VCC(atm_vcc); + u16 channel = vcc->channel; + + u32 buffers_required; + + /* signed for error return */ + short tx_channel; + + PRINTD (DBG_FLOW|DBG_TX, "hrz_send vc %x data %p len %u", + channel, skb->data, skb->len); + + dump_skb (">>>", channel, skb); + + if (atm_vcc->qos.txtp.traffic_class == ATM_NONE) { + PRINTK (KERN_ERR, "attempt to send on RX-only VC %x", channel); + hrz_kfree_skb (skb); + return -EIO; + } + + // don't understand this + ATM_SKB(skb)->vcc = atm_vcc; + + if (skb->len > atm_vcc->qos.txtp.max_sdu) { + PRINTK (KERN_ERR, "sk_buff length greater than agreed max_sdu, dropping..."); + hrz_kfree_skb (skb); + return -EIO; + } + + if (!channel) { + PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel"); + return -EIO; + } + +#if 0 + { + // where would be a better place for this? housekeeping? + u16 status; + pci_read_config_word (dev->pci_dev, PCI_STATUS, &status); + if (status & PCI_STATUS_REC_MASTER_ABORT) { + PRINTD (DBG_BUS|DBG_ERR, "Clearing PCI Master Abort (and cleaning up)"); + status &= ~PCI_STATUS_REC_MASTER_ABORT; + pci_write_config_word (dev->pci_dev, PCI_STATUS, status); + if (test_bit (tx_busy, &dev->flags)) { + hrz_kfree_skb (dev->tx_skb); + tx_release (dev); + } + } + } +#endif + +#ifdef DEBUG_HORIZON + /* wey-hey! */ + if (channel == 1023) { + unsigned int i; + unsigned short d = 0; + char * s = skb->data; + if (*s++ == 'D') { + for (i = 0; i < 4; ++i) { + d = (d<<4) | ((*s <= '9') ? (*s - '0') : (*s - 'a' + 10)); + ++s; + } + PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d); + } + } +#endif + + // wait until TX is free and grab lock + if (tx_hold (dev)) + return -ERESTARTSYS; + + // Wait for enough space to be available in transmit buffer memory. + + // should be number of cells needed + 2 (according to hardware docs) + // = ((framelen+8)+47) / 48 + 2 + // = (framelen+7) / 48 + 3, hmm... faster to put addition inside XXX + buffers_required = (skb->len+(ATM_AAL5_TRAILER-1)) / ATM_CELL_PAYLOAD + 3; + + // replace with timer and sleep, add dev->tx_buffers_queue (max 1 entry) + spin_count = 0; + while ((free_buffers = rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF)) < buffers_required) { + PRINTD (DBG_TX, "waiting for free TX buffers, got %d of %d", + free_buffers, buffers_required); + // what is the appropriate delay? implement a timeout? (depending on line speed?) + // mdelay (1); + // what happens if kill (current_pid, SIGKILL) ? + schedule(); + if (++spin_count > 1000) { + PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d", + free_buffers, buffers_required); + tx_release (dev); + return -ERESTARTSYS; + } + } + + // Select a channel to transmit the frame on. + if (channel == dev->last_vc) { + PRINTD (DBG_TX, "last vc hack: hit"); + tx_channel = dev->tx_last; + } else { + PRINTD (DBG_TX, "last vc hack: miss"); + // Are we currently transmitting this VC on one of the channels? + for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel) + if (dev->tx_channel_record[tx_channel] == channel) { + PRINTD (DBG_TX, "vc already on channel: hit"); + break; + } + if (tx_channel == TX_CHANS) { + PRINTD (DBG_TX, "vc already on channel: miss"); + // Find and set up an idle channel. + tx_channel = setup_idle_tx_channel (dev, vcc); + if (tx_channel < 0) { + PRINTD (DBG_TX|DBG_ERR, "failed to get channel"); + tx_release (dev); + return tx_channel; + } + } + + PRINTD (DBG_TX, "got channel"); + SELECT_TX_CHANNEL(dev, tx_channel); + + dev->last_vc = channel; + dev->tx_last = tx_channel; + } + + PRINTD (DBG_TX, "using channel %u", tx_channel); + + YELLOW_LED_OFF(dev); + + // TX start transfer + + { + unsigned int tx_len = skb->len; + unsigned int tx_iovcnt = ATM_SKB(skb)->iovcnt; + // remember this so we can free it later + dev->tx_skb = skb; + + if (tx_iovcnt) { + // scatter gather transfer + dev->tx_regions = tx_iovcnt; + dev->tx_iovec = (struct iovec *) skb->data; + dev->tx_bytes = 0; + PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", + skb->data, tx_len); + } else { + // simple transfer + dev->tx_regions = 0; + dev->tx_iovec = 0; + dev->tx_bytes = tx_len; + dev->tx_addr = skb->data; + PRINTD (DBG_TX|DBG_BUS, "TX start simple transfer (addr %p, len %d)", + skb->data, tx_len); + } + + // and do the business + tx_schedule (dev, 0); + + } + + return 0; +} + +/********** reset a card **********/ + +static void __init hrz_reset_card (const hrz_dev * dev) { + u32 control_0_reg = rd_regl (dev, CONTROL_0_REG); + + // why not set RESET_HORIZON to one and wait for the card to + // reassert that bit as zero? Like so: + control_0_reg = control_0_reg & RESET_HORIZON; + wr_regl (dev, CONTROL_0_REG, control_0_reg); + while (control_0_reg & RESET_HORIZON) + control_0_reg = rd_regl (dev, CONTROL_0_REG); + + // old reset code retained: + wr_regl (dev, CONTROL_0_REG, control_0_reg | + RESET_ATM | RESET_RX | RESET_TX | RESET_HOST); + // just guessing here + udelay (1000); + + wr_regl (dev, CONTROL_0_REG, control_0_reg); +} + +/********** shutdown a card **********/ + +#ifdef MODULE + +static void hrz_shutdown (const hrz_dev * dev) { + hrz_reset_card (dev); + + GREEN_LED_OFF(dev); +} + +#endif + +/********** read the burnt in address **********/ + +static u16 __init read_bia (const hrz_dev * dev, u16 addr) { + + u32 ctrl = rd_regl (dev, CONTROL_0_REG); + + inline void WRITE_IT_WAIT (void) { + wr_regl (dev, CONTROL_0_REG, ctrl); + udelay (5); + } + + inline void CLOCK_IT (void) { + // DI must be valid around rising SK edge + ctrl &= ~SEEPROM_SK; + WRITE_IT_WAIT(); + ctrl |= SEEPROM_SK; + WRITE_IT_WAIT(); + } + + const unsigned int addr_bits = 6; + const unsigned int data_bits = 16; + + unsigned int i; + + u16 res; + + ctrl &= ~(SEEPROM_CS | SEEPROM_SK | SEEPROM_DI); + WRITE_IT_WAIT(); + + // wake Serial EEPROM and send 110 (READ) command + ctrl |= (SEEPROM_CS | SEEPROM_DI); + CLOCK_IT(); + + ctrl |= SEEPROM_DI; + CLOCK_IT(); + + ctrl &= ~SEEPROM_DI; + CLOCK_IT(); + + for (i=0; i> 1; + + CLOCK_IT(); + + if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO) + res |= (1 << (data_bits-1)); + } + + ctrl &= ~(SEEPROM_SK | SEEPROM_CS); + WRITE_IT_WAIT(); + + return res; +} + +/********** initialise a card **********/ + +static int __init hrz_init (hrz_dev * dev) { + int onefivefive; + + u16 chan; + + int buff_count; + + HDW * mem; + + cell_buf * tx_desc; + cell_buf * rx_desc; + + u32 ctrl; + + ctrl = rd_regl (dev, CONTROL_0_REG); + PRINTD (DBG_INFO, "ctrl0reg is %#x", ctrl); + onefivefive = ctrl & ATM_LAYER_STATUS; + + if (onefivefive) + printk (DEV_LABEL ": Horizon Ultra (at 155.52 MBps)"); + else + printk (DEV_LABEL ": Horizon (at 25 MBps)"); + + printk (":"); + // Reset the card to get everything in a known state + + printk (" reset"); + hrz_reset_card (dev); + + // Clear all the buffer memory + + printk (" clearing memory"); + + for (mem = (HDW *) memmap; mem < (HDW *) (memmap + 1); ++mem) + wr_mem (dev, mem, 0); + + printk (" tx channels"); + + // All transmit eight channels are set up as AAL5 ABR channels with + // a 16us cell spacing. Why? + + // Channel 0 gets the free buffer at 100h, channel 1 gets the free + // buffer at 110h etc. + + for (chan = 0; chan < TX_CHANS; ++chan) { + tx_ch_desc * tx_desc = &memmap->tx_descs[chan]; + cell_buf * buf = &memmap->inittxbufs[chan]; + + // initialise the read and write buffer pointers + wr_mem (dev, &tx_desc->rd_buf_type, BUF_PTR(buf)); + wr_mem (dev, &tx_desc->wr_buf_type, BUF_PTR(buf)); + + // set the status of the initial buffers to empty + wr_mem (dev, &buf->next, BUFF_STATUS_EMPTY); + } + + // Use space bufn3 at the moment for tx buffers + + printk (" tx buffers"); + + tx_desc = memmap->bufn3; + + wr_mem (dev, &memmap->txfreebufstart.next, BUF_PTR(tx_desc) | BUFF_STATUS_EMPTY); + + for (buff_count = 0; buff_count < BUFN3_SIZE-1; buff_count++) { + wr_mem (dev, &tx_desc->next, BUF_PTR(tx_desc+1) | BUFF_STATUS_EMPTY); + tx_desc++; + } + + wr_mem (dev, &tx_desc->next, BUF_PTR(&memmap->txfreebufend) | BUFF_STATUS_EMPTY); + + // Initialise the transmit free buffer count + wr_regw (dev, TX_FREE_BUFFER_COUNT_OFF, BUFN3_SIZE); + + printk (" rx channels"); + + // Initialise all of the receive channels to be AAL5 disabled with + // an interrupt threshold of 0 + + for (chan = 0; chan < RX_CHANS; ++chan) { + rx_ch_desc * rx_desc = &memmap->rx_descs[chan]; + + wr_mem (dev, &rx_desc->wr_buf_type, CHANNEL_TYPE_AAL5 | RX_CHANNEL_DISABLED); + } + + printk (" rx buffers"); + + // Use space bufn4 at the moment for rx buffers + + rx_desc = memmap->bufn4; + + wr_mem (dev, &memmap->rxfreebufstart.next, BUF_PTR(rx_desc) | BUFF_STATUS_EMPTY); + + for (buff_count = 0; buff_count < BUFN4_SIZE-1; buff_count++) { + wr_mem (dev, &rx_desc->next, BUF_PTR(rx_desc+1) | BUFF_STATUS_EMPTY); + + rx_desc++; + } + + wr_mem (dev, &rx_desc->next, BUF_PTR(&memmap->rxfreebufend) | BUFF_STATUS_EMPTY); + + // Initialise the receive free buffer count + wr_regw (dev, RX_FREE_BUFFER_COUNT_OFF, BUFN4_SIZE); + + // Initialize Horizons registers + + // TX config + wr_regw (dev, TX_CONFIG_OFF, + ABR_ROUND_ROBIN | TX_NORMAL_OPERATION | DRVR_DRVRBAR_ENABLE); + + // RX config. Use 10-x VC bits, x VP bits, non user cells in channel 0. + wr_regw (dev, RX_CONFIG_OFF, + DISCARD_UNUSED_VPI_VCI_BITS_SET | NON_USER_CELLS_IN_ONE_CHANNEL | vpi_bits); + + // RX line config + wr_regw (dev, RX_LINE_CONFIG_OFF, + LOCK_DETECT_ENABLE | FREQUENCY_DETECT_ENABLE | GXTALOUT_SELECT_DIV4); + + // Set the max AAL5 cell count to be just enough to contain the + // largest AAL5 frame that the user wants to receive + wr_regw (dev, MAX_AAL5_CELL_COUNT_OFF, + (max_rx_size + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD); + + // Enable receive + wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE); + + printk (" control"); + + // Drive the OE of the LEDs then turn the green LED on + ctrl |= GREEN_LED_OE | YELLOW_LED_OE | GREEN_LED | YELLOW_LED; + wr_regl (dev, CONTROL_0_REG, ctrl); + + // Test for a 155-capable card + + if (onefivefive) { + // Select 155 mode... make this a choice (or: how do we detect + // external line speed and switch?) + ctrl |= ATM_LAYER_SELECT; + wr_regl (dev, CONTROL_0_REG, ctrl); + + // test SUNI-lite vs SAMBA + + // Register 0x00 in the SUNI will have some of bits 3-7 set, and + // they will always be zero for the SAMBA. Ha! Bloody hardware + // engineers. It'll never work. + + if (rd_framer (dev, 0) & 0x00f0) { + // SUNI + printk (" SUNI"); + + // Reset, just in case + wr_framer (dev, 0x00, 0x0080); + wr_framer (dev, 0x00, 0x0000); + + // Configure transmit FIFO + wr_framer (dev, 0x63, rd_framer (dev, 0x63) | 0x0002); + + // Set line timed mode + wr_framer (dev, 0x05, rd_framer (dev, 0x05) | 0x0001); + } else { + // SAMBA + printk (" SAMBA"); + + // Reset, just in case + wr_framer (dev, 0, rd_framer (dev, 0) | 0x0001); + wr_framer (dev, 0, rd_framer (dev, 0) &~ 0x0001); + + // Turn off diagnostic loopback and enable line-timed mode + wr_framer (dev, 0, 0x0002); + + // Turn on transmit outputs + wr_framer (dev, 2, 0x0B80); + } + } else { + // Select 25 mode + ctrl &= ~ATM_LAYER_SELECT; + + // Madge B154 setup + // none required? + } + + printk (" LEDs"); + + GREEN_LED_ON(dev); + YELLOW_LED_ON(dev); + + printk (" ESI="); + + { + u16 b = 0; + int i; + u8 * esi = dev->atm_dev->esi; + + // in the card I have, EEPROM + // addresses 0, 1, 2 contain 0 + // addresess 5, 6 etc. contain ffff + // NB: Madge prefix is 00 00 f6 (which is 00 00 6f in Ethernet bit order) + // the read_bia routine gets the BIA in Ethernet bit order + + for (i=0; i < ESI_LEN; ++i) { + if (i % 2 == 0) + b = read_bia (dev, i/2 + 2); + else + b = b >> 8; + esi[i] = b & 0xFF; + printk ("%02x", esi[i]); + } + } + + // Enable RX_Q and ?X_COMPLETE interrupts only + wr_regl (dev, INT_ENABLE_REG_OFF, INTERESTING_INTERRUPTS); + printk (" IRQ on"); + + printk (".\n"); + + return onefivefive; +} + +/********** check max_sdu **********/ + +static int check_max_sdu (hrz_aal aal, struct atm_trafprm * tp, unsigned int max_frame_size) { + PRINTD (DBG_FLOW|DBG_QOS, "check_max_sdu"); + + switch (aal) { + case aal0: + if (!(tp->max_sdu)) { + PRINTD (DBG_QOS, "defaulting max_sdu"); + tp->max_sdu = ATM_AAL0_SDU; + } else if (tp->max_sdu != ATM_AAL0_SDU) { + PRINTD (DBG_QOS|DBG_ERR, "rejecting max_sdu"); + return -EINVAL; + } + break; + case aal34: + if (tp->max_sdu == 0 || tp->max_sdu > ATM_MAX_AAL34_PDU) { + PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); + tp->max_sdu = ATM_MAX_AAL34_PDU; + } + break; + case aal5: + if (tp->max_sdu == 0 || tp->max_sdu > max_frame_size) { + PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); + tp->max_sdu = max_frame_size; + } + break; + } + return 0; +} + +/********** check pcr **********/ + +// something like this should be part of ATM Linux +static int atm_pcr_check (struct atm_trafprm * tp, unsigned int pcr) { + // we are assuming non-UBR, and non-special values of pcr + if (tp->min_pcr == ATM_MAX_PCR) + PRINTD (DBG_QOS, "luser gave min_pcr = ATM_MAX_PCR"); + else if (tp->min_pcr < 0) + PRINTD (DBG_QOS, "luser gave negative min_pcr"); + else if (tp->min_pcr && tp->min_pcr > pcr) + PRINTD (DBG_QOS, "pcr less than min_pcr"); + else + // !! max_pcr = UNSPEC (0) is equivalent to max_pcr = MAX (-1) + // easier to #define ATM_MAX_PCR 0 and have all rates unsigned? + // [this would get rid of next two conditionals] + if ((0) && tp->max_pcr == ATM_MAX_PCR) + PRINTD (DBG_QOS, "luser gave max_pcr = ATM_MAX_PCR"); + else if ((tp->max_pcr != ATM_MAX_PCR) && tp->max_pcr < 0) + PRINTD (DBG_QOS, "luser gave negative max_pcr"); + else if (tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && tp->max_pcr < pcr) + PRINTD (DBG_QOS, "pcr greater than max_pcr"); + else { + // each limit unspecified or not violated + PRINTD (DBG_QOS, "xBR(pcr) OK"); + return 0; + } + PRINTD (DBG_QOS, "pcr=%u, tp: min_pcr=%d, pcr=%d, max_pcr=%d", + pcr, tp->min_pcr, tp->pcr, tp->max_pcr); + return -EINVAL; +} + +/********** open VC **********/ + +static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { + int error; + u16 channel; + + struct atm_qos * qos; + struct atm_trafprm * txtp; + struct atm_trafprm * rxtp; + + hrz_dev * dev = HRZ_DEV(atm_vcc->dev); + hrz_vcc vcc; + hrz_vcc * vccp; // allocated late + PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci); + + // UNSPEC is deprecated, remove this code eventually +#if defined ATM_VPI_UNSPEC + if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { + PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); + return -EINVAL; + } +#endif + + // deal with possibly wildcarded VCs + error = atm_find_ci (atm_vcc, &vpi, &vci); + if (error) { + PRINTD (DBG_WARN|DBG_VCC, "atm_find_ci failed!"); + return error; + } + PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci); + + error = vpci_to_channel (&channel, vpi, vci); + if (error) { + PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci); + return error; + } + + vcc.channel = channel; + // max speed for the moment + vcc.tx_rate = 0x0; + + qos = &atm_vcc->qos; + + // check AAL and remember it + switch (qos->aal) { + case ATM_AAL0: + // we would if it were 48 bytes and not 52! + PRINTD (DBG_QOS|DBG_VCC, "AAL0"); + vcc.aal = aal0; + break; + case ATM_AAL34: + // we would if I knew how do the SAR! + PRINTD (DBG_QOS|DBG_VCC, "AAL3/4"); + vcc.aal = aal34; + break; + case ATM_AAL5: + PRINTD (DBG_QOS|DBG_VCC, "AAL5"); + vcc.aal = aal5; + break; + default: + PRINTD (DBG_QOS|DBG_VCC, "Bad AAL!"); + return -EINVAL; + break; + } + + // TX traffic parameters + + // there are two, interrelated problems here: 1. the reservation of + // PCR is not a binary choice, we are given bounds and/or a + // desirable value; 2. the device is only capable of certain values, + // most of which are not integers. It is almost certainly acceptable + // to be off by a maximum of 1 to 10 cps. + + // Pragmatic choice: always store an integral PCR as that which has + // been allocated, even if we allocate a little (or a lot) less, + // after rounding. The actual allocation depends on what we can + // manage with our rate selection algorithm. The rate selection + // algorithm is given an integral PCR and a tolerance and told + // whether it should round the value up or down if the tolerance is + // exceeded; it returns: a) the actual rate selected (rounded up to + // the nearest integer), b) a bit pattern to feed to the timer + // register, and c) a failure value if no applicable rate exists. + + // Part of the job is done by atm_pcr_goal which gives us a PCR + // specification which says: EITHER grab the maximum available PCR + // (and perhaps a lower bound which we musn't pass), OR grab this + // amount, rounding down if you have to (and perhaps a lower bound + // which we musn't pass) OR grab this amount, rounding up if you + // have to (and perhaps an upper bound which we musn't pass). If any + // bounds ARE passed we fail. Note that rounding is only rounding to + // match device limitations, we do not round down to satisfy + // bandwidth availability even if this would not violate any given + // lower bound. + + // Note: telephony = 64kb/s = 48 byte cell payload @ 500/3 cells/s + // (say) so this is not even a binary fixpoint cell rate (but this + // device can do it). To avoid this sort of hassle we use a + // tolerance parameter (currently fixed at 10 cps). + + PRINTD (DBG_QOS, "TX:"); + + txtp = &qos->txtp; + + // set up defaults for no traffic + vcc.tx_rate = 0; + // who knows what would actually happen if you try and send on this? + vcc.tx_xbr_bits = IDLE_RATE_TYPE; + vcc.tx_pcr_bits = CLOCK_DISABLE; +#if 0 + vcc.tx_scr_bits = CLOCK_DISABLE; + vcc.tx_bucket_bits = 0; +#endif + + if (txtp->traffic_class != ATM_NONE) { + error = check_max_sdu (vcc.aal, txtp, max_tx_size); + if (error) { + PRINTD (DBG_QOS, "TX max_sdu check failed"); + return error; + } + + switch (txtp->traffic_class) { + case ATM_UBR: { + // we take "the PCR" as a rate-cap + // not reserved + vcc.tx_rate = 0; + make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, 0); + vcc.tx_xbr_bits = ABR_RATE_TYPE; + break; + } +#if 0 + case ATM_ABR: { + // reserve min, allow up to max + vcc.tx_rate = 0; // ? + make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, 0); + vcc.tx_xbr_bits = ABR_RATE_TYPE; + break; + } +#endif + case ATM_CBR: { + int pcr = atm_pcr_goal (txtp); + rounding r; + if (!pcr) { + // down vs. up, remaining bandwidth vs. unlimited bandwidth!! + // should really have: once someone gets unlimited bandwidth + // that no more non-UBR channels can be opened until the + // unlimited one closes?? For the moment, round_down means + // greedy people actually get something and not nothing + r = round_down; + // slight race (no locking) here so we may get -EAGAIN + // later; the greedy bastards would deserve it :) + PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); + pcr = dev->tx_avail; + } else if (pcr < 0) { + r = round_down; + pcr = -pcr; + } else { + r = round_up; + } + error = make_rate_with_tolerance (dev, pcr, r, 10, + &vcc.tx_pcr_bits, &vcc.tx_rate); + if (error) { + PRINTD (DBG_QOS, "could not make rate from TX PCR"); + return error; + } + // not really clear what further checking is needed + error = atm_pcr_check (txtp, vcc.tx_rate); + if (error) { + PRINTD (DBG_QOS, "TX PCR failed consistency check"); + return error; + } + vcc.tx_xbr_bits = CBR_RATE_TYPE; + break; + } +#if 0 + case ATM_VBR: { + int pcr = atm_pcr_goal (txtp); + // int scr = atm_scr_goal (txtp); + int scr = pcr/2; // just for fun + unsigned int mbs = 60; // just for fun + rounding pr; + rounding sr; + unsigned int bucket; + if (!pcr) { + pr = round_nearest; + pcr = 1<<30; + } else if (pcr < 0) { + pr = round_down; + pcr = -pcr; + } else { + pr = round_up; + } + error = make_rate_with_tolerance (dev, pcr, pr, 10, + &vcc.tx_pcr_bits, 0); + if (!scr) { + // see comments for PCR with CBR above + sr = round_down; + // slight race (no locking) here so we may get -EAGAIN + // later; the greedy bastards would deserve it :) + PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); + scr = dev->tx_avail; + } else if (scr < 0) { + sr = round_down; + scr = -scr; + } else { + sr = round_up; + } + error = make_rate_with_tolerance (dev, scr, sr, 10, + &vcc.tx_scr_bits, &vcc.tx_rate); + if (error) { + PRINTD (DBG_QOS, "could not make rate from TX SCR"); + return error; + } + // not really clear what further checking is needed + // error = atm_scr_check (txtp, vcc.tx_rate); + if (error) { + PRINTD (DBG_QOS, "TX SCR failed consistency check"); + return error; + } + // bucket calculations (from a piece of paper...) cell bucket + // capacity must be largest integer smaller than m(p-s)/p + 1 + // where m = max burst size, p = pcr, s = scr + bucket = mbs*(pcr-scr)/pcr; + if (bucket*pcr != mbs*(pcr-scr)) + bucket += 1; + if (bucket > BUCKET_MAX_SIZE) { + PRINTD (DBG_QOS, "shrinking bucket from %u to %u", + bucket, BUCKET_MAX_SIZE); + bucket = BUCKET_MAX_SIZE; + } + vcc.tx_xbr_bits = VBR_RATE_TYPE; + vcc.tx_bucket_bits = bucket; + break; + } +#endif + default: { + PRINTD (DBG_QOS, "unsupported TX traffic class"); + return -EINVAL; + break; + } + } + } + + // RX traffic parameters + + PRINTD (DBG_QOS, "RX:"); + + rxtp = &qos->rxtp; + + // set up defaults for no traffic + vcc.rx_rate = 0; + + if (rxtp->traffic_class != ATM_NONE) { + error = check_max_sdu (vcc.aal, rxtp, max_rx_size); + if (error) { + PRINTD (DBG_QOS, "RX max_sdu check failed"); + return error; + } + switch (rxtp->traffic_class) { + case ATM_UBR: { + // not reserved + break; + } +#if 0 + case ATM_ABR: { + // reserve min + vcc.rx_rate = 0; // ? + break; + } +#endif + case ATM_CBR: { + int pcr = atm_pcr_goal (rxtp); + if (!pcr) { + // slight race (no locking) here so we may get -EAGAIN + // later; the greedy bastards would deserve it :) + PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); + pcr = dev->tx_avail; + } else if (pcr < 0) { + pcr = -pcr; + } + vcc.rx_rate = pcr; + // not really clear what further checking is needed + error = atm_pcr_check (rxtp, vcc.rx_rate); + if (error) { + PRINTD (DBG_QOS, "RX PCR failed consistency check"); + return error; + } + break; + } + case ATM_VBR: { + // int scr = atm_scr_goal (txtp); + int scr = 1<<16; // just for fun + if (!scr) { + // slight race (no locking) here so we may get -EAGAIN + // later; the greedy bastards would deserve it :) + PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); + scr = dev->tx_avail; + } else if (scr < 0) { + scr = -scr; + } + vcc.rx_rate = scr; + // not really clear what further checking is needed + // error = atm_scr_check (rxtp, vcc.rx_rate); + if (error) { + PRINTD (DBG_QOS, "RX SCR failed consistency check"); + return error; + } + break; + } + default: { + PRINTD (DBG_QOS, "unsupported RX traffic class"); + return -EINVAL; + break; + } + } + } + + + // late abort useful for diagnostics + if (vcc.aal != aal5) { + PRINTD (DBG_QOS, "AAL not supported"); + return -EINVAL; + } + + // get space for our vcc stuff and copy parameters into it + vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL); + if (!vccp) { + PRINTK (KERN_ERR, "out of memory!"); + return -ENOMEM; + } + *vccp = vcc; + + // clear error and grab cell rate resource lock + error = 0; + spin_lock (&dev->rates_lock); + + if (vcc.tx_rate > dev->tx_avail) { + PRINTD (DBG_QOS, "not enough TX PCR left"); + error = -EAGAIN; + } + + if (vcc.rx_rate > dev->rx_avail) { + PRINTD (DBG_QOS, "not enough RX PCR left"); + error = -EAGAIN; + } + + if (!error) { + // really consume cell rates + dev->tx_avail -= vcc.tx_rate; + dev->rx_avail -= vcc.rx_rate; + PRINTD (DBG_QOS|DBG_VCC, "reserving %u TX PCR and %u RX PCR", + vcc.tx_rate, vcc.rx_rate); + } + + // release lock and exit on error + spin_unlock (&dev->rates_lock); + if (error) { + PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); + kfree (vccp); + return error; + } + + // this is "immediately before allocating the connection identifier + // in hardware" - so long as the next call does not fail :) + atm_vcc->flags |= ATM_VF_ADDR; + + // any errors here are very serious and should never occur + + if (rxtp->traffic_class != ATM_NONE) { + if (dev->rxer[channel]) { + PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX"); + return -EBUSY; + } + error = hrz_open_rx (dev, channel); + if (error) { + kfree (vccp); + return error; + } + // this link allows RX frames through + dev->rxer[channel] = atm_vcc; + } + + // success, set elements of atm_vcc + atm_vcc->vpi = vpi; + atm_vcc->vci = vci; + atm_vcc->dev_data = (void *) vccp; + + // indicate readiness + atm_vcc->flags |= ATM_VF_READY; + + MOD_INC_USE_COUNT; + return 0; +} + +/********** close VC **********/ + +static void hrz_close (struct atm_vcc * atm_vcc) { + hrz_dev * dev = HRZ_DEV(atm_vcc->dev); + hrz_vcc * vcc = HRZ_VCC(atm_vcc); + u16 channel = vcc->channel; + PRINTD (DBG_VCC|DBG_FLOW, "hrz_close"); + + // indicate unreadiness + atm_vcc->flags &= ~ATM_VF_READY; + + if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { + unsigned int i; + + // let any TX on this channel that has started complete + // no restart, just keep trying + while (tx_hold (dev)) + ; + // remove record of any tx_channel having been setup for this channel + for (i = 0; i < TX_CHANS; ++i) + if (dev->tx_channel_record[i] == channel) { + dev->tx_channel_record[i] = -1; + break; + } + if (dev->last_vc == channel) + dev->tx_last = -1; + tx_release (dev); + } + + if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { + // disable RXing - it tries quite hard + hrz_close_rx (dev, channel); + // forget the vcc - no more skbs will be pushed + if (atm_vcc != dev->rxer[channel]) + PRINTK (KERN_ERR, "%s atm_vcc=%p rxer[channel]=%p", + "arghhh! we're going to die!", + atm_vcc, dev->rxer[channel]); + dev->rxer[channel] = 0; + } + + // atomically release our rate reservation + spin_lock (&dev->rates_lock); + PRINTD (DBG_QOS|DBG_VCC, "releasing %u TX PCR and %u RX PCR", + vcc->tx_rate, vcc->rx_rate); + dev->tx_avail += vcc->tx_rate; + dev->rx_avail += vcc->rx_rate; + spin_unlock (&dev->rates_lock); + + // free our structure + kfree (vcc); + // say the VPI/VCI is free again + atm_vcc->flags &= ~ATM_VF_ADDR; + MOD_DEC_USE_COUNT; +} + +static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, + void *optval, int optlen) { + PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt"); + switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_BCTXOPT: + // return the right thing + break; + case SO_BCRXOPT: + // return the right thing + break; + default: + return -ENOPROTOOPT; + break; + }; + break; + } + return -EINVAL; +} + +static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, + void *optval, int optlen) { + PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt"); + switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_BCTXOPT: + // not settable + break; + case SO_BCRXOPT: + // not settable + break; + default: + return -ENOPROTOOPT; + break; + }; + break; + } + return -EINVAL; +} + +static int hrz_sg_send (struct atm_vcc * atm_vcc, + unsigned long start, + unsigned long size) { + if (atm_vcc->qos.aal == ATM_AAL5) { + PRINTD (DBG_FLOW|DBG_VCC, "hrz_sg_send: yes"); + return 1; + } else { + PRINTD (DBG_FLOW|DBG_VCC, "hrz_sg_send: no"); + return 0; + } +} + +#if 0 +static int hrz_ioctl (struct atm_dev * atm_dev, unsigned int cmd, void *arg) { + hrz_dev * dev = HRZ_DEV(atm_dev); + PRINTD (DBG_FLOW, "hrz_ioctl"); + return -1; +} + +unsigned char hrz_phy_get (struct atm_dev * atm_dev, unsigned long addr) { + hrz_dev * dev = HRZ_DEV(atm_dev); + PRINTD (DBG_FLOW, "hrz_phy_get"); + return 0; +} + +static void hrz_phy_put (struct atm_dev * atm_dev, unsigned char value, + unsigned long addr) { + hrz_dev * dev = HRZ_DEV(atm_dev); + PRINTD (DBG_FLOW, "hrz_phy_put"); +} + +static int hrz_change_qos (struct atm_vcc * atm_vcc, struct atm_qos *qos, int flgs) { + hrz_dev * dev = HRZ_DEV(vcc->dev); + PRINTD (DBG_FLOW, "hrz_change_qos"); + return -1; +} +#endif + +/********** proc file contents **********/ + +static int hrz_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) { + hrz_dev * dev = HRZ_DEV(atm_dev); + int left = *pos; + PRINTD (DBG_FLOW, "hrz_proc_read"); + + /* more diagnostics here? */ + +#if 0 + { + // VBR temporary diags + unsigned int i; + for (i = 0; i < TX_CHANS; ++i) { + if (!left--) + return sprintf (page, "bucket %u: %u/%u\n", i, + query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS), + query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS)); + } + } +#endif + + if (!left--) + return sprintf (page, + "cells: TX %lu, RX %lu, HEC errors %lu, unassigned %lu.\n", + dev->tx_cell_count, dev->rx_cell_count, + dev->hec_error_count, dev->unassigned_cell_count); + + if (!left--) + return sprintf (page, + "free cell buffers: TX %hu, RX %hu+%hu.\n", + rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF), + rd_regw (dev, RX_FREE_BUFFER_COUNT_OFF), + dev->noof_spare_buffers); + + if (!left--) + return sprintf (page, + "cps remaining: TX %u, RX %u\n", + dev->tx_avail, dev->rx_avail); + + return 0; +} + +static const struct atmdev_ops hrz_ops = { + NULL, // no hrz_dev_close + hrz_open, + hrz_close, + NULL, // no hrz_ioctl + hrz_getsockopt, + hrz_setsockopt, + hrz_send, + hrz_sg_send, + NULL, // no send_oam - not in fact used yet + NULL, // no hrz_phy_put - not needed in this driver + NULL, // no hrz_phy_get - not needed in this driver + NULL, // no feedback - feedback to the driver! + NULL, // no hrz_change_qos + NULL, // no free_rx_skb + hrz_proc_read +}; + +static int __init hrz_probe (void) { + struct pci_dev * pci_dev; + int devs; + + PRINTD (DBG_FLOW, "hrz_probe"); + + if (!pci_present()) + return 0; + + devs = 0; + pci_dev = NULL; + while ((pci_dev = pci_find_device + (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev) + )) { + hrz_dev * dev; + + // adapter slot free, read resources from PCI configuration space + u32 iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + u32 * membase = bus_to_virt + (pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); + u8 irq = pci_dev->irq; + + // check IO region + if (check_region (iobase, HRZ_IO_EXTENT)) { + PRINTD (DBG_WARN, "IO range already in use"); + continue; + } + + dev = kmalloc (sizeof(hrz_dev), GFP_KERNEL); + if (!dev) { + // perhaps we should be nice: deregister all adapters and abort? + PRINTD (DBG_ERR, "out of memory"); + continue; + } + + memset (dev, 0, sizeof(hrz_dev)); + + // grab IRQ and install handler - move this someplace more sensible + if (request_irq (irq, + interrupt_handler, + SA_SHIRQ, /* irqflags guess */ + DEV_LABEL, /* name guess */ + dev)) { + PRINTD (DBG_WARN, "request IRQ failed!"); + // free_irq is at "endif" + } else { + + PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", + iobase, irq, membase); + + dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0); + if (!(dev->atm_dev)) { + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + } else { + unsigned char lat; + + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); + dev->atm_dev->dev_data = (void *) dev; + dev->pci_dev = pci_dev; + + /* XXX DEV_LABEL is a guess */ + request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL); + + // enable bus master accesses + pci_set_master (pci_dev); + + // frobnicate latency (upwards, usually) + pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); + if (pci_lat) { + PRINTD (DBG_INFO, "%s PCI latency timer from %hu to %hu", + "changing", lat, pci_lat); + pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat); + } else if (lat < MIN_PCI_LATENCY) { + PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu", + "increasing", lat, MIN_PCI_LATENCY); + pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); + } + + dev->iobase = iobase; + dev->irq = irq; + dev->membase = membase; + + dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0]; + dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1]; + + // these next three are performance hacks + dev->last_vc = -1; + dev->tx_last = -1; + dev->tx_idle = 0; + + dev->tx_regions = 0; + dev->tx_bytes = 0; + dev->tx_skb = 0; + dev->tx_iovec = 0; + + dev->tx_cell_count = 0; + dev->rx_cell_count = 0; + dev->hec_error_count = 0; + dev->unassigned_cell_count = 0; + + dev->noof_spare_buffers = 0; + + { + unsigned int i; + for (i = 0; i < TX_CHANS; ++i) + dev->tx_channel_record[i] = -1; + } + + dev->flags = 0; + + // Allocate cell rates and remember ASIC version + // Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 + // Copper: (WRONG) we want 6 into the above, close to 25Mb/s + // Copper: (plagarise!) 25600000/8/270*260/53 - n/53 + + if (hrz_init (dev)) { + // to be really pedantic, this should be ATM_OC3c_PCR + dev->tx_avail = ATM_OC3_PCR; + dev->rx_avail = ATM_OC3_PCR; + set_bit (ultra, &dev->flags); // NOT "|= ultra" ! + } else { + dev->tx_avail = ((25600000/8)*26)/(27*53); + dev->rx_avail = ((25600000/8)*26)/(27*53); + PRINTD (DBG_WARN, "Buggy ASIC: no TX bus-mastering."); + } + + // rate changes spinlock + spin_lock_init (&dev->rate_lock); + + // on-board memory access spinlock; we want atomic reads and + // writes to adapter memory (handles IRQ and SMP) + spin_lock_init (&dev->mem_lock); + + init_waitqueue_head(&dev->tx_queue); + + // vpi in 0..4, vci in 6..10 + dev->atm_dev->ci_range.vpi_bits = vpi_bits; + dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; + + // update count and linked list + ++devs; + dev->prev = hrz_devs; + hrz_devs = dev; + // success + continue; + + /* not currently reached */ + atm_dev_deregister (dev->atm_dev); + } /* atm_dev_register */ + free_irq (irq, dev); + } /* request_irq */ + kfree (dev); + } /* kmalloc and while */ + return devs; +} + +static void __init hrz_check_args (void) { +#ifdef DEBUG_HORIZON + PRINTK (KERN_NOTICE, "debug bitmap is %hx", debug &= DBG_MASK); +#else + if (debug) + PRINTK (KERN_NOTICE, "no debug support in this image"); +#endif + + if (vpi_bits > HRZ_MAX_VPI) + PRINTK (KERN_ERR, "vpi_bits has been limited to %hu", + vpi_bits = HRZ_MAX_VPI); + + if (max_tx_size > TX_AAL5_LIMIT) + PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu", + max_tx_size = TX_AAL5_LIMIT); + + if (max_rx_size > RX_AAL5_LIMIT) + PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu", + max_rx_size = RX_AAL5_LIMIT); + + return; +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR(maintainer_string); +MODULE_DESCRIPTION(description_string); +MODULE_PARM(debug, "h"); +MODULE_PARM(vpi_bits, "h"); +MODULE_PARM(max_tx_size, "h"); +MODULE_PARM(max_rx_size, "h"); +MODULE_PARM(pci_lat, "b"); +MODULE_PARM_DESC(debug, "debug bitmap, see .h file"); +MODULE_PARM_DESC(vpi_bits, "number of bits (0..4) to allocate to VPIs"); +MODULE_PARM_DESC(max_tx_size, "maximum size of TX AAL5 frames"); +MODULE_PARM_DESC(max_rx_size, "maximum size of RX AAL5 frames"); +MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles"); + +/********** module entry **********/ + +int init_module (void) { + int devs; + + // sanity check - cast is needed since printk does not support %Zu + if (sizeof(struct MEMMAP) != 128*1024/4) { + PRINTK (KERN_ERR, "Fix struct MEMMAP (is %lu fakewords).", + (unsigned long) sizeof(struct MEMMAP)); + return -ENOMEM; + } + + show_version(); + + // check arguments + hrz_check_args(); + + // get the juice + devs = hrz_probe(); + + if (devs) { + init_timer (&housekeeping); + housekeeping.function = do_housekeeping; + // paranoia + housekeeping.data = 1; + set_timer (&housekeeping, 0); + } else { + PRINTK (KERN_ERR, "no (usable) adapters found"); + } + + return devs ? 0 : -ENODEV; +} + +/********** module exit **********/ + +void cleanup_module (void) { + hrz_dev * dev; + PRINTD (DBG_FLOW, "cleanup_module"); + + // paranoia + housekeeping.data = 0; + del_timer (&housekeeping); + + while (hrz_devs) { + dev = hrz_devs; + hrz_devs = dev->prev; + + PRINTD (DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); + hrz_shutdown (dev); + atm_dev_deregister (dev->atm_dev); + free_irq (dev->irq, dev); + release_region (dev->iobase, HRZ_IO_EXTENT); + kfree (dev); + } + + return; +} + +#else + +/********** monolithic entry **********/ + +int __init hrz_detect (void) { + int devs; + + // sanity check - cast is needed since printk does not support %Zu + if (sizeof(struct MEMMAP) != 128*1024/4) { + PRINTK (KERN_ERR, "Fix struct MEMMAP (is %lu fakewords).", + (unsigned long) sizeof(struct MEMMAP)); + return 0; + } + + show_version(); + + // what about command line arguments? + // check arguments + hrz_check_args(); + + // get the juice + devs = hrz_probe(); + + if (devs) { + init_timer (&housekeeping); + housekeeping.function = do_housekeeping; + // paranoia + housekeeping.data = 1; + set_timer (&housekeeping, 0); + } else { + PRINTK (KERN_ERR, "no (usable) adapters found"); + } + + return devs; +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/horizon.h linux/drivers/atm/horizon.h --- v2.3.14/linux/drivers/atm/horizon.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/horizon.h Mon Aug 23 13:44:03 1999 @@ -0,0 +1,508 @@ +/* + Madge Horizon ATM Adapter driver. + Copyright (C) 1995-1999 Madge Networks Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian + system and in the file COPYING in the Linux kernel source. +*/ + +/* + IMPORTANT NOTE: Madge Networks no longer makes the adapters + supported by this driver and makes no commitment to maintain it. +*/ + +/* too many macros - change to inline functions */ + +#ifndef DRIVER_ATM_HORIZON_H +#define DRIVER_ATM_HORIZON_H + +#include + +#ifdef CONFIG_ATM_HORIZON_DEBUG +#define DEBUG_HORIZON +#endif + +#define DEV_LABEL "hrz" + +#ifndef PCI_VENDOR_ID_MADGE +#define PCI_VENDOR_ID_MADGE 0x10B6 +#endif +#ifndef PCI_VENDOR_ID_MADGE_HORIZON +#define PCI_DEVICE_ID_MADGE_HORIZON 0x1000 +#endif + +// diagnostic output + +#define PRINTK(severity,format,args...) \ + printk(severity DEV_LABEL ": " format "\n" , ## args) + +#ifdef DEBUG_HORIZON + +#define DBG_ERR 0x0001 +#define DBG_WARN 0x0002 +#define DBG_INFO 0x0004 +#define DBG_VCC 0x0008 +#define DBG_QOS 0x0010 +#define DBG_TX 0x0020 +#define DBG_RX 0x0040 +#define DBG_SKB 0x0080 +#define DBG_IRQ 0x0100 +#define DBG_FLOW 0x0200 +#define DBG_BUS 0x0400 +#define DBG_REGS 0x0800 +#define DBG_DATA 0x1000 +#define DBG_MASK 0x1fff + +/* the ## prevents the annoying double expansion of the macro arguments */ +/* KERN_INFO is used since KERN_DEBUG often does not make it to the console */ +#define PRINTDB(bits,format,args...) \ + ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format , ## args) : 1 ) +#define PRINTDM(bits,format,args...) \ + ( (debug & (bits)) ? printk (format , ## args) : 1 ) +#define PRINTDE(bits,format,args...) \ + ( (debug & (bits)) ? printk (format "\n" , ## args) : 1 ) +#define PRINTD(bits,format,args...) \ + ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format "\n" , ## args) : 1 ) + +#else + +#define PRINTD(bits,format,args...) +#define PRINTDB(bits,format,args...) +#define PRINTDM(bits,format,args...) +#define PRINTDE(bits,format,args...) + +#endif + +#define PRINTDD(sec,fmt,args...) +#define PRINTDDB(sec,fmt,args...) +#define PRINTDDM(sec,fmt,args...) +#define PRINTDDE(sec,fmt,args...) + +// fixed constants + +#define SPARE_BUFFER_POOL_SIZE MAX_VCS +#define HRZ_MAX_VPI 4 +#define MIN_PCI_LATENCY 48 // 24 IS TOO SMALL + +/* Horizon specific bits */ +/* Register offsets */ + +#define HRZ_IO_EXTENT 0x80 + +#define DATA_PORT_OFF 0x00 +#define TX_CHANNEL_PORT_OFF 0x04 +#define TX_DESCRIPTOR_PORT_OFF 0x08 +#define MEMORY_PORT_OFF 0x0C +#define MEM_WR_ADDR_REG_OFF 0x14 +#define MEM_RD_ADDR_REG_OFF 0x18 +#define CONTROL_0_REG 0x1C +#define INT_SOURCE_REG_OFF 0x20 +#define INT_ENABLE_REG_OFF 0x24 +#define MASTER_RX_ADDR_REG_OFF 0x28 +#define MASTER_RX_COUNT_REG_OFF 0x2C +#define MASTER_TX_ADDR_REG_OFF 0x30 +#define MASTER_TX_COUNT_REG_OFF 0x34 +#define TX_DESCRIPTOR_REG_OFF 0x38 +#define TX_CHANNEL_CONFIG_COMMAND_OFF 0x40 +#define TX_CHANNEL_CONFIG_DATA_OFF 0x44 +#define TX_FREE_BUFFER_COUNT_OFF 0x48 +#define RX_FREE_BUFFER_COUNT_OFF 0x4C +#define TX_CONFIG_OFF 0x50 +#define TX_STATUS_OFF 0x54 +#define RX_CONFIG_OFF 0x58 +#define RX_LINE_CONFIG_OFF 0x5C +#define RX_QUEUE_RD_PTR_OFF 0x60 +#define RX_QUEUE_WR_PTR_OFF 0x64 +#define MAX_AAL5_CELL_COUNT_OFF 0x68 +#define RX_CHANNEL_PORT_OFF 0x6C +#define TX_CELL_COUNT_OFF 0x70 +#define RX_CELL_COUNT_OFF 0x74 +#define HEC_ERROR_COUNT_OFF 0x78 +#define UNASSIGNED_CELL_COUNT_OFF 0x7C + +/* Register bit definitions */ + +/* Control 0 register */ + +#define SEEPROM_DO 0x00000001 +#define SEEPROM_DI 0x00000002 +#define SEEPROM_SK 0x00000004 +#define SEEPROM_CS 0x00000008 +#define DEBUG_BIT_0 0x00000010 +#define DEBUG_BIT_1 0x00000020 +#define DEBUG_BIT_2 0x00000040 +// RESERVED 0x00000080 +#define DEBUG_BIT_0_OE 0x00000100 +#define DEBUG_BIT_1_OE 0x00000200 +#define DEBUG_BIT_2_OE 0x00000400 +// RESERVED 0x00000800 +#define DEBUG_BIT_0_STATE 0x00001000 +#define DEBUG_BIT_1_STATE 0x00002000 +#define DEBUG_BIT_2_STATE 0x00004000 +// RESERVED 0x00008000 +#define GENERAL_BIT_0 0x00010000 +#define GENERAL_BIT_1 0x00020000 +#define GENERAL_BIT_2 0x00040000 +#define GENERAL_BIT_3 0x00080000 +#define RESET_HORIZON 0x00100000 +#define RESET_ATM 0x00200000 +#define RESET_RX 0x00400000 +#define RESET_TX 0x00800000 +#define RESET_HOST 0x01000000 +// RESERVED 0x02000000 +#define TARGET_RETRY_DISABLE 0x04000000 +#define ATM_LAYER_SELECT 0x08000000 +#define ATM_LAYER_STATUS 0x10000000 +// RESERVED 0xE0000000 + +/* Interrupt source and enable registers */ + +#define RX_DATA_AV 0x00000001 +#define RX_DISABLED 0x00000002 +#define TIMING_MARKER 0x00000004 +#define FORCED 0x00000008 +#define RX_BUS_MASTER_COMPLETE 0x00000010 +#define TX_BUS_MASTER_COMPLETE 0x00000020 +#define ABR_TX_CELL_COUNT_INT 0x00000040 +#define DEBUG_INT 0x00000080 +// RESERVED 0xFFFFFF00 + +/* PIO and Bus Mastering */ + +#define MAX_PIO_COUNT 0x000000ff // 255 - make tunable? +// 8188 is a hard limit for bus mastering +#define MAX_TRANSFER_COUNT 0x00001ffc // 8188 +#define MASTER_TX_AUTO_APPEND_DESC 0x80000000 + +/* TX channel config command port */ + +#define PCR_TIMER_ACCESS 0x0000 +#define SCR_TIMER_ACCESS 0x0001 +#define BUCKET_CAPACITY_ACCESS 0x0002 +#define BUCKET_FULLNESS_ACCESS 0x0003 +#define RATE_TYPE_ACCESS 0x0004 +// UNUSED 0x00F8 +#define TX_CHANNEL_CONFIG_MULT 0x0100 +// UNUSED 0xF800 +#define BUCKET_MAX_SIZE 0x003f + +/* TX channel config data port */ + +#define CLOCK_SELECT_SHIFT 4 +#define CLOCK_DISABLE 0x00ff + +#define IDLE_RATE_TYPE 0x0 +#define ABR_RATE_TYPE 0x1 +#define VBR_RATE_TYPE 0x2 +#define CBR_RATE_TYPE 0x3 + +/* TX config register */ + +#define DRVR_DRVRBAR_ENABLE 0x0001 +#define TXCLK_MUX_SELECT_RCLK 0x0002 +#define TRANSMIT_TIMING_MARKER 0x0004 +#define LOOPBACK_TIMING_MARKER 0x0008 +#define TX_TEST_MODE_16MHz 0x0000 +#define TX_TEST_MODE_8MHz 0x0010 +#define TX_TEST_MODE_5_33MHz 0x0020 +#define TX_TEST_MODE_4MHz 0x0030 +#define TX_TEST_MODE_3_2MHz 0x0040 +#define TX_TEST_MODE_2_66MHz 0x0050 +#define TX_TEST_MODE_2_29MHz 0x0060 +#define TX_NORMAL_OPERATION 0x0070 +#define ABR_ROUND_ROBIN 0x0080 + +/* TX status register */ + +#define IDLE_CHANNELS_MASK 0x00FF +#define ABR_CELL_COUNT_REACHED_MULT 0x0100 +#define ABR_CELL_COUNT_REACHED_MASK 0xFF + +/* RX config register */ + +#define NON_USER_CELLS_IN_ONE_CHANNEL 0x0008 +#define RX_ENABLE 0x0010 +#define IGNORE_UNUSED_VPI_VCI_BITS_SET 0x0000 +#define NON_USER_UNUSED_VPI_VCI_BITS_SET 0x0020 +#define DISCARD_UNUSED_VPI_VCI_BITS_SET 0x0040 + +/* RX line config register */ + +#define SIGNAL_LOSS 0x0001 +#define FREQUENCY_DETECT_ERROR 0x0002 +#define LOCK_DETECT_ERROR 0x0004 +#define SELECT_INTERNAL_LOOPBACK 0x0008 +#define LOCK_DETECT_ENABLE 0x0010 +#define FREQUENCY_DETECT_ENABLE 0x0020 +#define USER_FRAQ 0x0040 +#define GXTALOUT_SELECT_DIV4 0x0080 +#define GXTALOUT_SELECT_NO_GATING 0x0100 +#define TIMING_MARKER_RECEIVED 0x0200 + +/* RX channel port */ + +#define RX_CHANNEL_MASK 0x03FF +// UNUSED 0x3C00 +#define FLUSH_CHANNEL 0x4000 +#define RX_CHANNEL_UPDATE_IN_PROGRESS 0x8000 + +/* Receive queue entry */ + +#define RX_Q_ENTRY_LENGTH_MASK 0x0000FFFF +#define RX_Q_ENTRY_CHANNEL_SHIFT 16 +#define SIMONS_DODGEY_MARKER 0x08000000 +#define RX_CONGESTION_EXPERIENCED 0x10000000 +#define RX_CRC_10_OK 0x20000000 +#define RX_CRC_32_OK 0x40000000 +#define RX_COMPLETE_FRAME 0x80000000 + +/* Offsets and constants for use with the buffer memory */ + +/* Buffer pointers and channel types */ + +#define BUFFER_PTR_MASK 0x0000FFFF +#define RX_INT_THRESHOLD_MULT 0x00010000 +#define RX_INT_THRESHOLD_MASK 0x07FF +#define INT_EVERY_N_CELLS 0x08000000 +#define CONGESTION_EXPERIENCED 0x10000000 +#define FIRST_CELL_OF_AAL5_FRAME 0x20000000 +#define CHANNEL_TYPE_AAL5 0x00000000 +#define CHANNEL_TYPE_RAW_CELLS 0x40000000 +#define CHANNEL_TYPE_AAL3_4 0x80000000 + +/* Buffer status stuff */ + +#define BUFF_STATUS_MASK 0x00030000 +#define BUFF_STATUS_EMPTY 0x00000000 +#define BUFF_STATUS_CELL_AV 0x00010000 +#define BUFF_STATUS_LAST_CELL_AV 0x00020000 + +/* Transmit channel stuff */ + +/* Receive channel stuff */ + +#define RX_CHANNEL_DISABLED 0x00000000 +#define RX_CHANNEL_IDLE 0x00000001 + +/* General things */ + +#define INITIAL_CRC 0xFFFFFFFF + +// A Horizon u32, a byte! Really nasty. Horizon pointers are (32 bit) +// word addresses and so standard C pointer operations break (as they +// assume byte addresses); so we pretend that Horizon words (and word +// pointers) are bytes (and byte pointers) for the purposes of having +// a memory map that works. + +typedef u8 HDW; + +typedef struct cell_buf { + HDW payload[12]; + HDW next; + HDW cell_count; // AAL5 rx bufs + HDW res; + union { + HDW partial_crc; // AAL5 rx bufs + HDW cell_header; // RAW bufs + } u; +} cell_buf; + +typedef struct tx_ch_desc { + HDW rd_buf_type; + HDW wr_buf_type; + HDW partial_crc; + HDW cell_header; +} tx_ch_desc; + +typedef struct rx_ch_desc { + HDW wr_buf_type; + HDW rd_buf_type; +} rx_ch_desc; + +typedef struct rx_q_entry { + HDW entry; +} rx_q_entry; + +#define TX_CHANS 8 +#define RX_CHANS 1024 +#define RX_QS 1024 +#define MAX_VCS RX_CHANS + +/* Horizon buffer memory map */ + +// TX Channel Descriptors 2 +// TX Initial Buffers 8 // TX_CHANS +#define BUFN1_SIZE 118 // (126 - TX_CHANS) +// RX/TX Start/End Buffers 4 +#define BUFN2_SIZE 124 +// RX Queue Entries 64 +#define BUFN3_SIZE 192 +// RX Channel Descriptors 128 +#define BUFN4_SIZE 1408 +// TOTAL cell_buff chunks 2048 + +// cell_buf bufs[2048]; +// HDW dws[32768]; + +typedef struct MEMMAP { + tx_ch_desc tx_descs[TX_CHANS]; // 8 * 4 = 32 , 0x0020 + cell_buf inittxbufs[TX_CHANS]; // these are really + cell_buf bufn1[BUFN1_SIZE]; // part of this pool + cell_buf txfreebufstart; + cell_buf txfreebufend; + cell_buf rxfreebufstart; + cell_buf rxfreebufend; // 8+118+1+1+1+1+124 = 254 + cell_buf bufn2[BUFN2_SIZE]; // 16 * 254 = 4064 , 0x1000 + rx_q_entry rx_q_entries[RX_QS]; // 1 * 1024 = 1024 , 0x1400 + cell_buf bufn3[BUFN3_SIZE]; // 16 * 192 = 3072 , 0x2000 + rx_ch_desc rx_descs[MAX_VCS]; // 2 * 1024 = 2048 , 0x2800 + cell_buf bufn4[BUFN4_SIZE]; // 16 * 1408 = 22528 , 0x8000 +} MEMMAP; + +#define memmap ((MEMMAP *)0) + +#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0) + +/* end horizon specific bits */ + +typedef enum { + aal0, + aal34, + aal5 +} hrz_aal; + +typedef enum { + tx_busy, + rx_busy, + ultra +} hrz_flags; + +// a single struct pointed to by atm_vcc->dev_data + +typedef struct { + unsigned int tx_rate; + unsigned int rx_rate; + u16 channel; + u16 tx_xbr_bits; + u16 tx_pcr_bits; +#if 0 + u16 tx_scr_bits; + u16 tx_bucket_bits; +#endif + hrz_aal aal; +} hrz_vcc; + +struct hrz_dev { + + u32 iobase; + u32 * membase; + + struct sk_buff * rx_skb; // skb being RXed + unsigned int rx_bytes; // bytes remaining to RX within region + void * rx_addr; // addr to send bytes to (for PIO) + unsigned int rx_channel; // channel that the skb is going out on + + struct sk_buff * tx_skb; // skb being TXed + unsigned int tx_bytes; // bytes remaining to TX within region + void * tx_addr; // addr to send bytes from (for PIO) + struct iovec * tx_iovec; // remaining regions + unsigned int tx_regions; // number of remaining regions + + spinlock_t mem_lock; + wait_queue_head_t tx_queue; + + u8 irq; + u8 flags; + u8 tx_last; + u8 tx_idle; + + rx_q_entry * rx_q_reset; + rx_q_entry * rx_q_entry; + rx_q_entry * rx_q_wrap; + + struct atm_dev * atm_dev; + + u32 last_vc; + + int noof_spare_buffers; + u16 spare_buffers[SPARE_BUFFER_POOL_SIZE]; + + u16 tx_channel_record[TX_CHANS]; + + // this is what we follow when we get incoming data + u32 txer[MAX_VCS/32]; + struct atm_vcc * rxer[MAX_VCS]; + + // cell rate allocation + spinlock_t rate_lock; + unsigned int rx_avail; + unsigned int tx_avail; + + // dev stats + unsigned long tx_cell_count; + unsigned long rx_cell_count; + unsigned long hec_error_count; + unsigned long unassigned_cell_count; + + struct pci_dev * pci_dev; + struct hrz_dev * prev; +}; + +typedef struct hrz_dev hrz_dev; + +/* macros for use later */ + +#define INTERESTING_INTERRUPTS \ + (RX_DATA_AV | RX_DISABLED | TX_BUS_MASTER_COMPLETE | RX_BUS_MASTER_COMPLETE) + +// 190 cells by default (192 TX buffers - 2 elbow room, see docs) +#define TX_AAL5_LIMIT (190*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER) // 9112 + +// Have enough RX buffers (unless we allow other buffer splits) +#define RX_AAL5_LIMIT ATM_MAX_AAL5_PDU + +/* multi-statement macro protector */ +#define DW(x) do{ x } while(0) + +#define HRZ_DEV(atm_dev) ((hrz_dev *) (atm_dev)->dev_data) +#define HRZ_VCC(atm_vcc) ((hrz_vcc *) (atm_vcc)->dev_data) + +/* Turn the LEDs on and off */ +// The LEDs bits are upside down in that setting the bit in the debug +// register will turn the appropriate LED off. + +#define YELLOW_LED DEBUG_BIT_0 +#define GREEN_LED DEBUG_BIT_1 +#define YELLOW_LED_OE DEBUG_BIT_0_OE +#define GREEN_LED_OE DEBUG_BIT_1_OE + +#define GREEN_LED_OFF(dev) \ + wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) | GREEN_LED) +#define GREEN_LED_ON(dev) \ + wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) &~ GREEN_LED) +#define YELLOW_LED_OFF(dev) \ + wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) | YELLOW_LED) +#define YELLOW_LED_ON(dev) \ + wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) &~ YELLOW_LED) + +typedef enum { + round_up, + round_down, + round_nearest +} rounding; + +#endif /* DRIVER_ATM_HORIZON_H */ diff -u --recursive --new-file v2.3.14/linux/drivers/atm/midway.h linux/drivers/atm/midway.h --- v2.3.14/linux/drivers/atm/midway.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/midway.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,265 @@ +/* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef DRIVERS_ATM_MIDWAY_H +#define DRIVERS_ATM_MIDWAY_H + + +#define NR_VCI 1024 /* number of VCIs */ +#define NR_VCI_LD 10 /* log2(NR_VCI) */ +#define NR_DMA_RX 512 /* RX DMA queue entries */ +#define NR_DMA_TX 512 /* TX DMA queue entries */ +#define NR_SERVICE NR_VCI /* service list size */ +#define NR_CHAN 8 /* number of TX channels */ +#define TS_CLOCK 25000000 /* traffic shaper clock (cell/sec) */ + +#define MAP_MAX_SIZE 0x00400000 /* memory window for max config */ +#define EPROM_SIZE 0x00010000 +#define MEM_VALID 0xffc00000 /* mask base address with this */ +#define PHY_BASE 0x00020000 /* offset of PHY register are */ +#define REG_BASE 0x00040000 /* offset of Midway register area */ +#define RAM_BASE 0x00200000 /* offset of RAM area */ +#define RAM_INCREMENT 0x00020000 /* probe for RAM every 128kB */ + +#define MID_VCI_BASE RAM_BASE +#define MID_DMA_RX_BASE (MID_VCI_BASE+NR_VCI*16) +#define MID_DMA_TX_BASE (MID_DMA_RX_BASE+NR_DMA_RX*8) +#define MID_SERVICE_BASE (MID_DMA_TX_BASE+NR_DMA_TX*8) +#define MID_FREE_BASE (MID_SERVICE_BASE+NR_SERVICE*4) + +#define MAC_LEN 6 /* atm.h */ + +#define MID_MIN_BUF_SIZE (1024) /* 1 kB is minimum */ +#define MID_MAX_BUF_SIZE (128*1024) /* 128 kB is maximum */ + +#define RX_DESCR_SIZE 1 /* RX PDU descr is 1 longword */ +#define TX_DESCR_SIZE 2 /* TX PDU descr is 2 longwords */ +#define AAL5_TRAILER (ATM_AAL5_TRAILER/4) /* AAL5 trailer is 2 longwords */ + +#define TX_GAP 8 /* TX buffer gap (words) */ + +/* + * Midway Reset/ID + * + * All values read-only. Writing to this register resets Midway chip. + */ + +#define MID_RES_ID_MCON 0x00 /* Midway Reset/ID */ + +#define MID_ID 0xf0000000 /* Midway version */ +#define MID_SHIFT 24 +#define MID_MOTHER_ID 0x00000700 /* mother board id */ +#define MID_MOTHER_SHIFT 8 +#define MID_CON_TI 0x00000080 /* 0: normal ctrl; 1: SABRE */ +#define MID_CON_SUNI 0x00000040 /* 0: UTOPIA; 1: SUNI */ +#define MID_CON_V6 0x00000020 /* 0: non-pipel UTOPIA (required iff + !CON_SUNI; 1: UTOPIA */ +#define DAUGTHER_ID 0x0000001f /* daugther board id */ + +/* + * Interrupt Status Acknowledge, Interrupt Status & Interrupt Enable + */ + +#define MID_ISA 0x01 /* Interrupt Status Acknowledge */ +#define MID_IS 0x02 /* Interrupt Status */ +#define MID_IE 0x03 /* Interrupt Enable */ + +#define MID_TX_COMPLETE_7 0x00010000 /* channel N completed a PDU */ +#define MID_TX_COMPLETE_6 0x00008000 /* transmission */ +#define MID_TX_COMPLETE_5 0x00004000 +#define MID_TX_COMPLETE_4 0x00002000 +#define MID_TX_COMPLETE_3 0x00001000 +#define MID_TX_COMPLETE_2 0x00000800 +#define MID_TX_COMPLETE_1 0x00000400 +#define MID_TX_COMPLETE_0 0x00000200 +#define MID_TX_COMPLETE 0x0001fe00 /* any TX */ +#define MID_TX_DMA_OVFL 0x00000100 /* DMA to adapter overflow */ +#define MID_TX_IDENT_MISM 0x00000080 /* TX: ident mismatch => halted */ +#define MID_DMA_LERR_ACK 0x00000040 /* LERR - SBus ? */ +#define MID_DMA_ERR_ACK 0x00000020 /* DMA error */ +#define MID_RX_DMA_COMPLETE 0x00000010 /* DMA to host done */ +#define MID_TX_DMA_COMPLETE 0x00000008 /* DMA from host done */ +#define MID_SERVICE 0x00000004 /* something in service list */ +#define MID_SUNI_INT 0x00000002 /* interrupt from SUNI */ +#define MID_STAT_OVFL 0x00000001 /* statistics overflow */ + +/* + * Master Control/Status + */ + +#define MID_MC_S 0x04 + +#define MID_INT_SELECT 0x000001C0 /* Interrupt level (000: off) */ +#define MID_INT_SEL_SHIFT 6 +#define MID_TX_LOCK_MODE 0x00000020 /* 0: streaming; 1: TX ovfl->lock */ +#define MID_DMA_ENABLE 0x00000010 /* R: 0: disable; 1: enable + W: 0: no change; 1: enable */ +#define MID_TX_ENABLE 0x00000008 /* R: 0: TX disabled; 1: enabled + W: 0: no change; 1: enable */ +#define MID_RX_ENABLE 0x00000004 /* like TX */ +#define MID_WAIT_1MS 0x00000002 /* R: 0: timer not running; 1: running + W: 0: no change; 1: no interrupts + for 1 ms */ +#define MID_WAIT_500US 0x00000001 /* like WAIT_1MS, but 0.5 ms */ + +/* + * Statistics + * + * Cleared when reading. + */ + +#define MID_STAT 0x05 + +#define MID_VCI_TRASH 0xFFFF0000 /* trashed cells because of VCI mode */ +#define MID_VCI_TRASH_SHIFT 16 +#define MID_OVFL_TRASH 0x0000FFFF /* trashed cells because of overflow */ + +/* + * Address registers + */ + +#define MID_SERV_WRITE 0x06 /* free pos in service area (R, 10 bits) */ +#define MID_DMA_ADDR 0x07 /* virtual DMA address (R, 32 bits) */ +#define MID_DMA_WR_RX 0x08 /* (RW, 9 bits) */ +#define MID_DMA_RD_RX 0x09 +#define MID_DMA_WR_TX 0x0A +#define MID_DMA_RD_TX 0x0B + +/* + * Transmit Place Registers (0x10+4*channel) + */ + +#define MID_TX_PLACE(c) (0x10+4*(c)) + +#define MID_SIZE 0x00003800 /* size, N*256 x 32 bit */ +#define MID_SIZE_SHIFT 11 +#define MID_LOCATION 0x000007FF /* location in adapter memory (word) */ + +#define MID_LOC_SKIP 8 /* 8 bits of location are always zero + (applies to all uses of location) */ + +/* + * Transmit ReadPtr Registers (0x11+4*channel) + */ + +#define MID_TX_RDPTR(c) (0x11+4*(c)) + +#define MID_READ_PTR 0x00007FFF /* next word for PHY */ + +/* + * Transmit DescrStart Registers (0x12+4*channel) + */ + +#define MID_TX_DESCRSTART(c) (0x12+4*(c)) + +#define MID_DESCR_START 0x00007FFF /* seg buffer being DMAed */ + +#define ENI155_MAGIC 0xa54b872d + +struct midway_eprom { + unsigned char mac[MAC_LEN],inv_mac[MAC_LEN]; + unsigned char pad[36]; + u32 serial,inv_serial; + u32 magic,inv_magic; +}; + + +/* + * VCI table entry + */ + +#define MID_VCI_IN_SERVICE 0x00000001 /* set if VCI is currently in + service list */ +#define MID_VCI_SIZE 0x00038000 /* reassembly buffer size, + 2* kB */ +#define MID_VCI_SIZE_SHIFT 15 +#define MID_VCI_LOCATION 0x1ffc0000 /* buffer location */ +#define MID_VCI_LOCATION_SHIFT 18 +#define MID_VCI_PTI_MODE 0x20000000 /* 0: trash, 1: preserve */ +#define MID_VCI_MODE 0xc0000000 +#define MID_VCI_MODE_SHIFT 30 +#define MID_VCI_READ 0x00007fff +#define MID_VCI_READ_SHIFT 0 +#define MID_VCI_DESCR 0x7fff0000 +#define MID_VCI_DESCR_SHIFT 16 +#define MID_VCI_COUNT 0x000007ff +#define MID_VCI_COUNT_SHIFT 0 +#define MID_VCI_STATE 0x0000c000 +#define MID_VCI_STATE_SHIFT 14 +#define MID_VCI_WRITE 0x7fff0000 +#define MID_VCI_WRITE_SHIFT 16 + +#define MID_MODE_TRASH 0 +#define MID_MODE_RAW 1 +#define MID_MODE_AAL5 2 + +/* + * Reassembly buffer descriptor + */ + +#define MID_RED_COUNT 0x000007ff +#define MID_RED_CRC_ERR 0x00000800 +#define MID_RED_T 0x00001000 +#define MID_RED_CE 0x00010000 +#define MID_RED_CLP 0x01000000 +#define MID_RED_IDEN 0xfe000000 +#define MID_RED_SHIFT 25 + +#define MID_RED_RX_ID 0x1b /* constant identifier */ + +/* + * Segmentation buffer descriptor + */ + +#define MID_SEG_COUNT MID_RED_COUNT +#define MID_SEG_RATE 0x01f80000 +#define MID_SEG_RATE_SHIFT 19 +#define MID_SEG_PR 0x06000000 +#define MID_SEG_PR_SHIFT 25 +#define MID_SEG_AAL5 0x08000000 +#define MID_SEG_ID 0xf0000000 +#define MID_SEG_ID_SHIFT 28 +#define MID_SEG_MAX_RATE 63 + +#define MID_SEG_CLP 0x00000001 +#define MID_SEG_PTI 0x0000000e +#define MID_SEG_PTI_SHIFT 1 +#define MID_SEG_VCI 0x00003ff0 +#define MID_SEG_VCI_SHIFT 4 + +#define MID_SEG_TX_ID 0xb /* constant identifier */ + +/* + * DMA entry + */ + +#define MID_DMA_COUNT 0xffff0000 +#define MID_DMA_COUNT_SHIFT 16 +#define MID_DMA_END 0x00000020 +#define MID_DMA_TYPE 0x0000000f + +#define MID_DT_JK 0x3 +#define MID_DT_WORD 0x0 +#define MID_DT_2W 0x7 +#define MID_DT_4W 0x4 +#define MID_DT_8W 0x5 +#define MID_DT_16W 0x6 +#define MID_DT_2WM 0xf +#define MID_DT_4WM 0xc +#define MID_DT_8WM 0xd +#define MID_DT_16WM 0xe + +/* only for RX*/ +#define MID_DMA_VCI 0x0000ffc0 +#define MID_DMA_VCI_SHIFT 6 + +/* only for TX */ +#define MID_DMA_CHAN 0x000001c0 +#define MID_DMA_CHAN_SHIFT 6 + +#define MID_DT_BYTE 0x1 +#define MID_DT_HWORD 0x2 + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.3.14/linux/drivers/atm/nicstar.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/nicstar.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,3054 @@ +/****************************************************************************** + * + * nicstar.c + * + * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. + * + * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. + * It was taken from the frle-0.22 device driver. + * As the file doesn't have a copyright notice, in the file + * nicstarmac.copyright I put the copyright notice from the + * frle-0.22 device driver. + * Some code is based on the nicstar driver by M. Welsh. + * + * Author: Rui Prior (rprior@inescn.pt) + * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 + * + * + * (C) INESC 1999 + * + * + ******************************************************************************/ + + +/* Header files ***************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nicstar.h" +#include "nicstarmac.h" +#ifdef CONFIG_ATM_NICSTAR_USE_SUNI +#include "suni.h" +#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ + + +/* Additional code ************************************************************/ + +#include "nicstarmac.c" + + +/* Configurable parameters ****************************************************/ + +#undef PHY_LOOPBACK +#undef TX_DEBUG +#undef RX_DEBUG +#undef GENERAL_DEBUG +#undef EXTRA_DEBUG + +#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know + you're going to use only raw ATM */ + + +/* Do not touch these *********************************************************/ + +#ifdef TX_DEBUG +#define TXPRINTK(args...) printk(args) +#else +#define TXPRINTK(args...) +#endif /* TX_DEBUG */ + +#ifdef RX_DEBUG +#define RXPRINTK(args...) printk(args) +#else +#define RXPRINTK(args...) +#endif /* RX_DEBUG */ + +#ifdef GENERAL_DEBUG +#define PRINTK(args...) printk(args) +#else +#define PRINTK(args...) +#endif /* GENERAL_DEBUG */ + +#ifdef EXTRA_DEBUG +#define XPRINTK(args...) printk(args) +#else +#define XPRINTK(args...) +#endif /* EXTRA_DEBUG */ + + +/* Macros *********************************************************************/ + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) + +#define NS_DELAY mdelay(1) + +#define ALIGN_ADDRESS(addr, alignment) \ + ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1)) + +#undef CEIL(d) + +#ifndef ATM_SKB +#define ATM_SKB(s) (&(s)->atm) +#endif + + +/* Version definition *********************************************************/ +/* +#include +char kernel_version[] = UTS_RELEASE; +*/ + +/* Function declarations ******************************************************/ + +static u32 ns_read_sram(ns_dev *card, u32 sram_address); +static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count); +static int ns_init_card(int i, struct pci_dev *pcidev); +static void ns_init_card_error(ns_dev *card, int error); +static scq_info *get_scq(int size, u32 scd); +static void free_scq(scq_info *scq, struct atm_vcc *vcc); +static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, + u32 handle2, u32 addr2); +static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static int ns_open(struct atm_vcc *vcc, short vpi, int vci); +static void ns_close(struct atm_vcc *vcc); +static void fill_tst(ns_dev *card, int n, vc_map *vc); +static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, + struct sk_buff *skb); +static void process_tsq(ns_dev *card); +static void drain_scq(ns_dev *card, scq_info *scq, int pos); +static void process_rsq(ns_dev *card); +static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe); +#ifdef NS_USE_DESTRUCTORS +static void ns_sb_destructor(struct sk_buff *sb); +static void ns_lb_destructor(struct sk_buff *lb); +static void ns_hb_destructor(struct sk_buff *hb); +#endif /* NS_USE_DESTRUCTORS */ +static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb); +static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count); +static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb); +static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb); +static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb); +static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page); +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static void which_list(ns_dev *card, struct sk_buff *skb); +static void ns_poll(unsigned long arg); +static int ns_parse_mac(char *mac, unsigned char *esi); +static short ns_h2i(char c); +static void ns_phy_put(struct atm_dev *dev, unsigned char value, + unsigned long addr); +static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr); + + + +/* Global variables ***********************************************************/ + +static struct ns_dev *cards[NS_MAX_CARDS]; +static unsigned num_cards = 0; +static struct atmdev_ops atm_ops = +{ + NULL, /* dev_close */ + ns_open, /* open */ + ns_close, /* close */ + ns_ioctl, /* ioctl */ + NULL, /* getsockopt */ + NULL, /* setsockopt */ + ns_send, /* send */ + NULL, /* sg_send */ + NULL, /* send_oam */ + ns_phy_put, /* phy_put */ + ns_phy_get, /* phy_get */ + NULL, /* feedback */ + NULL, /* change_qos */ + NULL, /* free_rx_skb */ + ns_proc_read /* proc_read */ +}; +static struct timer_list ns_timer; +static char *mac[NS_MAX_CARDS] = { NULL +#if NS_MAX_CARDS > 1 + , NULL +#endif /* NS_MAX_CARDS > 1 */ +#if NS_MAX_CARDS > 2 + , NULL +#endif /* NS_MAX_CARDS > 2 */ +#if NS_MAX_CARDS > 3 + , NULL +#endif /* NS_MAX_CARDS > 3 */ +#if NS_MAX_CARDS > 4 + , NULL +#endif /* NS_MAX_CARDS > 4 */ + }; + +#ifdef MODULE +MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s"); +#endif /* MODULE */ + + +/* Functions*******************************************************************/ + +#ifdef MODULE + +int init_module(void) +{ + int i; + unsigned error = 0; /* Initialized to remove compile warning */ + struct pci_dev *pcidev; + + XPRINTK("nicstar: init_module() called.\n"); + if(!pci_present()) + { + printk("nicstar: no PCI subsystem found.\n"); + return -EIO; + } + + for(i = 0; i < NS_MAX_CARDS; i++) + cards[i] = NULL; + + pcidev = NULL; + for(i = 0; i < NS_MAX_CARDS; i++) + { + if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, + PCI_DEVICE_ID_IDT_IDT77201, + pcidev)) == NULL) + break; + + error = ns_init_card(i, pcidev); + if (error) + cards[i--] = NULL; /* Try to find another card but don't increment index */ + } + + if (i == 0) + { + if (!error) + { + printk("nicstar: no cards found.\n"); + return -ENXIO; + } + else + return -EIO; + } + TXPRINTK("nicstar: TX debug enabled.\n"); + RXPRINTK("nicstar: RX debug enabled.\n"); + PRINTK("nicstar: General debug enabled.\n"); +#ifdef PHY_LOOPBACK + printk("nicstar: using PHY loopback.\n"); +#endif /* PHY_LOOPBACK */ + XPRINTK("nicstar: init_module() returned.\n"); + + ns_timer.next = NULL; + ns_timer.prev = NULL; + ns_timer.expires = jiffies + NS_POLL_PERIOD; + ns_timer.data = 0UL; + ns_timer.function = ns_poll; + add_timer(&ns_timer); + return 0; +} + + + +void cleanup_module(void) +{ + int i, j; + unsigned short pci_command; + ns_dev *card; + struct sk_buff *hb; + struct sk_buff *iovb; + struct sk_buff *lb; + struct sk_buff *sb; + + XPRINTK("nicstar: cleanup_module() called.\n"); + + if (MOD_IN_USE) + printk("nicstar: module in use, remove delayed.\n"); + + del_timer(&ns_timer); + + for (i = 0; i < NS_MAX_CARDS; i++) + { + if (cards[i] == NULL) + continue; + + card = cards[i]; + + /* Stop everything */ + writel(0x00000000, card->membase + CFG); + + /* De-register device */ + atm_dev_deregister(card->atmdev); + + /* Disable memory mapping and busmastering */ + if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command) != 0) + { + printk("nicstar%d: can't read PCI_COMMAND.\n", i); + } + pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command) != 0) + { + printk("nicstar%d: can't write PCI_COMMAND.\n", i); + } + + /* Free up resources */ + j = 0; + PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); + while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) + { + kfree_skb(hb); + j++; + } + PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); + j = 0; + PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count); + while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) + { + kfree_skb(iovb); + j++; + } + PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); + while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) + kfree_skb(lb); + while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) + kfree_skb(sb); + free_scq(card->scq0, NULL); + for (j = 0; j < NS_FRSCD_NUM; j++) + { + if (card->scd2vc[j] != NULL) + free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); + } + kfree(card->rsq.org); + kfree(card->tsq.org); + free_irq(card->pcidev->irq, card); + iounmap((void *) card->membase); + kfree(card); + + } + XPRINTK("nicstar: cleanup_module() returned.\n"); +} + + +#else + +__initfunc(int nicstar_detect(void)) +{ + int i; + unsigned error = 0; /* Initialized to remove compile warning */ + struct pci_dev *pcidev; + + if(!pci_present()) + { + printk("nicstar: no PCI subsystem found.\n"); + return -EIO; + } + + for(i = 0; i < NS_MAX_CARDS; i++) + cards[i] = NULL; + + pcidev = NULL; + for(i = 0; i < NS_MAX_CARDS; i++) + { + if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, + PCI_DEVICE_ID_IDT_IDT77201, + pcidev)) == NULL) + break; + + error = ns_init_card(i, pcidev); + if (error) + cards[i--] = NULL; /* Try to find another card but don't increment index */ + } + + if (i == 0 && error) + return -EIO; + + TXPRINTK("nicstar: TX debug enabled.\n"); + RXPRINTK("nicstar: RX debug enabled.\n"); + PRINTK("nicstar: General debug enabled.\n"); +#ifdef PHY_LOOPBACK + printk("nicstar: using PHY loopback.\n"); +#endif /* PHY_LOOPBACK */ + XPRINTK("nicstar: init_module() returned.\n"); + + return i; +} + + +#endif /* MODULE */ + + +static u32 ns_read_sram(ns_dev *card, u32 sram_address) +{ + unsigned long flags; + u32 data; + sram_address <<= 2; + sram_address &= 0x0007FFFC; /* address must be dword aligned */ + sram_address |= 0x50000000; /* SRAM read command */ + save_flags(flags); cli(); + while (CMD_BUSY(card)); + writel(sram_address, card->membase + CMD); + while (CMD_BUSY(card)); + data = readl(card->membase + DR0); + restore_flags(flags); + return data; +} + + + +static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count) +{ + unsigned long flags; + int i, c; + count--; /* count range now is 0..3 instead of 1..4 */ + c = count; + c <<= 2; /* to use increments of 4 */ + save_flags(flags); cli(); + while (CMD_BUSY(card)); + for (i = 0; i <= c; i += 4) + writel(*(value++), card->membase + i); + /* Note: DR# registers are the first 4 dwords in nicstar's memspace, + so card->membase + DR0 == card->membase */ + sram_address <<= 2; + sram_address &= 0x0007FFFC; + sram_address |= (0x40000000 | count); + writel(sram_address, card->membase + CMD); + restore_flags(flags); +} + + +static int ns_init_card(int i, struct pci_dev *pcidev) +{ + int j; + struct ns_dev *card; + unsigned short pci_command; + unsigned char pci_latency; + unsigned error; + u32 data; + u32 u32d[4]; + u32 ns_cfg_rctsize; + int bcount; + + error = 0; + + if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) + { + printk("nicstar%d: can't allocate memory for device structure.\n", i); + error = 2; + ns_init_card_error(card, error); + return error; + } + cards[i] = card; + + card->index = i; + card->pcidev = pcidev; + card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); +#ifdef __powerpc__ + /* Compensate for different memory map between host CPU and PCI bus. + Shouldn't we use a macro for this? */ + card->membase += KERNELBASE; +#endif /* __powerpc__ */ + card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE); + if (card->membase == (u32) (NULL)) + { + printk("nicstar%d: can't ioremap() membase.\n",i); + error = 3; + ns_init_card_error(card, error); + return error; + } + PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase); + + if (pci_read_config_word(pcidev, PCI_COMMAND, &pci_command) != 0) + { + printk("nicstar%d: can't read PCI_COMMAND.\n", i); + error = 4; + ns_init_card_error(card, error); + return error; + } + pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(pcidev, PCI_COMMAND, pci_command) != 0) + { + printk("nicstar%d: can't write PCI_COMMAND.\n", i); + error = 5; + ns_init_card_error(card, error); + return error; + } + + if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) + { + printk("nicstar%d: can't read PCI latency timer.\n", i); + error = 6; + ns_init_card_error(card, error); + return error; + } + if (pci_latency < NS_PCI_LATENCY) + { + PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); + for (j = 1; j < 4; j++) + { + if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0); + break; + } + if (j == 4) + { + printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY); + error = 7; + ns_init_card_error(card, error); + return error; + } + } + + /* Clear timer overflow */ + data = readl(card->membase + STAT); + if (data & NS_STAT_TMROF) + writel(NS_STAT_TMROF, card->membase + STAT); + + /* Software reset */ + writel(NS_CFG_SWRST, card->membase + CFG); + NS_DELAY; + writel(0x00000000, card->membase + CFG); + + /* PHY reset */ + writel(0x00000008, card->membase + GP); + NS_DELAY; + writel(0x00000001, card->membase + GP); + NS_DELAY; + while (CMD_BUSY(card)); + writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ + NS_DELAY; + + /* Detect PHY type */ + while (CMD_BUSY(card)); + writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); + while (CMD_BUSY(card)); + data = readl(card->membase + DR0); + switch(data) { + case 0x00000009: + printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); + card->max_pcr = IDT_25_PCR; + while(CMD_BUSY(card)); + writel(0x00000008, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); + /* Clear an eventual pending interrupt */ + writel(NS_STAT_SFBQF, card->membase + STAT); +#ifdef PHY_LOOPBACK + while(CMD_BUSY(card)); + writel(0x00000022, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); +#endif /* PHY_LOOPBACK */ + break; + case 0x00000030: + case 0x00000031: + printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); + card->max_pcr = ATM_OC3_PCR; +#ifdef PHY_LOOPBACK + while(CMD_BUSY(card)); + writel(0x00000002, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); +#endif /* PHY_LOOPBACK */ + break; + default: + printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); + error = 8; + ns_init_card_error(card, error); + return error; + } + writel(0x00000000, card->membase + GP); + + /* Determine SRAM size */ + data = 0x76543210; + ns_write_sram(card, 0x1C003, &data, 1); + data = 0x89ABCDEF; + ns_write_sram(card, 0x14003, &data, 1); + if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && + ns_read_sram(card, 0x1C003) == 0x76543210) + card->sram_size = 128; + else + card->sram_size = 32; + PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); + + card->rct_size = NS_MAX_RCTSIZE; + +#if (NS_MAX_RCTSIZE == 4096) + if (card->sram_size == 128) + printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i); +#elif (NS_MAX_RCTSIZE == 16384) + if (card->sram_size == 32) + { + printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i); + card->rct_size = 4096; + } +#else +#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c +#endif + + card->vpibits = NS_VPIBITS; + if (card->rct_size == 4096) + card->vcibits = 12 - NS_VPIBITS; + else /* card->rct_size == 16384 */ + card->vcibits = 14 - NS_VPIBITS; + + /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ + if (mac[i] == NULL) + nicstar_init_eprom(card->membase); + + if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT | SA_SHIRQ, "nicstar", card) != 0) + { + printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq); + error = 9; + ns_init_card_error(card, error); + return error; + } + + /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ + writel(0x00000000, card->membase + VPM); + + /* Initialize TSQ */ + card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL); + if (card->tsq.org == NULL) + { + printk("nicstar%d: can't allocate TSQ.\n", i); + error = 10; + ns_init_card_error(card, error); + return error; + } + card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT); + card->tsq.next = card->tsq.base; + card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); + for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) + ns_tsi_init(card->tsq.base + j); + writel(0x00000000, card->membase + TSQH); + writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB); + PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base, + (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB)); + + /* Initialize RSQ */ + card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL); + if (card->rsq.org == NULL) + { + printk("nicstar%d: can't allocate RSQ.\n", i); + error = 11; + ns_init_card_error(card, error); + return error; + } + card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT); + card->rsq.next = card->rsq.base; + card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); + for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) + ns_rsqe_init(card->rsq.base + j); + writel(0x00000000, card->membase + RSQH); + writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB); + PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base); + + /* Initialize SCQ0, the only VBR SCQ used */ + card->scq1 = (scq_info *) NULL; + card->scq2 = (scq_info *) NULL; + card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); + if (card->scq0 == (scq_info *) NULL) + { + printk("nicstar%d: can't get SCQ0.\n", i); + error = 12; + ns_init_card_error(card, error); + return error; + } + u32d[0] = (u32) virt_to_bus(card->scq0->base); + u32d[1] = (u32) 0x00000000; + u32d[2] = (u32) 0xffffffff; + u32d[3] = (u32) 0x00000000; + ns_write_sram(card, NS_VRSCD0, u32d, 4); + ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ + ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ + card->scq0->scd = NS_VRSCD0; + PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base); + + /* Initialize TSTs */ + card->tst_addr = NS_TST0; + card->tst_free_entries = NS_TST_NUM_ENTRIES; + data = NS_TST_OPCODE_VARIABLE; + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + ns_write_sram(card, NS_TST0 + j, &data, 1); + data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); + ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + ns_write_sram(card, NS_TST1 + j, &data, 1); + data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); + ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + card->tste2vc[j] = NULL; + writel(NS_TST0 << 2, card->membase + TSTB); + + + /* Initialize RCT. AAL type is set on opening the VC. */ +#ifdef RCQ_SUPPORT + u32d[0] = NS_RCTE_RAWCELLINTEN; +#else + u32d[0] = 0x00000000; +#endif RCQ_SUPPORT + u32d[1] = 0x00000000; + u32d[2] = 0x00000000; + u32d[3] = 0xFFFFFFFF; + for (j = 0; j < card->rct_size; j++) + ns_write_sram(card, j * 4, u32d, 4); + + memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map)); + + for (j = 0; j < NS_FRSCD_NUM; j++) + card->scd2vc[j] = NULL; + + /* Initialize buffer levels */ + card->sbnr.min = MIN_SB; + card->sbnr.init = NUM_SB; + card->sbnr.max = MAX_SB; + card->lbnr.min = MIN_LB; + card->lbnr.init = NUM_LB; + card->lbnr.max = MAX_LB; + card->iovnr.min = MIN_IOVB; + card->iovnr.init = NUM_IOVB; + card->iovnr.max = MAX_IOVB; + card->hbnr.min = MIN_HB; + card->hbnr.init = NUM_HB; + card->hbnr.max = MAX_HB; + + card->sm_handle = 0x00000000; + card->sm_addr = 0x00000000; + card->lg_handle = 0x00000000; + card->lg_addr = 0x00000000; + + card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ + + /* Pre-allocate some huge buffers */ + skb_queue_head_init(&card->hbpool.queue); + card->hbpool.count = 0; + for (j = 0; j < NUM_HB; j++) + { + struct sk_buff *hb; + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", + i, j, NUM_HB); + error = 13; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } + + + /* Allocate large buffers */ + skb_queue_head_init(&card->lbpool.queue); + card->lbpool.count = 0; /* Not used */ + for (j = 0; j < NUM_LB; j++) + { + struct sk_buff *lb; + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d large buffers.\n", + i, j, NUM_LB); + error = 14; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + /* Due to the implementation of push_rxbufs() this is 1, not 0 */ + if (j == 1) + { + card->rcbuf = lb; + card->rawch = (u32) virt_to_bus(lb->data); + } + } + /* Test for strange behaviour which leads to crashes */ + if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) + { + printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", + i, j, bcount); + error = 14; + ns_init_card_error(card, error); + return error; + } + + + /* Allocate small buffers */ + skb_queue_head_init(&card->sbpool.queue); + card->sbpool.count = 0; /* Not used */ + for (j = 0; j < NUM_SB; j++) + { + struct sk_buff *sb; + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d small buffers.\n", + i, j, NUM_SB); + error = 15; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + /* Test for strange behaviour which leads to crashes */ + if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) + { + printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", + i, j, bcount); + error = 15; + ns_init_card_error(card, error); + return error; + } + + + /* Allocate iovec buffers */ + skb_queue_head_init(&card->iovpool.queue); + card->iovpool.count = 0; + for (j = 0; j < NUM_IOVB; j++) + { + struct sk_buff *iovb; + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); + if (iovb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", + i, j, NUM_IOVB); + error = 16; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + } + + + card->in_handler = 0; + card->in_poll = 0; + card->intcnt = 0; + + /* Configure NICStAR */ + if (card->rct_size == 4096) + ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; + else /* (card->rct_size == 16384) */ + ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; + + card->efbie = 1; + writel(NS_CFG_RXPATH | + NS_CFG_SMBUFSIZE | + NS_CFG_LGBUFSIZE | + NS_CFG_EFBIE | + NS_CFG_RSQSIZE | + NS_CFG_VPIBITS | + ns_cfg_rctsize | + NS_CFG_RXINT_NODELAY | + NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ + NS_CFG_RSQAFIE | + NS_CFG_TXEN | + NS_CFG_TXIE | + NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ + NS_CFG_PHYIE, + card->membase + CFG); + + /* Register device */ + card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL); + if (card->atmdev == NULL) + { + printk("nicstar%d: can't register device.\n", i); + error = 17; + ns_init_card_error(card, error); + return error; + } + + if (ns_parse_mac(mac[i], card->atmdev->esi)) + nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, + card->atmdev->esi, 6); + + printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, + card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], + card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); + + card->atmdev->dev_data = card; + card->atmdev->ci_range.vpi_bits = card->vpibits; + card->atmdev->ci_range.vci_bits = card->vcibits; + card->atmdev->link_rate = card->max_pcr; + +#ifdef CONFIG_ATM_NICSTAR_USE_SUNI + if (card->max_pcr == ATM_OC3_PCR) { + suni_init(card->atmdev); +#ifdef MODULE + MOD_INC_USE_COUNT; + /* Can't remove the nicstar driver or the suni driver would oops */ +#endif /* MODULE */ + } +#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ + if (card->atmdev->phy && card->atmdev->phy->start) + card->atmdev->phy->start(card->atmdev); + + num_cards++; + + return error; +} + + + +static void ns_init_card_error(ns_dev *card, int error) +{ + if (error >= 17) + { + writel(0x00000000, card->membase + CFG); + } + if (error >= 16) + { + struct sk_buff *iovb; + while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) + kfree_skb(iovb); + } + if (error >= 15) + { + struct sk_buff *sb; + while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) + kfree_skb(sb); + free_scq(card->scq0, NULL); + } + if (error >= 14) + { + struct sk_buff *lb; + while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) + kfree_skb(lb); + } + if (error >= 13) + { + struct sk_buff *hb; + while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) + kfree_skb(hb); + } + if (error >= 12) + { + kfree(card->rsq.org); + } + if (error >= 11) + { + kfree(card->tsq.org); + } + if (error >= 10) + { + free_irq(card->pcidev->irq, card); + } + if (error >= 4) + { + iounmap((void *) card->membase); + } + if (error >= 3) + { + kfree(card); + } +} + + + +static scq_info *get_scq(int size, u32 scd) +{ + scq_info *scq; + int i; + + if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) + return (scq_info *) NULL; + + scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); + if (scq == (scq_info *) NULL) + return (scq_info *) NULL; + scq->org = kmalloc(2 * size, GFP_KERNEL); + if (scq->org == NULL) + { + kfree(scq); + return (scq_info *) NULL; + } + scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * + (size / NS_SCQE_SIZE), GFP_KERNEL); + if (scq->skb == (struct sk_buff **) NULL) + { + kfree(scq->org); + kfree(scq); + return (scq_info *) NULL; + } + scq->num_entries = size / NS_SCQE_SIZE; + scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size); + scq->next = scq->base; + scq->last = scq->base + (scq->num_entries - 1); + scq->tail = scq->last; + scq->scd = scd; + scq->num_entries = size / NS_SCQE_SIZE; + scq->tbd_count = 0; + init_waitqueue_head(&scq->scqfull_waitq); + scq->full = 0; + + for (i = 0; i < scq->num_entries; i++) + scq->skb[i] = NULL; + + return scq; +} + + + +/* For variable rate SCQ vcc must be NULL */ +static void free_scq(scq_info *scq, struct atm_vcc *vcc) +{ + int i; + + if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) + for (i = 0; i < scq->num_entries; i++) + { + if (scq->skb[i] != NULL) + { + vcc = ATM_SKB(scq->skb[i])->vcc; + if (vcc->pop != NULL) + vcc->pop(vcc, scq->skb[i]); + else + dev_kfree_skb(scq->skb[i]); + } + } + else /* vcc must be != NULL */ + { + if (vcc == NULL) + { + printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); + for (i = 0; i < scq->num_entries; i++) + dev_kfree_skb(scq->skb[i]); + } + else + for (i = 0; i < scq->num_entries; i++) + { + if (scq->skb[i] != NULL) + { + if (vcc->pop != NULL) + vcc->pop(vcc, scq->skb[i]); + else + dev_kfree_skb(scq->skb[i]); + } + } + } + kfree(scq->skb); + kfree(scq->org); + kfree(scq); +} + + + +/* The handles passed must be pointers to the sk_buff containing the small + or large buffer(s) cast to u32. */ +static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, + u32 handle2, u32 addr2) +{ + u32 stat; + unsigned long flags; + + +#ifdef GENERAL_DEBUG + if (!addr1) + printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index); +#endif /* GENERAL_DEBUG */ + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + if (type == BUF_SM) + { + if (!addr2) + { + if (card->sm_addr) + { + addr2 = card->sm_addr; + handle2 = card->sm_handle; + card->sm_addr = 0x00000000; + card->sm_handle = 0x00000000; + } + else /* (!sm_addr) */ + { + card->sm_addr = addr1; + card->sm_handle = handle1; + } + } + } + else /* type == BUF_LG */ + { + if (!addr2) + { + if (card->lg_addr) + { + addr2 = card->lg_addr; + handle2 = card->lg_handle; + card->lg_addr = 0x00000000; + card->lg_handle = 0x00000000; + } + else /* (!lg_addr) */ + { + card->lg_addr = addr1; + card->lg_handle = handle1; + } + } + } + + if (addr2) + { + if (type == BUF_SM) + { + if (card->sbfqc >= card->sbnr.max) + { + skb_unlink((struct sk_buff *) handle1); + kfree_skb((struct sk_buff *) handle1); + skb_unlink((struct sk_buff *) handle2); + kfree_skb((struct sk_buff *) handle2); + return; + } + else + card->sbfqc += 2; + } + else /* (type == BUF_LG) */ + { + if (card->lbfqc >= card->lbnr.max) + { + skb_unlink((struct sk_buff *) handle1); + kfree_skb((struct sk_buff *) handle1); + skb_unlink((struct sk_buff *) handle2); + kfree_skb((struct sk_buff *) handle2); + return; + } + else + card->lbfqc += 2; + } + + save_flags(flags); cli(); + + while (CMD_BUSY(card)); + writel(handle1, card->membase + DR0); + writel(addr1, card->membase + DR1); + writel(handle2, card->membase + DR2); + writel(addr2, card->membase + DR3); + writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD); + + restore_flags(flags); + + XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index, + (type == BUF_SM ? "small" : "large"), addr1, addr2); + } + + if (!card->efbie && card->sbfqc >= card->sbnr.min && + card->lbfqc >= card->lbnr.min) + { + card->efbie = 1; + writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG); + } + + return; +} + + + +static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat_r; + ns_dev *card; + struct atm_dev *dev; + + card = (ns_dev *) dev_id; + dev = card->atmdev; + card->intcnt++; + + PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); + + if (card->in_handler) + { + printk("nicstar%d: Re-entering ns_irq_handler()???\n", card->index); + return; + } + card->in_handler = 1; + if (card->in_poll) + { + card->in_handler = 0; + printk("nicstar%d: Called irq handler while in ns_poll()!?\n", + card->index); + return; + } + + stat_r = readl(card->membase + STAT); + + /* Transmit Status Indicator has been written to T. S. Queue */ + if (stat_r & NS_STAT_TSIF) + { + TXPRINTK("nicstar%d: TSI interrupt\n", card->index); + process_tsq(card); + writel(NS_STAT_TSIF, card->membase + STAT); + } + + /* Incomplete CS-PDU has been transmitted */ + if (stat_r & NS_STAT_TXICP) + { + writel(NS_STAT_TXICP, card->membase + STAT); + TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", + card->index); + } + + /* Transmit Status Queue 7/8 full */ + if (stat_r & NS_STAT_TSQF) + { + writel(NS_STAT_TSQF, card->membase + STAT); + PRINTK("nicstar%d: TSQ full.\n", card->index); + process_tsq(card); + } + + /* Timer overflow */ + if (stat_r & NS_STAT_TMROF) + { + writel(NS_STAT_TMROF, card->membase + STAT); + PRINTK("nicstar%d: Timer overflow.\n", card->index); + } + + /* PHY device interrupt signal active */ + if (stat_r & NS_STAT_PHYI) + { + writel(NS_STAT_PHYI, card->membase + STAT); + PRINTK("nicstar%d: PHY interrupt.\n", card->index); + if (dev->phy && dev->phy->interrupt) { + dev->phy->interrupt(dev); + } + } + + /* Small Buffer Queue is full */ + if (stat_r & NS_STAT_SFBQF) + { + writel(NS_STAT_SFBQF, card->membase + STAT); + printk("nicstar%d: Small free buffer queue is full.\n", card->index); + } + + /* Large Buffer Queue is full */ + if (stat_r & NS_STAT_LFBQF) + { + writel(NS_STAT_LFBQF, card->membase + STAT); + printk("nicstar%d: Large free buffer queue is full.\n", card->index); + } + + /* Receive Status Queue is full */ + if (stat_r & NS_STAT_RSQF) + { + writel(NS_STAT_RSQF, card->membase + STAT); + printk("nicstar%d: RSQ full.\n", card->index); + process_rsq(card); + } + + /* Complete CS-PDU received */ + if (stat_r & NS_STAT_EOPDU) + { + RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); + process_rsq(card); + writel(NS_STAT_EOPDU, card->membase + STAT); + } + + /* Raw cell received */ + if (stat_r & NS_STAT_RAWCF) + { + writel(NS_STAT_RAWCF, card->membase + STAT); +#ifndef RCQ_SUPPORT + printk("nicstar%d: Raw cell received and no support yet...\n", + card->index); +#endif /* RCQ_SUPPORT */ + /* NOTE: the following procedure may keep a raw cell pending untill the + next interrupt. As this preliminary support is only meant to + avoid buffer leakage, this is not an issue. */ + while (readl(card->membase + RAWCT) != card->rawch) + { + ns_rcqe *rawcell; + + rawcell = (ns_rcqe *) bus_to_virt(card->rawch); + if (ns_rcqe_islast(rawcell)) + { + struct sk_buff *oldbuf; + + oldbuf = card->rcbuf; + card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell); + card->rawch = (u32) virt_to_bus(card->rcbuf->data); + recycle_rx_buf(card, oldbuf); + } + else + card->rawch += NS_RCQE_SIZE; + } + } + + /* Small buffer queue is empty */ + if (stat_r & NS_STAT_SFBQE) + { + int i; + struct sk_buff *sb; + + writel(NS_STAT_SFBQE, card->membase + STAT); + printk("nicstar%d: Small free buffer queue empty.\n", + card->index); + for (i = 0; i < card->sbnr.min; i++) + { + sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC); + if (sb == NULL) + { + writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); + card->efbie = 0; + break; + } + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + card->sbfqc = i; + process_rsq(card); + } + + /* Large buffer queue empty */ + if (stat_r & NS_STAT_LFBQE) + { + int i; + struct sk_buff *lb; + + writel(NS_STAT_LFBQE, card->membase + STAT); + printk("nicstar%d: Large free buffer queue empty.\n", + card->index); + for (i = 0; i < card->lbnr.min; i++) + { + lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC); + if (lb == NULL) + { + writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); + card->efbie = 0; + break; + } + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } + card->lbfqc = i; + process_rsq(card); + } + + /* Receive Status Queue is 7/8 full */ + if (stat_r & NS_STAT_RSQAF) + { + writel(NS_STAT_RSQAF, card->membase + STAT); + RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); + process_rsq(card); + } + + card->in_handler = 0; + PRINTK("nicstar%d: end of interrupt service\n", card->index); +} + + + +static int ns_open(struct atm_vcc *vcc, short vpi, int vci) +{ + ns_dev *card; + vc_map *vc; + int error; + unsigned long tmpl, modl; + int tcr, tcra; /* target cell rate, and absolute value */ + int n = 0; /* Number of entries in the TST. Initialized to remove + the compiler warning. */ + u32 u32d[4]; + int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler + warning. How I wish compilers were clever enough to + tell which variables can truly be used + uninitialized... */ + int inuse; /* tx or rx vc already in use by another vcc */ + + card = (ns_dev *) vcc->dev->dev_data; + PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci); + if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) + { + PRINTK("nicstar%d: unsupported AAL.\n", card->index); + return -EINVAL; + } + + if ((error = atm_find_ci(vcc, &vpi, &vci))) + { + PRINTK("nicstar%d: error in atm_find_ci().\n", card->index); + return error; + } + vc = &(card->vcmap[vpi << card->vcibits | vci]); + vcc->vpi = vpi; + vcc->vci = vci; + vcc->dev_data = vc; + + inuse = 0; + if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) + inuse = 1; + if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) + inuse += 2; + if (inuse) + { + printk("nicstar%d: %s vci already in use.\n", card->index, + inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); + return -EINVAL; + } + + vcc->flags |= ATM_VF_ADDR; + + /* NOTE: You are not allowed to modify an open connection's QOS. To change + that, remove the ATM_VF_PARTIAL flag checking. There may be other changes + needed to do that. */ + if (!(vcc->flags & ATM_VF_PARTIAL)) + { + scq_info *scq; + + vcc->flags |= ATM_VF_PARTIAL; + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + /* Check requested cell rate and availability of SCD */ + if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 && + vcc->qos.txtp.min_pcr == 0) + { + PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", + card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + + tcr = atm_pcr_goal(&(vcc->qos.txtp)); + tcra = tcr >= 0 ? tcr : -tcr; + + PRINTK("nicstar%d: target cell rate = %d.\n", card->index, + vcc->qos.txtp.max_pcr); + + tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES; + modl = tmpl % card->max_pcr; + + n = (int)(tmpl / card->max_pcr); + if (tcr > 0) + { + if (modl > 0) n++; + } + else if (tcr == 0) + { + if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) + { + PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + } + + if (n == 0) + { + printk("nicstar%d: selected bandwidth < granularity.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + + if (n > (card->tst_free_entries - NS_TST_RESERVED)) + { + PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + else + card->tst_free_entries -= n; + + XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n); + for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) + { + if (card->scd2vc[frscdi] == NULL) + { + card->scd2vc[frscdi] = vc; + break; + } + } + if (frscdi == NS_FRSCD_NUM) + { + PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); + card->tst_free_entries += n; + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EBUSY; + } + + vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; + + scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); + if (scq == (scq_info *) NULL) + { + PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); + card->scd2vc[frscdi] = NULL; + card->tst_free_entries += n; + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -ENOMEM; + } + vc->scq = scq; + u32d[0] = (u32) virt_to_bus(scq->base); + u32d[1] = (u32) 0x00000000; + u32d[2] = (u32) 0xffffffff; + u32d[3] = (u32) 0x00000000; + ns_write_sram(card, vc->cbr_scd, u32d, 4); + + fill_tst(card, n, vc); + } + else /* not CBR */ + { + vc->cbr_scd = 0x00000000; + vc->scq = card->scq0; + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + vc->tx = 1; + vc->tx_vcc = vcc; + vc->tbd_count = 0; + } + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + u32 status; + + vc->rx = 1; + vc->rx_vcc = vcc; + vc->rx_iov = NULL; + + /* Open the connection in hardware */ + if (vcc->qos.aal == ATM_AAL5) + status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; + else /* vcc->qos.aal == ATM_AAL0 */ + status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; +#ifdef RCQ_SUPPORT + status |= NS_RCTE_RAWCELLINTEN; +#endif /* RCQ_SUPPORT */ + ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) * + NS_RCT_ENTRY_SIZE, &status, 1); + } + + } + + vcc->flags |= ATM_VF_READY; + MOD_INC_USE_COUNT; + return 0; +} + + + +static void ns_close(struct atm_vcc *vcc) +{ + vc_map *vc; + ns_dev *card; + u32 data; + int i; + + vc = vcc->dev_data; + card = vcc->dev->dev_data; + PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, + (int) vcc->vpi, vcc->vci); + + vcc->flags &= ~(ATM_VF_READY); + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + u32 addr; + unsigned long flags; + + addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; + save_flags(flags); cli(); + while(CMD_BUSY(card)); + writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD); + restore_flags(flags); + + vc->rx = 0; + if (vc->rx_iov != NULL) + { + struct sk_buff *iovb; + u32 stat; + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + PRINTK("nicstar%d: closing a VC with pending rx buffers.\n", + card->index); + iovb = vc->rx_iov; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + ATM_SKB(iovb)->iovcnt); + ATM_SKB(iovb)->iovcnt = 0; + ATM_SKB(iovb)->vcc = NULL; + save_flags(flags); cli(); + recycle_iov_buf(card, iovb); + restore_flags(flags); + vc->rx_iov = NULL; + } + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + vc->tx = 0; + } + + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + unsigned long flags; + ns_scqe *scqep; + scq_info *scq; + + scq = vc->scq; + + for (;;) + { + save_flags(flags); cli(); + scqep = scq->next; + if (scqep == scq->base) + scqep = scq->last; + else + scqep--; + if (scqep == scq->tail) + { + restore_flags(flags); + break; + } + /* If the last entry is not a TSR, place one in the SCQ in order to + be able to completely drain it and then close. */ + if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) + { + ns_scqe tsr; + u32 scdi, scqi; + u32 data; + int index; + + tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); + scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; + scqi = scq->next - scq->base; + tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); + tsr.word_3 = 0x00000000; + tsr.word_4 = 0x00000000; + *scq->next = tsr; + index = (int) scqi; + scq->skb[index] = NULL; + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + data = (u32) virt_to_bus(scq->next); + ns_write_sram(card, scq->scd, &data, 1); + } + schedule(); + restore_flags(flags); + } + + /* Free all TST entries */ + data = NS_TST_OPCODE_VARIABLE; + for (i = 0; i < NS_TST_NUM_ENTRIES; i++) + { + if (card->tste2vc[i] == vc) + { + ns_write_sram(card, card->tst_addr + i, &data, 1); + card->tste2vc[i] = NULL; + card->tst_free_entries++; + } + } + + card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; + free_scq(vc->scq, vcc); + } + + vcc->dev_data = NULL; + vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR); + MOD_DEC_USE_COUNT; + +#ifdef RX_DEBUG + { + u32 stat, cfg; + stat = readl(card->membase + STAT); + cfg = readl(card->membase + CFG); + printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); + printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n", + (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last, + readl(card->membase + TSQT)); + printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n", + (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last, + readl(card->membase + RSQT)); + printk("Empty free buffer queue interrupt %s \n", + card->efbie ? "enabled" : "disabled"); + printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", + ns_stat_sfbqc_get(stat), card->sbpool.count, + ns_stat_lfbqc_get(stat), card->lbpool.count); + printk("hbpool.count = %d iovpool.count = %d \n", + card->hbpool.count, card->iovpool.count); + } +#endif /* RX_DEBUG */ +} + + + +static void fill_tst(ns_dev *card, int n, vc_map *vc) +{ + u32 new_tst; + unsigned long cl; + int e, r; + u32 data; + + /* It would be very complicated to keep the two TSTs synchronized while + assuring that writes are only made to the inactive TST. So, for now I + will use only one TST. If problems occur, I will change this again */ + + new_tst = card->tst_addr; + + /* Fill procedure */ + + for (e = 0; e < NS_TST_NUM_ENTRIES; e++) + { + if (card->tste2vc[e] == NULL) + break; + } + if (e == NS_TST_NUM_ENTRIES) { + printk("nicstar%d: No free TST entries found. \n", card->index); + return; + } + + r = n; + cl = NS_TST_NUM_ENTRIES; + data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); + + while (r > 0) + { + if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) + { + card->tste2vc[e] = vc; + ns_write_sram(card, new_tst + e, &data, 1); + cl -= NS_TST_NUM_ENTRIES; + r--; + } + + if (++e == NS_TST_NUM_ENTRIES) { + e = 0; + } + cl += n; + } + + /* End of fill procedure */ + + data = ns_tste_make(NS_TST_OPCODE_END, new_tst); + ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); + ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); + card->tst_addr = new_tst; +} + + + +static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + ns_dev *card; + vc_map *vc; + scq_info *scq; + unsigned long buflen; + ns_scqe scqe; + u32 flags; /* TBD flags, not CPU flags */ + + card = vcc->dev->dev_data; + TXPRINTK("nicstar%d: ns_send() called.\n", card->index); + if ((vc = (vc_map *) vcc->dev_data) == NULL) + { + printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (!vc->tx) + { + printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) + { + printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (ATM_SKB(skb)->iovcnt != 0) + { + printk("nicstar%d: No scatter-gather yet.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + ATM_SKB(skb)->vcc = vcc; + + if (vcc->qos.aal == ATM_AAL5) + { + buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ + flags = NS_TBD_AAL5; + scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data)); + scqe.word_3 = cpu_to_le32((u32) skb->len); + scqe.word_4 = cpu_to_le32(((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | + ((u32) vcc->vci) << NS_TBD_VCI_SHIFT); + flags |= NS_TBD_EOPDU; + } + else /* (vcc->qos.aal == ATM_AAL0) */ + { + buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ + flags = NS_TBD_AAL0; + scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER); + scqe.word_3 = cpu_to_le32(0x00000000); + if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ + flags |= NS_TBD_EOPDU; + scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); + /* Force the VPI/VCI to be the same as in VCC struct */ + scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | + ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & + NS_TBD_VC_MASK); + } + + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); + scq = ((vc_map *) vcc->dev_data)->scq; + } + else + { + scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); + scq = card->scq0; + } + + if (push_scqe(card, vc, scq, &scqe, skb) != 0) + { + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EIO; + } + vcc->stats->tx++; + + return 0; +} + + + +static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, + struct sk_buff *skb) +{ + unsigned long flags; + ns_scqe tsr; + u32 scdi, scqi; + int scq_is_vbr; + u32 data; + int index; + + if (scq->tail == scq->next) + { + if (in_interrupt()) { + printk("nicstar%d: Error pushing TBD.\n", card->index); + return 1; + } + + save_flags(flags); cli(); + scq->full = 1; + interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); + restore_flags(flags); + + if (scq->full) { + printk("nicstar%d: Timeout pushing TBD.\n", card->index); + return 1; + } + } + *scq->next = *tbd; + index = (int) (scq->next - scq->base); + scq->skb[index] = skb; + XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n", + card->index, (u32) skb, index); + XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", + card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), + le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), + (u32) scq->next); + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + + vc->tbd_count++; + if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) + { + scq->tbd_count++; + scq_is_vbr = 1; + } + else + scq_is_vbr = 0; + + if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ) + { + if (scq->tail == scq->next) + { + if (in_interrupt()) { + data = (u32) virt_to_bus(scq->next); + ns_write_sram(card, scq->scd, &data, 1); + printk("nicstar%d: Error pushing TSR.\n", card->index); + return 0; + } + + save_flags(flags); cli(); + scq->full = 1; + interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); + restore_flags(flags); + } + + if (!scq->full) + { + tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); + if (scq_is_vbr) + scdi = NS_TSR_SCDISVBR; + else + scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; + scqi = scq->next - scq->base; + tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); + tsr.word_3 = 0x00000000; + tsr.word_4 = 0x00000000; + + *scq->next = tsr; + index = (int) scqi; + scq->skb[index] = NULL; + XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", + card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2), + le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4), + (u32) scq->next); + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + vc->tbd_count = 0; + scq->tbd_count = 0; + } + else + PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index); + } + + data = (u32) virt_to_bus(scq->next); + ns_write_sram(card, scq->scd, &data, 1); + + return 0; +} + + + +static void process_tsq(ns_dev *card) +{ + u32 scdi; + scq_info *scq; + ns_tsi *previous, *one_ahead, *two_ahead; + int serviced_entries; /* flag indicating at least on entry was serviced */ + + serviced_entries = 0; + + if (card->tsq.next == card->tsq.last) + one_ahead = card->tsq.base; + else + one_ahead = card->tsq.next + 1; + + if (one_ahead == card->tsq.last) + two_ahead = card->tsq.base; + else + two_ahead = one_ahead + 1; + + while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || + !ns_tsi_isempty(two_ahead)) + /* At most two empty, as stated in the 77201 errata */ + { + serviced_entries = 1; + + /* Skip the one or two possible empty entries */ + while (ns_tsi_isempty(card->tsq.next)) { + if (card->tsq.next == card->tsq.last) + card->tsq.next = card->tsq.base; + else + card->tsq.next++; + } + + if (!ns_tsi_tmrof(card->tsq.next)) + { + scdi = ns_tsi_getscdindex(card->tsq.next); + if (scdi == NS_TSI_SCDISVBR) + scq = card->scq0; + else + { + if (card->scd2vc[scdi] == NULL) + { + printk("nicstar%d: could not find VC from SCD index.\n", + card->index); + ns_tsi_init(card->tsq.next); + return; + } + scq = card->scd2vc[scdi]->scq; + } + drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); + scq->full = 0; + wake_up_interruptible(&(scq->scqfull_waitq)); + } + + ns_tsi_init(card->tsq.next); + previous = card->tsq.next; + if (card->tsq.next == card->tsq.last) + card->tsq.next = card->tsq.base; + else + card->tsq.next++; + + if (card->tsq.next == card->tsq.last) + one_ahead = card->tsq.base; + else + one_ahead = card->tsq.next + 1; + + if (one_ahead == card->tsq.last) + two_ahead = card->tsq.base; + else + two_ahead = one_ahead + 1; + } + + if (serviced_entries) { + writel((((u32) previous) - ((u32) card->tsq.base)), + card->membase + TSQH); + } +} + + + +static void drain_scq(ns_dev *card, scq_info *scq, int pos) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + int i; + + XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n", + card->index, (u32) scq, pos); + if (pos >= scq->num_entries) + { + printk("nicstar%d: Bad index on drain_scq().\n", card->index); + return; + } + + i = (int) (scq->tail - scq->base); + if (++i == scq->num_entries) + i = 0; + while (i != pos) + { + skb = scq->skb[i]; + XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n", + card->index, (u32) skb, i); + if (skb != NULL) + { + vcc = ATM_SKB(skb)->vcc; + if (vcc->pop != NULL) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + scq->skb[i] = NULL; + } + if (++i == scq->num_entries) + i = 0; + } + scq->tail = scq->base + pos; +} + + + +static void process_rsq(ns_dev *card) +{ + ns_rsqe *previous; + + if (!ns_rsqe_valid(card->rsq.next)) + return; + while (ns_rsqe_valid(card->rsq.next)) + { + dequeue_rx(card, card->rsq.next); + ns_rsqe_init(card->rsq.next); + previous = card->rsq.next; + if (card->rsq.next == card->rsq.last) + card->rsq.next = card->rsq.base; + else + card->rsq.next++; + } + writel((((u32) previous) - ((u32) card->rsq.base)), + card->membase + RSQH); +} + + + +static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) +{ + u32 vpi, vci; + vc_map *vc; + struct sk_buff *iovb; + struct iovec *iov; + struct atm_vcc *vcc; + struct sk_buff *skb; + unsigned short aal5_len; + int len; + u32 stat; + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle); + vpi = ns_rsqe_vpi(rsqe); + vci = ns_rsqe_vci(rsqe); + if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) + { + printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", + card->index, vpi, vci); + recycle_rx_buf(card, skb); + return; + } + + vc = &(card->vcmap[vpi << card->vcibits | vci]); + if (!vc->rx) + { + RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", + card->index, vpi, vci); + recycle_rx_buf(card, skb); + return; + } + + vcc = vc->rx_vcc; + + if (vcc->qos.aal == ATM_AAL0) + { + struct sk_buff *sb; + unsigned char *cell; + int i; + + cell = skb->data; + for (i = ns_rsqe_cellcount(rsqe); i; i--) + { + if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL) + { + printk("nicstar%d: Can't allocate buffers for aal0.\n", + card->index); + vcc->stats->rx_drop += i; + break; + } + if (!atm_charge(vcc, sb->truesize)) + { + RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n", + card->index); + vcc->stats->rx_drop += i - 1; /* already increased by 1 */ + kfree_skb(sb); + break; + } + /* Rebuild the header */ + *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 | + (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); + if (i == 1 && ns_rsqe_eopdu(rsqe)) + *((u32 *) sb->data) |= 0x00000002; + skb_put(sb, NS_AAL0_HEADER); + memcpy(sb->tail, cell, ATM_CELL_PAYLOAD); + skb_put(sb, ATM_CELL_PAYLOAD); + ATM_SKB(sb)->vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + vcc->stats->rx++; + cell += ATM_CELL_PAYLOAD; + } + + recycle_rx_buf(card, skb); + return; + } + + /* To reach this point, the AAL layer can only be AAL5 */ + + if ((iovb = vc->rx_iov) == NULL) + { + iovb = skb_dequeue(&(card->iovpool.queue)); + if (iovb == NULL) /* No buffers in the queue */ + { + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); + if (iovb == NULL) + { + printk("nicstar%d: Out of iovec buffers.\n", card->index); + vcc->stats->rx_drop++; + recycle_rx_buf(card, skb); + return; + } + } + else + if (--card->iovpool.count < card->iovnr.min) + { + struct sk_buff *new_iovb; + if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->iovpool.queue, new_iovb); + card->iovpool.count++; + } + } + vc->rx_iov = iovb; + ATM_SKB(iovb)->iovcnt = 0; + iovb->len = 0; + iovb->tail = iovb->data = iovb->head; + ATM_SKB(iovb)->vcc = vcc; + /* IMPORTANT: a pointer to the sk_buff containing the small or large + buffer is stored as iovec base, NOT a pointer to the + small or large buffer itself. */ + } + else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) + { + printk("nicstar%d: received too big AAL5 SDU.\n", card->index); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); + ATM_SKB(iovb)->iovcnt = 0; + iovb->len = 0; + iovb->tail = iovb->data = iovb->head; + ATM_SKB(iovb)->vcc = vcc; + } + iov = &((struct iovec *) iovb->data)[ATM_SKB(iovb)->iovcnt++]; + iov->iov_base = (void *) skb; + iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; + iovb->len += iov->iov_len; + + if (ATM_SKB(iovb)->iovcnt == 1) + { + if (skb->list != &card->sbpool.queue) + { + printk("nicstar%d: Expected a small buffer, and this is not one.\n", + card->index); + which_list(card, skb); + vcc->stats->rx_err++; + recycle_rx_buf(card, skb); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + } + else /* ATM_SKB(iovb)->iovcnt >= 2 */ + { + if (skb->list != &card->lbpool.queue) + { + printk("nicstar%d: Expected a large buffer, and this is not one.\n", + card->index); + which_list(card, skb); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + ATM_SKB(iovb)->iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + } + + if (ns_rsqe_eopdu(rsqe)) + { + /* This works correctly regardless of the endianness of the host */ + unsigned char *L1L2 = (unsigned char *)((u32)skb->data + + iov->iov_len - 6); + aal5_len = L1L2[0] << 8 | L1L2[1]; + len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; + if (ns_rsqe_crcerr(rsqe) || + len + 8 > iovb->len || len + (47 + 8) < iovb->len) + { + printk("nicstar%d: AAL5 CRC error", card->index); + if (len + 8 > iovb->len || len + (47 + 8) < iovb->len) + printk(" - PDU size mismatch.\n"); + else + printk(".\n"); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + ATM_SKB(iovb)->iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + + /* By this point we (hopefully) have a complete SDU without errors. */ + + if (ATM_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ + { + /* skb points to a small buffer */ + if (!atm_charge(vcc, skb->truesize)) + { + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + } + else + { + skb_put(skb, len); + dequeue_sm_buf(card, skb); +#ifdef NS_USE_DESTRUCTORS + skb->destructor = ns_sb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + ATM_SKB(skb)->vcc = vcc; + skb->stamp = xtime; + vcc->push(vcc, skb); + vcc->stats->rx++; + } + } + else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ + { + struct sk_buff *sb; + + sb = (struct sk_buff *) (iov - 1)->iov_base; + /* skb points to a large buffer */ + + if (len <= NS_SMBUFSIZE) + { + if (!atm_charge(vcc, sb->truesize)) + { + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + } + else + { + skb_put(sb, len); + dequeue_sm_buf(card, sb); +#ifdef NS_USE_DESTRUCTORS + sb->destructor = ns_sb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + ATM_SKB(sb)->vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + vcc->stats->rx++; + } + + push_rxbufs(card, BUF_LG, (u32) skb, + (u32) virt_to_bus(skb->data), 0, 0); + + } + else /* len > NS_SMBUFSIZE, the usual case */ + { + if (!atm_charge(vcc, skb->truesize)) + { + push_rxbufs(card, BUF_LG, (u32) skb, + (u32) virt_to_bus(skb->data), 0, 0); + } + else + { + dequeue_lg_buf(card, skb); +#ifdef NS_USE_DESTRUCTORS + skb->destructor = ns_lb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + skb_push(skb, NS_SMBUFSIZE); + memcpy(skb->data, sb->data, NS_SMBUFSIZE); + skb_put(skb, len - NS_SMBUFSIZE); + ATM_SKB(skb)->vcc = vcc; + skb->stamp = xtime; + vcc->push(vcc, skb); + vcc->stats->rx++; + } + + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + + } + + } + else /* Must push a huge buffer */ + { + struct sk_buff *hb, *sb, *lb; + int remaining, tocopy; + int j; + + hb = skb_dequeue(&(card->hbpool.queue)); + if (hb == NULL) /* No buffers in the queue */ + { + + hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC); + if (hb == NULL) + { + printk("nicstar%d: Out of huge buffers.\n", card->index); + vcc->stats->rx_drop++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + ATM_SKB(iovb)->iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + else if (card->hbpool.count < card->hbnr.min) + { + struct sk_buff *new_hb; + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + } + } + else + if (--card->hbpool.count < card->hbnr.min) + { + struct sk_buff *new_hb; + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + if (card->hbpool.count < card->hbnr.min) + { + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + } + } + + iov = (struct iovec *) iovb->data; + + if (!atm_charge(vcc, hb->truesize)) + { + recycle_iovec_rx_bufs(card, iov, ATM_SKB(iovb)->iovcnt); + if (card->hbpool.count < card->hbnr.max) + { + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } + else + kfree_skb(hb); + } + else + { + /* Copy the small buffer to the huge buffer */ + sb = (struct sk_buff *) iov->iov_base; + memcpy(hb->data, sb->data, iov->iov_len); + skb_put(hb, iov->iov_len); + remaining = len - iov->iov_len; + iov++; + /* Free the small buffer */ + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + + /* Copy all large buffers to the huge buffer and free them */ + for (j = 1; j < ATM_SKB(iovb)->iovcnt; j++) + { + lb = (struct sk_buff *) iov->iov_base; + tocopy = MIN(remaining, iov->iov_len); + memcpy(hb->tail, lb->data, tocopy); + skb_put(hb, tocopy); + iov++; + remaining -= tocopy; + push_rxbufs(card, BUF_LG, (u32) lb, + (u32) virt_to_bus(lb->data), 0, 0); + } +#ifdef EXTRA_DEBUG + if (remaining != 0 || hb->len != len) + printk("nicstar%d: Huge buffer len mismatch.\n", card->index); +#endif /* EXTRA_DEBUG */ + ATM_SKB(hb)->vcc = vcc; +#ifdef NS_USE_DESTRUCTORS + hb->destructor = ns_hb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + hb->stamp = xtime; + vcc->push(vcc, hb); + vcc->stats->rx++; + } + } + + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + } + +} + + + +#ifdef NS_USE_DESTRUCTORS + +static void ns_sb_destructor(struct sk_buff *sb) +{ + ns_dev *card; + u32 stat; + + card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data; + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + do + { + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + break; + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } while (card->sbfqc < card->sbnr.min); +} + + + +static void ns_lb_destructor(struct sk_buff *lb) +{ + ns_dev *card; + u32 stat; + + card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data; + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + do + { + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + break; + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } while (card->lbfqc < card->lbnr.min); +} + + + +static void ns_hb_destructor(struct sk_buff *hb) +{ + ns_dev *card; + + card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data; + + while (card->hbpool.count < card->hbnr.init) + { + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + break; + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } +} + +#endif /* NS_USE_DESTRUCTORS */ + + + +static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb) +{ + if (skb->list == &card->sbpool.queue) + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); + else if (skb->list == &card->lbpool.queue) + push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); + else + { + printk("nicstar%d: What kind of rx buffer is this?\n", card->index); + kfree_skb(skb); + } +} + + + +static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count) +{ + struct sk_buff *skb; + + for (; count > 0; count--) + { + skb = (struct sk_buff *) (iov++)->iov_base; + if (skb->list == &card->sbpool.queue) + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + else if (skb->list == &card->lbpool.queue) + push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + else + { + printk("nicstar%d: What kind of rx buffer is this?\n", card->index); + kfree_skb(skb); + } + } +} + + + +static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb) +{ + if (card->iovpool.count < card->iovnr.max) + { + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + } + else + kfree_skb(iovb); +} + + + +static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb) +{ + skb_unlink(sb); +#ifdef NS_USE_DESTRUCTORS + if (card->sbfqc < card->sbnr.min) +#else + if (card->sbfqc < card->sbnr.init) + { + struct sk_buff *new_sb; + if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->sbpool.queue, new_sb); + skb_reserve(new_sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) new_sb, + (u32) virt_to_bus(new_sb->data), 0, 0); + } + } + if (card->sbfqc < card->sbnr.init) +#endif /* NS_USE_DESTRUCTORS */ + { + struct sk_buff *new_sb; + if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->sbpool.queue, new_sb); + skb_reserve(new_sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) new_sb, + (u32) virt_to_bus(new_sb->data), 0, 0); + } + } +} + + + +static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb) +{ + skb_unlink(lb); +#ifdef NS_USE_DESTRUCTORS + if (card->lbfqc < card->lbnr.min) +#else + if (card->lbfqc < card->lbnr.init) + { + struct sk_buff *new_lb; + if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->lbpool.queue, new_lb); + skb_reserve(new_lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) new_lb, + (u32) virt_to_bus(new_lb->data), 0, 0); + } + } + if (card->lbfqc < card->lbnr.init) +#endif /* NS_USE_DESTRUCTORS */ + { + struct sk_buff *new_lb; + if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->lbpool.queue, new_lb); + skb_reserve(new_lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) new_lb, + (u32) virt_to_bus(new_lb->data), 0, 0); + } + } +} + + + +static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page) +{ + u32 stat; + ns_dev *card; + int left; + + left = (int) *pos; + card = (ns_dev *) dev->dev_data; + stat = readl(card->membase + STAT); + if (!left--) + return sprintf(page, "Pool count min init max \n"); + if (!left--) + return sprintf(page, "Small %5d %5d %5d %5d \n", + ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init, + card->sbnr.max); + if (!left--) + return sprintf(page, "Large %5d %5d %5d %5d \n", + ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init, + card->lbnr.max); + if (!left--) + return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count, + card->hbnr.min, card->hbnr.init, card->hbnr.max); + if (!left--) + return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count, + card->iovnr.min, card->iovnr.init, card->iovnr.max); + if (!left--) + { + int retval; + retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt); + card->intcnt = 0; + return retval; + } + /* Dump 25.6 Mbps PHY registers */ + if (card->max_pcr == IDT_25_PCR && !left--) + { + u32 phy_regs[4]; + u32 i; + + for (i = 0; i < 4; i++) + { + while (CMD_BUSY(card)); + writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD); + while (CMD_BUSY(card)); + phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; + } + + return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", + phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]); + } +#if 0 + /* Dump TST */ + if (left-- < NS_TST_NUM_ENTRIES) + { + if (card->tste2vc[left + 1] == NULL) + return sprintf(page, "%5d - VBR/UBR \n", left + 1); + else + return sprintf(page, "%5d - %d %d \n", left + 1, + card->tste2vc[left + 1]->tx_vcc->vpi, + card->tste2vc[left + 1]->tx_vcc->vci); + } +#endif /* 0 */ + return 0; +} + + + +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +{ + ns_dev *card; + pool_levels pl; + int btype; + unsigned long flags; + + card = dev->dev_data; + switch (cmd) + { + case NS_GETPSTAT: + if (get_user(pl.buftype, &((pool_levels *) arg)->buftype)) + return -EFAULT; + switch (pl.buftype) + { + case NS_BUFTYPE_SMALL: + pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT)); + pl.level.min = card->sbnr.min; + pl.level.init = card->sbnr.init; + pl.level.max = card->sbnr.max; + break; + + case NS_BUFTYPE_LARGE: + pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT)); + pl.level.min = card->lbnr.min; + pl.level.init = card->lbnr.init; + pl.level.max = card->lbnr.max; + break; + + case NS_BUFTYPE_HUGE: + pl.count = card->hbpool.count; + pl.level.min = card->hbnr.min; + pl.level.init = card->hbnr.init; + pl.level.max = card->hbnr.max; + break; + + case NS_BUFTYPE_IOVEC: + pl.count = card->iovpool.count; + pl.level.min = card->iovnr.min; + pl.level.init = card->iovnr.init; + pl.level.max = card->iovnr.max; + break; + + default: + return -EINVAL; + + } + if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) + return (sizeof(pl)); + else + return -EFAULT; + + case NS_SETBUFLEV: + if (!suser()) + return -EPERM; + if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl))) + return -EFAULT; + if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max) + return -EINVAL; + if (pl.level.min == 0) + return -EINVAL; + switch (pl.buftype) + { + case NS_BUFTYPE_SMALL: + if (pl.level.max > TOP_SB) + return -EINVAL; + card->sbnr.min = pl.level.min; + card->sbnr.init = pl.level.init; + card->sbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_LARGE: + if (pl.level.max > TOP_LB) + return -EINVAL; + card->lbnr.min = pl.level.min; + card->lbnr.init = pl.level.init; + card->lbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_HUGE: + if (pl.level.max > TOP_HB) + return -EINVAL; + card->hbnr.min = pl.level.min; + card->hbnr.init = pl.level.init; + card->hbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_IOVEC: + if (pl.level.max > TOP_IOVB) + return -EINVAL; + card->iovnr.min = pl.level.min; + card->iovnr.init = pl.level.init; + card->iovnr.max = pl.level.max; + break; + + default: + return -EINVAL; + + } + return 0; + + case NS_ADJBUFLEV: + if (!suser()) + return -EPERM; + btype = (int) arg; /* an int is the same size as a pointer */ + switch (btype) + { + case NS_BUFTYPE_SMALL: + while (card->sbfqc < card->sbnr.init) + { + struct sk_buff *sb; + + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + return -ENOMEM; + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + break; + + case NS_BUFTYPE_LARGE: + while (card->lbfqc < card->lbnr.init) + { + struct sk_buff *lb; + + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + return -ENOMEM; + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } + break; + + case NS_BUFTYPE_HUGE: + while (card->hbpool.count > card->hbnr.init) + { + struct sk_buff *hb; + + save_flags(flags); cli(); + hb = skb_dequeue(&card->hbpool.queue); + card->hbpool.count--; + restore_flags(flags); + if (hb == NULL) + printk("nicstar%d: huge buffer count inconsistent.\n", + card->index); + else + kfree_skb(hb); + + } + while (card->hbpool.count < card->hbnr.init) + { + struct sk_buff *hb; + + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + return -ENOMEM; + save_flags(flags); cli(); + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + restore_flags(flags); + } + break; + + case NS_BUFTYPE_IOVEC: + while (card->iovpool.count > card->iovnr.init) + { + struct sk_buff *iovb; + + save_flags(flags); cli(); + iovb = skb_dequeue(&card->iovpool.queue); + card->iovpool.count--; + restore_flags(flags); + if (iovb == NULL) + printk("nicstar%d: iovec buffer count inconsistent.\n", + card->index); + else + kfree_skb(iovb); + + } + while (card->iovpool.count < card->iovnr.init) + { + struct sk_buff *iovb; + + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); + if (iovb == NULL) + return -ENOMEM; + save_flags(flags); cli(); + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + restore_flags(flags); + } + break; + + default: + return -EINVAL; + + } + return 0; + + default: + if (dev->phy && dev->phy->ioctl) { + return dev->phy->ioctl(dev, cmd, arg); + } + else { + printk("nicstar%d: %s == NULL \n", card->index, + dev->phy ? "dev->phy->ioctl" : "dev->phy"); + return -EINVAL; + } + } +} + + + +static void which_list(ns_dev *card, struct sk_buff *skb) +{ + printk("It's a %s buffer.\n", skb->list == &card->sbpool.queue ? + "small" : skb->list == &card->lbpool.queue ? "large" : + skb->list == &card->hbpool.queue ? "huge" : + skb->list == &card->iovpool.queue ? "iovec" : "unknown"); +} + + + +static void ns_poll(unsigned long arg) +{ + int i; + ns_dev *card; + unsigned long flags; + u32 stat_r, stat_w; + + PRINTK("nicstar: Entering ns_poll().\n"); + for (i = 0; i < num_cards; i++) + { + card = cards[i]; + save_flags(flags); cli(); + if (card->in_poll) + { + printk("nicstar: Re-entering ns_poll()???\n"); + restore_flags(flags); + continue; + } + card->in_poll = 1; + if (card->in_handler) + { + card->in_poll = 0; + printk("nicstar%d: ns_poll called while in interrupt handler!?\n", + card->index); + restore_flags(flags); + continue; + } + + stat_w = 0; + stat_r = readl(card->membase + STAT); + if (stat_r & NS_STAT_TSIF) + stat_w |= NS_STAT_TSIF; + if (stat_r & NS_STAT_EOPDU) + stat_w |= NS_STAT_EOPDU; + + process_tsq(card); + process_rsq(card); + + writel(stat_w, card->membase + STAT); + card->in_poll = 0; + restore_flags(flags); + } + mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); + PRINTK("nicstar: Leaving ns_poll().\n"); +} + + + +static int ns_parse_mac(char *mac, unsigned char *esi) +{ + int i, j; + short byte1, byte0; + + if (mac == NULL || esi == NULL) + return -1; + j = 0; + for (i = 0; i < 6; i++) + { + if ((byte1 = ns_h2i(mac[j++])) < 0) + return -1; + if ((byte0 = ns_h2i(mac[j++])) < 0) + return -1; + esi[i] = (unsigned char) (byte1 * 16 + byte0); + if (i < 5) + { + if (mac[j++] != ':') + return -1; + } + } + return 0; +} + + + +static short ns_h2i(char c) +{ + if (c >= '0' && c <= '9') + return (short) (c - '0'); + if (c >= 'A' && c <= 'A') + return (short) (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (short) (c - 'a' + 10); + return -1; +} + + + +static void ns_phy_put(struct atm_dev *dev, unsigned char value, + unsigned long addr) +{ + ns_dev *card; + unsigned long flags; + + card = dev->dev_data; + save_flags(flags); cli(); + while(CMD_BUSY(card)); + writel((unsigned long) value, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF), + card->membase + CMD); + restore_flags(flags); +} + + + +static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr) +{ + ns_dev *card; + unsigned long flags; + unsigned long data; + + card = dev->dev_data; + save_flags(flags); cli(); + while(CMD_BUSY(card)); + writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF), + card->membase + CMD); + while(CMD_BUSY(card)); + data = readl(card->membase + DR0) & 0x000000FF; + restore_flags(flags); + return (unsigned char) data; +} diff -u --recursive --new-file v2.3.14/linux/drivers/atm/nicstar.c.old_skb linux/drivers/atm/nicstar.c.old_skb --- v2.3.14/linux/drivers/atm/nicstar.c.old_skb Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/nicstar.c.old_skb Mon Aug 23 09:56:31 1999 @@ -0,0 +1,2883 @@ +/****************************************************************************** + * + * nicstar.c + * + * Device driver supporting CBR for NICStAR based cards. + * + * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. + * It was taken from the frle-0.22 device driver. + * As the file doesn't have a copyright notice, in the file + * nicstarmac.copyright I put the copyright notice from the + * frle-0.22 device driver. + * Some code is based on the nicstar driver by M. Welsh. + * + * Author: Rui Prior + * + * (C) INESC 1998 + * + ******************************************************************************/ + + +/* Header files ***************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nicstar.h" +#include "nicstarmac.h" + + +/* Additional code ************************************************************/ + +#include "nicstarmac.c" + + +/* Configurable parameters ****************************************************/ + +#undef PHY_LOOPBACK +#undef TX_DEBUG +#undef RX_DEBUG +#undef GENERAL_DEBUG +#undef EXTRA_DEBUG + +#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know + you're going to use only raw ATM */ + + +/* Do not touch these *********************************************************/ + +#ifdef TX_DEBUG +#define TXPRINTK(args...) printk(args) +#else +#define TXPRINTK(args...) +#endif /* TX_DEBUG */ + +#ifdef RX_DEBUG +#define RXPRINTK(args...) printk(args) +#else +#define RXPRINTK(args...) +#endif /* RX_DEBUG */ + +#ifdef GENERAL_DEBUG +#define PRINTK(args...) printk(args) +#else +#define PRINTK(args...) +#endif /* GENERAL_DEBUG */ + +#ifdef EXTRA_DEBUG +#define XPRINTK(args...) printk(args) +#else +#define XPRINTK(args...) +#endif /* EXTRA_DEBUG */ + + +/* Macros *********************************************************************/ + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) + +#define NS_DELAY mdelay(1) + +#define ALIGN_ADDRESS(addr, alignment) \ + ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1)) + +#undef CEIL(d) + + +/* Version definition *********************************************************/ +/* +#include +char kernel_version[] = UTS_RELEASE; +*/ + +/* Function declarations ******************************************************/ + +static u32 ns_read_sram(ns_dev *card, u32 sram_address); +static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count); +static int ns_init_card(int i, struct pci_dev *pcidev); +static void ns_init_card_error(ns_dev *card, int error); +static scq_info *get_scq(int size, u32 scd); +static void free_scq(scq_info *scq, struct atm_vcc *vcc); +static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, + u32 handle2, u32 addr2); +static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static int ns_open(struct atm_vcc *vcc, short vpi, int vci); +static void ns_close(struct atm_vcc *vcc); +static void fill_tst(ns_dev *card, int n, vc_map *vc); +static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, + struct sk_buff *skb); +static void process_tsq(ns_dev *card); +static void drain_scq(ns_dev *card, scq_info *scq, int pos); +static void process_rsq(ns_dev *card); +static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe); +#ifdef NS_USE_DESTRUCTORS +static void ns_sb_destructor(struct sk_buff *sb); +static void ns_lb_destructor(struct sk_buff *lb); +static void ns_hb_destructor(struct sk_buff *hb); +#endif /* NS_USE_DESTRUCTORS */ +static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb); +static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count); +static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb); +static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb); +static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb); +static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page); +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static void which_list(ns_dev *card, struct sk_buff *skb); +static void ns_poll(unsigned long arg); + + +/* Global variables ***********************************************************/ + +static struct ns_dev *cards[NS_MAX_CARDS]; +static unsigned num_cards = 0; +static struct atmdev_ops atm_ops = +{ + NULL, /* dev_close */ + ns_open, /* open */ + ns_close, /* close */ + ns_ioctl, /* ioctl */ + NULL, /* getsockopt */ + NULL, /* setsockopt */ + ns_send, /* send */ + NULL, /* sg_send */ + NULL, /* send_oam */ + NULL, /* phy_put */ + NULL, /* phy_get */ + NULL, /* feedback */ + NULL, /* change_qos */ + NULL, /* free_rx_skb */ + ns_proc_read /* proc_read */ +}; +static struct timer_list ns_timer; + + +/* Functions*******************************************************************/ + +#ifdef MODULE + +int init_module(void) +{ + int i; + unsigned error = 0; /* Initialized to remove compile warning */ + struct pci_dev *pcidev; + + XPRINTK("nicstar: init_module() called.\n"); + if(!pci_present()) + { + printk("nicstar: no PCI subsystem found.\n"); + return -EIO; + } + + for(i = 0; i < NS_MAX_CARDS; i++) + cards[i] = NULL; + + pcidev = NULL; + for(i = 0; i < NS_MAX_CARDS; i++) + { + if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, + PCI_DEVICE_ID_IDT_IDT77201, + pcidev)) == NULL) + break; + + error = ns_init_card(i, pcidev); + if (error) + i--; /* Try to find another card but don't increment index */ + } + + if (i == 0) + { + if (!error) + { + printk("nicstar: no cards found.\n"); + return -ENXIO; + } + else + return -EIO; + } + TXPRINTK("nicstar: TX debug enabled.\n"); + RXPRINTK("nicstar: RX debug enabled.\n"); + PRINTK("nicstar: General debug enabled.\n"); +#ifdef PHY_LOOPBACK + printk("nicstar: using PHY loopback.\n"); +#endif /* PHY_LOOPBACK */ + XPRINTK("nicstar: init_module() returned.\n"); + + ns_timer.next = NULL; + ns_timer.prev = NULL; + ns_timer.expires = jiffies + NS_POLL_PERIOD; + ns_timer.data = 0UL; + ns_timer.function = ns_poll; + add_timer(&ns_timer); + return 0; +} + + + +void cleanup_module(void) +{ + int i, j; + unsigned short pci_command; + ns_dev *card; + struct sk_buff *hb; + struct sk_buff *iovb; + struct sk_buff *lb; + struct sk_buff *sb; + + XPRINTK("nicstar: cleanup_module() called.\n"); + + if (MOD_IN_USE) + printk("nicstar: module in use, remove delayed.\n"); + + del_timer(&ns_timer); + + for (i = 0; i < NS_MAX_CARDS; i++) + { + if (cards[i] == NULL) + continue; + + card = cards[i]; + + /* Stop everything */ + writel(0x00000000, card->membase + CFG); + + /* De-register device */ + atm_dev_deregister(card->atmdev); + + /* Disable memory mapping and busmastering */ + if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command) != 0) + { + printk("nicstar%d: can't read PCI_COMMAND.\n", i); + } + pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command) != 0) + { + printk("nicstar%d: can't write PCI_COMMAND.\n", i); + } + + /* Free up resources */ + j = 0; + PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); + while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) + { + kfree_skb(hb); + j++; + } + PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); + j = 0; + PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count); + while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) + { + kfree_skb(iovb); + j++; + } + PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); + while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) + kfree_skb(lb); + while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) + kfree_skb(sb); + free_scq(card->scq0, NULL); + for (j = 0; j < NS_FRSCD_NUM; j++) + { + if (card->scd2vc[j] != NULL) + free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); + } + kfree(card->rsq.org); + kfree(card->tsq.org); + free_irq(card->pcidev->irq, card); + iounmap((void *) card->membase); + kfree(card); + + } + XPRINTK("nicstar: cleanup_module() returned.\n"); +} + + +#else + +__initfunc(int nicstar_detect(void)) +{ + int i; + unsigned error = 0; /* Initialized to remove compile warning */ + struct pci_dev *pcidev; + + if(!pci_present()) + { + printk("nicstar: no PCI subsystem found.\n"); + return -EIO; + } + + for(i = 0; i < NS_MAX_CARDS; i++) + cards[i] = NULL; + + pcidev = NULL; + for(i = 0; i < NS_MAX_CARDS; i++) + { + if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, + PCI_DEVICE_ID_IDT_IDT77201, + pcidev)) == NULL) + break; + + error = ns_init_card(i, pcidev); + if (error) + i--; /* Try to find another card but don't increment index */ + } + + if (i == 0 && error) + return -EIO; + + TXPRINTK("nicstar: TX debug enabled.\n"); + RXPRINTK("nicstar: RX debug enabled.\n"); + PRINTK("nicstar: General debug enabled.\n"); +#ifdef PHY_LOOPBACK + printk("nicstar: using PHY loopback.\n"); +#endif /* PHY_LOOPBACK */ + XPRINTK("nicstar: init_module() returned.\n"); + + return i; +} + + +#endif /* MODULE */ + + +static u32 ns_read_sram(ns_dev *card, u32 sram_address) +{ + unsigned long flags; + u32 data; + sram_address <<= 2; + sram_address &= 0x0007FFFC; /* address must be dword aligned */ + sram_address |= 0x50000000; /* SRAM read command */ + save_flags(flags); cli(); + while (CMD_BUSY(card)); + writel(sram_address, card->membase + CMD); + while (CMD_BUSY(card)); + data = readl(card->membase + DR0); + restore_flags(flags); + return data; +} + + + +static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count) +{ + unsigned long flags; + int i, c; + count--; /* count range now is 0..3 instead of 1..4 */ + c = count; + c <<= 2; /* to use increments of 4 */ + save_flags(flags); cli(); + while (CMD_BUSY(card)); + for (i = 0; i <= c; i += 4) + writel(*(value++), card->membase + i); + /* Note: DR# registers are the first 4 dwords in nicstar's memspace, + so card->membase + DR0 == card->membase */ + sram_address <<= 2; + sram_address &= 0x0007FFFC; + sram_address |= (0x40000000 | count); + writel(sram_address, card->membase + CMD); + restore_flags(flags); +} + + +static int ns_init_card(int i, struct pci_dev *pcidev) +{ + int j; + struct ns_dev *card; + unsigned short pci_command; + unsigned char pci_latency; + unsigned error; + u32 data; + u32 u32d[4]; + u32 ns_cfg_rctsize; + int bcount; + + error = 0; + + if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) + { + printk("nicstar%d: can't allocate memory for device structure.\n", i); + error = 2; + ns_init_card_error(card, error); + return error; + } + cards[i] = card; + + card->index = i; + card->pcidev = pcidev; + card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); + card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE); + if (card->membase == (u32) (NULL)) + { + printk("nicstar%d: can't ioremap() membase.\n",i); + error = 3; + ns_init_card_error(card, error); + return error; + } + PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase); + + if (pci_read_config_word(pcidev, PCI_COMMAND, &pci_command) != 0) + { + printk("nicstar%d: can't read PCI_COMMAND.\n", i); + error = 4; + ns_init_card_error(card, error); + return error; + } + pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(pcidev, PCI_COMMAND, pci_command) != 0) + { + printk("nicstar%d: can't write PCI_COMMAND.\n", i); + error = 5; + ns_init_card_error(card, error); + return error; + } + + if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) + { + printk("nicstar%d: can't read PCI latency timer.\n", i); + error = 6; + ns_init_card_error(card, error); + return error; + } + if (pci_latency < NS_PCI_LATENCY) + { + PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); + for (j = 1; j < 4; j++) + { + if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0); + break; + } + if (j == 10) + { + printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY); + error = 7; + ns_init_card_error(card, error); + return error; + } + } + + /* Clear timer overflow */ + data = readl(card->membase + STAT); + if (data & NS_STAT_TMROF) + writel(NS_STAT_TMROF, card->membase + STAT); + + /* Software reset */ + writel(NS_CFG_SWRST, card->membase + CFG); + NS_DELAY; + writel(0x00000000, card->membase + CFG); + + /* PHY reset */ + writel(0x00000008, card->membase + GP); + NS_DELAY; + writel(0x00000001, card->membase + GP); + NS_DELAY; + while (CMD_BUSY(card)); + writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ + NS_DELAY; + + /* Detect PHY type */ + while (CMD_BUSY(card)); + writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); + while (CMD_BUSY(card)); + data = readl(card->membase + DR0); + if (data == 0x00000009) + { + printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); + card->max_pcr = IDT_25_PCR; + while(CMD_BUSY(card)); + writel(0x00000008, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); + /* Clear an eventual pending interrupt */ + writel(NS_STAT_SFBQF, card->membase + STAT); +#ifdef PHY_LOOPBACK + while(CMD_BUSY(card)); + writel(0x00000022, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); +#endif /* PHY_LOOPBACK */ + } + else if (data == 0x00000030) + { + printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); + card->max_pcr = ATM_OC3_PCR; +#ifdef PHY_LOOPBACK + while(CMD_BUSY(card)); + writel(0x00000002, card->membase + DR0); + writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); +#endif /* PHY_LOOPBACK */ + } + else + { + printk("nicstar%d: can't determine PHY type.\n", i); + error = 8; + ns_init_card_error(card, error); + return error; + } + writel(0x00000000, card->membase + GP); + + /* Determine SRAM size */ + data = 0x76543210; + ns_write_sram(card, 0x1C003, &data, 1); + data = 0x89ABCDEF; + ns_write_sram(card, 0x14003, &data, 1); + if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && + ns_read_sram(card, 0x1C003) == 0x76543210) + card->sram_size = 128; + else + card->sram_size = 32; + PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); + + card->rct_size = NS_MAX_RCTSIZE; + +#if (NS_MAX_RCTSIZE == 4096) + if (card->sram_size == 128) + printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i); +#elif (NS_MAX_RCTSIZE == 16384) + if (card->sram_size == 32) + { + printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i); + card->rct_size = 4096; + } +#else +#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c +#endif + + card->vpibits = NS_VPIBITS; + if (card->rct_size == 4096) + card->vcibits = 12 - NS_VPIBITS; + else /* card->rct_size == 16384 */ + card->vcibits = 14 - NS_VPIBITS; + +#ifdef ESI_FROM_EPROM + /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ + nicstar_init_eprom(card->membase); +#endif /* ESI_FROM_EPROM */ + + if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT, "nicstar", card) != 0) + { + printk("nicstar%d: can't allocate IRQ.\n", i); + error = 9; + ns_init_card_error(card, error); + return error; + } + + /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ + writel(0x00000000, card->membase + VPM); + + /* Initialize TSQ */ + card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL); + if (card->tsq.org == NULL) + { + printk("nicstar%d: can't allocate TSQ.\n", i); + error = 10; + ns_init_card_error(card, error); + return error; + } + card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT); + card->tsq.next = card->tsq.base; + card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); + for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) + ns_tsi_init(card->tsq.base + j); + writel(0x00000000, card->membase + TSQH); + writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB); + PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base, + (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB)); + + /* Initialize RSQ */ + card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL); + if (card->rsq.org == NULL) + { + printk("nicstar%d: can't allocate RSQ.\n", i); + error = 11; + ns_init_card_error(card, error); + return error; + } + card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT); + card->rsq.next = card->rsq.base; + card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); + for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) + ns_rsqe_init(card->rsq.base + j); + writel(0x00000000, card->membase + RSQH); + writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB); + PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base); + + /* Initialize SCQ0, the only VBR SCQ used */ + card->scq1 = (scq_info *) NULL; + card->scq2 = (scq_info *) NULL; + card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); + if (card->scq0 == (scq_info *) NULL) + { + printk("nicstar%d: can't get SCQ0.\n", i); + error = 12; + ns_init_card_error(card, error); + return error; + } + u32d[0] = (u32) virt_to_bus(card->scq0->base); + u32d[1] = (u32) 0x00000000; + u32d[2] = (u32) 0xffffffff; + u32d[3] = (u32) 0x00000000; + ns_write_sram(card, NS_VRSCD0, u32d, 4); + ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ + ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ + card->scq0->scd = NS_VRSCD0; + PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base); + + /* Initialize TSTs */ + card->tst_addr = NS_TST0; + card->tst_free_entries = NS_TST_NUM_ENTRIES; + data = NS_TST_OPCODE_VARIABLE; + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + ns_write_sram(card, NS_TST0 + j, &data, 1); + data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); + ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + ns_write_sram(card, NS_TST1 + j, &data, 1); + data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); + ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); + for (j = 0; j < NS_TST_NUM_ENTRIES; j++) + card->tste2vc[j] = NULL; + writel(NS_TST0 << 2, card->membase + TSTB); + + + /* Initialize RCT. AAL type is set on opening the VC. */ +#ifdef RCQ_SUPPORT + u32d[0] = NS_RCTE_RAWCELLINTEN; +#else + u32d[0] = 0x00000000; +#endif RCQ_SUPPORT + u32d[1] = 0x00000000; + u32d[2] = 0x00000000; + u32d[3] = 0xFFFFFFFF; + for (j = 0; j < card->rct_size; j++) + ns_write_sram(card, j * 4, u32d, 4); + + memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map)); + + for (j = 0; j < NS_FRSCD_NUM; j++) + card->scd2vc[j] = NULL; + + /* Initialize buffer levels */ + card->sbnr.min = MIN_SB; + card->sbnr.init = NUM_SB; + card->sbnr.max = MAX_SB; + card->lbnr.min = MIN_LB; + card->lbnr.init = NUM_LB; + card->lbnr.max = MAX_LB; + card->iovnr.min = MIN_IOVB; + card->iovnr.init = NUM_IOVB; + card->iovnr.max = MAX_IOVB; + card->hbnr.min = MIN_HB; + card->hbnr.init = NUM_HB; + card->hbnr.max = MAX_HB; + + card->sm_handle = 0x00000000; + card->sm_addr = 0x00000000; + card->lg_handle = 0x00000000; + card->lg_addr = 0x00000000; + + card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ + + /* Allocate small buffers */ + skb_queue_head_init(&card->sbpool.queue); + card->sbpool.count = 0; /* Not used */ + for (j = 0; j < NUM_SB; j++) + { + struct sk_buff *sb; + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d small buffers.\n", + i, j, NUM_SB); + error = 13; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + /* Test for strange behaviour which leads to crashes */ + if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) + { + printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", + i, j, bcount); + error = 13; + ns_init_card_error(card, error); + return error; + } + + + /* Allocate large buffers */ + skb_queue_head_init(&card->lbpool.queue); + card->lbpool.count = 0; /* Not used */ + for (j = 0; j < NUM_LB; j++) + { + struct sk_buff *lb; + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d large buffers.\n", + i, j, NUM_LB); + error = 14; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + /* Due to the implementation of push_rxbufs() this is 1, not 0 */ + if (j == 1) + { + card->rcbuf = lb; + card->rawch = (u32) virt_to_bus(lb->data); + } + } + /* Test for strange behaviour which leads to crashes */ + if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) + { + printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", + i, j, bcount); + error = 14; + ns_init_card_error(card, error); + return error; + } + + + /* Allocate iovec buffers */ + skb_queue_head_init(&card->iovpool.queue); + card->iovpool.count = 0; + for (j = 0; j < NUM_IOVB; j++) + { + struct sk_buff *iovb; + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); + if (iovb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", + i, j, NUM_IOVB); + error = 15; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + } + + + /* Pre-allocate some huge buffers */ + skb_queue_head_init(&card->hbpool.queue); + card->hbpool.count = 0; + for (j = 0; j < NUM_HB; j++) + { + struct sk_buff *hb; + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + { + printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", + i, j, NUM_HB); + error = 16; + ns_init_card_error(card, error); + return error; + } + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } + + card->in_handler = 0; + card->in_poll = 0; + card->intcnt = 0; + + /* Configure NICStAR */ + if (card->rct_size == 4096) + ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; + else /* (card->rct_size == 16384) */ + ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; + + card->efbie = 1; + writel(NS_CFG_RXPATH | + NS_CFG_SMBUFSIZE | + NS_CFG_LGBUFSIZE | + NS_CFG_EFBIE | + NS_CFG_RSQSIZE | + NS_CFG_VPIBITS | + ns_cfg_rctsize | + NS_CFG_RXINT_NODELAY | + NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ + NS_CFG_RSQAFIE | + NS_CFG_TXEN | + NS_CFG_TXIE | + NS_CFG_TSQFIE_OPT, /* Only enabled if ENABLE_TSQFIE */ + card->membase + CFG); + + /* Register device */ + card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL); + if (card->atmdev == NULL) + { + printk("nicstar%d: can't register device.\n", i); + error = 17; + ns_init_card_error(card, error); + return error; + } + +#ifdef ESI_FROM_EPROM + nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, + card->atmdev->esi, 6); + printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, + card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], + card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); +#else + card->atmdev->esi[0] = NS_ESI0; + card->atmdev->esi[1] = NS_ESI1; + card->atmdev->esi[2] = NS_ESI2; + card->atmdev->esi[3] = NS_ESI3; + card->atmdev->esi[4] = NS_ESI4; + card->atmdev->esi[5] = NS_ESI5; +#endif /* ESI_FROM_EPROM */ + + card->atmdev->dev_data = card; + card->atmdev->ci_range.vpi_bits = card->vpibits; + card->atmdev->ci_range.vci_bits = card->vcibits; + + num_cards++; + + return error; +} + + + +static void ns_init_card_error(ns_dev *card, int error) +{ + if (error >= 17) + { + writel(0x00000000, card->membase + CFG); + } + if (error >= 16) + { + struct sk_buff *hb; + while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) + kfree_skb(hb); + } + if (error >= 15) + { + struct sk_buff *iovb; + while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) + kfree_skb(iovb); + } + if (error >= 14) + { + struct sk_buff *lb; + while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) + kfree_skb(lb); + } + if (error >= 13) + { + struct sk_buff *sb; + while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) + kfree_skb(sb); + free_scq(card->scq0, NULL); + } + if (error >= 12) + { + kfree(card->rsq.org); + } + if (error >= 11) + { + kfree(card->tsq.org); + } + if (error >= 10) + { + free_irq(card->pcidev->irq, card); + } + if (error >= 4) + { + iounmap((void *) card->membase); + } + if (error >= 3) + { + kfree(card); + } +} + + + +static scq_info *get_scq(int size, u32 scd) +{ + scq_info *scq; + int i; + + if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) + return (scq_info *) NULL; + + scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); + if (scq == (scq_info *) NULL) + return (scq_info *) NULL; + scq->org = kmalloc(2 * size, GFP_KERNEL); + if (scq->org == NULL) + { + kfree(scq); + return (scq_info *) NULL; + } + scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * + (size / NS_SCQE_SIZE), GFP_KERNEL); + if (scq->skb == (struct sk_buff **) NULL) + { + kfree(scq->org); + kfree(scq); + return (scq_info *) NULL; + } + scq->num_entries = size / NS_SCQE_SIZE; + scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size); + scq->next = scq->base; + scq->last = scq->base + (scq->num_entries - 1); + scq->tail = scq->last; + scq->scd = scd; + scq->num_entries = size / NS_SCQE_SIZE; + scq->tbd_count = 0; + scq->scqfull_waitq = NULL; + scq->full = 0; + + for (i = 0; i < scq->num_entries; i++) + scq->skb[i] = NULL; + + return scq; +} + + + +/* For variable rate SCQ vcc must be NULL */ +static void free_scq(scq_info *scq, struct atm_vcc *vcc) +{ + int i; + + if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) + for (i = 0; i < scq->num_entries; i++) + { + if (scq->skb[i] != NULL) + { + vcc = scq->skb[i]->atm.vcc; + if (vcc->pop != NULL) + vcc->pop(vcc, scq->skb[i]); + else + dev_kfree_skb(scq->skb[i]); + } + } + else /* vcc must be != NULL */ + { + if (vcc == NULL) + { + printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); + for (i = 0; i < scq->num_entries; i++) + dev_kfree_skb(scq->skb[i]); + } + else + for (i = 0; i < scq->num_entries; i++) + { + if (scq->skb[i] != NULL) + { + if (vcc->pop != NULL) + vcc->pop(vcc, scq->skb[i]); + else + dev_kfree_skb(scq->skb[i]); + } + } + } + kfree(scq->skb); + kfree(scq->org); + kfree(scq); +} + + + +/* The handles passed must be pointers to the sk_buff containing the small + or large buffer(s) cast to u32. */ +static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, + u32 handle2, u32 addr2) +{ + u32 stat; + unsigned long flags; + + +#ifdef GENERAL_DEBUG + if (!addr1) + printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index); +#endif /* GENERAL_DEBUG */ + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + if (type == BUF_SM) + { + if (!addr2) + { + if (card->sm_addr) + { + addr2 = card->sm_addr; + handle2 = card->sm_handle; + card->sm_addr = 0x00000000; + card->sm_handle = 0x00000000; + } + else /* (!sm_addr) */ + { + card->sm_addr = addr1; + card->sm_handle = handle1; + } + } + } + else /* type == BUF_LG */ + { + if (!addr2) + { + if (card->lg_addr) + { + addr2 = card->lg_addr; + handle2 = card->lg_handle; + card->lg_addr = 0x00000000; + card->lg_handle = 0x00000000; + } + else /* (!lg_addr) */ + { + card->lg_addr = addr1; + card->lg_handle = handle1; + } + } + } + + if (addr2) + { + if (type == BUF_SM) + { + if (card->sbfqc >= card->sbnr.max) + { + skb_unlink((struct sk_buff *) handle1); + kfree_skb((struct sk_buff *) handle1); + skb_unlink((struct sk_buff *) handle2); + kfree_skb((struct sk_buff *) handle2); + return; + } + else + card->sbfqc += 2; + } + else /* (type == BUF_LG) */ + { + if (card->lbfqc >= card->lbnr.max) + { + skb_unlink((struct sk_buff *) handle1); + kfree_skb((struct sk_buff *) handle1); + skb_unlink((struct sk_buff *) handle2); + kfree_skb((struct sk_buff *) handle2); + return; + } + else + card->lbfqc += 2; + } + + save_flags(flags); cli(); + + while (CMD_BUSY(card)); + writel(handle1, card->membase + DR0); + writel(addr1, card->membase + DR1); + writel(handle2, card->membase + DR2); + writel(addr2, card->membase + DR3); + writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD); + + restore_flags(flags); + + XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index, + (type == BUF_SM ? "small" : "large"), addr1, addr2); + } + + if (!card->efbie && card->sbfqc >= card->sbnr.min && + card->lbfqc >= card->lbnr.min) + { + card->efbie = 1; + writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG); + } + + return; +} + + + +static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat_r; + ns_dev *card; + + card = (ns_dev *) dev_id; + card->intcnt++; + + PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); + + if (card->in_handler) + { + printk("nicstar%d: Re-entering ns_irq_handler()???\n", card->index); + return; + } + card->in_handler = 1; + if (card->in_poll) + { + card->in_handler = 0; + printk("nicstar%d: Called irq handler while in ns_poll()!?\n", + card->index); + return; + } + + stat_r = readl(card->membase + STAT); + + /* Transmit Status Indicator has been written to T. S. Queue */ + if (stat_r & NS_STAT_TSIF) + { + TXPRINTK("nicstar%d: TSI interrupt\n", card->index); + process_tsq(card); + writel(NS_STAT_TSIF, card->membase + STAT); + } + + /* Incomplete CS-PDU has been transmitted */ + if (stat_r & NS_STAT_TXICP) + { + writel(NS_STAT_TXICP, card->membase + STAT); + TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", + card->index); + } + + /* Transmit Status Queue 7/8 full */ + if (stat_r & NS_STAT_TSQF) + { + writel(NS_STAT_TSQF, card->membase + STAT); + PRINTK("nicstar%d: TSQ full.\n", card->index); + process_tsq(card); + } + + /* Timer overflow */ + if (stat_r & NS_STAT_TMROF) + { + writel(NS_STAT_TMROF, card->membase + STAT); + PRINTK("nicstar%d: Timer overflow.\n", card->index); + } + + /* PHY device interrupt signal active */ + if (stat_r & NS_STAT_PHYI) + { + writel(NS_STAT_PHYI, card->membase + STAT); + printk("nicstar%d: PHY interrupt.\n", card->index); + } + + /* Small Buffer Queue is full */ + if (stat_r & NS_STAT_SFBQF) + { + writel(NS_STAT_SFBQF, card->membase + STAT); + printk("nicstar%d: Small free buffer queue is full.\n", card->index); + } + + /* Large Buffer Queue is full */ + if (stat_r & NS_STAT_LFBQF) + { + writel(NS_STAT_LFBQF, card->membase + STAT); + printk("nicstar%d: Large free buffer queue is full.\n", card->index); + } + + /* Receive Status Queue is full */ + if (stat_r & NS_STAT_RSQF) + { + writel(NS_STAT_RSQF, card->membase + STAT); + printk("nicstar%d: RSQ full.\n", card->index); + process_rsq(card); + } + + /* Complete CS-PDU received */ + if (stat_r & NS_STAT_EOPDU) + { + RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); + process_rsq(card); + writel(NS_STAT_EOPDU, card->membase + STAT); + } + + /* Raw cell received */ + if (stat_r & NS_STAT_RAWCF) + { + writel(NS_STAT_RAWCF, card->membase + STAT); +#ifndef RCQ_SUPPORT + printk("nicstar%d: Raw cell received and no support yet...\n", + card->index); +#endif /* RCQ_SUPPORT */ + /* NOTE: the following procedure may keep a raw cell pending untill the + next interrupt. As this preliminary support is only meant to + avoid buffer leakage, this is not an issue. */ + while (readl(card->membase + RAWCT) != card->rawch) + { + ns_rcqe *rawcell; + + rawcell = (ns_rcqe *) bus_to_virt(card->rawch); + if (ns_rcqe_islast(rawcell)) + { + struct sk_buff *oldbuf; + + oldbuf = card->rcbuf; + card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell); + card->rawch = (u32) virt_to_bus(card->rcbuf->data); + recycle_rx_buf(card, oldbuf); + } + else + card->rawch += NS_RCQE_SIZE; + } + } + + /* Small buffer queue is empty */ + if (stat_r & NS_STAT_SFBQE) + { + int i; + struct sk_buff *sb; + + writel(NS_STAT_SFBQE, card->membase + STAT); + printk("nicstar%d: Small free buffer queue empty.\n", + card->index); + for (i = 0; i < card->sbnr.min; i++) + { + sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC); + if (sb == NULL) + { + writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); + card->efbie = 0; + break; + } + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + card->sbfqc = i; + process_rsq(card); + } + + /* Large buffer queue empty */ + if (stat_r & NS_STAT_LFBQE) + { + int i; + struct sk_buff *lb; + + writel(NS_STAT_LFBQE, card->membase + STAT); + printk("nicstar%d: Large free buffer queue empty.\n", + card->index); + for (i = 0; i < card->lbnr.min; i++) + { + lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC); + if (lb == NULL) + { + writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); + card->efbie = 0; + break; + } + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } + card->lbfqc = i; + process_rsq(card); + } + + /* Receive Status Queue is 7/8 full */ + if (stat_r & NS_STAT_RSQAF) + { + writel(NS_STAT_RSQAF, card->membase + STAT); + RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); + process_rsq(card); + } + + card->in_handler = 0; + PRINTK("nicstar%d: end of interrupt service\n", card->index); +} + + + +static int ns_open(struct atm_vcc *vcc, short vpi, int vci) +{ + ns_dev *card; + vc_map *vc; + int error; + double tmpd; + int tcr, tcra; /* target cell rate, and absolute value */ + int n = 0; /* Number of entries in the TST. Initialized to remove + the compiler warning. */ + u32 u32d[4]; + int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler + warning. How I wish compilers were clever enough to + tell which variables can truly be used + uninitialized... */ + int inuse; /* tx or rx vc already in use by another vcc */ + + card = (ns_dev *) vcc->dev->dev_data; + PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci); + if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) + { + PRINTK("nicstar%d: unsupported AAL.\n", card->index); + return -EINVAL; + } + + if ((error = atm_find_ci(vcc, &vpi, &vci))) + { + PRINTK("nicstar%d: error in atm_find_ci().\n", card->index); + return error; + } + vc = &(card->vcmap[vpi << card->vcibits | vci]); + vcc->vpi = vpi; + vcc->vci = vci; + vcc->dev_data = vc; + + inuse = 0; + if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) + inuse = 1; + if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) + inuse += 2; + if (inuse) + { + printk("nicstar%d: %s vci already in use.\n", card->index, + inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); + return -EINVAL; + } + + vcc->flags |= ATM_VF_ADDR; + + /* NOTE: You are not allowed to modify an open connection's QOS. To change + that, remove the ATM_VF_PARTIAL flag checking. There may be other changes + needed to do that. */ + if (!(vcc->flags & ATM_VF_PARTIAL)) + { + scq_info *scq; + + vcc->flags |= ATM_VF_PARTIAL; + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + /* Check requested cell rate and availability of SCD */ + if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 && + vcc->qos.txtp.min_pcr == 0) + { + PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", + card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + + tcr = atm_pcr_goal(&(vcc->qos.txtp)); + tcra = tcr >= 0 ? tcr : -tcr; + + PRINTK("nicstar%d: target cell rate = %d.\n", card->index, + vcc->qos.txtp.max_pcr); + + tmpd = ((double) tcra) * ((double) NS_TST_NUM_ENTRIES) / + ((double) card->max_pcr); + + n = (int) tmpd; + if (tcr > 0) + { + if (tmpd > (double) n) n++; + } + else if (tcr < 0) + { + if (tmpd < (double) n) n--; + } + else /* tcr == 0 */ + { + if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) + { + PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + } + + if (n == 0) + { + printk("nicstar%d: selected bandwidth < granularity.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + + if (vcc->qos.txtp.max_pcr > 0) + { + tmpd = (double) n * (double) card->max_pcr / + (double) NS_TST_NUM_ENTRIES; + if (tmpd > PCR_TOLERANCE * (double) vcc->qos.txtp.max_pcr) + { + PRINTK("nicstar%d: target cell rate exceeded requested max_pcr.\n", + card->index); + } + } + + if (n > (card->tst_free_entries - NS_TST_RESERVED)) + { + PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EINVAL; + } + else + card->tst_free_entries -= n; + + XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n); + for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) + { + if (card->scd2vc[frscdi] == NULL) + { + card->scd2vc[frscdi] = vc; + break; + } + } + if (frscdi == NS_FRSCD_NUM) + { + PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); + card->tst_free_entries += n; + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -EBUSY; + } + + vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; + + scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); + if (scq == (scq_info *) NULL) + { + PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); + card->scd2vc[frscdi] = NULL; + card->tst_free_entries += n; + vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + return -ENOMEM; + } + vc->scq = scq; + u32d[0] = (u32) virt_to_bus(scq->base); + u32d[1] = (u32) 0x00000000; + u32d[2] = (u32) 0xffffffff; + u32d[3] = (u32) 0x00000000; + ns_write_sram(card, vc->cbr_scd, u32d, 4); + + fill_tst(card, n, vc); + } + else /* not CBR */ + { + vc->cbr_scd = 0x00000000; + vc->scq = card->scq0; + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + vc->tx = 1; + vc->tx_vcc = vcc; + vc->tbd_count = 0; + } + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + u32 status; + + vc->rx = 1; + vc->rx_vcc = vcc; + vc->rx_iov = NULL; + + /* Open the connection in hardware */ + if (vcc->qos.aal == ATM_AAL5) + status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; + else /* vcc->qos.aal == ATM_AAL0 */ + status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; +#ifdef RCQ_SUPPORT + status |= NS_RCTE_RAWCELLINTEN; +#endif /* RCQ_SUPPORT */ + ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) * + NS_RCT_ENTRY_SIZE, &status, 1); + } + + } + + vcc->flags |= ATM_VF_READY; + return 0; +} + + + +static void ns_close(struct atm_vcc *vcc) +{ + vc_map *vc; + ns_dev *card; + u32 data; + int i; + + vc = vcc->dev_data; + card = vcc->dev->dev_data; + PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, + (int) vcc->vpi, vcc->vci); + + vcc->flags &= ~(ATM_VF_READY); + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + u32 addr; + unsigned long flags; + + addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; + save_flags(flags); cli(); + while(CMD_BUSY(card)); + writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD); + restore_flags(flags); + + vc->rx = 0; + if (vc->rx_iov != NULL) + { + struct sk_buff *iovb; + u32 stat; + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + PRINTK("nicstar%d: closing a VC with pending rx buffers.\n", + card->index); + iovb = vc->rx_iov; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + iovb->atm.iovcnt); + iovb->atm.iovcnt = 0; + iovb->atm.vcc = NULL; + save_flags(flags); cli(); + recycle_iov_buf(card, iovb); + restore_flags(flags); + vc->rx_iov = NULL; + } + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + vc->tx = 0; + } + + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + unsigned long flags; + ns_scqe *scqep; + scq_info *scq; + + scq = vc->scq; + + for (;;) + { + save_flags(flags); cli(); + scqep = scq->next; + if (scqep == scq->base) + scqep = scq->last; + else + scqep--; + if (scqep == scq->tail) + { + restore_flags(flags); + break; + } + /* If the last entry is not a TSR, place one in the SCQ in order to + be able to completely drain it and then close. */ + if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) + { + ns_scqe tsr; + u32 scdi, scqi; + u32 data; + int index; + + tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); + scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; + scqi = scq->next - scq->base; + tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); + tsr.word_3 = 0x00000000; + tsr.word_4 = 0x00000000; + *scq->next = tsr; + index = (int) scqi; + scq->skb[index] = NULL; + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + data = (u32) virt_to_bus(scq->next); + ns_write_sram(card, scq->scd, &data, 1); + } + schedule(); + restore_flags(flags); + } + + /* Free all TST entries */ + data = NS_TST_OPCODE_VARIABLE; + for (i = 0; i < NS_TST_NUM_ENTRIES; i++) + { + if (card->tste2vc[i] == vc) + { + ns_write_sram(card, card->tst_addr + i, &data, 1); + card->tste2vc[i] = NULL; + card->tst_free_entries++; + } + } + + card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; + free_scq(vc->scq, vcc); + } + + vcc->dev_data = NULL; + vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR); + +#ifdef RX_DEBUG + { + u32 stat, cfg; + stat = readl(card->membase + STAT); + cfg = readl(card->membase + CFG); + printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); + printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n", + (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last, + readl(card->membase + TSQT)); + printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n", + (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last, + readl(card->membase + RSQT)); + printk("Empty free buffer queue interrupt %s \n", + card->efbie ? "enabled" : "disabled"); + printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", + ns_stat_sfbqc_get(stat), card->sbpool.count, + ns_stat_lfbqc_get(stat), card->lbpool.count); + printk("hbpool.count = %d iovpool.count = %d \n", + card->hbpool.count, card->iovpool.count); + } +#endif /* RX_DEBUG */ +} + + + +static void fill_tst(ns_dev *card, int n, vc_map *vc) +{ + u32 new_tst; + double c, q; + int e, r; + u32 data; + + /* It would be very complicated to keep the two TSTs synchronized while + assuring that writes are only made to the inactive TST. So, for now I + will use only one TST. If problems occur, I will change this again */ + + new_tst = card->tst_addr; + + /* Fill procedure */ + + for (e = 0; e < NS_TST_NUM_ENTRIES; e++) + { + if (card->tste2vc[e] == NULL) + break; + } + if (e == NS_TST_NUM_ENTRIES) + printk("nicstar%d: No free TST entries found. \n", card->index); + + r = n; + c = 1.0; + q = (double) n / (double) NS_TST_NUM_ENTRIES; + + data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); + + while (e < NS_TST_NUM_ENTRIES) + { + if (c >= 1.0 && card->tste2vc[e] == NULL) + { + card->tste2vc[e] = vc; + ns_write_sram(card, new_tst + e, &data, 1); + c -= 1.0; + if (--r == 0) + break; + } + + e++; + c += q; + } + if (r != 0) + printk("nicstar%d: Not enough free TST entries. CBR lower than requested.\n", + card->index); + + /* End of fill procedure */ + + data = ns_tste_make(NS_TST_OPCODE_END, new_tst); + ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); + ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); + card->tst_addr = new_tst; +} + + + +static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + ns_dev *card; + vc_map *vc; + scq_info *scq; + unsigned long buflen; + ns_scqe scqe; + u32 flags; /* TBD flags, not CPU flags */ + + card = vcc->dev->dev_data; + TXPRINTK("nicstar%d: ns_send() called.\n", card->index); + if ((vc = (vc_map *) vcc->dev_data) == NULL) + { + printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (!vc->tx) + { + printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) + { + printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + if (skb->atm.iovcnt != 0) + { + printk("nicstar%d: No scatter-gather yet.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EINVAL; + } + + skb->atm.vcc = vcc; + + if (vcc->qos.aal == ATM_AAL5) + { + buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ + flags = NS_TBD_AAL5; + scqe.word_2 = (u32) virt_to_bus(skb->data); + scqe.word_3 = (u32) skb->len; + scqe.word_4 = ((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | + ((u32) vcc->vci) << NS_TBD_VCI_SHIFT; + flags |= NS_TBD_EOPDU; + } + else /* (vcc->qos.aal == ATM_AAL0) */ + { + buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ + flags = NS_TBD_AAL0; + scqe.word_2 = (u32) virt_to_bus(skb->data) + NS_AAL0_HEADER; + scqe.word_3 = 0x00000000; + if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ + flags |= NS_TBD_EOPDU; + scqe.word_4 = *((u32 *) skb->data) & ~NS_TBD_VC_MASK; + /* Force the VPI/VCI to be the same as in VCC struct */ + scqe.word_4 |= (((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | + ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK; + } + + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); + scq = ((vc_map *) vcc->dev_data)->scq; + } + else + { + scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); + scq = card->scq0; + } + + if (push_scqe(card, vc, scq, &scqe, skb) != 0) /* Timeout pushing the TBD */ + { + printk("nicstar%d: Timeout pushing TBD.\n", card->index); + vcc->stats->tx_err++; + dev_kfree_skb(skb); + return -EIO; + } + vcc->stats->tx++; + + return 0; +} + + + +static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, + struct sk_buff *skb) +{ + unsigned long flags; + ns_scqe tsr; + u32 scdi, scqi; + int scq_is_vbr; + u32 data; + int index; + + if (scq->tail == scq->next) + { + save_flags(flags); cli(); + scq->full = 1; + current->timeout = jiffies + SCQFULL_TIMEOUT; + interruptible_sleep_on(&scq->scqfull_waitq); + restore_flags(flags); + + if (scq->full) + return 1; + } + *scq->next = *tbd; + index = (int) (scq->next - scq->base); + scq->skb[index] = skb; + XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n", + card->index, (u32) skb, index); + XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", + card->index, tbd->word_1, tbd->word_2, tbd->word_3, tbd->word_4, + (u32) scq->next); + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + + vc->tbd_count++; + if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) + { + scq->tbd_count++; + scq_is_vbr = 1; + } + else + scq_is_vbr = 0; + + if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ) + { + if (scq->tail == scq->next) + { + save_flags(flags); cli(); + scq->full = 1; + current->timeout = jiffies + SCQFULL_TIMEOUT; + interruptible_sleep_on(&scq->scqfull_waitq); + restore_flags(flags); + } + + if (!scq->full) + { + tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); + if (scq_is_vbr) + scdi = NS_TSR_SCDISVBR; + else + scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; + scqi = scq->next - scq->base; + tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); + tsr.word_3 = 0x00000000; + tsr.word_4 = 0x00000000; + + *scq->next = tsr; + index = (int) scqi; + scq->skb[index] = NULL; + XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", + card->index, tsr.word_1, tsr.word_2, tsr.word_3, tsr.word_4, + (u32) scq->next); + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + vc->tbd_count = 0; + scq->tbd_count = 0; + } + else + PRINTK("nicstar%d: Could not write TSI.\n", card->index); + } + + data = (u32) virt_to_bus(scq->next); + ns_write_sram(card, scq->scd, &data, 1); + + return 0; +} + + + +static void process_tsq(ns_dev *card) +{ + u32 scdi; + scq_info *scq; + ns_tsi *previous; + + if (ns_tsi_isempty(card->tsq.next)) + return; + while (!ns_tsi_isempty(card->tsq.next)) + { + if (!ns_tsi_tmrof(card->tsq.next)) + { + scdi = ns_tsi_getscdindex(card->tsq.next); + if (scdi == NS_TSI_SCDISVBR) + scq = card->scq0; + else + { + if (card->scd2vc[scdi] == NULL) + { + printk("nicstar%d: could not find VC from SCD index.\n", + card->index); + ns_tsi_init(card->tsq.next); + return; + } + scq = card->scd2vc[scdi]->scq; + } + drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); + scq->full = 0; + wake_up_interruptible(&(scq->scqfull_waitq)); + } + + ns_tsi_init(card->tsq.next); + previous = card->tsq.next; + if (card->tsq.next == card->tsq.last) + card->tsq.next = card->tsq.base; + else + card->tsq.next++; + } + writel((((u32) previous) - ((u32) card->tsq.base)), + card->membase + TSQH); +} + + + +static void drain_scq(ns_dev *card, scq_info *scq, int pos) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + int i; + + XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n", + card->index, (u32) scq, pos); + if (pos >= scq->num_entries) + { + printk("nicstar%d: Bad index on drain_scq().\n", card->index); + return; + } + + i = (int) (scq->tail - scq->base); + if (++i == scq->num_entries) + i = 0; + while (i != pos) + { + skb = scq->skb[i]; + XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n", + card->index, (u32) skb, i); + if (skb != NULL) + { + vcc = skb->atm.vcc; + if (vcc->pop != NULL) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + scq->skb[i] = NULL; + } + if (++i == scq->num_entries) + i = 0; + } + scq->tail = scq->base + pos; +} + + + +static void process_rsq(ns_dev *card) +{ + ns_rsqe *previous; + + if (!ns_rsqe_valid(card->rsq.next)) + return; + while (ns_rsqe_valid(card->rsq.next)) + { + dequeue_rx(card, card->rsq.next); + ns_rsqe_init(card->rsq.next); + previous = card->rsq.next; + if (card->rsq.next == card->rsq.last) + card->rsq.next = card->rsq.base; + else + card->rsq.next++; + } + writel((((u32) previous) - ((u32) card->rsq.base)), + card->membase + RSQH); +} + + + +static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) +{ + u32 vpi, vci; + vc_map *vc; + struct sk_buff *iovb; + struct iovec *iov; + struct atm_vcc *vcc; + struct sk_buff *skb; + unsigned short aal5_len; + int len; + u32 stat; + + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + skb = (struct sk_buff *) rsqe->buffer_handle; + vpi = ns_rsqe_vpi(rsqe); + vci = ns_rsqe_vci(rsqe); + if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) + { + printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", + card->index, vpi, vci); + recycle_rx_buf(card, skb); + return; + } + + vc = &(card->vcmap[vpi << card->vcibits | vci]); + if (!vc->rx) + { + RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", + card->index, vpi, vci); + recycle_rx_buf(card, skb); + return; + } + + vcc = vc->rx_vcc; + + if (vcc->qos.aal == ATM_AAL0) + { + struct sk_buff *sb; + unsigned char *cell; + int i; + + cell = skb->data; + for (i = ns_rsqe_cellcount(rsqe); i; i--) + { + if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL) + { + printk("nicstar%d: Can't allocate buffers for aal0.\n", + card->index); + vcc->stats->rx_drop += i; + break; + } + if (!atm_charge(vcc, sb->truesize)) + { + RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n", + card->index); + vcc->stats->rx_drop += i - 1; /* already increased by 1 */ + kfree_skb(sb); + break; + } + /* Rebuild the header */ + *((u32 *) sb->data) = rsqe->word_1 << 4 | + (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); + if (i == 1 && ns_rsqe_eopdu(rsqe)) + *((u32 *) sb->data) |= 0x00000002; + skb_put(sb, NS_AAL0_HEADER); + memcpy(sb->tail, cell, ATM_CELL_PAYLOAD); + skb_put(sb, ATM_CELL_PAYLOAD); + sb->atm.vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + vcc->stats->rx++; + cell += ATM_CELL_PAYLOAD; + } + + recycle_rx_buf(card, skb); + return; + } + + /* To reach this point, the AAL layer can only be AAL5 */ + + if ((iovb = vc->rx_iov) == NULL) + { + iovb = skb_dequeue(&(card->iovpool.queue)); + if (iovb == NULL) /* No buffers in the queue */ + { + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); + if (iovb == NULL) + { + printk("nicstar%d: Out of iovec buffers.\n", card->index); + vcc->stats->rx_drop++; + recycle_rx_buf(card, skb); + return; + } + } + else + if (--card->iovpool.count < card->iovnr.min) + { + struct sk_buff *new_iovb; + if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->iovpool.queue, new_iovb); + card->iovpool.count++; + } + } + vc->rx_iov = iovb; + iovb->atm.iovcnt = 0; + iovb->len = 0; + iovb->tail = iovb->data = iovb->head; + iovb->atm.vcc = vcc; + /* IMPORTANT: a pointer to the sk_buff containing the small or large + buffer is stored as iovec base, NOT a pointer to the + small or large buffer itself. */ + } + else if (iovb->atm.iovcnt >= NS_MAX_IOVECS) + { + printk("nicstar%d: received too big AAL5 SDU.\n", card->index); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); + iovb->atm.iovcnt = 0; + iovb->len = 0; + iovb->tail = iovb->data = iovb->head; + iovb->atm.vcc = vcc; + } + iov = &((struct iovec *) iovb->data)[iovb->atm.iovcnt++]; + iov->iov_base = (void *) skb; + iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; + iovb->len += iov->iov_len; + + if (iovb->atm.iovcnt == 1) + { + if (skb->list != &card->sbpool.queue) + { + printk("nicstar%d: Expected a small buffer, and this is not one.\n", + card->index); + which_list(card, skb); + vcc->stats->rx_err++; + recycle_rx_buf(card, skb); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + } + else /* iovb->atm.iovcnt >= 2 */ + { + if (skb->list != &card->lbpool.queue) + { + printk("nicstar%d: Expected a large buffer, and this is not one.\n", + card->index); + which_list(card, skb); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + iovb->atm.iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + } + + if (ns_rsqe_eopdu(rsqe)) + { + aal5_len = *((unsigned short *) ((u32) skb->data + iov->iov_len - 6)); + /* Swap byte order. Is it just me or the nicstar manual sais this should + already be in little endian format? */ + aal5_len = ((aal5_len & 0x00ff) << 8 | (aal5_len & 0xff00) >> 8); + len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; + if (ns_rsqe_crcerr(rsqe) || + len + 8 > iovb->len || len + (47 + 8) < iovb->len) + { + if (ns_rsqe_crcerr(rsqe)) + printk("nicstar%d: AAL5 CRC error.\n", card->index); + else + printk("nicstar%d: AAL5 PDU size mismatch.\n", card->index); + vcc->stats->rx_err++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, iovb->atm.iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + + /* By this point we (hopefully) have a complete SDU without errors. */ + + if (iovb->atm.iovcnt == 1) /* Just a small buffer */ + { + /* skb points to a small buffer */ + if (!atm_charge(vcc, skb->truesize)) + { + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + } + else + { + skb_put(skb, len); + dequeue_sm_buf(card, skb); +#ifdef NS_USE_DESTRUCTORS + skb->destructor = ns_sb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + skb->atm.vcc = vcc; + skb->stamp = xtime; + vcc->push(vcc, skb); + vcc->stats->rx++; + } + } + else if (iovb->atm.iovcnt == 2) /* One small plus one large buffer */ + { + struct sk_buff *sb; + + sb = (struct sk_buff *) (iov - 1)->iov_base; + /* skb points to a large buffer */ + + if (len <= NS_SMBUFSIZE) + { + if (!atm_charge(vcc, sb->truesize)) + { + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + } + else + { + skb_put(sb, len); + dequeue_sm_buf(card, sb); +#ifdef NS_USE_DESTRUCTORS + sb->destructor = ns_sb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + sb->atm.vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + vcc->stats->rx++; + } + + push_rxbufs(card, BUF_LG, (u32) skb, + (u32) virt_to_bus(skb->data), 0, 0); + + } + else /* len > NS_SMBUFSIZE, the usual case */ + { + if (!atm_charge(vcc, skb->truesize)) + { + push_rxbufs(card, BUF_LG, (u32) skb, + (u32) virt_to_bus(skb->data), 0, 0); + } + else + { + dequeue_lg_buf(card, skb); +#ifdef NS_USE_DESTRUCTORS + skb->destructor = ns_lb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + skb_push(skb, NS_SMBUFSIZE); + memcpy(skb->data, sb->data, NS_SMBUFSIZE); + skb_put(skb, len - NS_SMBUFSIZE); + skb->atm.vcc = vcc; + skb->stamp = xtime; + vcc->push(vcc, skb); + vcc->stats->rx++; + } + + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + + } + + } + else /* Must push a huge buffer */ + { + struct sk_buff *hb, *sb, *lb; + int remaining, tocopy; + int j; + + hb = skb_dequeue(&(card->hbpool.queue)); + if (hb == NULL) /* No buffers in the queue */ + { + + hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC); + if (hb == NULL) + { + printk("nicstar%d: Out of huge buffers.\n", card->index); + vcc->stats->rx_drop++; + recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, + iovb->atm.iovcnt); + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + return; + } + else if (card->hbpool.count < card->hbnr.min) + { + struct sk_buff *new_hb; + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + } + } + else + if (--card->hbpool.count < card->hbnr.min) + { + struct sk_buff *new_hb; + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + if (card->hbpool.count < card->hbnr.min) + { + if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->hbpool.queue, new_hb); + card->hbpool.count++; + } + } + } + + iov = (struct iovec *) iovb->data; + + if (!atm_charge(vcc, hb->truesize)) + { + recycle_iovec_rx_bufs(card, iov, iovb->atm.iovcnt); + if (card->hbpool.count < card->hbnr.max) + { + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } + else + kfree_skb(hb); + } + else + { + /* Copy the small buffer to the huge buffer */ + sb = (struct sk_buff *) iov->iov_base; + memcpy(hb->data, sb->data, iov->iov_len); + skb_put(hb, iov->iov_len); + remaining = len - iov->iov_len; + iov++; + /* Free the small buffer */ + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), + 0, 0); + + /* Copy all large buffers to the huge buffer and free them */ + for (j = 1; j < iovb->atm.iovcnt; j++) + { + lb = (struct sk_buff *) iov->iov_base; + tocopy = MIN(remaining, iov->iov_len); + memcpy(hb->tail, lb->data, tocopy); + skb_put(hb, tocopy); + iov++; + remaining -= tocopy; + push_rxbufs(card, BUF_LG, (u32) lb, + (u32) virt_to_bus(lb->data), 0, 0); + } +#ifdef EXTRA_DEBUG + if (remaining != 0 || hb->len != len) + printk("nicstar%d: Huge buffer len mismatch.\n", card->index); +#endif /* EXTRA_DEBUG */ + hb->atm.vcc = vcc; +#ifdef NS_USE_DESTRUCTORS + hb->destructor = ns_hb_destructor; +#endif /* NS_USE_DESTRUCTORS */ + hb->stamp = xtime; + vcc->push(vcc, hb); + vcc->stats->rx++; + } + } + + vc->rx_iov = NULL; + recycle_iov_buf(card, iovb); + } + +} + + + +#ifdef NS_USE_DESTRUCTORS + +static void ns_sb_destructor(struct sk_buff *sb) +{ + ns_dev *card; + u32 stat; + + card = (ns_dev *) sb->atm.vcc->dev->dev_data; + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + do + { + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + break; + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } while (card->sbfqc < card->sbnr.min); +} + + + +static void ns_lb_destructor(struct sk_buff *lb) +{ + ns_dev *card; + u32 stat; + + card = (ns_dev *) lb->atm.vcc->dev->dev_data; + stat = readl(card->membase + STAT); + card->sbfqc = ns_stat_sfbqc_get(stat); + card->lbfqc = ns_stat_lfbqc_get(stat); + + do + { + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + break; + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } while (card->lbfqc < card->lbnr.min); +} + + + +static void ns_hb_destructor(struct sk_buff *hb) +{ + ns_dev *card; + + card = (ns_dev *) hb->atm.vcc->dev->dev_data; + + while (card->hbpool.count < card->hbnr.init) + { + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + break; + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + } +} + +#endif /* NS_USE_DESTRUCTORS */ + + + +static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb) +{ + if (skb->list == &card->sbpool.queue) + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); + else if (skb->list == &card->lbpool.queue) + push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); + else + { + printk("nicstar%d: What kind of rx buffer is this?\n", card->index); + kfree_skb(skb); + } +} + + + +static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count) +{ + struct sk_buff *skb; + + for (; count > 0; count--) + { + skb = (struct sk_buff *) (iov++)->iov_base; + if (skb->list == &card->sbpool.queue) + push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + else if (skb->list == &card->lbpool.queue) + push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), + 0, 0); + else + { + printk("nicstar%d: What kind of rx buffer is this?\n", card->index); + kfree_skb(skb); + } + } +} + + + +static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb) +{ + if (card->iovpool.count < card->iovnr.max) + { + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + } + else + kfree_skb(iovb); +} + + + +static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb) +{ + skb_unlink(sb); +#ifdef NS_USE_DESTRUCTORS + if (card->sbfqc < card->sbnr.min) +#else + if (card->sbfqc < card->sbnr.init) + { + struct sk_buff *new_sb; + if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->sbpool.queue, new_sb); + skb_reserve(new_sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) new_sb, + (u32) virt_to_bus(new_sb->data), 0, 0); + } + } + if (card->sbfqc < card->sbnr.init) +#endif /* NS_USE_DESTRUCTORS */ + { + struct sk_buff *new_sb; + if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->sbpool.queue, new_sb); + skb_reserve(new_sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) new_sb, + (u32) virt_to_bus(new_sb->data), 0, 0); + } + } +} + + + +static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb) +{ + skb_unlink(lb); +#ifdef NS_USE_DESTRUCTORS + if (card->lbfqc < card->lbnr.min) +#else + if (card->lbfqc < card->lbnr.init) + { + struct sk_buff *new_lb; + if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->lbpool.queue, new_lb); + skb_reserve(new_lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) new_lb, + (u32) virt_to_bus(new_lb->data), 0, 0); + } + } + if (card->lbfqc < card->lbnr.init) +#endif /* NS_USE_DESTRUCTORS */ + { + struct sk_buff *new_lb; + if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + { + skb_queue_tail(&card->lbpool.queue, new_lb); + skb_reserve(new_lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) new_lb, + (u32) virt_to_bus(new_lb->data), 0, 0); + } + } +} + + + +static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page) +{ + u32 stat; + ns_dev *card; + int left; + + left = (int) *pos; + card = (ns_dev *) dev->dev_data; + stat = readl(card->membase + STAT); + if (!left--) + return sprintf(page, "Pool count min init max \n"); + if (!left--) + return sprintf(page, "Small %5d %5d %5d %5d \n", + ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init, + card->sbnr.max); + if (!left--) + return sprintf(page, "Large %5d %5d %5d %5d \n", + ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init, + card->lbnr.max); + if (!left--) + return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count, + card->hbnr.min, card->hbnr.init, card->hbnr.max); + if (!left--) + return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count, + card->iovnr.min, card->iovnr.init, card->iovnr.max); + if (!left--) + { + int retval; + retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt); + card->intcnt = 0; + return retval; + } + /* Dump 25.6 Mbps PHY registers */ + if (card->max_pcr == IDT_25_PCR && !left--) + { + u32 phy_regs[4]; + u32 i; + + for (i = 0; i < 4; i++) + { + while (CMD_BUSY(card)); + writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD); + while (CMD_BUSY(card)); + phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; + } + + return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", + phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]); + } +#if 0 + /* Dump TST */ + if (left-- < NS_TST_NUM_ENTRIES) + { + if (card->tste2vc[left + 1] == NULL) + return sprintf(page, "%5d - VBR/UBR \n", left + 1); + else + return sprintf(page, "%5d - %d %d \n", left + 1, + card->tste2vc[left + 1]->tx_vcc->vpi, + card->tste2vc[left + 1]->tx_vcc->vci); + } +#endif /* 0 */ + return 0; +} + + + +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +{ + ns_dev *card; + pool_levels pl; + int btype; + unsigned long flags; + + card = dev->dev_data; + switch (cmd) + { + case NS_GETPSTAT: + if (get_user(pl.buftype, &((pool_levels *) arg)->buftype)) + return -EFAULT; + switch (pl.buftype) + { + case NS_BUFTYPE_SMALL: + pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT)); + pl.level.min = card->sbnr.min; + pl.level.init = card->sbnr.init; + pl.level.max = card->sbnr.max; + break; + + case NS_BUFTYPE_LARGE: + pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT)); + pl.level.min = card->lbnr.min; + pl.level.init = card->lbnr.init; + pl.level.max = card->lbnr.max; + break; + + case NS_BUFTYPE_HUGE: + pl.count = card->hbpool.count; + pl.level.min = card->hbnr.min; + pl.level.init = card->hbnr.init; + pl.level.max = card->hbnr.max; + break; + + case NS_BUFTYPE_IOVEC: + pl.count = card->iovpool.count; + pl.level.min = card->iovnr.min; + pl.level.init = card->iovnr.init; + pl.level.max = card->iovnr.max; + break; + + default: + return -EINVAL; + + } + if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) + return (sizeof(pl)); + else + return -EFAULT; + + case NS_SETBUFLEV: + if (!suser()) + return -EPERM; + if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl))) + return -EFAULT; + if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max) + return -EINVAL; + if (pl.level.min == 0) + return -EINVAL; + switch (pl.buftype) + { + case NS_BUFTYPE_SMALL: + if (pl.level.max > TOP_SB) + return -EINVAL; + card->sbnr.min = pl.level.min; + card->sbnr.init = pl.level.init; + card->sbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_LARGE: + if (pl.level.max > TOP_LB) + return -EINVAL; + card->lbnr.min = pl.level.min; + card->lbnr.init = pl.level.init; + card->lbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_HUGE: + if (pl.level.max > TOP_HB) + return -EINVAL; + card->hbnr.min = pl.level.min; + card->hbnr.init = pl.level.init; + card->hbnr.max = pl.level.max; + break; + + case NS_BUFTYPE_IOVEC: + if (pl.level.max > TOP_IOVB) + return -EINVAL; + card->iovnr.min = pl.level.min; + card->iovnr.init = pl.level.init; + card->iovnr.max = pl.level.max; + break; + + default: + return -EINVAL; + + } + return 0; + + case NS_ADJBUFLEV: + if (!suser()) + return -EPERM; + btype = (int) arg; /* an int is the same size as a pointer */ + switch (btype) + { + case NS_BUFTYPE_SMALL: + while (card->sbfqc < card->sbnr.init) + { + struct sk_buff *sb; + + sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + if (sb == NULL) + return -ENOMEM; + skb_queue_tail(&card->sbpool.queue, sb); + skb_reserve(sb, NS_AAL0_HEADER); + push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); + } + break; + + case NS_BUFTYPE_LARGE: + while (card->lbfqc < card->lbnr.init) + { + struct sk_buff *lb; + + lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + if (lb == NULL) + return -ENOMEM; + skb_queue_tail(&card->lbpool.queue, lb); + skb_reserve(lb, NS_SMBUFSIZE); + push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); + } + break; + + case NS_BUFTYPE_HUGE: + while (card->hbpool.count > card->hbnr.init) + { + struct sk_buff *hb; + + save_flags(flags); cli(); + hb = skb_dequeue(&card->hbpool.queue); + card->hbpool.count--; + restore_flags(flags); + if (hb == NULL) + printk("nicstar%d: huge buffer count inconsistent.\n", + card->index); + else + kfree_skb(hb); + + } + while (card->hbpool.count < card->hbnr.init) + { + struct sk_buff *hb; + + hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + if (hb == NULL) + return -ENOMEM; + save_flags(flags); cli(); + skb_queue_tail(&card->hbpool.queue, hb); + card->hbpool.count++; + restore_flags(flags); + } + break; + + case NS_BUFTYPE_IOVEC: + while (card->iovpool.count > card->iovnr.init) + { + struct sk_buff *iovb; + + save_flags(flags); cli(); + iovb = skb_dequeue(&card->iovpool.queue); + card->iovpool.count--; + restore_flags(flags); + if (iovb == NULL) + printk("nicstar%d: iovec buffer count inconsistent.\n", + card->index); + else + kfree_skb(iovb); + + } + while (card->iovpool.count < card->iovnr.init) + { + struct sk_buff *iovb; + + iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); + if (iovb == NULL) + return -ENOMEM; + save_flags(flags); cli(); + skb_queue_tail(&card->iovpool.queue, iovb); + card->iovpool.count++; + restore_flags(flags); + } + break; + + default: + return -EINVAL; + + } + return 0; + + default: + if (dev->phy->ioctl == NULL) return -EINVAL; + return dev->phy->ioctl(dev, cmd, arg); + } +} + + + +static void which_list(ns_dev *card, struct sk_buff *skb) +{ + printk("It's a %s buffer.\n", skb->list == &card->sbpool.queue ? + "small" : skb->list == &card->lbpool.queue ? "large" : + skb->list == &card->hbpool.queue ? "huge" : + skb->list == &card->iovpool.queue ? "iovec" : "unknown"); +} + + + +static void ns_poll(unsigned long arg) +{ + int i; + ns_dev *card; + unsigned long flags; + u32 stat_r, stat_w; + + PRINTK("nicstar: Entering ns_poll().\n"); + for (i = 0; i < num_cards; i++) + { + card = cards[i]; + save_flags(flags); cli(); + if (card->in_poll) + { + printk("nicstar: Re-entering ns_poll()???\n"); + continue; + } + card->in_poll = 1; + if (card->in_handler) + { + card->in_poll = 0; + printk("nicstar%d: ns_poll called while in interrupt handler!?\n", + card->index); + continue; + } + + stat_w = 0; + stat_r = readl(card->membase + STAT); + if (stat_r & NS_STAT_TSIF) + stat_w |= NS_STAT_TSIF; + if (stat_r & NS_STAT_EOPDU) + stat_w |= NS_STAT_EOPDU; + + process_tsq(card); + process_rsq(card); + + writel(card->membase + STAT, stat_w); + card->in_poll = 0; + restore_flags(flags); + } + mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); + PRINTK("nicstar: Leaving ns_poll().\n"); +} diff -u --recursive --new-file v2.3.14/linux/drivers/atm/nicstar.h linux/drivers/atm/nicstar.h --- v2.3.14/linux/drivers/atm/nicstar.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/nicstar.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,774 @@ +/****************************************************************************** + * + * nicstar.h + * + * Header file for the nicstar device driver. + * + * Author: Rui Prior (rprior@inescn.pt) + * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 + * + * (C) INESC 1998 + * + ******************************************************************************/ + + +#ifndef _LINUX_NICSTAR_H_ +#define _LINUX_NICSTAR_H_ + + +/* Includes *******************************************************************/ + +#include +#include +#include +#include +#include +#include + + +/* Options ********************************************************************/ + +#define NS_MAX_CARDS 4 /* Maximum number of NICStAR based cards + controlled by the device driver. Must + be <= 5 */ + +#undef RCQ_SUPPORT /* Do not define this for now */ + +#define NS_TST_NUM_ENTRIES 2340 /* + 1 for return */ +#define NS_TST_RESERVED 340 /* N. entries reserved for UBR/ABR/VBR */ + +#define NS_SMBUFSIZE 48 /* 48, 96, 240 or 2048 */ +#define NS_LGBUFSIZE 16384 /* 2048, 4096, 8192 or 16384 */ +#define NS_RSQSIZE 8192 /* 2048, 4096 or 8192 */ +#define NS_VPIBITS 2 /* 0, 1, 2, or 8 */ + +#define NS_MAX_RCTSIZE 4096 /* Number of entries. 4096 or 16384. + Define 4096 only if (all) your card(s) + have 32K x 32bit SRAM, in which case + setting this to 16384 will just waste a + lot of memory. + Setting this to 4096 for a card with + 128K x 32bit SRAM will limit the maximum + VCI. */ + +#define NS_PCI_LATENCY 64 /* Must be a multiple of 32 */ + + /* Number of buffers initially allocated */ +#define NUM_SB 32 /* Must be even */ +#define NUM_LB 24 /* Must be even */ +#define NUM_HB 8 /* Pre-allocated huge buffers */ +#define NUM_IOVB 48 /* Iovec buffers */ + + /* Lower level for count of buffers */ +#define MIN_SB 8 /* Must be even */ +#define MIN_LB 8 /* Must be even */ +#define MIN_HB 6 +#define MIN_IOVB 8 + + /* Upper level for count of buffers */ +#define MAX_SB 64 /* Must be even, <= 508 */ +#define MAX_LB 48 /* Must be even, <= 508 */ +#define MAX_HB 10 +#define MAX_IOVB 80 + + /* These are the absolute maximum allowed for the ioctl() */ +#define TOP_SB 256 /* Must be even, <= 508 */ +#define TOP_LB 128 /* Must be even, <= 508 */ +#define TOP_HB 64 +#define TOP_IOVB 256 + + +#define MAX_TBD_PER_VC 1 /* Number of TBDs before a TSR */ +#define MAX_TBD_PER_SCQ 10 /* Only meaningful for variable rate SCQs */ + +#undef ENABLE_TSQFIE + +#define SCQFULL_TIMEOUT (5 * HZ) + +#define NS_POLL_PERIOD (HZ) + +#define PCR_TOLERANCE (1.0001) + + + +/* ESI stuff ******************************************************************/ + +#define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C + + +/* #defines *******************************************************************/ + +#define NS_IOREMAP_SIZE 4096 + +#define IDT_25_PCR ((25600000 / 8 - 8000) / 54) + +#define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */ +#define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */ + +#define NS_HBUFSIZE 65568 /* Size of max. AAL5 PDU */ +#define NS_MAX_IOVECS (2 + (65568 - NS_SMBUFSIZE) / \ + (NS_LGBUFSIZE - (NS_LGBUFSIZE % 48))) +#define NS_IOVBUFSIZE (NS_MAX_IOVECS * (sizeof(struct iovec))) + +#define NS_SMBUFSIZE_USABLE (NS_SMBUFSIZE - NS_SMBUFSIZE % 48) +#define NS_LGBUFSIZE_USABLE (NS_LGBUFSIZE - NS_LGBUFSIZE % 48) + +#define NS_AAL0_HEADER (ATM_AAL0_SDU - ATM_CELL_PAYLOAD) /* 4 bytes */ + +#define NS_SMSKBSIZE (NS_SMBUFSIZE + NS_AAL0_HEADER) +#define NS_LGSKBSIZE (NS_SMBUFSIZE + NS_LGBUFSIZE) + + +/* NICStAR structures located in host memory **********************************/ + + + +/* RSQ - Receive Status Queue + * + * Written by the NICStAR, read by the device driver. + */ + +typedef struct ns_rsqe +{ + u32 word_1; + u32 buffer_handle; + u32 final_aal5_crc32; + u32 word_4; +} ns_rsqe; + +#define ns_rsqe_vpi(ns_rsqep) \ + ((le32_to_cpu((ns_rsqep)->word_1) & 0x00FF0000) >> 16) +#define ns_rsqe_vci(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_1) & 0x0000FFFF) + +#define NS_RSQE_VALID 0x80000000 +#define NS_RSQE_NZGFC 0x00004000 +#define NS_RSQE_EOPDU 0x00002000 +#define NS_RSQE_BUFSIZE 0x00001000 +#define NS_RSQE_CONGESTION 0x00000800 +#define NS_RSQE_CLP 0x00000400 +#define NS_RSQE_CRCERR 0x00000200 + +#define NS_RSQE_BUFSIZE_SM 0x00000000 +#define NS_RSQE_BUFSIZE_LG 0x00001000 + +#define ns_rsqe_valid(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_VALID) +#define ns_rsqe_nzgfc(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_NZGFC) +#define ns_rsqe_eopdu(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_EOPDU) +#define ns_rsqe_bufsize(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_BUFSIZE) +#define ns_rsqe_congestion(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CONGESTION) +#define ns_rsqe_clp(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CLP) +#define ns_rsqe_crcerr(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CRCERR) + +#define ns_rsqe_cellcount(ns_rsqep) \ + (le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF) +#define ns_rsqe_init(ns_rsqep) \ + ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000)) + +#define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16) +#define NS_RSQ_ALIGNMENT NS_RSQSIZE + + + +/* RCQ - Raw Cell Queue + * + * Written by the NICStAR, read by the device driver. + */ + +typedef struct cell_payload +{ + u32 word[12]; +} cell_payload; + +typedef struct ns_rcqe +{ + u32 word_1; + u32 word_2; + u32 word_3; + u32 word_4; + cell_payload payload; +} ns_rcqe; + +#define NS_RCQE_SIZE 64 /* bytes */ + +#define ns_rcqe_islast(ns_rcqep) \ + (le32_to_cpu((ns_rcqep)->word_2) != 0x00000000) +#define ns_rcqe_cellheader(ns_rcqep) \ + (le32_to_cpu((ns_rcqep)->word_1)) +#define ns_rcqe_nextbufhandle(ns_rcqep) \ + (le32_to_cpu((ns_rcqep)->word_2)) + + + +/* SCQ - Segmentation Channel Queue + * + * Written by the device driver, read by the NICStAR. + */ + +typedef struct ns_scqe +{ + u32 word_1; + u32 word_2; + u32 word_3; + u32 word_4; +} ns_scqe; + + /* NOTE: SCQ entries can be either a TBD (Transmit Buffer Descriptors) + or TSR (Transmit Status Requests) */ + +#define NS_SCQE_TYPE_TBD 0x00000000 +#define NS_SCQE_TYPE_TSR 0x80000000 + + +#define NS_TBD_EOPDU 0x40000000 +#define NS_TBD_AAL0 0x00000000 +#define NS_TBD_AAL34 0x04000000 +#define NS_TBD_AAL5 0x08000000 + +#define NS_TBD_VPI_MASK 0x0FF00000 +#define NS_TBD_VCI_MASK 0x000FFFF0 +#define NS_TBD_VC_MASK (NS_TBD_VPI_MASK | NS_TBD_VCI_MASK) + +#define NS_TBD_VPI_SHIFT 20 +#define NS_TBD_VCI_SHIFT 4 + +#define ns_tbd_mkword_1(flags, m, n, buflen) \ + (cpu_to_le32(flags | m << 23 | n << 16 | buflen)) +#define ns_tbd_mkword_1_novbr(flags, buflen) \ + (cpu_to_le32(flags | buflen | 0x00810000)) +#define ns_tbd_mkword_3(control, pdulen) \ + (cpu_to_le32(control << 16 | pdulen)) +#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \ + (cpu_to_le32(gfc << 28 | vpi << 20 | vci << 4 | pt << 1 | clp))) + + +#define NS_TSR_INTENABLE 0x20000000 + +#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */ + +#define ns_tsr_mkword_1(flags) \ + (cpu_to_le32(NS_SCQE_TYPE_TSR | (flags))) +#define ns_tsr_mkword_2(scdi, scqi) \ + (cpu_to_le32((scdi) << 16 | 0x00008000 | (scqi))) + +#define ns_scqe_is_tsr(ns_scqep) \ + (le32_to_cpu((ns_scqep)->word_1) & NS_SCQE_TYPE_TSR) + +#define VBR_SCQ_NUM_ENTRIES 512 +#define VBR_SCQSIZE 8192 +#define CBR_SCQ_NUM_ENTRIES 64 +#define CBR_SCQSIZE 1024 + +#define NS_SCQE_SIZE 16 + + + +/* TSQ - Transmit Status Queue + * + * Written by the NICStAR, read by the device driver. + */ + +typedef struct ns_tsi +{ + u32 word_1; + u32 word_2; +} ns_tsi; + + /* NOTE: The first word can be a status word copied from the TSR which + originated the TSI, or a timer overflow indicator. In this last + case, the value of the first word is all zeroes. */ + +#define NS_TSI_EMPTY 0x80000000 +#define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF + +#define ns_tsi_isempty(ns_tsip) \ + (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_EMPTY) +#define ns_tsi_gettimestamp(ns_tsip) \ + (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_TIMESTAMP_MASK) + +#define ns_tsi_init(ns_tsip) \ + ((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY)) + + +#define NS_TSQSIZE 8192 +#define NS_TSQ_NUM_ENTRIES 1024 +#define NS_TSQ_ALIGNMENT 8192 + + +#define NS_TSI_SCDISVBR NS_TSR_SCDISVBR + +#define ns_tsi_tmrof(ns_tsip) \ + (le32_to_cpu((ns_tsip)->word_1) == 0x00000000) +#define ns_tsi_getscdindex(ns_tsip) \ + ((le32_to_cpu((ns_tsip)->word_1) & 0xFFFF0000) >> 16) +#define ns_tsi_getscqpos(ns_tsip) \ + (le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF) + + + +/* NICStAR structures located in local SRAM ***********************************/ + + + +/* RCT - Receive Connection Table + * + * Written by both the NICStAR and the device driver. + */ + +typedef struct ns_rcte +{ + u32 word_1; + u32 buffer_handle; + u32 dma_address; + u32 aal5_crc32; +} ns_rcte; + +#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */ +#define NS_RCTE_NZGFC 0x00100000 +#define NS_RCTE_CONNECTOPEN 0x00080000 +#define NS_RCTE_AALMASK 0x00070000 +#define NS_RCTE_AAL0 0x00000000 +#define NS_RCTE_AAL34 0x00010000 +#define NS_RCTE_AAL5 0x00020000 +#define NS_RCTE_RCQ 0x00030000 +#define NS_RCTE_RAWCELLINTEN 0x00008000 +#define NS_RCTE_RXCONSTCELLADDR 0x00004000 +#define NS_RCTE_BUFFVALID 0x00002000 +#define NS_RCTE_FBDSIZE 0x00001000 +#define NS_RCTE_EFCI 0x00000800 +#define NS_RCTE_CLP 0x00000400 +#define NS_RCTE_CRCERROR 0x00000200 +#define NS_RCTE_CELLCOUNT_MASK 0x000001FF + +#define NS_RCTE_FBDSIZE_SM 0x00000000 +#define NS_RCTE_FBDSIZE_LG 0x00001000 + +#define NS_RCT_ENTRY_SIZE 4 /* Number of dwords */ + + /* NOTE: We could make macros to contruct the first word of the RCTE, + but that doesn't seem to make much sense... */ + + + +/* FBD - Free Buffer Descriptor + * + * Written by the device driver using via the command register. + */ + +typedef struct ns_fbd +{ + u32 buffer_handle; + u32 dma_address; +} ns_fbd; + + + + +/* TST - Transmit Schedule Table + * + * Written by the device driver. + */ + +typedef u32 ns_tste; + +#define NS_TST_OPCODE_MASK 0x60000000 + +#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */ +#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */ +#define NS_TST_OPCODE_VARIABLE 0x40000000 +#define NS_TST_OPCODE_END 0x60000000 /* Jump */ + +#define ns_tste_make(opcode, sramad) (opcode | sramad) + + /* NOTE: + + - When the opcode is FIXED, sramad specifies the SRAM address of the + SCD for that fixed rate channel. + - When the opcode is END, sramad specifies the SRAM address of the + location of the next TST entry to read. + */ + + + +/* SCD - Segmentation Channel Descriptor + * + * Written by both the device driver and the NICStAR + */ + +typedef struct ns_scd +{ + u32 word_1; + u32 word_2; + u32 partial_aal5_crc; + u32 reserved; + ns_scqe cache_a; + ns_scqe cache_b; +} ns_scd; + +#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */ +#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */ +#define NS_SCD_TAIL_MASK_VAR 0x00001FF0 +#define NS_SCD_TAIL_MASK_FIX 0x000003F0 +#define NS_SCD_HEAD_MASK_VAR 0x00001FF0 +#define NS_SCD_HEAD_MASK_FIX 0x000003F0 +#define NS_SCD_XMITFOREVER 0x02000000 + + /* NOTE: There are other fields in word 2 of the SCD, but as they should + not be needed in the device driver they are not defined here. */ + + + + +/* NICStAR local SRAM memory map **********************************************/ + + +#define NS_RCT 0x00000 +#define NS_RCT_32_END 0x03FFF +#define NS_RCT_128_END 0x0FFFF +#define NS_UNUSED_32 0x04000 +#define NS_UNUSED_128 0x10000 +#define NS_UNUSED_END 0x1BFFF +#define NS_TST_FRSCD 0x1C000 +#define NS_TST_FRSCD_END 0x1E7DB +#define NS_VRSCD2 0x1E7DC +#define NS_VRSCD2_END 0x1E7E7 +#define NS_VRSCD1 0x1E7E8 +#define NS_VRSCD1_END 0x1E7F3 +#define NS_VRSCD0 0x1E7F4 +#define NS_VRSCD0_END 0x1E7FF +#define NS_RXFIFO 0x1E800 +#define NS_RXFIFO_END 0x1F7FF +#define NS_SMFBQ 0x1F800 +#define NS_SMFBQ_END 0x1FBFF +#define NS_LGFBQ 0x1FC00 +#define NS_LGFBQ_END 0x1FFFF + + + +/* NISCtAR operation registers ************************************************/ + + +enum ns_regs +{ + DR0 = 0x00, + DR1 = 0x04, + DR2 = 0x08, + DR3 = 0x0C, + CMD = 0x10, + CFG = 0x14, + STAT = 0x18, + RSQB = 0x1C, + RSQT = 0x20, + RSQH = 0x24, + CDC = 0x28, + VPEC = 0x2C, + ICC = 0x30, + RAWCT = 0x34, + TMR = 0x38, + TSTB = 0x3C, + TSQB = 0x40, + TSQT = 0x44, + TSQH = 0x48, + GP = 0x4C, + VPM = 0x50 +}; + + +/* NICStAR commands issued to the CMD register ********************************/ + +#define NS_CMD_NO_OPERATION 0x00000000 +#define NS_CMD_OPENCLOSE_CONNECTION 0x20000000 +#define NS_CMD_WRITE_SRAM 0x40000000 +#define NS_CMD_READ_SRAM 0x50000000 +#define NS_CMD_WRITE_FREEBUFQ 0x60000000 +#define NS_CMD_READ_UTILITY 0x80000000 +#define NS_CMD_WRITE_UTILITY 0x90000000 + +#define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000) +#define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION + + +/* NICStAR configuration bits *************************************************/ + +#define NS_CFG_SWRST 0x80000000 +#define NS_CFG_RXPATH 0x20000000 +#define NS_CFG_SMBUFSIZE_MASK 0x18000000 +#define NS_CFG_LGBUFSIZE_MASK 0x06000000 +#define NS_CFG_EFBIE 0x01000000 +#define NS_CFG_RSQSIZE_MASK 0x00C00000 +#define NS_CFG_ICACCEPT 0x00200000 +#define NS_CFG_IGNOREGFC 0x00100000 +#define NS_CFG_VPIBITS_MASK 0x000C0000 +#define NS_CFG_RCTSIZE_MASK 0x00030000 +#define NS_CFG_VCERRACCEPT 0x00008000 +#define NS_CFG_RXINT_MASK 0x00007000 +#define NS_CFG_RAWIE 0x00000800 +#define NS_CFG_RSQAFIE 0x00000400 +#define NS_CFG_RXRM 0x00000200 +#define NS_CFG_TMRROIE 0x00000080 +#define NS_CFG_TXEN 0x00000020 +#define NS_CFG_TXIE 0x00000010 +#define NS_CFG_TXURIE 0x00000008 +#define NS_CFG_UMODE 0x00000004 +#define NS_CFG_TSQFIE 0x00000002 +#define NS_CFG_PHYIE 0x00000001 + +#define NS_CFG_SMBUFSIZE_48 0x00000000 +#define NS_CFG_SMBUFSIZE_96 0x08000000 +#define NS_CFG_SMBUFSIZE_240 0x10000000 +#define NS_CFG_SMBUFSIZE_2048 0x18000000 + +#define NS_CFG_LGBUFSIZE_2048 0x00000000 +#define NS_CFG_LGBUFSIZE_4096 0x02000000 +#define NS_CFG_LGBUFSIZE_8192 0x04000000 +#define NS_CFG_LGBUFSIZE_16384 0x06000000 + +#define NS_CFG_RSQSIZE_2048 0x00000000 +#define NS_CFG_RSQSIZE_4096 0x00400000 +#define NS_CFG_RSQSIZE_8192 0x00800000 + +#define NS_CFG_VPIBITS_0 0x00000000 +#define NS_CFG_VPIBITS_1 0x00040000 +#define NS_CFG_VPIBITS_2 0x00080000 +#define NS_CFG_VPIBITS_8 0x000C0000 + +#define NS_CFG_RCTSIZE_4096_ENTRIES 0x00000000 +#define NS_CFG_RCTSIZE_8192_ENTRIES 0x00010000 +#define NS_CFG_RCTSIZE_16384_ENTRIES 0x00020000 + +#define NS_CFG_RXINT_NOINT 0x00000000 +#define NS_CFG_RXINT_NODELAY 0x00001000 +#define NS_CFG_RXINT_314US 0x00002000 +#define NS_CFG_RXINT_624US 0x00003000 +#define NS_CFG_RXINT_899US 0x00004000 + + +/* NICStAR STATus bits ********************************************************/ + +#define NS_STAT_SFBQC_MASK 0xFF000000 +#define NS_STAT_LFBQC_MASK 0x00FF0000 +#define NS_STAT_TSIF 0x00008000 +#define NS_STAT_TXICP 0x00004000 +#define NS_STAT_TSQF 0x00001000 +#define NS_STAT_TMROF 0x00000800 +#define NS_STAT_PHYI 0x00000400 +#define NS_STAT_CMDBZ 0x00000200 +#define NS_STAT_SFBQF 0x00000100 +#define NS_STAT_LFBQF 0x00000080 +#define NS_STAT_RSQF 0x00000040 +#define NS_STAT_EOPDU 0x00000020 +#define NS_STAT_RAWCF 0x00000010 +#define NS_STAT_SFBQE 0x00000008 +#define NS_STAT_LFBQE 0x00000004 +#define NS_STAT_RSQAF 0x00000002 + +#define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23) +#define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15) + + + +/* #defines which depend on other #defines ************************************/ + + +#define NS_TST0 NS_TST_FRSCD +#define NS_TST1 (NS_TST_FRSCD + NS_TST_NUM_ENTRIES + 1) + +#define NS_FRSCD (NS_TST1 + NS_TST_NUM_ENTRIES + 1) +#define NS_FRSCD_SIZE 12 /* 12 dwords */ +#define NS_FRSCD_NUM ((NS_TST_FRSCD_END + 1 - NS_FRSCD) / NS_FRSCD_SIZE) + +#if (NS_SMBUFSIZE == 48) +#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_48 +#elif (NS_SMBUFSIZE == 96) +#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_96 +#eliif (NS_SMBUFSIZE == 240) +#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_240 +#elif (NS_SMBUFSIZE == 2048) +#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_2048 +#else +#error NS_SMBUFSIZE is incorrect in nicstar.h +#endif /* NS_SMBUFSIZE */ + +#if (NS_LGBUFSIZE == 2048) +#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_2048 +#elif (NS_LGBUFSIZE == 4096) +#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_4096 +#eliif (NS_LGBUFSIZE == 8192) +#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_8192 +#elif (NS_LGBUFSIZE == 16384) +#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_16384 +#else +#error NS_LGBUFSIZE is incorrect in nicstar.h +#endif /* NS_LGBUFSIZE */ + +#if (NS_RSQSIZE == 2048) +#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_2048 +#elif (NS_RSQSIZE == 4096) +#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_4096 +#elif (NS_RSQSIZE == 8192) +#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_8192 +#else +#error NS_RSQSIZE is incorrect in nicstar.h +#endif /* NS_RSQSIZE */ + +#if (NS_VPIBITS == 0) +#define NS_CFG_VPIBITS NS_CFG_VPIBITS_0 +#elif (NS_VPIBITS == 1) +#define NS_CFG_VPIBITS NS_CFG_VPIBITS_1 +#elif (NS_VPIBITS == 2) +#define NS_CFG_VPIBITS NS_CFG_VPIBITS_2 +#elif (NS_VPIBITS == 8) +#define NS_CFG_VPIBITS NS_CFG_VPIBITS_8 +#else +#error NS_VPIBITS is incorrect in nicstar.h +#endif /* NS_VPIBITS */ + +#ifdef RCQ_SUPPORT +#define NS_CFG_RAWIE_OPT NS_CFG_RAWIE +#else +#define NS_CFG_RAWIE_OPT 0x00000000 +#endif /* RCQ_SUPPORT */ + +#ifdef ENABLE_TSQFIE +#define NS_CFG_TSQFIE_OPT NS_CFG_TSQFIE +#else +#define NS_CFG_TSQFIE_OPT 0x00000000 +#endif /* ENABLE_TSQFIE */ + + +/* PCI stuff ******************************************************************/ + +#ifndef PCI_VENDOR_ID_IDT +#define PCI_VENDOR_ID_IDT 0x111D +#endif /* PCI_VENDOR_ID_IDT */ + +#ifndef PCI_DEVICE_ID_IDT_IDT77201 +#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 +#endif /* PCI_DEVICE_ID_IDT_IDT77201 */ + + + +/* Device driver structures ***************************************************/ + + +typedef struct tsq_info +{ + void *org; + ns_tsi *base; + ns_tsi *next; + ns_tsi *last; +} tsq_info; + + +typedef struct scq_info +{ + void *org; + ns_scqe *base; + ns_scqe *last; + ns_scqe *next; + volatile ns_scqe *tail; /* Not related to the nicstar register */ + unsigned num_entries; + struct sk_buff **skb; /* Pointer to an array of pointers + to the sk_buffs used for tx */ + u32 scd; /* SRAM address of the corresponding + SCD */ + int tbd_count; /* Only meaningful on variable rate */ + wait_queue_head_t scqfull_waitq; + volatile char full; /* SCQ full indicator */ +} scq_info; + + + +typedef struct rsq_info +{ + void *org; + ns_rsqe *base; + ns_rsqe *next; + ns_rsqe *last; +} rsq_info; + + +typedef struct skb_pool +{ + volatile int count; /* number of buffers in the queue */ + struct sk_buff_head queue; +} skb_pool; + +/* NOTE: for small and large buffer pools, the count is not used, as the + actual value used for buffer management is the one read from the + card. */ + + +typedef struct vc_map +{ + volatile int tx:1; /* TX vc? */ + volatile int rx:1; /* RX vc? */ + struct atm_vcc *tx_vcc, *rx_vcc; + struct sk_buff *rx_iov; /* RX iovector skb */ + scq_info *scq; /* To keep track of the SCQ */ + u32 cbr_scd; /* SRAM address of the corresponding + SCD. 0x00000000 for UBR/VBR/ABR */ + int tbd_count; +} vc_map; + + +typedef struct ns_dev +{ + int index; /* Card ID to the device driver */ + int sram_size; /* In k x 32bit words. 32 or 128 */ + u32 membase; /* Card's memory base address */ + unsigned long max_pcr; + int rct_size; /* Number of entries */ + int vpibits; + int vcibits; + struct pci_dev *pcidev; + struct atm_dev *atmdev; + tsq_info tsq; + rsq_info rsq; + scq_info *scq0, *scq1, *scq2; /* VBR SCQs */ + skb_pool sbpool; /* Small buffers */ + skb_pool lbpool; /* Large buffers */ + skb_pool hbpool; /* Pre-allocated huge buffers */ + skb_pool iovpool; /* iovector buffers */ + volatile int efbie; /* Empty free buf. queue int. enabled */ + volatile u32 tst_addr; /* SRAM address of the TST in use */ + volatile int tst_free_entries; + vc_map vcmap[NS_MAX_RCTSIZE]; + vc_map *tste2vc[NS_TST_NUM_ENTRIES]; + vc_map *scd2vc[NS_FRSCD_NUM]; + buf_nr sbnr; + buf_nr lbnr; + buf_nr hbnr; + buf_nr iovnr; + int sbfqc; + int lbfqc; + u32 sm_handle; + u32 sm_addr; + u32 lg_handle; + u32 lg_addr; + struct sk_buff *rcbuf; /* Current raw cell buffer */ + u32 rawch; /* Raw cell queue head */ + unsigned intcnt; /* Interrupt counter */ + volatile int in_handler: 1; + volatile int in_poll: 1; +} ns_dev; + + + /* NOTE: Each tste2vc entry relates a given TST entry to the corresponding + CBR vc. If the entry is not allocated, it must be NULL. + + There are two TSTs so the driver can modify them on the fly + without stopping the transmission. + + scd2vc allows us to find out unused fixed rate SCDs, because + they must have a NULL pointer here. */ + + +#endif /* _LINUX_NICSTAR_H_ */ diff -u --recursive --new-file v2.3.14/linux/drivers/atm/nicstarmac.c linux/drivers/atm/nicstarmac.c --- v2.3.14/linux/drivers/atm/nicstarmac.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/nicstarmac.c Mon Aug 23 09:56:31 1999 @@ -0,0 +1,269 @@ +/* + * this file included by nicstar.c + */ + +/* + * nicstarmac.c + * Read this ForeRunner's MAC address from eprom/eeprom + */ + +#define CYCLE_DELAY 5 + +/* This was the original definition +#define osp_MicroDelay(microsec) \ + do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) +*/ +#define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \ + udelay((useconds));} + + +/* The following tables represent the timing diagrams found in + * the Data Sheet for the Xicor X25020 EEProm. The #defines below + * represent the bits in the NICStAR's General Purpose register + * that must be toggled for the corresponding actions on the EEProm + * to occur. + */ + +/* Write Data To EEProm from SI line on rising edge of CLK */ +/* Read Data From EEProm on falling edge of CLK */ + +#define CS_HIGH 0x0002 /* Chip select high */ +#define CS_LOW 0x0000 /* Chip select low (active low)*/ +#define CLK_HIGH 0x0004 /* Clock high */ +#define CLK_LOW 0x0000 /* Clock low */ +#define SI_HIGH 0x0001 /* Serial input data high */ +#define SI_LOW 0x0000 /* Serial input data low */ + +/* Read Status Register = 0000 0101b */ +static u_int32_t rdsrtab[] = +{ + CS_HIGH | CLK_HIGH, + CS_LOW | CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH, /* 1 */ + CLK_LOW | SI_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH /* 1 */ +}; + + +/* Read from EEPROM = 0000 0011b */ +static u_int32_t readtab[] = +{ + /* + CS_HIGH | CLK_HIGH, + */ + CS_LOW | CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH, /* 1 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH /* 1 */ +}; + + +/* Clock to read from/write to the eeprom */ +static u_int32_t clocktab[] = +{ + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW +}; + + +#define NICSTAR_REG_WRITE(bs, reg, val) \ + while ( readl(bs + STAT) & 0x0200 ) ; \ + writel((val),(base)+(reg)) +#define NICSTAR_REG_READ(bs, reg) \ + readl((base)+(reg)) +#define NICSTAR_REG_GENERAL_PURPOSE GP + +/* + * This routine will clock the Read_Status_reg function into the X2520 + * eeprom, then pull the result from bit 16 of the NicSTaR's General Purpose + * register. + */ + +u_int32_t +nicstar_read_eprom_status( virt_addr_t base ) +{ + u_int32_t val; + u_int32_t rbyte; + int32_t i, j; + + /* Send read instruction */ + val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0; + + for (i=0; i=0; i--) + { + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++]) ); + rbyte |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE) + & 0x00010000) >> 16) << i); + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++]) ); + osp_MicroDelay( CYCLE_DELAY ); + } + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 ); + osp_MicroDelay( CYCLE_DELAY ); + return rbyte; +} + + +/* + * This routine will clock the Read_data function into the X2520 + * eeprom, followed by the address to read from, through the NicSTaR's General + * Purpose register. + */ + +static u_int8_t +read_eprom_byte(u_int32_t base, u_int8_t offset) +{ + u_int32_t val = 0; + int i,j=0; + u_int8_t tempread = 0; + + val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0; + + /* Send READ instruction */ + for (i=0; i=0; i--) + { + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++] | ((offset >> i) & 1) ) ); + osp_MicroDelay(CYCLE_DELAY); + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++] | ((offset >> i) & 1) ) ); + osp_MicroDelay( CYCLE_DELAY ); + } + + j = 0; + + /* Now, we can read data from the eeprom by clocking it in */ + for (i=7; i>=0; i--) + { + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++]) ); + osp_MicroDelay( CYCLE_DELAY ); + tempread |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) + & 0x00010000) >> 16) << i); + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, + (val | clocktab[j++]) ); + osp_MicroDelay( CYCLE_DELAY ); + } + + NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 ); + osp_MicroDelay( CYCLE_DELAY ); + return tempread; +} + + +void +nicstar_init_eprom( virt_addr_t base ) +{ + u_int32_t val; + + /* + * turn chip select off + */ + val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; + + NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, + (val | CS_HIGH | CLK_HIGH)); + osp_MicroDelay( CYCLE_DELAY ); + + NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, + (val | CS_HIGH | CLK_LOW)); + osp_MicroDelay( CYCLE_DELAY ); + + NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, + (val | CS_HIGH | CLK_HIGH)); + osp_MicroDelay( CYCLE_DELAY ); + + NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, + (val | CS_HIGH | CLK_LOW)); + osp_MicroDelay( CYCLE_DELAY ); +} + + +/* + * This routine will be the interface to the ReadPromByte function + * above. + */ + +void +nicstar_read_eprom( + virt_addr_t base, + u_int8_t prom_offset, + u_int8_t *buffer, + u_int32_t nbytes ) +{ + u_int i; + + for (i=0; i, Aug. 6, 1997 $Revision: 1.1 $ $Date: 1999/08/20 11:00:11 $ + * + * Linux driver for the IDT77201 NICStAR PCI ATM controller. + * PHY component is expected to be 155 Mbps S/UNI-Lite or IDT 77155; + * see init_nicstar() for PHY initialization to change this. This driver + * expects the Linux ATM stack to support scatter-gather lists + * (skb->atm.iovcnt != 0) for Rx skb's passed to vcc->push. + * + * Implementing minimal-copy of received data: + * IDT always receives data into a small buffer, then large buffers + * as needed. This means that data must always be copied to create + * the linear buffer needed by most non-ATM protocol stacks (e.g. IP) + * Fix is simple: make large buffers large enough to hold entire + * SDU, and leave bytes empty at the start. Then + * copy small buffer contents to head of large buffer. + * Trick is to avoid fragmenting Linux, due to need for a lot of large + * buffers. This is done by 2 things: + * 1) skb->destructor / skb->atm.recycle_buffer + * combined, allow nicstar_free_rx_skb to be called to + * recycle large data buffers + * 2) skb_clone of received buffers + * See nicstar_free_rx_skb and linearize_buffer for implementation + * details. + * + * + * + * Copyright (c) 1996 University of Cambridge Computer Laboratory + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * M. Welsh, 6 July 1996 + * + * + */ diff -u --recursive --new-file v2.3.14/linux/drivers/atm/nicstarmac.h linux/drivers/atm/nicstarmac.h --- v2.3.14/linux/drivers/atm/nicstarmac.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/nicstarmac.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,14 @@ +/****************************************************************************** + * + * nicstarmac.h + * + * Header file for nicstarmac.c + * + ******************************************************************************/ + + +typedef unsigned int virt_addr_t; + +u_int32_t nicstar_read_eprom_status( virt_addr_t base ); +void nicstar_init_eprom( virt_addr_t base ); +void nicstar_read_eprom( virt_addr_t, u_int8_t, u_int8_t *, u_int32_t); diff -u --recursive --new-file v2.3.14/linux/drivers/atm/suni.c linux/drivers/atm/suni.c --- v2.3.14/linux/drivers/atm/suni.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/suni.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,302 @@ +/* drivers/atm/suni.c - PMC SUNI (PHY) driver */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "suni.h" + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +struct suni_priv { + struct sonet_stats sonet_stats; /* link diagnostics */ + unsigned char loop_mode; /* loopback mode */ + struct atm_dev *dev; /* device back-pointer */ + struct suni_priv *next; /* next SUNI */ +}; + + +#define PRIV(dev) ((struct suni_priv *) dev->phy_data) + +#define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg) +#define GET(reg) dev->ops->phy_get(dev,SUNI_##reg) +#define REG_CHANGE(mask,shift,value,reg) \ + PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg) + + +static struct timer_list poll_timer = { NULL, NULL, 0L, 0L, NULL }; +static int start_timer = 1; +static struct suni_priv *sunis = NULL; + + +static void suni_hz(unsigned long dummy) +{ + struct suni_priv *walk; + struct atm_dev *dev; + struct sonet_stats *stats; + + for (walk = sunis; walk; walk = walk->next) { + dev = walk->dev; + stats = &walk->sonet_stats; + PUT(0,MRI); /* latch counters */ + udelay(1); + stats->section_bip += (GET(RSOP_SBL) & 0xff) | + ((GET(RSOP_SBM) & 0xff) << 8); + if (stats->section_bip < 0) stats->section_bip = LONG_MAX; + stats->line_bip += (GET(RLOP_LBL) & 0xff) | + ((GET(RLOP_LB) & 0xff) << 8) | + ((GET(RLOP_LBM) & 0xf) << 16); + if (stats->line_bip < 0) stats->line_bip = LONG_MAX; + stats->path_bip += (GET(RPOP_PBL) & 0xff) | + ((GET(RPOP_PBM) & 0xff) << 8); + if (stats->path_bip < 0) stats->path_bip = LONG_MAX; + stats->line_febe += (GET(RLOP_LFL) & 0xff) | + ((GET(RLOP_LF) & 0xff) << 8) | + ((GET(RLOP_LFM) & 0xf) << 16); + if (stats->line_febe < 0) stats->line_febe = LONG_MAX; + stats->path_febe += (GET(RPOP_PFL) & 0xff) | + ((GET(RPOP_PFM) & 0xff) << 8); + if (stats->path_febe < 0) stats->path_febe = LONG_MAX; + stats->corr_hcs += GET(RACP_CHEC) & 0xff; + if (stats->corr_hcs < 0) stats->corr_hcs = LONG_MAX; + stats->uncorr_hcs += GET(RACP_UHEC) & 0xff; + if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX; + stats->rx_cells += (GET(RACP_RCCL) & 0xff) | + ((GET(RACP_RCC) & 0xff) << 8) | + ((GET(RACP_RCCM) & 7) << 16); + if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX; + stats->tx_cells += (GET(TACP_TCCL) & 0xff) | + ((GET(TACP_TCC) & 0xff) << 8) | + ((GET(TACP_TCCM) & 7) << 16); + if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX; + } + if (!start_timer) { + del_timer(&poll_timer); + poll_timer.expires = jiffies+HZ; + add_timer(&poll_timer); + } +} + + +static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) +{ + unsigned long flags; + int error; + + error = 0; + save_flags(flags); + cli(); + if (arg) + error = copy_to_user(arg,&PRIV(dev)->sonet_stats, + sizeof(struct sonet_stats)); + if (zero && !error) + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + restore_flags(flags); + return error ? -EFAULT : 0; +} + + +#define HANDLE_FLAG(flag,reg,bit) \ + if (todo & flag) { \ + if (set) PUT(GET(reg) | bit,reg); \ + else PUT(GET(reg) & ~bit,reg); \ + todo &= ~flag; \ + } + + +static int change_diag(struct atm_dev *dev,void *arg,int set) +{ + int todo; + + if (get_user(todo,(int *) arg)) return -EFAULT; + HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8); + HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP); + HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3); + HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF); + HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS); + HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS); + HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS); + HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS); + return put_user(todo,(int *) arg) ? -EFAULT : 0; +} + + +#undef HANDLE_FLAG + + +static int get_diag(struct atm_dev *dev,void *arg) +{ + int set; + + set = 0; + if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP; + if (GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP; + if (GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP; + /* SONET_INS_FRAME is one-shot only */ + if (GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS; + if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS; + if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS; + if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS; + return put_user(set,(int *) arg) ? -EFAULT : 0; +} + + +static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + switch (cmd) { + case SONET_GETSTATZ: + case SONET_GETSTAT: + return fetch_stats(dev,(struct sonet_stats *) arg, + cmd == SONET_GETSTATZ); + case SONET_SETDIAG: + return change_diag(dev,arg,1); + case SONET_CLRDIAG: + return change_diag(dev,arg,0); + case SONET_GETDIAG: + return get_diag(dev,arg); + case SONET_SETFRAMING: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (arg != SONET_FRAME_SONET) return -EINVAL; + return 0; + case SONET_GETFRAMING: + return put_user(SONET_FRAME_SONET,(int *) arg) ? + -EFAULT : 0; + case SONET_GETFRSENSE: + return -EINVAL; + case SUNI_SETLOOP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if ((int) arg < 0 || (int) arg > SUNI_LM_LOOP) + return -EINVAL; + PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) | + ((int) arg == SUNI_LM_DIAG ? SUNI_MCT_DLE : 0) | + ((int) arg == SUNI_LM_LOOP ? SUNI_MCT_LLE : 0),MCT); + PRIV(dev)->loop_mode = (int) arg; + return 0; + case SUNI_GETLOOP: + return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + -EFAULT : 0; + default: + return -EINVAL; + } +} + + +static void poll_los(struct atm_dev *dev) +{ + dev->signal = GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? ATM_PHY_SIG_LOST : + ATM_PHY_SIG_FOUND; +} + + +static void suni_int(struct atm_dev *dev) +{ + poll_los(dev); + printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number, + dev->signal == ATM_PHY_SIG_LOST ? "lost" : "detected again"); +} + + +static int suni_start(struct atm_dev *dev) +{ + unsigned long flags; + + if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) + return -ENOMEM; + PRIV(dev)->dev = dev; + save_flags(flags); + cli(); + PRIV(dev)->next = sunis; + sunis = PRIV(dev); + restore_flags(flags); + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE); + /* interrupt on loss of signal */ + poll_los(dev); /* ... and clear SUNI interrupts */ + if (dev->signal == ATM_PHY_SIG_LOST) + printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type, + dev->number); + PRIV(dev)->loop_mode = SUNI_LM_NONE; + suni_hz(0); /* clear SUNI counters */ + (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ + cli(); + if (!start_timer) restore_flags(flags); + else { + start_timer = 0; + restore_flags(flags); + /*init_timer(&poll_timer);*/ + poll_timer.expires = jiffies+HZ; + poll_timer.function = suni_hz; +#if 0 +printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev, + (unsigned long) poll_timer.next); +#endif + add_timer(&poll_timer); + } + return 0; +} + + +static const struct atmphy_ops suni_ops = { + suni_start, + suni_ioctl, + suni_int +}; + + +__initfunc(int suni_init(struct atm_dev *dev)) +{ + unsigned char mri; + + mri = GET(MRI); /* reset SUNI */ + PUT(mri | SUNI_MRI_RESET,MRI); + PUT(mri,MRI); + PUT(0,MT); /* disable all tests */ + REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET, + TPOP_APM); /* use SONET */ + REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP, + TACP_IUCHP); /* idle cells */ + PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP); + dev->phy = &suni_ops; + return 0; +} + + +#ifdef MODULE + +EXPORT_SYMBOL(suni_init); + + +int init_module(void) +{ + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* Nay */ +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/suni.h linux/drivers/atm/suni.h --- v2.3.14/linux/drivers/atm/suni.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/suni.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,210 @@ +/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ + +/* Written 1995,1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef DRIVER_ATM_SUNI_H +#define DRIVER_ATM_SUNI_H + +#include +#include + + +/* SUNI registers */ + +#define SUNI_MRI 0x00 /* Master Reset and Identity / Load + Meter */ +#define SUNI_MC 0x01 /* Master Configuration */ +#define SUNI_MIS 0x02 /* Master Interrupt Status */ + /* no 0x03 */ +#define SUNI_MCM 0x04 /* Master Clock Monitor */ +#define SUNI_MCT 0x05 /* Master Control */ +#define SUNI_CSCS 0x06 /* Clock Synthesis Control and Status */ +#define SUNI_CRCS 0x07 /* Clock Recovery Control and Status */ + /* 0x08-0x0F reserved */ +#define SUNI_RSOP_CIE 0x10 /* RSOP Control/Interrupt Enable */ +#define SUNI_RSOP_SIS 0x11 /* RSOP Status/Interrupt Status */ +#define SUNI_RSOP_SBL 0x12 /* RSOP Section BIP-8 LSB */ +#define SUNI_RSOP_SBM 0x13 /* RSOP Section BIP-8 MSB */ +#define SUNI_TSOP_CTRL 0x14 /* TSOP Control */ +#define SUNI_TSOP_DIAG 0x15 /* TSOP Diagnostic */ + /* 0x16-0x17 reserved */ +#define SUNI_RLOP_CS 0x18 /* RLOP Control/Status */ +#define SUNI_RLOP_IES 0x19 /* RLOP Interrupt Enable/Status */ +#define SUNI_RLOP_LBL 0x1A /* RLOP Line BIP-8/24 LSB */ +#define SUNI_RLOP_LB 0x1B /* RLOP Line BIP-8/24 */ +#define SUNI_RLOP_LBM 0x1C /* RLOP Line BIP-8/24 MSB */ +#define SUNI_RLOP_LFL 0x1D /* RLOP Line FEBE LSB */ +#define SUNI_RLOP_LF 0x1E /* RLOP Line FEBE */ +#define SUNI_RLOP_LFM 0x1F /* RLOP Line FEBE MSB */ +#define SUNI_TLOP_CTRL 0x20 /* TLOP Control */ +#define SUNI_TLOP_DIAG 0x21 /* TLOP Diagnostic */ + /* 0x22-0x2F reserved */ +#define SUNI_RPOP_SC 0x30 /* RPOP Status/Control */ +#define SUNI_RPOP_IS 0x31 /* RPOP Interrupt Status */ + /* 0x32 reserved */ +#define SUNI_RPOP_IE 0x33 /* RPOP Interrupt Enable */ + /* 0x34-0x36 reserved */ +#define SUNI_RPOP_PSL 0x37 /* RPOP Path Signal Label */ +#define SUNI_RPOP_PBL 0x38 /* RPOP Path BIP-8 LSB */ +#define SUNI_RPOP_PBM 0x39 /* RPOP Path BIP-8 MSB */ +#define SUNI_RPOP_PFL 0x3A /* RPOP Path FEBE LSB */ +#define SUNI_RPOP_PFM 0x3B /* RPOP Path FEBE MSB */ + /* 0x3C reserved */ +#define SUNI_RPOP_PBC 0x3D /* RPOP Path BIP-8 Configuration */ + /* 0x3E-0x3F reserved */ +#define SUNI_TPOP_CD 0x40 /* TPOP Control/Diagnostic */ +#define SUNI_TPOP_PC 0x41 /* TPOP Pointer Control */ + /* 0x42-0x44 reserved */ +#define SUNI_TPOP_APL 0x45 /* TPOP Arbitrary Pointer LSB */ +#define SUNI_TPOP_APM 0x46 /* TPOP Arbitrary Pointer MSB */ + /* 0x47 reserved */ +#define SUNI_TPOP_PSL 0x48 /* TPOP Path Signal Label */ +#define SUNI_TPOP_PS 0x49 /* TPOP Path Status */ + /* 0x4A-0x4F reserved */ +#define SUNI_RACP_CS 0x50 /* RACP Control/Status */ +#define SUNI_RACP_IES 0x51 /* RACP Interrupt Enable/Status */ +#define SUNI_RACP_MHP 0x52 /* RACP Match Header Pattern */ +#define SUNI_RACP_MHM 0x53 /* RACP Match Header Mask */ +#define SUNI_RACP_CHEC 0x54 /* RACP Correctable HCS Error Count */ +#define SUNI_RACP_UHEC 0x55 /* RACP Uncorrectable HCS Err Count */ +#define SUNI_RACP_RCCL 0x56 /* RACP Receive Cell Counter LSB */ +#define SUNI_RACP_RCC 0x57 /* RACP Receive Cell Counter */ +#define SUNI_RACP_RCCM 0x58 /* RACP Receive Cell Counter MSB */ +#define SUNI_RACP_CFG 0x59 /* RACP Configuration */ + /* 0x5A-0x5F reserved */ +#define SUNI_TACP_CS 0x60 /* TACP Control/Status */ +#define SUNI_TACP_IUCHP 0x61 /* TACP Idle/Unassigned Cell Hdr Pat */ +#define SUNI_TACP_IUCPOP 0x62 /* TACP Idle/Unassigned Cell Payload + Octet Pattern */ +#define SUNI_TACP_FIFO 0x63 /* TACP FIFO Configuration */ +#define SUNI_TACP_TCCL 0x64 /* TACP Transmit Cell Counter LSB */ +#define SUNI_TACP_TCC 0x65 /* TACP Transmit Cell Counter */ +#define SUNI_TACP_TCCM 0x66 /* TACP Transmit Cell Counter MSB */ +#define SUNI_TACP_CFG 0x67 /* TACP Configuration */ + /* 0x68-0x7F reserved */ +#define SUNI_MT 0x80 /* Master Test */ + /* 0x81-0xFF reserved */ + +/* SUNI register values */ + + +/* MRI is reg 0 */ +#define SUNI_MRI_ID 0x0f /* R, SUNI revision number */ +#define SUNI_MRI_ID_SHIFT 0 +#define SUNI_MRI_TYPE 0x70 /* R, SUNI type (lite is 011) */ +#define SUNI_MRI_TYPE_SHIFT 4 +#define SUNI_MRI_RESET 0x80 /* RW, reset & power down chip + 0: normal operation + 1: reset & low power */ +/* MCT is reg 5 */ +#define SUNI_MCT_LOOPT 0x01 /* RW, timing source, 0: from + TRCLK+/- */ +#define SUNI_MCT_DLE 0x02 /* RW, diagnostic loopback */ +#define SUNI_MCT_LLE 0x04 /* RW, line loopback */ +#define SUNI_MCT_FIXPTR 0x20 /* RW, disable transmit payload pointer + adjustments + 0: payload ptr controlled by TPOP + ptr control reg + 1: payload pointer fixed at 522 */ +#define SUNI_MCT_LCDV 0x40 /* R, loss of cell delineation */ +#define SUNI_MCT_LCDE 0x80 /* RW, loss of cell delineation + interrupt (1: on) */ +/* RSOP_CIE is reg 0x10 */ +#define SUNI_RSOP_CIE_OOFE 0x01 /* RW, enable interrupt on frame alarm + state change */ +#define SUNI_RSOP_CIE_LOFE 0x02 /* RW, enable interrupt on loss of + frame state change */ +#define SUNI_RSOP_CIE_LOSE 0x04 /* RW, enable interrupt on loss of + signal state change */ +#define SUNI_RSOP_CIE_BIPEE 0x08 /* RW, enable interrupt on section + BIP-8 error (B1) */ +#define SUNI_RSOP_CIE_FOOF 0x20 /* W, force RSOP out of frame at next + boundary */ +#define SUNI_RSOP_CIE_DDS 0x40 /* RW, disable scrambling */ + +/* RSOP_SIS is reg 0x11 */ +#define SUNI_RSOP_SIS_OOFV 0x01 /* R, out of frame */ +#define SUNI_RSOP_SIS_LOFV 0x02 /* R, loss of frame */ +#define SUNI_RSOP_SIS_LOSV 0x04 /* R, loss of signal */ +#define SUNI_RSOP_SIS_OOFI 0x08 /* R, out of frame interrupt */ +#define SUNI_RSOP_SIS_LOFI 0x10 /* R, loss of frame interrupt */ +#define SUNI_RSOP_SIS_LOSI 0x20 /* R, loss of signal interrupt */ +#define SUNI_RSOP_SIS_BIPEI 0x40 /* R, section BIP-8 interrupt */ + +/* TSOP_CTRL is reg 0x14 */ +#define SUNI_TSOP_CTRL_LAIS 0x01 /* insert alarm indication signal */ +#define SUNI_TSOP_CTRL_DS 0x40 /* disable scrambling */ + +/* TSOP_DIAG is reg 0x15 */ +#define SUNI_TSOP_DIAG_DFP 0x01 /* insert single bit error cont. */ +#define SUNI_TSOP_DIAG_DBIP8 0x02 /* insert section BIP err (cont) */ +#define SUNI_TSOP_DIAG_DLOS 0x04 /* set line to zero (loss of signal) */ + +/* TLOP_DIAG is reg 0x21 */ +#define SUNI_TLOP_DIAG_DBIP 0x01 /* insert line BIP err (continuously) */ + +/* TPOP_DIAG is reg 0x40 */ +#define SUNI_TPOP_DIAG_PAIS 0x01 /* insert STS path alarm ind (cont) */ +#define SUNI_TPOP_DIAG_DB3 0x02 /* insert path BIP err (continuously) */ + +/* TPOP_APM is reg 0x46 */ +#define SUNI_TPOP_APM_APTR 0x03 /* RW, arbitrary pointer, upper 2 + bits */ +#define SUNI_TPOP_APM_APTR_SHIFT 0 +#define SUNI_TPOP_APM_S 0x0c /* RW, "unused" bits of payload + pointer */ +#define SUNI_TPOP_APM_S_SHIFT 2 +#define SUNI_TPOP_APM_NDF 0xf0 /* RW, NDF bits */ +#define SUNI_TPOP_APM_NDF_SHIFT 4 + +#define SUNI_TPOP_S_SONET 0 /* set S bits to 00 */ +#define SUNI_TPOP_S_SDH 2 /* set S bits to 10 */ + +/* RACP_IES is reg 0x51 */ +#define SUNI_RACP_IES_FOVRI 0x02 /* R, FIFO overrun */ +#define SUNI_RACP_IES_UHCSI 0x04 /* R, uncorrectable HCS error */ +#define SUNI_RACP_IES_CHCSI 0x08 /* R, correctable HCS error */ +#define SUNI_RACP_IES_OOCDI 0x10 /* R, change of cell delineation + state */ +#define SUNI_RACP_IES_FIFOE 0x20 /* RW, enable FIFO overrun interrupt */ +#define SUNI_RACP_IES_HCSE 0x40 /* RW, enable HCS error interrupt */ +#define SUNI_RACP_IES_OOCDE 0x80 /* RW, enable cell delineation state + change interrupt */ + +/* TACP_CS is reg 0x60 */ +#define SUNI_TACP_CS_FIFORST 0x01 /* RW, reset transmit FIFO (sticky) */ +#define SUNI_TACP_CS_DSCR 0x02 /* RW, disable payload scrambling */ +#define SUNI_TACP_CS_HCAADD 0x04 /* RW, add coset polynomial to HCS */ +#define SUNI_TACP_CS_DHCS 0x10 /* RW, insert HCS errors */ +#define SUNI_TACP_CS_FOVRI 0x20 /* R, FIFO overrun */ +#define SUNI_TACP_CS_TSOCI 0x40 /* R, TSOC input high */ +#define SUNI_TACP_CS_FIFOE 0x80 /* RW, enable FIFO overrun interrupt */ + +/* TACP_IUCHP is reg 0x61 */ +#define SUNI_TACP_IUCHP_CLP 0x01 /* RW, 8th bit of 4th octet of i/u + pattern */ +#define SUNI_TACP_IUCHP_PTI 0x0e /* RW, 5th-7th bits of 4th octet of i/u + pattern */ +#define SUNI_TACP_IUCHP_PTI_SHIFT 1 +#define SUNI_TACP_IUCHP_GFC 0xf0 /* RW, 1st-4th bits of 1st octet of i/u + pattern */ +#define SUNI_TACP_IUCHP_GFC_SHIFT 4 + +/* MT is reg 0x80 */ +#define SUNI_MT_HIZIO 0x01 /* RW, all but data bus & MP interface + tri-state */ +#define SUNI_MT_HIZDATA 0x02 /* W, also tri-state data bus */ +#define SUNI_MT_IOTST 0x04 /* RW, enable test mode */ +#define SUNI_MT_DBCTRL 0x08 /* W, control data bus by CSB pin */ +#define SUNI_MT_PMCTST 0x10 /* W, PMC test mode */ + + +#define SUNI_IDLE_PATTERN 0x6a /* idle pattern */ + + +#ifdef __KERNEL__ +int suni_init(struct atm_dev *dev); +#endif + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/tonga.h linux/drivers/atm/tonga.h --- v2.3.14/linux/drivers/atm/tonga.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/tonga.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,20 @@ +/* drivers/atm/tonga.h - Efficient Networks Tonga (PCI bridge) declarations */ + +/* Written 1995 by Werner Almesberger, EPFL LRC */ + + +#ifndef DRIVER_ATM_TONGA_H +#define DRIVER_ATM_TONGA_H + +#define PCI_TONGA_CTRL 0x60 /* control register */ + +#define END_SWAP_DMA 0x80 /* endian swap on DMA */ +#define END_SWAP_BYTE 0x40 /* endian swap on slave byte accesses */ +#define END_SWAP_WORD 0x20 /* endian swap on slave word accesses */ +#define SEPROM_MAGIC 0x0c /* obscure required pattern (ASIC only) */ +#define SEPROM_DATA 0x02 /* serial EEPROM data (ASIC only) */ +#define SEPROM_CLK 0x01 /* serial EEPROM clock (ASIC only) */ + +#define SEPROM_ESI_BASE 64 /* start of ESI in serial EEPROM */ + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/uPD98401.h linux/drivers/atm/uPD98401.h --- v2.3.14/linux/drivers/atm/uPD98401.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/uPD98401.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,292 @@ +/* drivers/atm/uPD98401.h - NEC uPD98401 (SAR) declarations */ + +/* Written 1995 by Werner Almesberger, EPFL LRC */ + + +#ifndef DRIVERS_ATM_uPD98401_H +#define DRIVERS_ATM_uPD98401_H + + +#define MAX_CRAM_SIZE (1 << 18) /* 2^18 words */ +#define RAM_INCREMENT 1024 /* check in 4 kB increments */ + +#define uPD98401_PORTS 0x24 /* probably more ? */ + + +/* + * Commands + */ + +#define uPD98401_OPEN_CHAN 0x20000000 /* open channel */ +#define uPD98401_CHAN_ADDR 0x0003fff8 /* channel address */ +#define uPD98401_CHAN_ADDR_SHIFT 3 +#define uPD98401_CLOSE_CHAN 0x24000000 /* close channel */ +#define uPD98401_CHAN_RT 0x02000000 /* RX/TX (0 TX, 1 RX) */ +#define uPD98401_DEACT_CHAN 0x28000000 /* deactivate channel */ +#define uPD98401_TX_READY 0x30000000 /* TX ready */ +#define uPD98401_ADD_BAT 0x34000000 /* add batches */ +#define uPD98401_POOL 0x000f0000 /* pool number */ +#define uPD98401_POOL_SHIFT 16 +#define uPD98401_POOL_NUMBAT 0x0000ffff /* number of batches */ +#define uPD98401_NOP 0x3f000000 /* NOP */ +#define uPD98401_IND_ACC 0x00000000 /* Indirect Access */ +#define uPD98401_IA_RW 0x10000000 /* Read/Write (0 W, 1 R) */ +#define uPD98401_IA_B3 0x08000000 /* Byte select, 1 enable */ +#define uPD98401_IA_B2 0x04000000 +#define uPD98401_IA_B1 0x02000000 +#define uPD98401_IA_B0 0x01000000 +#define uPD98401_IA_BALL 0x0f000000 /* whole longword */ +#define uPD98401_IA_TGT 0x000c0000 /* Target */ +#define uPD98401_IA_TGT_SHIFT 18 +#define uPD98401_IA_TGT_CM 0 /* - Control Memory */ +#define uPD98401_IA_TGT_SAR 1 /* - uPD98401 registers */ +#define uPD98401_IA_TGT_PHY 3 /* - PHY device */ +#define uPD98401_IA_ADDR 0x0003ffff + +/* + * Command Register Status + */ + +#define uPD98401_BUSY 0x80000000 /* SAR is busy */ +#define uPD98401_LOCKED 0x40000000 /* SAR is locked by other CPU */ + +/* + * Indications + */ + +/* Normal (AAL5) Receive Indication */ +#define uPD98401_AAL5_UINFO 0xffff0000 /* user-supplied information */ +#define uPD98401_AAL5_UINFO_SHIFT 16 +#define uPD98401_AAL5_SIZE 0x0000ffff /* PDU size (in _CELLS_ !!) */ +#define uPD98401_AAL5_CHAN 0x7fff0000 /* Channel number */ +#define uPD98401_AAL5_CHAN_SHIFT 16 +#define uPD98401_AAL5_ERR 0x00008000 /* Error indication */ +#define uPD98401_AAL5_CI 0x00004000 /* Congestion Indication */ +#define uPD98401_AAL5_CLP 0x00002000 /* CLP (>= 1 cell had CLP=1) */ +#define uPD98401_AAL5_ES 0x00000f00 /* Error Status */ +#define uPD98401_AAL5_ES_SHIFT 8 +#define uPD98401_AAL5_ES_NONE 0 /* No error */ +#define uPD98401_AAL5_ES_FREE 1 /* Receiver free buf underflow */ +#define uPD98401_AAL5_ES_FIFO 2 /* Receiver FIFO overrun */ +#define uPD98401_AAL5_ES_TOOBIG 3 /* Maximum length violation */ +#define uPD98401_AAL5_ES_CRC 4 /* CRC error */ +#define uPD98401_AAL5_ES_ABORT 5 /* User abort */ +#define uPD98401_AAL5_ES_LENGTH 6 /* Length violation */ +#define uPD98401_AAL5_ES_T1 7 /* T1 error (timeout) */ +#define uPD98401_AAL5_ES_DEACT 8 /* Deactivated with DEACT_CHAN */ +#define uPD98401_AAL5_POOL 0x0000001f /* Free buffer pool number */ + +/* Raw Cell Indication */ +#define uPD98401_RAW_UINFO uPD98401_AAL5_UINFO +#define uPD98401_RAW_UINFO_SHIFT uPD98401_AAL5_UINFO_SHIFT +#define uPD98401_RAW_HEC 0x000000ff /* HEC */ +#define uPD98401_RAW_CHAN uPD98401_AAL5_CHAN +#define uPD98401_RAW_CHAN_SHIFT uPD98401_AAL5_CHAN_SHIFT + +/* Transmit Indication */ +#define uPD98401_TXI_CONN 0x7fff0000 /* Connection Number */ +#define uPD98401_TXI_CONN_SHIFT 16 +#define uPD98401_TXI_ACTIVE 0x00008000 /* Channel remains active */ +#define uPD98401_TXI_PQP 0x00007fff /* Packet Queue Pointer */ + +/* + * Directly Addressable Registers + */ + +#define uPD98401_GMR 0x00 /* General Mode Register */ +#define uPD98401_GSR 0x01 /* General Status Register */ +#define uPD98401_IMR 0x02 /* Interrupt Mask Register */ +#define uPD98401_RQU 0x03 /* Receive Queue Underrun */ +#define uPD98401_RQA 0x04 /* Receive Queue Alert */ +#define uPD98401_ADDR 0x05 /* Last Burst Address */ +#define uPD98401_VER 0x06 /* Version Number */ +#define uPD98401_SWR 0x07 /* Software Reset */ +#define uPD98401_CMR 0x08 /* Command Register */ +#define uPD98401_CMR_L 0x09 /* Command Register and Lock/Unlock */ +#define uPD98401_CER 0x0a /* Command Extension Register */ +#define uPD98401_CER_L 0x0b /* Command Ext Reg and Lock/Unlock */ + +#define uPD98401_MSH(n) (0x10+(n)) /* Mailbox n Start Address High */ +#define uPD98401_MSL(n) (0x14+(n)) /* Mailbox n Start Address High */ +#define uPD98401_MBA(n) (0x18+(n)) /* Mailbox n Bottom Address */ +#define uPD98401_MTA(n) (0x1c+(n)) /* Mailbox n Tail Address */ +#define uPD98401_MWA(n) (0x20+(n)) /* Mailbox n Write Address */ + +/* GMR is at 0x00 */ +#define uPD98401_GMR_ONE 0x80000000 /* Must be set to one */ +#define uPD98401_GMR_SLM 0x40000000 /* Address mode (0 word, 1 byte) */ +#define uPD98401_GMR_CPE 0x00008000 /* Control Memory Parity Enable */ +#define uPD98401_GMR_LP 0x00004000 /* Loopback */ +#define uPD98401_GMR_WA 0x00002000 /* Early Bus Write Abort/RDY */ +#define uPD98401_GMR_RA 0x00001000 /* Early Read Abort/RDY */ +#define uPD98401_GMR_SZ 0x00000f00 /* Burst Size Enable */ +#define uPD98401_BURST16 0x00000800 /* 16-word burst */ +#define uPD98401_BURST8 0x00000400 /* 8-word burst */ +#define uPD98401_BURST4 0x00000200 /* 4-word burst */ +#define uPD98401_BURST2 0x00000100 /* 2-word burst */ +#define uPD98401_GMR_AD 0x00000080 /* Address (burst resolution) Disable */ +#define uPD98401_GMR_BO 0x00000040 /* Byte Order (0 little, 1 big) */ +#define uPD98401_GMR_PM 0x00000020 /* Bus Parity Mode (0 byte, 1 word)*/ +#define uPD98401_GMR_PC 0x00000010 /* Bus Parity Control (0even,1odd) */ +#define uPD98401_GMR_BPE 0x00000008 /* Bus Parity Enable */ +#define uPD98401_GMR_DR 0x00000004 /* Receive Drop Mode (0drop,1don't)*/ +#define uPD98401_GMR_SE 0x00000002 /* Shapers Enable */ +#define uPD98401_GMR_RE 0x00000001 /* Receiver Enable */ + +/* GSR is at 0x01, IMR is at 0x02 */ +#define uPD98401_INT_PI 0x80000000 /* PHY interrupt */ +#define uPD98401_INT_RQA 0x40000000 /* Receive Queue Alert */ +#define uPD98401_INT_RQU 0x20000000 /* Receive Queue Underrun */ +#define uPD98401_INT_RD 0x10000000 /* Receiver Deactivated */ +#define uPD98401_INT_SPE 0x08000000 /* System Parity Error */ +#define uPD98401_INT_CPE 0x04000000 /* Control Memory Parity Error */ +#define uPD98401_INT_SBE 0x02000000 /* System Bus Error */ +#define uPD98401_INT_IND 0x01000000 /* Initialization Done */ +#define uPD98401_INT_RCR 0x0000ff00 /* Raw Cell Received */ +#define uPD98401_INT_RCR_SHIFT 8 +#define uPD98401_INT_MF 0x000000f0 /* Mailbox Full */ +#define uPD98401_INT_MF_SHIFT 4 +#define uPD98401_INT_MM 0x0000000f /* Mailbox Modified */ + +/* VER is at 0x06 */ +#define uPD98401_MAJOR 0x0000ff00 /* Major revision */ +#define uPD98401_MAJOR_SHIFT 8 +#define uPD98401_MINOR 0x000000ff /* Minor revision */ + +/* + * Indirectly Addressable Registers + */ + +#define uPD98401_IM(n) (0x40000+(n)) /* Scheduler n I and M */ +#define uPD98401_X(n) (0x40010+(n)) /* Scheduler n X */ +#define uPD98401_Y(n) (0x40020+(n)) /* Scheduler n Y */ +#define uPD98401_PC(n) (0x40030+(n)) /* Scheduler n P, C, p and c */ +#define uPD98401_PS(n) (0x40040+(n)) /* Scheduler n priority and status */ + +/* IM contents */ +#define uPD98401_IM_I 0xff000000 /* I */ +#define uPD98401_IM_I_SHIFT 24 +#define uPD98401_IM_M 0x00ffffff /* M */ + +/* PC contents */ +#define uPD98401_PC_P 0xff000000 /* P */ +#define uPD98401_PC_P_SHIFT 24 +#define uPD98401_PC_C 0x00ff0000 /* C */ +#define uPD98401_PC_C_SHIFT 16 +#define uPD98401_PC_p 0x0000ff00 /* p */ +#define uPD98401_PC_p_SHIFT 8 +#define uPD98401_PC_c 0x000000ff /* c */ + +/* PS contents */ +#define uPD98401_PS_PRIO 0xf0 /* Priority level (0 high, 15 low) */ +#define uPD98401_PS_PRIO_SHIFT 4 +#define uPD98401_PS_S 0x08 /* Scan - must be 0 (internal) */ +#define uPD98401_PS_R 0x04 /* Round Robin (internal) */ +#define uPD98401_PS_A 0x02 /* Active (internal) */ +#define uPD98401_PS_E 0x01 /* Enabled */ + +#define uPD98401_TOS 0x40100 /* Top of Stack Control Memory Address */ +#define uPD98401_SMA 0x40200 /* Shapers Control Memory Start Address */ +#define uPD98401_PMA 0x40201 /* Receive Pool Control Memory Start Address */ +#define uPD98401_T1R 0x40300 /* T1 Register */ +#define uPD98401_VRR 0x40301 /* VPI/VCI Reduction Register/Recv. Shutdown */ +#define uPD98401_TSR 0x40302 /* Time-Stamp Register */ + +/* VRR is at 0x40301 */ +#define uPD98401_VRR_SDM 0x80000000 /* Shutdown Mode */ +#define uPD98401_VRR_SHIFT 0x000f0000 /* VPI/VCI Shift */ +#define uPD98401_VRR_SHIFT_SHIFT 16 +#define uPD98401_VRR_MASK 0x0000ffff /* VPI/VCI mask */ + +/* + * TX packet descriptor + */ + +#define uPD98401_TXPD_SIZE 16 /* descriptor size (in bytes) */ + +#define uPD98401_TXPD_V 0x80000000 /* Valid bit */ +#define uPD98401_TXPD_DP 0x40000000 /* Descriptor (1) or Pointer (0) */ +#define uPD98401_TXPD_SM 0x20000000 /* Single (1) or Multiple (0) */ +#define uPD98401_TXPD_CLPM 0x18000000 /* CLP mode */ +#define uPD98401_CLPM_0 0 /* 00 CLP = 0 */ +#define uPD98401_CLPM_1 3 /* 11 CLP = 1 */ +#define uPD98401_CLPM_LAST 1 /* 01 CLP unless last cell */ +#define uPD98401_TXPD_CLPM_SHIFT 27 +#define uPD98401_TXPD_PTI 0x07000000 /* PTI pattern */ +#define uPD98401_TXPD_PTI_SHIFT 24 +#define uPD98401_TXPD_GFC 0x00f00000 /* GFC pattern */ +#define uPD98401_TXPD_GFC_SHIFT 20 +#define uPD98401_TXPD_C10 0x00040000 /* insert CRC-10 */ +#define uPD98401_TXPD_AAL5 0x00020000 /* AAL5 processing */ +#define uPD98401_TXPD_MB 0x00010000 /* TX mailbox number */ +#define uPD98401_TXPD_UU 0x0000ff00 /* CPCS-UU */ +#define uPD98401_TXPD_UU_SHIFT 8 +#define uPD98401_TXPD_CPI 0x000000ff /* CPI */ + +/* + * TX buffer descriptor + */ + +#define uPD98401_TXBD_SIZE 8 /* descriptor size (in bytes) */ + +#define uPD98401_TXBD_LAST 0x80000000 /* last buffer in packet */ + +/* + * TX VC table + */ + +/* 1st word has the same structure as in a TX packet descriptor */ +#define uPD98401_TXVC_L 0x80000000 /* last buffer */ +#define uPD98401_TXVC_SHP 0x0f000000 /* shaper number */ +#define uPD98401_TXVC_SHP_SHIFT 24 +#define uPD98401_TXVC_VPI 0x00ff0000 /* VPI */ +#define uPD98401_TXVC_VPI_SHIFT 16 +#define uPD98401_TXVC_VCI 0x0000ffff /* VCI */ +#define uPD98401_TXVC_QRP 6 /* Queue Read Pointer is in word 6 */ + +/* + * RX free buffer pools descriptor + */ + +#define uPD98401_RXFP_ALERT 0x70000000 /* low water mark */ +#define uPD98401_RXFP_ALERT_SHIFT 28 +#define uPD98401_RXFP_BFSZ 0x0f000000 /* buffer size, 64*2^n */ +#define uPD98401_RXFP_BFSZ_SHIFT 24 +#define uPD98401_RXFP_BTSZ 0x00ff0000 /* batch size, n+1 */ +#define uPD98401_RXFP_BTSZ_SHIFT 16 +#define uPD98401_RXFP_REMAIN 0x0000ffff /* remaining batches in pool */ + +/* + * RX VC table + */ + +#define uPD98401_RXVC_BTSZ 0xff000000 /* remaining free buffers in batch */ +#define uPD98401_RXVC_BTSZ_SHIFT 24 +#define uPD98401_RXVC_MB 0x00200000 /* RX mailbox number */ +#define uPD98401_RXVC_POOL 0x001f0000 /* free buffer pool number */ +#define uPD98401_RXVC_POOL_SHIFT 16 +#define uPD98401_RXVC_UINFO 0x0000ffff /* user-supplied information */ +#define uPD98401_RXVC_T1 0xffff0000 /* T1 timestamp */ +#define uPD98401_RXVC_T1_SHIFT 16 +#define uPD98401_RXVC_PR 0x00008000 /* Packet Reception, 1 if busy */ +#define uPD98401_RXVC_DR 0x00004000 /* FIFO Drop */ +#define uPD98401_RXVC_OD 0x00001000 /* Drop OAM cells */ +#define uPD98401_RXVC_AR 0x00000800 /* AAL5 or raw cell; 1 if AAL5 */ +#define uPD98401_RXVC_MAXSEG 0x000007ff /* max number of segments per PDU */ +#define uPD98401_RXVC_REM 0xfffe0000 /* remaining words in curr buffer */ +#define uPD98401_RXVC_REM_SHIFT 17 +#define uPD98401_RXVC_CLP 0x00010000 /* CLP received */ +#define uPD98401_RXVC_BFA 0x00008000 /* Buffer Assigned */ +#define uPD98401_RXVC_BTA 0x00004000 /* Batch Assigned */ +#define uPD98401_RXVC_CI 0x00002000 /* Congestion Indication */ +#define uPD98401_RXVC_DD 0x00001000 /* Dropping incoming cells */ +#define uPD98401_RXVC_DP 0x00000800 /* like PR ? */ +#define uPD98401_RXVC_CURSEG 0x000007ff /* Current Segment count */ + +/* + * RX lookup table + */ + +#define uPD98401_RXLT_ENBL 0x8000 /* Enable */ + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c --- v2.3.14/linux/drivers/atm/uPD98402.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/uPD98402.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,224 @@ +/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include /* for jiffies */ +#include +#include +#include +#include +#include +#include + +#include "uPD98402.h" + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +struct uPD98402_priv { + struct sonet_stats sonet_stats; /* link diagnostics */ + unsigned char framing; /* SONET/SDH framing */ +}; + + +#define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data) + +#define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg) +#define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg) + + +static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) +{ + unsigned long flags; + int error; + + error = 0; + save_flags(flags); + cli(); + PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); + if (arg) + error = copy_to_user(arg,&PRIV(dev)->sonet_stats, + sizeof(struct sonet_stats)); + if (zero && !error) { + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + PRIV(dev)->sonet_stats.corr_hcs = -1; + PRIV(dev)->sonet_stats.tx_cells = -1; + PRIV(dev)->sonet_stats.rx_cells = -1; + } + restore_flags(flags); + return error ? -EFAULT : 0; +} + + +static int set_framing(struct atm_dev *dev,unsigned char framing) +{ + static const unsigned char sonet[] = { 1,2,3,0 }; + static const unsigned char sdh[] = { 1,0,0,2 }; + const char *set; + unsigned long flags; + + switch (framing) { + case SONET_FRAME_SONET: + set = sonet; + break; + case SONET_FRAME_SDH: + set = sdh; + break; + default: + return -EINVAL; + } + save_flags(flags); + cli(); + PUT(set[0],C11T); + PUT(set[1],C12T); + PUT(set[2],C13T); + PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] << + uPD98402_MDR_SS_SHIFT),MDR); + restore_flags(flags); + return 0; +} + + +static int get_sense(struct atm_dev *dev,u8 *arg) +{ + unsigned long flags; + int error; + + save_flags(flags); + cli(); + error = put_user(GET(C11R),arg) || put_user(GET(C12R),arg+1) || + put_user(GET(C13R),arg+2); + restore_flags(flags); + error = error || put_user(0xff,arg+3) || put_user(0xff,arg+4) || + put_user(0xff,arg+5); + return error ? -EFAULT : 0; +} + + +static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + switch (cmd) { + + case SONET_GETSTATZ: + case SONET_GETSTAT: + return fetch_stats(dev,(struct sonet_stats *) arg, + cmd == SONET_GETSTATZ); + case SONET_SETFRAMING: + return set_framing(dev,(int) arg); + case SONET_GETFRAMING: + return put_user(PRIV(dev)->framing,(int *) arg) ? + -EFAULT : 0; + case SONET_GETFRSENSE: + return get_sense(dev,arg); + default: + return -EINVAL; + } +} + + +static void stat_event(struct atm_dev *dev) +{ + unsigned char events; + + events = GET(PCR); + if (events & uPD98402_PFM_PFEB) + if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0) + PRIV(dev)->sonet_stats.path_febe = LONG_MAX; + if (events & uPD98402_PFM_LFEB) + if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0) + PRIV(dev)->sonet_stats.line_febe = LONG_MAX; + if (events & uPD98402_PFM_B3E) + if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0) + PRIV(dev)->sonet_stats.path_bip = LONG_MAX; + if (events & uPD98402_PFM_B2E) + if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0) + PRIV(dev)->sonet_stats.line_bip = LONG_MAX; + if (events & uPD98402_PFM_B1E) + if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0) + PRIV(dev)->sonet_stats.section_bip = LONG_MAX; +} + + +static void uPD98402_int(struct atm_dev *dev) +{ + static unsigned long silence = 0; + unsigned char reason; + + while ((reason = GET(PICR))) { + if (reason & uPD98402_INT_LOS) + printk(KERN_NOTICE "%s(itf %d): signal lost\n", + dev->type,dev->number); + if (reason & uPD98402_INT_PFM) stat_event(dev); + if (reason & uPD98402_INT_PCO) { + (void) GET(PCOCR); /* clear interrupt cause */ + PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); + } + if ((reason & uPD98402_INT_RFO) && + (time_after(jiffies, silence) || silence == 0)) { + printk(KERN_WARNING "%s(itf %d): uPD98402 receive " + "FIFO overflow\n",dev->type,dev->number); + silence = (jiffies+HZ/2)|1; + } + } +} + + +static int uPD98402_start(struct atm_dev *dev) +{ +DPRINTK("phy_start\n"); + if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) + return -ENOMEM; + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + (void) GET(PCR); /* clear performance events */ + PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */ + (void) GET(PCOCR); /* clear overflows */ + PUT(~uPD98402_PCO_HECC,PCOMR); + (void) GET(PICR); /* clear interrupts */ + PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO | + uPD98402_INT_LOS),PIMR); /* enable them */ + (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ + return 0; +} + + + +static const struct atmphy_ops uPD98402_ops = { + uPD98402_start, + uPD98402_ioctl, /* no ioctl yet */ + uPD98402_int +}; + + +__initfunc(int uPD98402_init(struct atm_dev *dev)) +{ +DPRINTK("phy_init\n"); + dev->phy = &uPD98402_ops; + return 0; +} + + +#ifdef MODULE + +EXPORT_SYMBOL(uPD98402_init); + + +int init_module(void) +{ + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* Nay */ +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/uPD98402.h linux/drivers/atm/uPD98402.h --- v2.3.14/linux/drivers/atm/uPD98402.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/uPD98402.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,106 @@ +/* drivers/atm/uPD98402.h - NEC uPD98402 (PHY) declarations */ + +/* Written 1995 by Werner Almesberger, EPFL LRC */ + + +#ifndef DRIVERS_ATM_uPD98402_H +#define DRIVERS_ATM_uPD98402_H + +/* + * Registers + */ + +#define uPD98402_CMR 0x00 /* Command Register */ +#define uPD98402_MDR 0x01 /* Mode Register */ +#define uPD98402_PICR 0x02 /* PHY Interrupt Cause Register */ +#define uPD98402_PIMR 0x03 /* PHY Interrupt Mask Register */ +#define uPD98402_ACR 0x04 /* Alarm Cause Register */ +#define uPD98402_ACMR 0x05 /* Alarm Cause Mask Register */ +#define uPD98402_PCR 0x06 /* Performance Cause Register */ +#define uPD98402_PCMR 0x07 /* Performance Cause Mask Register */ +#define uPD98402_IACM 0x08 /* Internal Alarm Cause Mask Register */ +#define uPD98402_B1ECT 0x09 /* B1 Error Count Register */ +#define uPD98402_B2ECT 0x0a /* B2 Error Count Register */ +#define uPD98402_B3ECT 0x0b /* B3 Error Count Regster */ +#define uPD98402_PFECB 0x0c /* Path FEBE Count Register */ +#define uPD98402_LECCT 0x0d /* Line FEBE Count Register */ +#define uPD98402_HECCT 0x0e /* HEC Error Count Register */ +#define uPD98402_FJCT 0x0f /* Frequence Justification Count Reg */ +#define uPD98402_PCOCR 0x10 /* Perf. Counter Overflow Cause Reg */ +#define uPD98402_PCOMR 0x11 /* Perf. Counter Overflow Mask Reg */ +#define uPD98402_C11T 0x20 /* C11T Data Register */ +#define uPD98402_C12T 0x21 /* C12T Data Register */ +#define uPD98402_C13T 0x22 /* C13T Data Register */ +#define uPD98402_F1T 0x23 /* F1T Data Register */ +#define uPD98402_K2T 0x25 /* K2T Data Register */ +#define uPD98402_C2T 0x26 /* C2T Data Register */ +#define uPD98402_F2T 0x27 /* F2T Data Register */ +#define uPD98402_C11R 0x30 /* C11T Data Register */ +#define uPD98402_C12R 0x31 /* C12T Data Register */ +#define uPD98402_C13R 0x32 /* C13T Data Register */ +#define uPD98402_F1R 0x33 /* F1T Data Register */ +#define uPD98402_K2R 0x35 /* K2T Data Register */ +#define uPD98402_C2R 0x36 /* C2T Data Register */ +#define uPD98402_F2R 0x37 /* F2T Data Register */ + +/* CMR is at 0x00 */ +#define uPD98402_CMR_PFRF 0x01 /* Send path FERF */ +#define uPD98402_CMR_LFRF 0x02 /* Send line FERF */ +#define uPD98402_CMR_PAIS 0x04 /* Send path AIS */ +#define uPD98402_CMR_LAIS 0x08 /* Send line AIS */ + +/* MDR is at 0x01 */ +#define uPD98402_MDR_ALP 0x01 /* ATM layer loopback */ +#define uPD98402_MDR_TPLP 0x02 /* PMD loopback, to host */ +#define uPD98402_MDR_RPLP 0x04 /* PMD loopback, to network */ +#define uPD98402_MDR_SS0 0x08 /* SS0 */ +#define uPD98402_MDR_SS1 0x10 /* SS1 */ +#define uPD98402_MDR_SS_MASK 0x18 /* mask */ +#define uPD98402_MDR_SS_SHIFT 3 /* shift */ +#define uPD98402_MDR_HEC 0x20 /* disable HEC inbound processing */ +#define uPD98402_MDR_FSR 0x40 /* disable frame scrambler */ +#define uPD98402_MDR_CSR 0x80 /* disable cell scrambler */ + +/* PICR is at 0x02, PIMR is at 0x03 */ +#define uPD98402_INT_PFM 0x01 /* performance counter has changed */ +#define uPD98402_INT_ALM 0x02 /* line fault */ +#define uPD98402_INT_RFO 0x04 /* receive FIFO overflow */ +#define uPD98402_INT_PCO 0x08 /* performance counter overflow */ +#define uPD98402_INT_OTD 0x20 /* OTD has occurred */ +#define uPD98402_INT_LOS 0x40 /* Loss Of Signal */ +#define uPD98402_INT_LOF 0x80 /* Loss Of Frame */ + +/* ACR is as 0x04, ACMR is at 0x05 */ +#define uPD98402_ALM_PFRF 0x01 /* path FERF */ +#define uPD98402_ALM_LFRF 0x02 /* line FERF */ +#define uPD98402_ALM_PAIS 0x04 /* path AIS */ +#define uPD98402_ALM_LAIS 0x08 /* line AIS */ +#define uPD98402_ALM_LOD 0x10 /* loss of delineation */ +#define uPD98402_ALM_LOP 0x20 /* loss of pointer */ +#define uPD98402_ALM_OOF 0x40 /* out of frame */ + +/* PCR is at 0x06, PCMR is at 0x07 */ +#define uPD98402_PFM_PFEB 0x01 /* path FEBE */ +#define uPD98402_PFM_LFEB 0x02 /* line FEBE */ +#define uPD98402_PFM_B3E 0x04 /* B3 error */ +#define uPD98402_PFM_B2E 0x08 /* B2 error */ +#define uPD98402_PFM_B1E 0x10 /* B1 error */ +#define uPD98402_PFM_FJ 0x20 /* frequency justification */ + +/* IACM is at 0x08 */ +#define uPD98402_IACM_PFRF 0x01 /* don't generate path FERF */ +#define uPD98402_IACM_LFRF 0x02 /* don't generate line FERF */ + +/* PCOCR is at 0x010, PCOMR is at 0x11 */ +#define uPD98402_PCO_B1EC 0x01 /* B1ECT overflow */ +#define uPD98402_PCO_B2EC 0x02 /* B2ECT overflow */ +#define uPD98402_PCO_B3EC 0x04 /* B3ECT overflow */ +#define uPD98402_PCO_PFBC 0x08 /* PFEBC overflow */ +#define uPD98402_PCO_LFBC 0x10 /* LFEVC overflow */ +#define uPD98402_PCO_HECC 0x20 /* HECCT overflow */ +#define uPD98402_PCO_FJC 0x40 /* FJCT overflow */ + + +int uPD98402_init(struct atm_dev *dev); + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.3.14/linux/drivers/atm/zatm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/zatm.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,1878 @@ +/* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for request_region */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uPD98401.h" +#include "uPD98402.h" +#include "zeprom.h" +#include "zatm.h" + + +/* + * TODO: + * + * Minor features + * - support 64 kB SDUs (will have to use multibuffer batches then :-( ) + * - proper use of CDV, credit = max(1,CDVT*PCR) + * - AAL0 + * - better receive timestamps + * - OAM + */ + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +#ifndef CONFIG_ATM_ZATM_DEBUG + + +#define NULLCHECK(x) + +#define EVENT(s,a,b) + + +static void event_dump(void) +{ +} + + +#else + + +/* + * NULL pointer checking + */ + +#define NULLCHECK(x) \ + if ((unsigned long) (x) < 0x30) printk(KERN_CRIT #x "==0x%x\n", (int) (x)) + +/* + * Very extensive activity logging. Greatly improves bug detection speed but + * costs a few Mbps if enabled. + */ + +#define EV 64 + +static const char *ev[EV]; +static unsigned long ev_a[EV],ev_b[EV]; +static int ec = 0; + + +static void EVENT(const char *s,unsigned long a,unsigned long b) +{ + ev[ec] = s; + ev_a[ec] = a; + ev_b[ec] = b; + ec = (ec+1) % EV; +} + + +static void event_dump(void) +{ + int n,i; + + printk(KERN_NOTICE "----- event dump follows -----\n"); + for (n = 0; n < EV; n++) { + i = (ec+n) % EV; + printk(KERN_NOTICE); + printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]); + } + printk(KERN_NOTICE "----- event dump ends here -----\n"); +} + + +#endif /* CONFIG_ATM_ZATM_DEBUG */ + + +#define RING_BUSY 1 /* indication from do_tx that PDU has to be + backlogged */ + +static struct atm_dev *zatm_boards = NULL; +static unsigned long dummy[2] = {0,0}; + + +#define zin_n(r) inl(zatm_dev->base+r*4) +#define zin(r) inl(zatm_dev->base+uPD98401_##r*4) +#define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4) +#define zwait while (zin(CMR) & uPD98401_BUSY) + +/* RX0, RX1, TX0, TX1 */ +static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 }; +static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */ + +#define MBX_SIZE(i) (mbx_entries[i]*mbx_esize[i]) + + +/*-------------------------------- utilities --------------------------------*/ + + +static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr) +{ + zwait; + zout(value,CER); + zout(uPD98401_IND_ACC | uPD98401_IA_BALL | + (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); +} + + +static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr) +{ + zwait; + zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW | + (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); + zwait; + return zin(CER); +} + + +/*------------------------------- free lists --------------------------------*/ + + +/* + * Free buffer head structure: + * [0] pointer to buffer (for SAR) + * [1] buffer descr link pointer (for SAR) + * [2] back pointer to skb (for poll_rx) + * [3] data + * ... + */ + +struct rx_buffer_head { + u32 buffer; /* pointer to buffer (for SAR) */ + u32 link; /* buffer descriptor link pointer (for SAR) */ + struct sk_buff *skb; /* back pointer to skb (for poll_rx) */ +}; + + +static void refill_pool(struct atm_dev *dev,int pool) +{ + struct zatm_dev *zatm_dev; + struct sk_buff *skb; + struct rx_buffer_head *first; + unsigned long flags; + int align,offset,free,count,size; + + EVENT("refill_pool\n",0,0); + zatm_dev = ZATM_DEV(dev); + size = (64 << (pool <= ZATM_AAL5_POOL_BASE ? 0 : + pool-ZATM_AAL5_POOL_BASE))+sizeof(struct rx_buffer_head); + if (size < PAGE_SIZE) { + align = 32; /* for 32 byte alignment */ + offset = sizeof(struct rx_buffer_head); + } + else { + align = 4096; + offset = zatm_dev->pool_info[pool].offset+ + sizeof(struct rx_buffer_head); + } + size += align; + save_flags(flags); + cli(); + free = zpeekl(zatm_dev,zatm_dev->pool_base+2*pool) & + uPD98401_RXFP_REMAIN; + restore_flags(flags); + if (free >= zatm_dev->pool_info[pool].low_water) return; + EVENT("starting ... POOL: 0x%x, 0x%x\n", + zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), + zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); + EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); + count = 0; + first = NULL; + while (free < zatm_dev->pool_info[pool].high_water) { + struct rx_buffer_head *head; + + skb = alloc_skb(size,GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING DEV_LABEL "(Itf %d): got no new " + "skb (%d) with %d free\n",dev->number,size,free); + break; + } + skb_reserve(skb,(unsigned char *) ((((unsigned long) skb->data+ + align+offset-1) & ~(unsigned long) (align-1))-offset)- + skb->data); + head = (struct rx_buffer_head *) skb->data; + skb_reserve(skb,sizeof(struct rx_buffer_head)); + if (!first) first = head; + count++; + head->buffer = virt_to_bus(skb->data); + head->link = 0; + head->skb = skb; + EVENT("enq skb 0x%08lx/0x%08lx\n",(unsigned long) skb, + (unsigned long) head); + cli(); + if (zatm_dev->last_free[pool]) + ((struct rx_buffer_head *) (zatm_dev->last_free[pool]-> + data))[-1].link = virt_to_bus(head); + zatm_dev->last_free[pool] = skb; + skb_queue_tail(&zatm_dev->pool[pool],skb); + restore_flags(flags); + free++; + } + if (first) { + cli(); + zwait; + zout(virt_to_bus(first),CER); + zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count, + CMR); + restore_flags(flags); + EVENT ("POOL: 0x%x, 0x%x\n", + zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), + zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); + EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); + } +} + + +static void drain_free(struct atm_dev *dev,int pool) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) kfree_skb(skb); +} + + +static int pool_index(int max_pdu) +{ + int i; + + if (max_pdu % ATM_CELL_PAYLOAD) + printk(KERN_ERR DEV_LABEL ": driver error in pool_index: " + "max_pdu is %d\n",max_pdu); + if (max_pdu > 65536) return -1; + for (i = 0; (64 << i) < max_pdu; i++); + return i+ZATM_AAL5_POOL_BASE; +} + + +/* use_pool isn't reentrant */ + + +static void use_pool(struct atm_dev *dev,int pool) +{ + struct zatm_dev *zatm_dev; + unsigned long flags; + int size; + + zatm_dev = ZATM_DEV(dev); + if (!(zatm_dev->pool_info[pool].ref_count++)) { + skb_queue_head_init(&zatm_dev->pool[pool]); + size = pool-ZATM_AAL5_POOL_BASE; + if (size < 0) size = 0; /* 64B... */ + else if (size > 10) size = 10; /* ... 64kB */ + save_flags(flags); + cli(); + zpokel(zatm_dev,((zatm_dev->pool_info[pool].low_water/4) << + uPD98401_RXFP_ALERT_SHIFT) | + (1 << uPD98401_RXFP_BTSZ_SHIFT) | + (size << uPD98401_RXFP_BFSZ_SHIFT), + zatm_dev->pool_base+pool*2); + zpokel(zatm_dev,(unsigned long) dummy,zatm_dev->pool_base+ + pool*2+1); + restore_flags(flags); + zatm_dev->last_free[pool] = NULL; + refill_pool(dev,pool); + } + DPRINTK("pool %d: %d\n",pool,zatm_dev->pool_info[pool].ref_count); +} + + +static void unuse_pool(struct atm_dev *dev,int pool) +{ + if (!(--ZATM_DEV(dev)->pool_info[pool].ref_count)) + drain_free(dev,pool); +} + + +static void zatm_feedback(struct atm_vcc *vcc,struct sk_buff *skb, + unsigned long start,unsigned long dest,int len) +{ + struct zatm_pool_info *pool; + unsigned long offset,flags; + + DPRINTK("start 0x%08lx dest 0x%08lx len %d\n",start,dest,len); + if (len < PAGE_SIZE) return; + pool = &ZATM_DEV(vcc->dev)->pool_info[ZATM_VCC(vcc)->pool]; + offset = (dest-start) & (PAGE_SIZE-1); + save_flags(flags); + cli(); + if (!offset || pool->offset == offset) { + pool->next_cnt = 0; + restore_flags(flags); + return; + } + if (offset != pool->next_off) { + pool->next_off = offset; + pool->next_cnt = 0; + restore_flags(flags); + return; + } + if (++pool->next_cnt >= pool->next_thres) { + pool->offset = pool->next_off; + pool->next_cnt = 0; + } + restore_flags(flags); +} + + +/*----------------------- high-precision timestamps -------------------------*/ + + +#ifdef CONFIG_ATM_ZATM_EXACT_TS + +static struct timer_list sync_timer = { NULL, NULL, 0L, 0L, NULL }; + + +/* + * Note: the exact time is not normalized, i.e. tv_usec can be > 1000000. + * This must be handled by higher layers. + */ + +static inline struct timeval exact_time(struct zatm_dev *zatm_dev,u32 ticks) +{ + struct timeval tmp; + + tmp = zatm_dev->last_time; + tmp.tv_usec += ((s64) (ticks-zatm_dev->last_clk)* + (s64) zatm_dev->factor) >> TIMER_SHIFT; + return tmp; +} + + +static void zatm_clock_sync(unsigned long dummy) +{ + struct atm_dev *atm_dev; + struct zatm_dev *zatm_dev; + + for (atm_dev = zatm_boards; atm_dev; atm_dev = zatm_dev->more) { + unsigned long flags,interval; + int diff; + struct timeval now,expected; + u32 ticks; + + zatm_dev = ZATM_DEV(atm_dev); + save_flags(flags); + cli(); + ticks = zpeekl(zatm_dev,uPD98401_TSR); + do_gettimeofday(&now); + restore_flags(flags); + expected = exact_time(zatm_dev,ticks); + diff = 1000000*(expected.tv_sec-now.tv_sec)+ + (expected.tv_usec-now.tv_usec); + zatm_dev->timer_history[zatm_dev->th_curr].real = now; + zatm_dev->timer_history[zatm_dev->th_curr].expected = expected; + zatm_dev->th_curr = (zatm_dev->th_curr+1) & + (ZATM_TIMER_HISTORY_SIZE-1); + interval = 1000000*(now.tv_sec-zatm_dev->last_real_time.tv_sec) + +(now.tv_usec-zatm_dev->last_real_time.tv_usec); + if (diff >= -ADJ_REP_THRES && diff <= ADJ_REP_THRES) + zatm_dev->timer_diffs = 0; + else +#ifndef AGGRESSIVE_DEBUGGING + if (++zatm_dev->timer_diffs >= ADJ_MSG_THRES) +#endif + { + zatm_dev->timer_diffs = 0; + printk(KERN_INFO DEV_LABEL ": TSR update after %ld us:" + " calculation differed by %d us\n",interval,diff); +#ifdef AGGRESSIVE_DEBUGGING + printk(KERN_DEBUG " %d.%08d -> %d.%08d (%lu)\n", + zatm_dev->last_real_time.tv_sec, + zatm_dev->last_real_time.tv_usec, + now.tv_sec,now.tv_usec,interval); + printk(KERN_DEBUG " %u -> %u (%d)\n", + zatm_dev->last_clk,ticks,ticks-zatm_dev->last_clk); + printk(KERN_DEBUG " factor %u\n",zatm_dev->factor); +#endif + } + if (diff < -ADJ_IGN_THRES || diff > ADJ_IGN_THRES) { + /* filter out any major changes (e.g. time zone setup and + such) */ + zatm_dev->last_time = now; + zatm_dev->factor = + (1000 << TIMER_SHIFT)/(zatm_dev->khz+1); + } + else { + zatm_dev->last_time = expected; + /* + * Is the accuracy of udelay really only about 1:300 on + * a 90 MHz Pentium ? Well, the following line avoids + * the problem, but ... + * + * What it does is simply: + * + * zatm_dev->factor = (interval << TIMER_SHIFT)/ + * (ticks-zatm_dev->last_clk); + */ +#define S(x) #x /* "stringification" ... */ +#define SX(x) S(x) + asm("movl %2,%%ebx\n\t" + "subl %3,%%ebx\n\t" + "xorl %%edx,%%edx\n\t" + "shldl $" SX(TIMER_SHIFT) ",%1,%%edx\n\t" + "shl $" SX(TIMER_SHIFT) ",%1\n\t" + "divl %%ebx\n\t" + : "=eax" (zatm_dev->factor) + : "eax" (interval-diff),"g" (ticks), + "g" (zatm_dev->last_clk) + : "ebx","edx","cc"); +#undef S +#undef SX +#ifdef AGGRESSIVE_DEBUGGING + printk(KERN_DEBUG " (%ld << %d)/(%u-%u) = %u\n", + interval,TIMER_SHIFT,ticks,zatm_dev->last_clk, + zatm_dev->factor); +#endif + } + zatm_dev->last_real_time = now; + zatm_dev->last_clk = ticks; + } + del_timer(&sync_timer); + sync_timer.expires += POLL_INTERVAL*HZ; + add_timer(&sync_timer); +} + + +__initfunc(static void zatm_clock_init(struct zatm_dev *zatm_dev)) +{ + static int start_timer = 1; + unsigned long flags; + + zatm_dev->factor = (1000 << TIMER_SHIFT)/(zatm_dev->khz+1); + zatm_dev->timer_diffs = 0; + memset(zatm_dev->timer_history,0,sizeof(zatm_dev->timer_history)); + zatm_dev->th_curr = 0; + save_flags(flags); + cli(); + do_gettimeofday(&zatm_dev->last_time); + zatm_dev->last_clk = zpeekl(zatm_dev,uPD98401_TSR); + if (start_timer) { + start_timer = 0; + sync_timer.expires = jiffies+POLL_INTERVAL*HZ; + sync_timer.function = zatm_clock_sync; + add_timer(&sync_timer); + } + restore_flags(flags); +} + + +#endif + + +/*----------------------------------- RX ------------------------------------*/ + + +#if 0 +static void exception(struct atm_vcc *vcc) +{ + static int count = 0; + struct zatm_dev *zatm_dev = ZATM_DEV(vcc->dev); + struct zatm_vcc *zatm_vcc = ZATM_VCC(vcc); + unsigned long *qrp; + int i; + + if (count++ > 2) return; + for (i = 0; i < 8; i++) + printk("TX%d: 0x%08lx\n",i, + zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+i)); + for (i = 0; i < 5; i++) + printk("SH%d: 0x%08lx\n",i, + zpeekl(zatm_dev,uPD98401_IM(zatm_vcc->shaper)+16*i)); + qrp = (unsigned long *) zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ + uPD98401_TXVC_QRP); + printk("qrp=0x%08lx\n",(unsigned long) qrp); + for (i = 0; i < 4; i++) printk("QRP[%d]: 0x%08lx",i,qrp[i]); +} +#endif + + +static const char *err_txt[] = { + "No error", + "RX buf underflow", + "RX FIFO overrun", + "Maximum len violation", + "CRC error", + "User abort", + "Length violation", + "T1 error", + "Deactivated", + "???", + "???", + "???", + "???", + "???", + "???", + "???" +}; + + +static void poll_rx(struct atm_dev *dev,int mbx) +{ + struct zatm_dev *zatm_dev; + unsigned long pos; + u32 x; + int error; + + EVENT("poll_rx\n",0,0); + zatm_dev = ZATM_DEV(dev); + pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx)); + while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { + u32 *here; + struct sk_buff *skb; + struct atm_vcc *vcc; + int cells,size,chan; + + EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x); + here = (u32 *) pos; + if (((pos += 16) & 0xffff) == zatm_dev->mbx_end[mbx]) + pos = zatm_dev->mbx_start[mbx]; + cells = here[0] & uPD98401_AAL5_SIZE; +#if 0 +printk("RX IND: 0x%x, 0x%x, 0x%x, 0x%x\n",here[0],here[1],here[2],here[3]); +{ +unsigned long *x; + printk("POOL: 0x%08x, 0x%08x\n",zpeekl(zatm_dev, + zatm_dev->pool_base), + zpeekl(zatm_dev,zatm_dev->pool_base+1)); + x = (unsigned long *) here[2]; + printk("[0..3] = 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n", + x[0],x[1],x[2],x[3]); +} +#endif + error = 0; + if (here[3] & uPD98401_AAL5_ERR) { + error = (here[3] & uPD98401_AAL5_ES) >> + uPD98401_AAL5_ES_SHIFT; + if (error == uPD98401_AAL5_ES_DEACT || + error == uPD98401_AAL5_ES_FREE) continue; + } +EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >> + uPD98401_AAL5_ES_SHIFT,error); + skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb; +#ifdef CONFIG_ATM_ZATM_EXACT_TS + skb->stamp = exact_time(zatm_dev,here[1]); +#else + skb->stamp = xtime; +#endif +#if 0 +printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3], + ((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1], + ((unsigned *) skb->data)[0]); +#endif + EVENT("skb 0x%lx, here 0x%lx\n",(unsigned long) skb, + (unsigned long) here); +#if 0 +printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); +#endif + size = error ? 0 : ntohs(((u16 *) skb->data)[cells* + ATM_CELL_PAYLOAD/sizeof(u16)-3]); + EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size); + chan = (here[3] & uPD98401_AAL5_CHAN) >> + uPD98401_AAL5_CHAN_SHIFT; + if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) { + vcc = zatm_dev->rx_map[chan]; + if (skb == zatm_dev->last_free[ZATM_VCC(vcc)->pool]) + zatm_dev->last_free[ZATM_VCC(vcc)->pool] = NULL; + skb_unlink(skb); + } + else { + printk(KERN_ERR DEV_LABEL "(itf %d): RX indication " + "for non-existing channel\n",dev->number); + size = 0; + vcc = NULL; + event_dump(); + } + if (error) { + static unsigned long silence = 0; + static int last_error = 0; + + if (error != last_error || + time_after(jiffies, silence) || silence == 0){ + printk(KERN_WARNING DEV_LABEL "(itf %d): " + "chan %d error %s\n",dev->number,chan, + err_txt[error]); + last_error = error; + silence = (jiffies+2*HZ)|1; + } + size = 0; + } + if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER || + size <= (cells-1)*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER)) { + printk(KERN_ERR DEV_LABEL "(itf %d): size %d with %d " + "cells\n",dev->number,size,cells); + size = 0; + event_dump(); + } + if (size > ATM_MAX_AAL5_PDU) { + printk(KERN_ERR DEV_LABEL "(itf %d): size too big " + "(%d)\n",dev->number,size); + size = 0; + event_dump(); + } + if (!size) { + kfree_skb(skb); + if (vcc) vcc->stats->rx_err++; + continue; + } + if (!atm_charge(vcc,skb->truesize)) { + kfree_skb(skb); + continue; + } + skb->len = size; + ATM_SKB(skb)->vcc = vcc; + vcc->push(vcc,skb); + vcc->stats->rx++; + } + zout(pos & 0xffff,MTA(mbx)); +#if 0 /* probably a stupid idea */ + refill_pool(dev,zatm_vcc->pool); + /* maybe this saves us a few interrupts */ +#endif +} + + +static int open_rx_first(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + unsigned short chan; + int cells; + + DPRINTK("open_rx_first (0x%x)\n",inb_p(0xc053)); + zatm_dev = ZATM_DEV(vcc->dev); + zatm_vcc = ZATM_VCC(vcc); + zatm_vcc->rx_chan = 0; + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + if (vcc->qos.aal == ATM_AAL5) { + if (vcc->qos.rxtp.max_sdu > 65464) + vcc->qos.rxtp.max_sdu = 65464; + /* fix this - we may want to receive 64kB SDUs + later */ + cells = (vcc->qos.rxtp.max_sdu+ATM_AAL5_TRAILER+ + ATM_CELL_PAYLOAD-1)/ATM_CELL_PAYLOAD; + zatm_vcc->pool = pool_index(cells*ATM_CELL_PAYLOAD); + } + else { + cells = 1; + zatm_vcc->pool = ZATM_AAL0_POOL; + } + if (zatm_vcc->pool < 0) return -EMSGSIZE; + save_flags(flags); + cli(); + zwait; + zout(uPD98401_OPEN_CHAN,CMR); + zwait; + DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); + chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; + restore_flags(flags); + DPRINTK("chan is %d\n",chan); + if (!chan) return -EAGAIN; + use_pool(vcc->dev,zatm_vcc->pool); + DPRINTK("pool %d\n",zatm_vcc->pool); + /* set up VC descriptor */ + cli(); + zpokel(zatm_dev,zatm_vcc->pool << uPD98401_RXVC_POOL_SHIFT, + chan*VC_SIZE/4); + zpokel(zatm_dev,uPD98401_RXVC_OD | (vcc->qos.aal == ATM_AAL5 ? + uPD98401_RXVC_AR : 0) | cells,chan*VC_SIZE/4+1); + zpokel(zatm_dev,0,chan*VC_SIZE/4+2); + zatm_vcc->rx_chan = chan; + zatm_dev->rx_map[chan] = vcc; + restore_flags(flags); + return 0; +} + + +static int open_rx_second(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + int pos,shift; + + DPRINTK("open_rx_second (0x%x)\n",inb_p(0xc053)); + zatm_dev = ZATM_DEV(vcc->dev); + zatm_vcc = ZATM_VCC(vcc); + if (!zatm_vcc->rx_chan) return 0; + save_flags(flags); + cli(); + /* should also handle VPI @@@ */ + pos = vcc->vci >> 1; + shift = (1-(vcc->vci & 1)) << 4; + zpokel(zatm_dev,(zpeekl(zatm_dev,pos) & ~(0xffff << shift)) | + ((zatm_vcc->rx_chan | uPD98401_RXLT_ENBL) << shift),pos); + restore_flags(flags); +/* Ugly hack to ensure that ttcp_atm will work with the current allocation + scheme. @@@ */ +if (vcc->rx_quota < 200000) vcc->rx_quota = 200000; + return 0; +} + + +static void close_rx(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + int pos,shift; + + zatm_vcc = ZATM_VCC(vcc); + zatm_dev = ZATM_DEV(vcc->dev); + if (!zatm_vcc->rx_chan) return; + DPRINTK("close_rx\n"); + /* disable receiver */ + save_flags(flags); + if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { + cli(); + pos = vcc->vci >> 1; + shift = (1-(vcc->vci & 1)) << 4; + zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos); + zwait; + zout(uPD98401_NOP,CMR); + zwait; + zout(uPD98401_NOP,CMR); + restore_flags(flags); + } + cli(); + zwait; + zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << + uPD98401_CHAN_ADDR_SHIFT),CMR); + zwait; + udelay(10); /* why oh why ... ? */ + zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << + uPD98401_CHAN_ADDR_SHIFT),CMR); + zwait; + if (!(zin(CMR) & uPD98401_CHAN_ADDR)) + printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel " + "%d\n",vcc->dev->number,zatm_vcc->rx_chan); + restore_flags(flags); + zatm_dev->rx_map[zatm_vcc->rx_chan] = NULL; + zatm_vcc->rx_chan = 0; + unuse_pool(vcc->dev,zatm_vcc->pool); +} + + +static int start_rx(struct atm_dev *dev) +{ + struct zatm_dev *zatm_dev; + int size,i; + +DPRINTK("start_rx\n"); + zatm_dev = ZATM_DEV(dev); + size = sizeof(struct atm_vcc *)*zatm_dev->chans; + zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL); + if (!zatm_dev->rx_map) return -ENOMEM; + memset(zatm_dev->rx_map,0,size); + /* set VPI/VCI split (use all VCIs and give what's left to VPIs) */ + zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR); + /* prepare free buffer pools */ + for (i = 0; i <= ZATM_LAST_POOL; i++) { + zatm_dev->pool_info[i].ref_count = 0; + zatm_dev->pool_info[i].rqa_count = 0; + zatm_dev->pool_info[i].rqu_count = 0; + zatm_dev->pool_info[i].low_water = LOW_MARK; + zatm_dev->pool_info[i].high_water = HIGH_MARK; + zatm_dev->pool_info[i].offset = 0; + zatm_dev->pool_info[i].next_off = 0; + zatm_dev->pool_info[i].next_cnt = 0; + zatm_dev->pool_info[i].next_thres = OFF_CNG_THRES; + } + return 0; +} + + +/*----------------------------------- TX ------------------------------------*/ + + +static int do_tx(struct sk_buff *skb) +{ + struct atm_vcc *vcc; + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + u32 *dsc; + unsigned long flags; + + EVENT("do_tx\n",0,0); + DPRINTK("sending skb %p\n",skb); + vcc = ATM_SKB(skb)->vcc; + zatm_dev = ZATM_DEV(vcc->dev); + zatm_vcc = ZATM_VCC(vcc); + EVENT("iovcnt=%d\n",ATM_SKB(skb)->iovcnt,0); + save_flags(flags); + cli(); + if (!ATM_SKB(skb)->iovcnt) { + if (zatm_vcc->txing == RING_ENTRIES-1) { + restore_flags(flags); + return RING_BUSY; + } + zatm_vcc->txing++; + dsc = zatm_vcc->ring+zatm_vcc->ring_curr; + zatm_vcc->ring_curr = (zatm_vcc->ring_curr+RING_WORDS) & + (RING_ENTRIES*RING_WORDS-1); + dsc[1] = 0; + dsc[2] = skb->len; + dsc[3] = virt_to_bus(skb->data); + mb(); + dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | uPD98401_TXPD_SM + | (vcc->qos.aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0 | + (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? + uPD98401_CLPM_1 : uPD98401_CLPM_0)); + EVENT("dsc (0x%lx)\n",(unsigned long) dsc,0); + } + else { +printk("NONONONOO!!!!\n"); + dsc = NULL; +#if 0 + u32 *put; + int i; + + dsc = (u32 *) kmalloc(uPD98401_TXPD_SIZE*2+ + uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC); + if (!dsc) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EAGAIN; + } + /* @@@ should check alignment */ + put = dsc+8; + dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | + (vcc->aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0 | + (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? + uPD98401_CLPM_1 : uPD98401_CLPM_0)); + dsc[1] = 0; + dsc[2] = ATM_SKB(skb)->iovcnt*uPD98401_TXBD_SIZE; + dsc[3] = virt_to_bus(put); + for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) { + *put++ = ((struct iovec *) skb->data)[i].iov_len; + *put++ = virt_to_bus(((struct iovec *) + skb->data)[i].iov_base); + } + put[-2] |= uPD98401_TXBD_LAST; +#endif + } + ZATM_PRV_DSC(skb) = dsc; + skb_queue_tail(&zatm_vcc->tx_queue,skb); + DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ + uPD98401_TXVC_QRP)); + zwait; + zout(uPD98401_TX_READY | (zatm_vcc->tx_chan << + uPD98401_CHAN_ADDR_SHIFT),CMR); + restore_flags(flags); + EVENT("done\n",0,0); + return 0; +} + + +static inline void dequeue_tx(struct atm_vcc *vcc) +{ + struct zatm_vcc *zatm_vcc; + struct sk_buff *skb; + + EVENT("dequeue_tx\n",0,0); + zatm_vcc = ZATM_VCC(vcc); + skb = skb_dequeue(&zatm_vcc->tx_queue); + if (!skb) { + printk(KERN_CRIT DEV_LABEL "(itf %d): dequeue_tx but not " + "txing\n",vcc->dev->number); + return; + } +#if 0 /* @@@ would fail on CLP */ +if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP | + uPD98401_TXPD_SM | uPD98401_TXPD_AAL5)) printk("@#*$!!!! (%08x)\n", + *ZATM_PRV_DSC(skb)); +#endif + *ZATM_PRV_DSC(skb) = 0; /* mark as invalid */ + zatm_vcc->txing--; + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + while ((skb = skb_dequeue(&zatm_vcc->backlog))) + if (do_tx(skb) == RING_BUSY) { + skb_queue_head(&zatm_vcc->backlog,skb); + break; + } + vcc->stats->tx++; + wake_up(&zatm_vcc->tx_wait); +} + + +static void poll_tx(struct atm_dev *dev,int mbx) +{ + struct zatm_dev *zatm_dev; + unsigned long pos; + u32 x; + + EVENT("poll_tx\n",0,0); + zatm_dev = ZATM_DEV(dev); + pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx)); + while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { + int chan; + +#if 1 + u32 data,*addr; + + EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x); + addr = (u32 *) pos; + data = *addr; + chan = (data & uPD98401_TXI_CONN) >> uPD98401_TXI_CONN_SHIFT; + EVENT("addr = 0x%lx, data = 0x%08x,",(unsigned long) addr, + data); + EVENT("chan = %d\n",chan,0); +#else +NO ! + chan = (zatm_dev->mbx_start[mbx][pos >> 2] & uPD98401_TXI_CONN) + >> uPD98401_TXI_CONN_SHIFT; +#endif + if (chan < zatm_dev->chans && zatm_dev->tx_map[chan]) + dequeue_tx(zatm_dev->tx_map[chan]); + else { + printk(KERN_CRIT DEV_LABEL "(itf %d): TX indication " + "for non-existing channel %d\n",dev->number,chan); + event_dump(); + } + if (((pos += 4) & 0xffff) == zatm_dev->mbx_end[mbx]) + pos = zatm_dev->mbx_start[mbx]; + } + zout(pos & 0xffff,MTA(mbx)); +} + + +/* + * BUG BUG BUG: Doesn't handle "new-style" rate specification yet. + */ + +static int alloc_shaper(struct atm_dev *dev,int *pcr,int min,int max,int ubr) +{ + struct zatm_dev *zatm_dev; + unsigned long flags; + unsigned long i,m,c; + int shaper; + + DPRINTK("alloc_shaper (min = %d, max = %d)\n",min,max); + zatm_dev = ZATM_DEV(dev); + if (!zatm_dev->free_shapers) return -EAGAIN; + for (shaper = 0; !((zatm_dev->free_shapers >> shaper) & 1); shaper++); + zatm_dev->free_shapers &= ~1 << shaper; + if (ubr) { + c = 5; + i = m = 1; + zatm_dev->ubr_ref_cnt++; + zatm_dev->ubr = shaper; + } + else { + if (min) { + if (min <= 255) { + i = min; + m = ATM_OC3_PCR; + } + else { + i = 255; + m = ATM_OC3_PCR*255/min; + } + } + else { + if (max > zatm_dev->tx_bw) max = zatm_dev->tx_bw; + if (max <= 255) { + i = max; + m = ATM_OC3_PCR; + } + else { + i = 255; + m = (ATM_OC3_PCR*255+max-1)/max; + } + } + if (i > m) { + printk(KERN_CRIT DEV_LABEL "shaper algorithm botched " + "[%d,%d] -> i=%ld,m=%ld\n",min,max,i,m); + m = i; + } + *pcr = i*ATM_OC3_PCR/m; + c = 20; /* @@@ should use max_cdv ! */ + if ((min && *pcr < min) || (max && *pcr > max)) return -EINVAL; + if (zatm_dev->tx_bw < *pcr) return -EAGAIN; + zatm_dev->tx_bw -= *pcr; + } + save_flags(flags); + cli(); + DPRINTK("i = %d, m = %d, PCR = %d\n",i,m,*pcr); + zpokel(zatm_dev,(i << uPD98401_IM_I_SHIFT) | m,uPD98401_IM(shaper)); + zpokel(zatm_dev,c << uPD98401_PC_C_SHIFT,uPD98401_PC(shaper)); + zpokel(zatm_dev,0,uPD98401_X(shaper)); + zpokel(zatm_dev,0,uPD98401_Y(shaper)); + zpokel(zatm_dev,uPD98401_PS_E,uPD98401_PS(shaper)); + restore_flags(flags); + return shaper; +} + + +static void dealloc_shaper(struct atm_dev *dev,int shaper) +{ + struct zatm_dev *zatm_dev; + unsigned long flags; + + zatm_dev = ZATM_DEV(dev); + if (shaper == zatm_dev->ubr) { + if (--zatm_dev->ubr_ref_cnt) return; + zatm_dev->ubr = -1; + } + save_flags(flags); + cli(); + zpokel(zatm_dev,zpeekl(zatm_dev,uPD98401_PS(shaper)) & ~uPD98401_PS_E, + uPD98401_PS(shaper)); + restore_flags(flags); + zatm_dev->free_shapers |= 1 << shaper; +} + + +static void close_tx(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + int chan; +struct sk_buff *skb; +int once = 1; + + zatm_vcc = ZATM_VCC(vcc); + zatm_dev = ZATM_DEV(vcc->dev); + chan = zatm_vcc->tx_chan; + if (!chan) return; + DPRINTK("close_tx\n"); + save_flags(flags); + cli(); + while (skb_peek(&zatm_vcc->backlog)) { +if (once) { +printk("waiting for backlog to drain ...\n"); +event_dump(); +once = 0; +} + sleep_on(&zatm_vcc->tx_wait); + } +once = 1; + while ((skb = skb_peek(&zatm_vcc->tx_queue))) { +if (once) { +printk("waiting for TX queue to drain ... %p\n",skb); +event_dump(); +once = 0; +} + DPRINTK("waiting for TX queue to drain ... %p\n",skb); + sleep_on(&zatm_vcc->tx_wait); + } +#if 0 + zwait; + zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); +#endif + zwait; + zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); + zwait; + if (!(zin(CMR) & uPD98401_CHAN_ADDR)) + printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel " + "%d\n",vcc->dev->number,chan); + restore_flags(flags); + zatm_vcc->tx_chan = 0; + zatm_dev->tx_map[chan] = NULL; + if (zatm_vcc->shaper != zatm_dev->ubr) { + zatm_dev->tx_bw += vcc->qos.txtp.min_pcr; + dealloc_shaper(vcc->dev,zatm_vcc->shaper); + } + if (zatm_vcc->ring) kfree(zatm_vcc->ring); +} + + +static int open_tx_first(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + u32 *loop; + unsigned short chan; + int pcr,unlimited; + + DPRINTK("open_tx_first\n"); + zatm_dev = ZATM_DEV(vcc->dev); + zatm_vcc = ZATM_VCC(vcc); + zatm_vcc->tx_chan = 0; + if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; + save_flags(flags); + cli(); + zwait; + zout(uPD98401_OPEN_CHAN,CMR); + zwait; + DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); + chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; + restore_flags(flags); + DPRINTK("chan is %d\n",chan); + if (!chan) return -EAGAIN; + unlimited = vcc->qos.txtp.traffic_class == ATM_UBR && + (!vcc->qos.txtp.max_pcr || vcc->qos.txtp.max_pcr == ATM_MAX_PCR || + vcc->qos.txtp.max_pcr >= ATM_OC3_PCR); + if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr; + else { + if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU; + if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr, + vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,unlimited)) + < 0) { + close_tx(vcc); + return zatm_vcc->shaper; + } + if (pcr > ATM_OC3_PCR) pcr = ATM_OC3_PCR; + vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr; + } + zatm_vcc->tx_chan = chan; + skb_queue_head_init(&zatm_vcc->tx_queue); + init_waitqueue_head(&zatm_vcc->tx_wait); + /* initialize ring */ + zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL); + if (!zatm_vcc->ring) return -ENOMEM; + memset(zatm_vcc->ring,0,RING_SIZE); + loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS; + loop[0] = uPD98401_TXPD_V; + loop[1] = loop[2] = 0; + loop[3] = virt_to_bus(zatm_vcc->ring); + zatm_vcc->ring_curr = 0; + zatm_vcc->txing = 0; + skb_queue_head_init(&zatm_vcc->backlog); + zpokel(zatm_dev,virt_to_bus(zatm_vcc->ring), + chan*VC_SIZE/4+uPD98401_TXVC_QRP); + return 0; +} + + +static int open_tx_second(struct atm_vcc *vcc) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + unsigned long flags; + + DPRINTK("open_tx_second\n"); + zatm_dev = ZATM_DEV(vcc->dev); + zatm_vcc = ZATM_VCC(vcc); + if (!zatm_vcc->tx_chan) return 0; + save_flags(flags); + /* set up VC descriptor */ + cli(); + zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4); + zpokel(zatm_dev,uPD98401_TXVC_L | (zatm_vcc->shaper << + uPD98401_TXVC_SHP_SHIFT) | (vcc->vpi << uPD98401_TXVC_VPI_SHIFT) | + vcc->vci,zatm_vcc->tx_chan*VC_SIZE/4+1); + zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4+2); + restore_flags(flags); + zatm_dev->tx_map[zatm_vcc->tx_chan] = vcc; + return 0; +} + + +static int start_tx(struct atm_dev *dev) +{ + struct zatm_dev *zatm_dev; + int i; + + DPRINTK("start_tx\n"); + zatm_dev = ZATM_DEV(dev); + zatm_dev->tx_map = (struct atm_vcc **) kmalloc(sizeof(struct atm_vcc *)* + zatm_dev->chans,GFP_KERNEL); + if (!zatm_dev->tx_map) return -ENOMEM; + zatm_dev->tx_bw = ATM_OC3_PCR; + zatm_dev->free_shapers = (1 << NR_SHAPERS)-1; + zatm_dev->ubr = -1; + zatm_dev->ubr_ref_cnt = 0; + /* initialize shapers */ + for (i = 0; i < NR_SHAPERS; i++) zpokel(zatm_dev,0,uPD98401_PS(i)); + return 0; +} + + +/*------------------------------- interrupts --------------------------------*/ + + +static void zatm_int(int irq,void *dev_id,struct pt_regs *regs) +{ + struct atm_dev *dev; + struct zatm_dev *zatm_dev; + u32 reason; + + dev = dev_id; + zatm_dev = ZATM_DEV(dev); + while ((reason = zin(GSR))) { + EVENT("reason 0x%x\n",reason,0); + if (reason & uPD98401_INT_PI) { + EVENT("PHY int\n",0,0); + dev->phy->interrupt(dev); + } + if (reason & uPD98401_INT_RQA) { + unsigned long pools; + int i; + + pools = zin(RQA); + EVENT("RQA (0x%08x)\n",pools,0); + for (i = 0; pools; i++) { + if (pools & 1) { + refill_pool(dev,i); + zatm_dev->pool_info[i].rqa_count++; + } + pools >>= 1; + } + } + if (reason & uPD98401_INT_RQU) { + unsigned long pools; + int i; + pools = zin(RQU); + printk(KERN_WARNING DEV_LABEL "(itf %d): RQU 0x%08lx\n", + dev->number,pools); + event_dump(); + for (i = 0; pools; i++) { + if (pools & 1) { + refill_pool(dev,i); + zatm_dev->pool_info[i].rqu_count++; + } + pools >>= 1; + } + } + /* don't handle RD */ + if (reason & uPD98401_INT_SPE) + printk(KERN_ALERT DEV_LABEL "(itf %d): system parity " + "error at 0x%08x\n",dev->number,zin(ADDR)); + if (reason & uPD98401_INT_CPE) + printk(KERN_ALERT DEV_LABEL "(itf %d): control memory " + "parity error at 0x%08x\n",dev->number,zin(ADDR)); + if (reason & uPD98401_INT_SBE) { + printk(KERN_ALERT DEV_LABEL "(itf %d): system bus " + "error at 0x%08x\n",dev->number,zin(ADDR)); + event_dump(); + } + /* don't handle IND */ + if (reason & uPD98401_INT_MF) { + printk(KERN_CRIT DEV_LABEL "(itf %d): mailbox full " + "(0x%x)\n",dev->number,(reason & uPD98401_INT_MF) + >> uPD98401_INT_MF_SHIFT); + event_dump(); + /* @@@ should try to recover */ + } + if (reason & uPD98401_INT_MM) { + if (reason & 1) poll_rx(dev,0); + if (reason & 2) poll_rx(dev,1); + if (reason & 4) poll_tx(dev,2); + if (reason & 8) poll_tx(dev,3); + } + /* @@@ handle RCRn */ + } +} + + +/*----------------------------- (E)EPROM access -----------------------------*/ + + +__initfunc(static void eprom_set(struct zatm_dev *zatm_dev,unsigned long value, + unsigned short cmd)) +{ + int error; + + if ((error = pci_write_config_dword(zatm_dev->pci_dev,cmd,value))) + printk(KERN_ERR DEV_LABEL ": PCI write failed (0x%02x)\n", + error); +} + + +__initfunc(static unsigned long eprom_get(struct zatm_dev *zatm_dev, + unsigned short cmd)) +{ + unsigned int value; + int error; + + if ((error = pci_read_config_dword(zatm_dev->pci_dev,cmd,&value))) + printk(KERN_ERR DEV_LABEL ": PCI read failed (0x%02x)\n", + error); + return value; +} + + +__initfunc(static void eprom_put_bits(struct zatm_dev *zatm_dev, + unsigned long data,int bits,unsigned short cmd)) +{ + unsigned long value; + int i; + + for (i = bits-1; i >= 0; i--) { + value = ZEPROM_CS | (((data >> i) & 1) ? ZEPROM_DI : 0); + eprom_set(zatm_dev,value,cmd); + eprom_set(zatm_dev,value | ZEPROM_SK,cmd); + eprom_set(zatm_dev,value,cmd); + } +} + + +__initfunc(static void eprom_get_byte(struct zatm_dev *zatm_dev, + unsigned char *byte,unsigned short cmd)) +{ + int i; + + *byte = 0; + for (i = 8; i; i--) { + eprom_set(zatm_dev,ZEPROM_CS,cmd); + eprom_set(zatm_dev,ZEPROM_CS | ZEPROM_SK,cmd); + *byte <<= 1; + if (eprom_get(zatm_dev,cmd) & ZEPROM_DO) *byte |= 1; + eprom_set(zatm_dev,ZEPROM_CS,cmd); + } +} + + +__initfunc(static unsigned char eprom_try_esi(struct atm_dev *dev, + unsigned short cmd,int offset,int swap)) +{ + unsigned char buf[ZEPROM_SIZE]; + struct zatm_dev *zatm_dev; + int i; + + zatm_dev = ZATM_DEV(dev); + for (i = 0; i < ZEPROM_SIZE; i += 2) { + eprom_set(zatm_dev,ZEPROM_CS,cmd); /* select EPROM */ + eprom_put_bits(zatm_dev,ZEPROM_CMD_READ,ZEPROM_CMD_LEN,cmd); + eprom_put_bits(zatm_dev,i >> 1,ZEPROM_ADDR_LEN,cmd); + eprom_get_byte(zatm_dev,buf+i+swap,cmd); + eprom_get_byte(zatm_dev,buf+i+1-swap,cmd); + eprom_set(zatm_dev,0,cmd); /* deselect EPROM */ + } + memcpy(dev->esi,buf+offset,ESI_LEN); + return memcmp(dev->esi,"\0\0\0\0\0",ESI_LEN); /* assumes ESI_LEN == 6 */ +} + + +__initfunc(static void eprom_get_esi(struct atm_dev *dev)) +{ + if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return; + (void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0); +} + + +/*--------------------------------- entries ---------------------------------*/ + + +__initfunc(static int zatm_init(struct atm_dev *dev)) +{ + struct zatm_dev *zatm_dev; + struct pci_dev *pci_dev; + unsigned short command; + unsigned char revision; + int error,i,last; + unsigned long t0,t1,t2; + + DPRINTK(">zatm_init\n"); + zatm_dev = ZATM_DEV(dev); + pci_dev = zatm_dev->pci_dev; + zatm_dev->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + zatm_dev->irq = pci_dev->irq; + if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command)) || + (error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision))) { + printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n", + dev->number,error); + return -EINVAL; + } + if ((error = pci_write_config_word(pci_dev,PCI_COMMAND, + command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { + printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)" + "\n",dev->number,error); + return error; + } + eprom_get_esi(dev); + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", + dev->number,revision,zatm_dev->base,zatm_dev->irq); + /* reset uPD98401 */ + zout(0,SWR); + while (!(zin(GSR) & uPD98401_INT_IND)); + zout(uPD98401_GMR_ONE /*uPD98401_BURST4*/,GMR); + last = MAX_CRAM_SIZE; + for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { + zpokel(zatm_dev,0x55555555,i); + if (zpeekl(zatm_dev,i) != 0x55555555) last = i; + else { + zpokel(zatm_dev,0xAAAAAAAA,i); + if (zpeekl(zatm_dev,i) != 0xAAAAAAAA) last = i; + else zpokel(zatm_dev,i,i); + } + } + for (i = 0; i < last; i += RAM_INCREMENT) + if (zpeekl(zatm_dev,i) != i) break; + zatm_dev->mem = i << 2; + while (i) zpokel(zatm_dev,0,--i); + /* reset again to rebuild memory pointers */ + zout(0,SWR); + while (!(zin(GSR) & uPD98401_INT_IND)); + zout(uPD98401_GMR_ONE | uPD98401_BURST8 | uPD98401_BURST4 | + uPD98401_BURST2 | uPD98401_GMR_PM | uPD98401_GMR_DR,GMR); + /* TODO: should shrink allocation now */ + printk("mem=%dkB,%s (",zatm_dev->mem >> 10,zatm_dev->copper ? "UTP" : + "MMF"); + for (i = 0; i < ESI_LEN; i++) + printk("%02X%s",dev->esi[i],i == ESI_LEN-1 ? ")\n" : "-"); + do { + unsigned long flags; + + save_flags(flags); + cli(); + t0 = zpeekl(zatm_dev,uPD98401_TSR); + udelay(10); + t1 = zpeekl(zatm_dev,uPD98401_TSR); + udelay(1010); + t2 = zpeekl(zatm_dev,uPD98401_TSR); + restore_flags(flags); + } + while (t0 > t1 || t1 > t2); /* loop if wrapping ... */ + zatm_dev->khz = t2-2*t1+t0; + printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %d.%d at %d.%03d " + "MHz\n",dev->number, + (zin(VER) & uPD98401_MAJOR) >> uPD98401_MAJOR_SHIFT, + zin(VER) & uPD98401_MINOR,zatm_dev->khz/1000,zatm_dev->khz % 1000); +#ifdef CONFIG_ATM_ZATM_EXACT_TS + zatm_clock_init(zatm_dev); +#endif + return uPD98402_init(dev); +} + + +__initfunc(static int zatm_start(struct atm_dev *dev)) +{ + struct zatm_dev *zatm_dev; + unsigned long curr; + int pools,vccs,rx; + int error,i,ld; + + DPRINTK("zatm_start\n"); + zatm_dev = ZATM_DEV(dev); + if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) { + printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", + dev->number,zatm_dev->irq); + return -EAGAIN; + } + request_region(zatm_dev->base,uPD98401_PORTS,DEV_LABEL); + /* define memory regions */ + pools = NR_POOLS; + if (NR_SHAPERS*SHAPER_SIZE > pools*POOL_SIZE) + pools = NR_SHAPERS*SHAPER_SIZE/POOL_SIZE; + vccs = (zatm_dev->mem-NR_SHAPERS*SHAPER_SIZE-pools*POOL_SIZE)/ + (2*VC_SIZE+RX_SIZE); + ld = -1; + for (rx = 1; rx < vccs; rx <<= 1) ld++; + dev->ci_range.vpi_bits = 0; /* @@@ no VPI for now */ + dev->ci_range.vci_bits = ld; + dev->link_rate = ATM_OC3_PCR; + zatm_dev->chans = vccs; /* ??? */ + curr = rx*RX_SIZE/4; + DPRINTK("RX pool 0x%08lx\n",curr); + zpokel(zatm_dev,curr,uPD98401_PMA); /* receive pool */ + zatm_dev->pool_base = curr; + curr += pools*POOL_SIZE/4; + DPRINTK("Shapers 0x%08lx\n",curr); + zpokel(zatm_dev,curr,uPD98401_SMA); /* shapers */ + curr += NR_SHAPERS*SHAPER_SIZE/4; + DPRINTK("Free 0x%08lx\n",curr); + zpokel(zatm_dev,curr,uPD98401_TOS); /* free pool */ + printk(KERN_INFO DEV_LABEL "(itf %d): %d shapers, %d pools, %d RX, " + "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx, + (zatm_dev->mem-curr*4)/VC_SIZE); + /* create mailboxes */ + for (i = 0; i < NR_MBX; i++) zatm_dev->mbx_start[i] = 0; + for (i = 0; i < NR_MBX; i++) + if (mbx_entries[i]) { + unsigned long here; + + here = (unsigned long) kmalloc(2*MBX_SIZE(i), + GFP_KERNEL); + if (!here) return -ENOMEM; + if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */ + here = (here & ~0xffffUL)+0x10000; + if ((here^virt_to_bus((void *) here)) & 0xffff) { + printk(KERN_ERR DEV_LABEL "(itf %d): system " + "bus incompatible with driver\n", + dev->number); + kfree((void *) here); + return -ENODEV; + } + DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i)); + zatm_dev->mbx_start[i] = here; + zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff; + zout(virt_to_bus((void *) here) >> 16,MSH(i)); + zout(virt_to_bus((void *) here),MSL(i)); + zout((here+MBX_SIZE(i)) & 0xffff,MBA(i)); + zout(here & 0xffff,MTA(i)); + zout(here & 0xffff,MWA(i)); + } + error = start_tx(dev); + if (error) return error; + error = start_rx(dev); + if (error) return error; + error = dev->phy->start(dev); + if (error) return error; + zout(0xffffffff,IMR); /* enable interrupts */ + /* enable TX & RX */ + zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR); + return 0; +} + + +static void zatm_close(struct atm_vcc *vcc) +{ + DPRINTK(">zatm_close\n"); + if (!ZATM_VCC(vcc)) return; + vcc->flags &= ~ATM_VF_READY; + close_rx(vcc); + EVENT("close_tx\n",0,0); + close_tx(vcc); + DPRINTK("zatm_close: done waiting\n"); + /* deallocate memory */ + kfree(ZATM_VCC(vcc)); + ZATM_VCC(vcc) = NULL; + vcc->flags &= ~ATM_VF_ADDR; +} + + +static int zatm_open(struct atm_vcc *vcc,short vpi,int vci) +{ + struct zatm_dev *zatm_dev; + struct zatm_vcc *zatm_vcc; + int error; + + DPRINTK(">zatm_open\n"); + zatm_dev = ZATM_DEV(vcc->dev); + if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL; + error = atm_find_ci(vcc,&vpi,&vci); + if (error) return error; + vcc->vpi = vpi; + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) + vcc->flags |= ATM_VF_ADDR; + if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ + DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, + vcc->vci); + if (!(vcc->flags & ATM_VF_PARTIAL)) { + zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL); + if (!zatm_vcc) { + vcc->flags &= ~ATM_VF_ADDR; + return -ENOMEM; + } + ZATM_VCC(vcc) = zatm_vcc; + ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */ + if ((error = open_rx_first(vcc))) { + zatm_close(vcc); + return error; + } + if ((error = open_tx_first(vcc))) { + zatm_close(vcc); + return error; + } + } + if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; + if ((error = open_rx_second(vcc))) { + zatm_close(vcc); + return error; + } + if ((error = open_tx_second(vcc))) { + zatm_close(vcc); + return error; + } + vcc->flags |= ATM_VF_READY; + return 0; +} + + +static int zatm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags) +{ + printk("Not yet implemented\n"); + return -ENOSYS; + /* @@@ */ +} + + +static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + struct zatm_dev *zatm_dev; + unsigned long flags; + + zatm_dev = ZATM_DEV(dev); + switch (cmd) { + case ZATM_GETPOOLZ: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* fall through */ + case ZATM_GETPOOL: + { + struct zatm_pool_info info; + int pool; + + if (get_user(pool, + &((struct zatm_pool_req *) arg)->pool_num)) + return -EFAULT; + if (pool < 0 || pool > ZATM_LAST_POOL) + return -EINVAL; + save_flags(flags); + cli(); + info = zatm_dev->pool_info[pool]; + if (cmd == ZATM_GETPOOLZ) { + zatm_dev->pool_info[pool].rqa_count = 0; + zatm_dev->pool_info[pool].rqu_count = 0; + } + restore_flags(flags); + return copy_to_user( + &((struct zatm_pool_req *) arg)->info, + &info,sizeof(info)) ? -EFAULT : 0; + } + case ZATM_SETPOOL: + { + struct zatm_pool_info info; + int pool; + + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (get_user(pool, + &((struct zatm_pool_req *) arg)->pool_num)) + return -EFAULT; + if (pool < 0 || pool > ZATM_LAST_POOL) + return -EINVAL; + if (copy_from_user(&info, + &((struct zatm_pool_req *) arg)->info, + sizeof(info))) return -EFAULT; + if (!info.low_water) + info.low_water = zatm_dev-> + pool_info[pool].low_water; + if (!info.high_water) + info.high_water = zatm_dev-> + pool_info[pool].high_water; + if (!info.next_thres) + info.next_thres = zatm_dev-> + pool_info[pool].next_thres; + if (info.low_water >= info.high_water || + info.low_water < 0) + return -EINVAL; + save_flags(flags); + cli(); + zatm_dev->pool_info[pool].low_water = + info.low_water; + zatm_dev->pool_info[pool].high_water = + info.high_water; + zatm_dev->pool_info[pool].next_thres = + info.next_thres; + restore_flags(flags); + return 0; + } +#ifdef CONFIG_ATM_ZATM_EXACT_TS + case ZATM_GETTHIST: + { + int i; + + save_flags(flags); + cli(); + for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) { + if (!copy_to_user( + (struct zatm_t_hist *) arg+i, + &zatm_dev->timer_history[ + (zatm_dev->th_curr+i) & + (ZATM_TIMER_HISTORY_SIZE-1)], + sizeof(struct zatm_t_hist))) + continue; + restore_flags(flags); + return -EFAULT; + } + restore_flags(flags); + return 0; + } +#endif + default: + if (!dev->phy->ioctl) return -EINVAL; + return dev->phy->ioctl(dev,cmd,arg); + } +} + + +static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen) +{ +#ifdef CONFIG_MMU_HACKS + +static const struct atm_buffconst bctx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; +static const struct atm_buffconst bcrx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; + +#else + +static const struct atm_buffconst bctx = { 4,0,4,0,0,0 }; +static const struct atm_buffconst bcrx = { 4,0,4,0,0,0 }; + +#endif + if (level == SOL_AAL && (optname == SO_BCTXOPT || + optname == SO_BCRXOPT)) + return copy_to_user(optval,optname == SO_BCTXOPT ? &bctx : + &bcrx,sizeof(struct atm_buffconst)) ? -EFAULT : 0; + return -EINVAL; +} + + +static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen) +{ + return -EINVAL; +} + + +#if 0 +static int zatm_sg_send(struct atm_vcc *vcc,unsigned long start, + unsigned long size) +{ + return vcc->aal == ATM_AAL5; + /* @@@ should check size and maybe alignment*/ +} +#endif + + +static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ + int error; + + EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0); + if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } + if (!skb) { + printk(KERN_CRIT "!skb in zatm_send ?\n"); + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } + ATM_SKB(skb)->vcc = vcc; + error = do_tx(skb); + if (error != RING_BUSY) return error; + skb_queue_tail(&ZATM_VCC(vcc)->backlog,skb); + return 0; +} + + +static void zatm_phy_put(struct atm_dev *dev,unsigned char value, + unsigned long addr) +{ + struct zatm_dev *zatm_dev; + + zatm_dev = ZATM_DEV(dev); + zwait; + zout(value,CER); + zout(uPD98401_IND_ACC | uPD98401_IA_B0 | + (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); +} + + +static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr) +{ + struct zatm_dev *zatm_dev; + + zatm_dev = ZATM_DEV(dev); + zwait; + zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW | + (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); + zwait; + return zin(CER) & 0xff; +} + + +static const struct atmdev_ops ops = { + NULL, /* no dev_close */ + zatm_open, + zatm_close, + zatm_ioctl, + zatm_getsockopt, + zatm_setsockopt, + zatm_send, + NULL /*zatm_sg_send*/, + NULL, /* no send_oam */ + zatm_phy_put, + zatm_phy_get, + zatm_feedback, + zatm_change_qos, + NULL, /* no free_rx_skb */ + NULL /* no proc_read */ +}; + + +__initfunc(int zatm_detect(void)) +{ + struct atm_dev *dev; + struct zatm_dev *zatm_dev; + int devs,type; + + zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev), + GFP_KERNEL); + if (!zatm_dev) return -ENOMEM; + devs = 0; + for (type = 0; type < 2; type++) { + struct pci_dev *pci_dev; + + pci_dev = NULL; + while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ? + PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221, + pci_dev))) { + dev = atm_dev_register(DEV_LABEL,&ops,-1,0); + if (!dev) break; + zatm_dev->pci_dev = pci_dev; + ZATM_DEV(dev) = zatm_dev; + zatm_dev->copper = type; + if (zatm_init(dev) || zatm_start(dev)) { + atm_dev_deregister(dev); + break; + } + zatm_dev->more = zatm_boards; + zatm_boards = dev; + devs++; + zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct + zatm_dev),GFP_KERNEL); + if (!zatm_dev) break; + } + } + return devs; +} + + +#ifdef MODULE + +int init_module(void) +{ + if (!zatm_detect()) { + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); + return -ENXIO; + } + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* + * Well, there's no way to get rid of the driver yet, so we don't + * have to clean up, right ? :-) + */ +} + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/zatm.h linux/drivers/atm/zatm.h --- v2.3.14/linux/drivers/atm/zatm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/zatm.h Mon Aug 23 13:44:03 1999 @@ -0,0 +1,138 @@ +/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef DRIVER_ATM_ZATM_H +#define DRIVER_ATM_ZATM_H + +#include +#include +#include +#include +#include +#include + + +#define DEV_LABEL "zatm" + +#define MAX_AAL5_PDU 10240 /* allocate for AAL5 PDUs of this size */ +#define MAX_RX_SIZE_LD 14 /* ceil(log2((MAX_AAL5_PDU+47)/48)) */ + +#define LOW_MARK 12 /* start adding new buffers if less than 12 */ +#define HIGH_MARK 30 /* stop adding buffers after reaching 30 */ +#define OFF_CNG_THRES 5 /* threshold for offset changes */ + +#define RX_SIZE 2 /* RX lookup entry size (in bytes) */ +#define NR_POOLS 32 /* number of free buffer pointers */ +#define POOL_SIZE 8 /* buffer entry size (in bytes) */ +#define NR_SHAPERS 16 /* number of shapers */ +#define SHAPER_SIZE 4 /* shaper entry size (in bytes) */ +#define VC_SIZE 32 /* VC dsc (TX or RX) size (in bytes) */ + +#define RING_ENTRIES 32 /* ring entries (without back pointer) */ +#define RING_WORDS 4 /* ring element size */ +#define RING_SIZE (sizeof(unsigned long)*(RING_ENTRIES+1)*RING_WORDS) + +#define NR_MBX 4 /* four mailboxes */ +#define MBX_RX_0 0 /* mailbox indices */ +#define MBX_RX_1 1 +#define MBX_TX_0 2 +#define MBX_TX_1 3 + + +/* + * mkdep doesn't spot this dependency, but that's okay, because zatm.c uses + * CONFIG_ATM_ZATM_EXACT_TS too. + */ + +#ifdef CONFIG_ATM_ZATM_EXACT_TS +#define POLL_INTERVAL 60 /* TSR poll interval in seconds; must be <= + (2^31-1)/clock */ +#define TIMER_SHIFT 20 /* scale factor for fixed-point arithmetic; + 1 << TIMER_SHIFT must be + (1) <= (2^64-1)/(POLL_INTERVAL*clock), + (2) >> clock/10^6, and + (3) <= (2^32-1)/1000 */ +#define ADJ_IGN_THRES 1000000 /* don't adjust if we're off by more than that + many usecs - this filters clock corrections, + time zone changes, etc. */ +#define ADJ_REP_THRES 20000 /* report only differences of more than that + many usecs (don't mention single lost timer + ticks; 10 msec is only 0.03% anyway) */ +#define ADJ_MSG_THRES 5 /* issue complaints only if getting that many + significant timer differences in a row */ +#endif + + +struct zatm_vcc { + /*-------------------------------- RX part */ + int rx_chan; /* RX channel, 0 if none */ + int pool; /* free buffer pool */ + /*-------------------------------- TX part */ + int tx_chan; /* TX channel, 0 if none */ + int shaper; /* shaper, <0 if none */ + struct sk_buff_head tx_queue; /* list of buffers in transit */ + wait_queue_head_t tx_wait; /* for close */ + u32 *ring; /* transmit ring */ + int ring_curr; /* current write position */ + int txing; /* number of transmits in progress */ + struct sk_buff_head backlog; /* list of buffers waiting for ring */ +}; + +struct zatm_dev { + /*-------------------------------- TX part */ + int tx_bw; /* remaining bandwidth */ + u32 free_shapers; /* bit set */ + int ubr; /* UBR shaper; -1 if none */ + int ubr_ref_cnt; /* number of VCs using UBR shaper */ + /*-------------------------------- RX part */ + int pool_ref[NR_POOLS]; /* free buffer pool usage counters */ + volatile struct sk_buff *last_free[NR_POOLS]; + /* last entry in respective pool */ + struct sk_buff_head pool[NR_POOLS];/* free buffer pools */ + struct zatm_pool_info pool_info[NR_POOLS]; /* pool information */ + /*-------------------------------- maps */ + struct atm_vcc **tx_map; /* TX VCCs */ + struct atm_vcc **rx_map; /* RX VCCs */ + int chans; /* map size, must be 2^n */ + /*-------------------------------- mailboxes */ + unsigned long mbx_start[NR_MBX];/* start addresses */ + u16 mbx_end[NR_MBX]; /* end offset (in bytes) */ + /*-------------------------------- other pointers */ + u32 pool_base; /* Free buffer pool dsc (word addr) */ + /*-------------------------------- ZATM links */ + struct atm_dev *more; /* other ZATM devices */ +#ifdef CONFIG_ATM_ZATM_EXACT_TS + /*-------------------------------- timestamp calculation */ + u32 last_clk; /* results of last poll: clock, */ + struct timeval last_time; /* virtual time and */ + struct timeval last_real_time; /* real time */ + u32 factor; /* multiplication factor */ + int timer_diffs; /* number of significant deviations */ + struct zatm_t_hist timer_history[ZATM_TIMER_HISTORY_SIZE]; + /* record of timer synchronizations */ + int th_curr; /* current position */ +#endif + /*-------------------------------- general information */ + int mem; /* RAM on board (in bytes) */ + int khz; /* timer clock */ + int copper; /* PHY type */ + unsigned char irq; /* IRQ */ + unsigned int base; /* IO base address */ + struct pci_dev *pci_dev; /* PCI stuff */ +}; + + +#define ZATM_DEV(d) ((struct zatm_dev *) (d)->dev_data) +#define ZATM_VCC(d) ((struct zatm_vcc *) (d)->dev_data) + + +struct zatm_skb_prv { + struct atm_skb_data _; /* reserved */ + u32 *dsc; /* pointer to skb's descriptor */ +}; + +#define ZATM_PRV_DSC(skb) (((struct zatm_skb_prv *) (skb)->cb)->dsc) + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/atm/zeprom.h linux/drivers/atm/zeprom.h --- v2.3.14/linux/drivers/atm/zeprom.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/zeprom.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,34 @@ +/* drivers/atm/zeprom.h - ZeitNet ZN122x EEPROM (NM93C46) declarations */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ + + +#ifndef DRIVER_ATM_ZEPROM_H +#define DRIVER_ATM_ZEPROM_H + +/* Different versions use different control registers */ + +#define ZEPROM_V1_REG PCI_VENDOR_ID /* PCI register */ +#define ZEPROM_V2_REG 0x40 + +/* Bits in contol register */ + +#define ZEPROM_SK 0x80000000 /* strobe (probably on raising edge) */ +#define ZEPROM_CS 0x40000000 /* Chip Select */ +#define ZEPROM_DI 0x20000000 /* Data Input */ +#define ZEPROM_DO 0x10000000 /* Data Output */ + +#define ZEPROM_SIZE 32 /* 32 bytes */ +#define ZEPROM_V1_ESI_OFF 24 /* ESI offset in EEPROM (V1) */ +#define ZEPROM_V2_ESI_OFF 4 /* ESI offset in EEPROM (V2) */ + +#define ZEPROM_CMD_LEN 3 /* commands are three bits */ +#define ZEPROM_ADDR_LEN 6 /* addresses are six bits */ + +/* Commands (3 bits) */ + +#define ZEPROM_CMD_READ 6 + +/* No other commands are needed. */ + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.3.14/linux/drivers/block/genhd.c Thu Aug 12 12:26:06 1999 +++ linux/drivers/block/genhd.c Mon Aug 23 09:56:31 1999 @@ -22,6 +22,7 @@ extern int net_dev_init(void); extern void console_map_init(void); extern int soc_probe(void); +extern int atmdev_init(void); void __init device_init(void) { @@ -50,6 +51,9 @@ #endif #ifdef CONFIG_INET net_dev_init(); +#endif +#ifdef CONFIG_ATM + (void) atmdev_init(); #endif #ifdef CONFIG_VT console_map_init(); diff -u --recursive --new-file v2.3.14/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.14/linux/drivers/char/Config.in Thu Aug 5 14:47:44 1999 +++ linux/drivers/char/Config.in Mon Aug 23 10:23:23 1999 @@ -37,6 +37,7 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8 + tristate 'Computone IntelliPort Plus serial support' CONFIG_COMPUTONE tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX if [ "$CONFIG_SPECIALIX" != "n" ]; then bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS @@ -90,7 +91,6 @@ fi dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN - dep_tristate ' Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG diff -u --recursive --new-file v2.3.14/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.14/linux/drivers/char/Makefile Mon Aug 9 14:06:59 1999 +++ linux/drivers/char/Makefile Mon Aug 23 10:23:23 1999 @@ -116,6 +116,14 @@ endif endif +ifeq ($(CONFIG_COMPUTONE),y) +L_OBJS += ip2.o ip2main.o +else + ifeq ($(CONFIG_COMPUTONE),m) + M_OBJS += ip2.o ip2main.o + endif +endif + ifeq ($(CONFIG_RISCOM8),y) O_OBJS += riscom8.o else diff -u --recursive --new-file v2.3.14/linux/drivers/char/README.computone linux/drivers/char/README.computone --- v2.3.14/linux/drivers/char/README.computone Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/README.computone Mon Aug 23 10:23:23 1999 @@ -0,0 +1,195 @@ + +Computone Intelliport II/Plus Multiport Serial Driver +----------------------------------------------------- + +Release Notes For Linux Kernel 2.2 +These notes have been tested on Linux kernels 2.0 and 2.2. + + +Version: 1.2.4 +Date: 08/04/99 +Fixes and Updates: Doug McNash +Historical Author: Andrew Manison + +1. INTRODUCTION + +This driver supports the entire family of Intelliport II/Plus controllers +with the exception of the MicroChannel controllers. + +This driver was developed on the v2.0.x Linux source tree and has been +tested up to v2.2.10; it will probably not work with earlier v1.X kernels, +and has not yet been tested on the v2.1.x tree. The most likely problems +will be in patching the kernel sources to support the driver. For this +reason there are 2 different patch files for 2.0.XX and 2.2.XX kernels. +Make sure you use the right one! +Someday soon it should be included in the 2.3.XX tree. + +2. QUICK INSTALLATION + +Hardware - If you have an ISA card, find a free interrupt and io port. + List those in use with `cat /proc/interrupts` and + `cat /proc/ioports`. Set the card dip switches to that free + address. You may need to configure your BIOS to reserve the + irq for the ISA card. PCI and EISA parameters are set + automagically and need no attention. Insert card into + computer with the power off before or after driver installation. + +Software - + +Module installation: + +a) Obtain driver-kernel patch file +b) Copy to the linux source tree root, Run ip2build (if not patch) +c) Determine free irq/address to use if any (configure BIOS if need be) +d) Run "make config" or "make menuconfig" or "make xconfig" + Select (m) module for CONFIG_COMPUTONE under character + devices. CONFIG_PCI and CONFIG_MODULES also may need to be set. +e) Set address on ISA cards then: + edit /usr/src/linux/drivers/char/ip2/ip2.h if needed + or + edit /etc/conf.modules (or /etc/modules.conf) if needed (module). + or both to match this setting. +f) Run "make dep" +g) Run "make modules" +h) Run "make modules_install" +i) Run "/sbin/depmod -a" +i) install driver using `modprobe ip2 ` (options listed below) +j) run mkip2dev + + +Kernel installation: + +a) Obtain driver-kernel patch file +b) Copy to the linux source tree root, Run ip2build (if not patch) +c) Determine free irq/address to use if any (configure BIOS if need be) +d) Run "make config" or "make menuconfig" or "make xconfig" + Select (y) kernel for CONFIG_COMPUTONE under character + devices. CONFIG_PCI may need to be set if you have PCI bus. +e) Set address on ISA cards then: + edit /usr/src/linux/drivers/char/ip2/ip2.h +f) Run "make dep" +g) Run "make zImage" or whatever target you prefer. +h) mv /usr/src/linux/arch/i386/boot/zImage to /boot. +i) add new config for this kernel into /etc/lilo.conf, run "lilo" +j) reboot using this kernel +k) make and run ip2/mkip2dev + +3. INSTALLATION + +Previously, the driver sources were packaged with a set of patch files +to update the character drivers' makefile and configuration file, and other +kernel source files. A build script (ip2build) was included which applies +the patches if needed, and build any utilities needed. +What you recieve may be a single patch file in conventional kernel +patch format build script. That form can also be applied by +running patch -p1 < ThePatchFile. Otherwise run ip2build. + +The driver can be installed as a module (recommended) or built into the +kernel. This is selected as for other drivers through the `make config` +command from the root of the Linux source tree. If the driver is built +into the kernel you will need to edit the file ip2.h to match the boards +you are installing. See that file for instructions. If the driver is +installed as a module the configuration can also be specified on the +modprobe command line as follows: + + modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4 + +where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11, +12,15) and addr1-4 are the base addresses for up to four controllers. If +the irqs are not specified the driver uses the default in ip2/ip2.h (which +selects polled mode). If no base addresses are specified the defaults in +ip2.h are used. If you are autoloading the driver module with kerneld or +kmod the base addresses and interrupt number must also be set in ip2/ip2.h +and recompile or just insert and options line in /etc/modules.conf or both. +The options line is equivalent to the command line and takes precidence over +what is in ip2.h. + +/etc/modules.conf sample: + options ip2 io=1,0x328 irq=1,10 + alias char-major-71 ip2 + alias char-major-72 ip2 + alias char-major-73 ip2 + +equivelant ip2.h: +static ip2config_t ip2config = +{ + {1,10,0,0}, + { + 0x0001, // Board 0, ttyF0 - ttyF63 /* PCI card */ + 0x0328, // Board 1, ttyF64 - ttyF127 /* ISA card */ + 0x0000, // Board 2, ttyF128 - ttyF191 /* empty */ + 0x0000 // Board 3, ttyF192 - ttyF255 /* empty */ + } +}; + +Specifying an invalid or in-use irq will default the driver into +running in polled mode for that card. If all irq entries are 0 then +all cards will operate in polled mode. + +Tarball Install: + +The whole tarfile should be untarred in the /usr/src/linux/drivers/char/ +directory. Most files required for the driver are placed in the ip2 +subdirectory. Then execute the script + + ip2build + +which will patch the files. + +Kernel Patch Install: + + cd to the Linux source root, run patch -p1 < ThePatchFile. + +Now return to the root directory of the Linux +source tree and run make config or make menuconfig. You will be prompted +for the Computone drivers, either as a module or part of the kernel. +If you have a PCI card you many need to select PCI bios support (CONFIG_PCI) +if not enabled already. Ditto for CONFIG_MODULES if you use modules. + +If you select the driver as part of the kernel run : + + make depend + make zlilo (or whatever you do to create a bootable kernel) + +If you selected a module run : + + make modules && make modules_install + +The utility ip2mkdev creates all the device nodes required by the driver. +For a device to be created it must be configured in the driver and the +board must be installed. Only devices corresponding to real IntelliPort II +ports are created. With multiple boards and expansion boxes this will +leave gaps in the sequence of device names. ip2mkdev uses Linux tty naming +conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for +callout devices. + +4. USING THE DRIVERS + +As noted above, the driver implements the ports in accordance with Linux +conventions, and the devices should be interchangeable with the standard +serial devices. (This is a key point for problem reporting: please make +sure that what you are trying do works on the ttySx/cuax ports first; then +tell us what went wrong with the ip2 ports!) + +Higher speeds can be obtained using the setserial utility which remaps +38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. +Intelliport II installations using the PowerPort expansion module can +use the custom speed setting to select the highest speeds: 153,600 bps, +230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for +custom baud rate configuration is fixed at 921,600 for cards/expantion +modules with ST654's and 115200 for those with Cirrus CD1400's. This +corresponds to the maximum bit rates those chips are capable. +For example if the baud base is 921600 and the baud divisor is 18 then +the custom rate is 921600/18 = 51200 bps. See the setserial man page for +complete details. Of course if stty accepts the higher rates now you can +use that as well as the standard ioctls(). + +5. NOTES + +This is a release version of the driver, but it is impossible to test it +in all configurations of Linux. If there is any anomalous behaviour that +does not match the standard serial port's behaviour please let us know. + +Author: dmcnash@computine.com +Testing: larryg@computone.com +Spport: support@computone.com diff -u --recursive --new-file v2.3.14/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.14/linux/drivers/char/bttv.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/char/bttv.c Mon Aug 23 10:10:29 1999 @@ -563,7 +563,7 @@ /* MIRO PCTV pro */ { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}}, /* ADS Technologies Channel Surfer TV (and maybe TV+FM) */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, + { 3, 4, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* AVerMedia TVCapture 98 */ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* Aimslab VHX */ @@ -576,6 +576,8 @@ { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, /* AVEC Intercapture */ { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}}, + /* LifeView FlyKit w/o Tuner */ + { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}} }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -1986,12 +1988,7 @@ v.height > 16 && v.bytesperline > 16) return -EINVAL; if (v.base) - { - if ((unsigned long)v.base&1) - btv->win.vidadr=(unsigned long)(PAGE_OFFSET|uvirt_to_bus((unsigned long)v.base)); - else - btv->win.vidadr=(unsigned long)v.base; - } + btv->win.vidadr=(unsigned long)v.base; btv->win.sheight=v.height; btv->win.swidth=v.width; btv->win.bpp=((v.depth+7)&0x38)/8; @@ -3145,7 +3142,7 @@ break; } printk("%s\n",btv->video_dev.name); - audio(btv, AUDIO_MUTE); + audio(btv, AUDIO_INTERN); } diff -u --recursive --new-file v2.3.14/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.14/linux/drivers/char/console.c Fri Aug 13 12:19:25 1999 +++ linux/drivers/char/console.c Thu Aug 19 10:54:10 1999 @@ -33,7 +33,7 @@ * APM screenblank bug fixed Takashi Manabe * * Merge with the abstract console driver by Geert Uytterhoeven - * , Jan 1997. + * , Jan 1997. * * Original m68k console driver modifications by * diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/Makefile linux/drivers/char/ip2/Makefile --- v2.3.14/linux/drivers/char/ip2/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/Makefile Mon Aug 23 10:23:23 1999 @@ -0,0 +1,12 @@ + +all: ip2mkdev ip2trace ip2stat + +ip2mkdev: ip2mkdev.c + cc -o ip2mkdev ip2mkdev.c + +ip2trace: ip2trace.c + cc -o ip2trace ip2trace.c + +ip2stat: ip2stat.c + cc -o ip2stat ip2stat.c + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/fip_firm.h linux/drivers/char/ip2/fip_firm.h --- v2.3.14/linux/drivers/char/ip2/fip_firm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/fip_firm.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,2149 @@ +/* fip_firm.h - Intelliport II loadware */ +/* -31232 bytes read from ff.lod */ + +unsigned char fip_firm[] __initdata = { +0x3C,0x42,0x8A,0xE1,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x57,0x65,0x64,0x20,0x4A,0x75,0x6E,0x20,0x32,0x33,0x20,0x31,0x35,0x3A,0x33,0x30, +0x3A,0x31,0x33,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE9,0x68,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20, +0x63,0x4F,0x64,0x45,0xCC,0x13,0x5A,0x15,0xE8,0x16,0x76,0x18,0x04,0x1A,0x92,0x1B, +0x20,0x1D,0xAE,0x1E,0x3C,0x20,0xCA,0x21,0x58,0x23,0xE6,0x24,0x74,0x26,0x02,0x28, +0x90,0x29,0x1E,0x2B,0xAC,0x2C,0x3A,0x2E,0xC8,0x2F,0x56,0x31,0xE4,0x32,0x72,0x34, +0x00,0x36,0x8E,0x37,0x1C,0x39,0xAA,0x3A,0x38,0x3C,0xC6,0x3D,0x54,0x3F,0xE2,0x40, +0x70,0x42,0xFE,0x43,0x8C,0x45,0x1A,0x47,0xA8,0x48,0x36,0x4A,0xC4,0x4B,0x52,0x4D, +0xE0,0x4E,0x6E,0x50,0xFC,0x51,0x8A,0x53,0x18,0x55,0xA6,0x56,0x34,0x58,0xC2,0x59, +0x50,0x5B,0xDE,0x5C,0x6C,0x5E,0xFA,0x5F,0x88,0x61,0x16,0x63,0xA4,0x64,0x32,0x66, +0xC0,0x67,0x4E,0x69,0xDC,0x6A,0x6A,0x6C,0xF8,0x6D,0x86,0x6F,0x14,0x71,0xA2,0x72, +0x30,0x74,0xBE,0x75,0x4C,0x77,0x6C,0x77,0x8C,0x77,0xAC,0x77,0x33,0xDB,0x8A,0xDC, +0x53,0x33,0xDB,0x25,0x07,0x00,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x83,0xE3,0x0C,0xEB, +0x20,0x90,0x3C,0x01,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x80,0xE3,0xC0,0xEB,0x12,0x90, +0x8A,0x1E,0x0D,0x01,0x3C,0x02,0x75,0x06,0x80,0xE3,0x0C,0xEB,0x04,0x90,0x80,0xE3, +0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x4C,0x65,0x55,0x8B,0xEC,0x53, +0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,0xD1,0xE3, +0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x2A,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3,0x55,0x8B, +0xEC,0x53,0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06, +0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x34,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3, +0xFB,0x55,0x8B,0xEC,0x53,0x51,0x52,0x56,0x57,0x1E,0x06,0x1E,0x07,0x33,0xC0,0x8E, +0xD8,0x8B,0x5E,0x04,0x26,0x8A,0x47,0x59,0x25,0x03,0x00,0x8B,0xF0,0xD1,0xE6,0x2E, +0x8B,0xB4,0xC4,0x00,0xC1,0xE0,0x04,0x26,0x02,0x47,0x1A,0xD1,0xE0,0x8B,0xE8,0x2E, +0x8B,0xAE,0x44,0x00,0x89,0x2C,0x26,0x8A,0x47,0x1C,0x88,0x44,0x0F,0x26,0x8A,0x47, +0x1D,0x88,0x44,0x10,0x26,0x8A,0x47,0x1E,0x88,0x44,0x11,0x26,0x8A,0x47,0x1F,0x88, +0x44,0x12,0x26,0x8A,0x47,0x20,0x88,0x44,0x13,0x26,0x8A,0x47,0x23,0x88,0x44,0x14, +0x26,0x8A,0x47,0x24,0x88,0x44,0x15,0x26,0x8A,0x47,0x5A,0x88,0x44,0x0E,0x33,0xC0, +0x89,0x44,0x06,0x89,0x44,0x08,0x88,0x44,0x0B,0x88,0x44,0x0A,0xB0,0x21,0xB4,0x64, +0x89,0x44,0x04,0x89,0x44,0x02,0xB0,0x55,0x88,0x44,0x0D,0x88,0x44,0x0C,0xE8,0x6A, +0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xBD,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01, +0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA5, +0x10,0x8B,0xF8,0x2B,0x44,0x08,0x3D,0xA0,0x0F,0x72,0x10,0x89,0x7C,0x08,0x33,0xC0, +0x87,0x44,0x06,0x85,0xC0,0x75,0x04,0xC6,0x44,0x0A,0xFF,0x8A,0x44,0x0A,0x84,0xC0, +0x75,0x0B,0xB8,0x08,0x00,0xE8,0x4C,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01, +0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x00,0x0E,0x8A,0x44, +0x0A,0x98,0x07,0x1F,0x5F,0x5E,0x5A,0x59,0x5B,0x5D,0xC3,0x81,0x4E,0x48,0x80,0x00, +0xB0,0x40,0xE8,0x1F,0x4A,0xE8,0x6B,0x40,0x73,0x2A,0xE8,0x49,0x10,0x8B,0xD8,0xB0, +0x05,0xE8,0x10,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x39,0x10,0x2B,0xC3,0x3D, +0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC0,0x0D,0xC6,0x44, +0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0xE4,0x49, +0xFA,0xE8,0x95,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0, +0x01,0xE8,0xD0,0x49,0xFA,0xE8,0x81,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA, +0xE8,0x76,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88, +0x44,0x18,0xE4,0xF0,0x88,0x44,0x19,0xE4,0x10,0x88,0x44,0x1A,0xE4,0x12,0x88,0x44, +0x1B,0xE4,0x14,0x88,0x44,0x1C,0xE4,0x34,0x88,0x44,0x1D,0xE4,0x36,0x88,0x44,0x1E, +0xE4,0xD8,0x24,0x01,0x8A,0xE0,0xE4,0xDA,0x24,0x02,0x0A,0xC4,0x88,0x44,0x1F,0x8A, +0x44,0x10,0xE8,0xC9,0x1F,0x8A,0x44,0x11,0xE8,0x31,0x21,0x8A,0x44,0x12,0xE8,0x85, +0x21,0x8A,0x44,0x13,0xE8,0x3F,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10, +0xE6,0x14,0xE4,0x12,0x24,0x3D,0xE6,0x12,0x8A,0x44,0x15,0x3C,0x01,0x72,0x1E,0x77, +0x16,0xB0,0x11,0xE6,0x34,0xB0,0x13,0xE6,0x36,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4, +0x12,0x0C,0x40,0xE6,0x12,0xEB,0x06,0xE4,0x12,0x0C,0x02,0xE6,0x12,0x8A,0x44,0x0F, +0x3C,0x01,0x74,0x06,0x3C,0x02,0x74,0x0A,0xEB,0x0E,0xE4,0x12,0x0C,0x08,0xE6,0x12, +0xEB,0x06,0xE4,0x12,0x0C,0x10,0xE6,0x12,0xE8,0x2F,0xFF,0x8A,0x44,0x14,0x3C,0x02, +0x75,0x08,0xB0,0x55,0x88,0x44,0x0C,0x88,0x44,0x0D,0xB0,0x21,0xB4,0x64,0x89,0x44, +0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xCF,0x39,0xFB,0xC3,0xE8, +0x41,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0xEA,0x48,0xEB,0xF3,0xFA,0xE8,0x99,0x1D, +0x8A,0x64,0x16,0x8A,0x44,0x17,0x89,0x86,0x94,0x00,0xE6,0xE4,0x8A,0xC4,0xE6,0xEC, +0x8A,0x64,0x18,0x8A,0x44,0x19,0x89,0x86,0x96,0x00,0xE6,0xF0,0x8A,0xC4,0xE6,0xF8, +0x8A,0x44,0x1A,0xE6,0x10,0x8A,0x44,0x1B,0xE6,0x12,0x8A,0x44,0x1C,0xE6,0x14,0x8A, +0x44,0x1D,0xE6,0x34,0x8A,0x44,0x1E,0xE6,0x36,0x8A,0x44,0x1F,0xE6,0xD8,0xE6,0xDA, +0xE9,0xB7,0xFE,0x90,0xFA,0x8A,0x44,0x0E,0xE6,0xFE,0xE4,0x02,0xA8,0x01,0x75,0x05, +0x33,0xC0,0xFB,0xF8,0xC3,0x33,0xC0,0xE4,0x00,0xFB,0xF9,0xC3,0x8A,0x64,0x14,0x80, +0xFC,0x02,0x74,0x2B,0xFE,0xC0,0xFE,0xC7,0x80,0xFF,0x4E,0x72,0x1C,0x74,0x09,0x80, +0xFF,0x50,0x73,0x08,0xB0,0x0A,0xEB,0x17,0xB0,0x0D,0xEB,0x13,0x02,0xDC,0x32,0xFF, +0x80,0xFB,0x7F,0x7C,0x02,0xB3,0x21,0x8A,0xC3,0x3C,0x7F,0x7C,0x02,0xB0,0x21,0xC3, +0xFA,0x80,0x7C,0x0B,0x04,0x76,0x02,0xFB,0xC3,0x8B,0x46,0x24,0x3D,0x08,0x00,0x72, +0xF6,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0x44,0x0C,0x8B,0x5C,0x02,0xAA,0xE8,0xAB, +0xFF,0xAA,0xE8,0xA7,0xFF,0xAA,0xE8,0xA3,0xFF,0xAA,0xE8,0x9F,0xFF,0x88,0x44,0x0C, +0x89,0x5C,0x02,0x80,0x44,0x0B,0x04,0x89,0x7E,0x22,0x83,0x6E,0x24,0x04,0x83,0x46, +0x1A,0x04,0x80,0x7E,0x26,0x02,0x74,0x06,0x80,0x66,0x26,0xFD,0xFB,0xC3,0x60,0xB0, +0xFD,0xE8,0xE4,0x3E,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44, +0x0B,0x00,0xE8,0xC7,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75, +0x35,0x26,0x8B,0x0D,0x47,0x47,0xE3,0xEA,0x3B,0x7E,0x04,0x76,0x22,0xB8,0x02,0x00, +0x39,0x46,0x2E,0x77,0x07,0xC7,0x46,0x2E,0x00,0x00,0xEB,0x13,0x8B,0x5E,0x2C,0x89, +0x5E,0x04,0x26,0xC7,0x07,0x00,0x00,0x43,0x43,0x89,0x5E,0x2C,0x29,0x46,0x2E,0x85, +0xC9,0x78,0xCE,0x89,0x4E,0x3A,0x8A,0x44,0x0D,0x8B,0x5C,0x04,0x26,0x8A,0x25,0x47, +0x3A,0xC4,0x75,0x16,0xFE,0x4C,0x0B,0xFF,0x44,0x06,0xE8,0x0F,0xFF,0xE2,0xED,0x88, +0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x5B, +0x38,0xFB,0xC3,0x90,0xE8,0xAF,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A, +0xC1,0xEE,0xEB,0x00,0xEC,0x3A,0xC1,0x75,0x09,0x02,0xCD,0xFE,0xCB,0x75,0xF0,0xEB, +0x0C,0x90,0x88,0x0E,0xCB,0x13,0x8A,0xE8,0xBB,0xFF,0xFF,0xF9,0xC3,0x88,0x0E,0xCB, +0x13,0xF8,0xC3,0x90,0xBB,0x3F,0x3F,0x8A,0x8E,0x9E,0x00,0xBA,0xFE,0x00,0xEC,0x8A, +0xE8,0x32,0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0xE8,0xE5,0xFF,0x73, +0x01,0xC3,0xBA,0xD0,0x00,0xBB,0x03,0x03,0x8A,0x8E,0x9F,0x00,0xEC,0x8A,0xE8,0x32, +0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0, +0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x08,0x47,0xEB,0xF2,0xFB,0x33, +0xDB,0x8A,0x1E,0xC9,0x13,0x43,0x43,0x83,0xFB,0x7E,0x76,0x07,0x33,0xDB,0xB0,0x02, +0xE8,0xF1,0x46,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E, +0xC9,0x13,0xB0,0x02,0xE8,0xDD,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8, +0x92,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E, +0xEB,0x0C,0x90,0xE8,0x73,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33, +0xFF,0x73,0xAB,0x23,0xCB,0x89,0x8E,0x9A,0x00,0x89,0x96,0x9C,0x00,0xFE,0x86,0xB5, +0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x63,0x0A,0xFB,0xEB,0x89,0x10,0x18, +0x08,0x28,0x33,0xC0,0xA0,0x05,0x01,0x8A,0xC8,0x24,0x40,0x75,0x24,0xC7,0x06,0x7C, +0x12,0x70,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08, +0xF6,0xC1,0x01,0x74,0x02,0xB0,0x04,0xA3,0x46,0x12,0xA2,0x4C,0x12,0xA2,0x94,0x12, +0xC3,0xC7,0x06,0x7C,0x12,0x98,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xAD,0x0C,0x90,0xC7,0x06,0x44,0x12, +0x01,0x00,0xA3,0x42,0x12,0x8B,0xD8,0xC1,0xE3,0x04,0x88,0x1E,0x94,0x12,0xBE,0xE2, +0x05,0x2B,0xF0,0x8B,0xC8,0x33,0xDB,0x8B,0xFB,0x2E,0xAC,0x88,0x85,0x48,0x12,0x8A, +0xD8,0x0C,0x05,0xE6,0xFE,0x8A,0xE0,0xEB,0x00,0xE4,0xFE,0x32,0xC4,0xA8,0x3F,0x74, +0x03,0xE9,0x9A,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10, +0xFF,0x3C,0x30,0x74,0x12,0x80,0xFC,0x04,0x74,0x0A,0xBA,0x04,0x03,0xF6,0x06,0x08, +0x01,0xFE,0x74,0x03,0xBA,0x08,0x0F,0x88,0x95,0x4C,0x12,0x02,0xFA,0x32,0xC0,0xF6, +0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x57, +0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B,0x3C,0x15,0x74,0x47, +0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4,0x03,0x8A,0xC3,0x89, +0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85,0x64,0x12,0xD1,0xEF, +0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x70,0xFF,0xC6,0x85,0x54,0x12,0x02,0xD1,0xE7, +0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF,0x47,0xE2,0xE7,0x33, +0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06,0xEB,0xBB,0xC6,0x85, +0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C,0x12,0x88,0x85,0x58, +0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89,0x46,0x00,0x89,0x46, +0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00,0xC3,0xC7,0x46,0x3C, +0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30,0x89,0x76,0x04,0x89, +0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89,0x76,0x2C,0x89,0x46, +0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3,0x33,0xC0,0x89,0x46, +0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E,0x8B,0x46,0x44,0x89, +0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3,0x33,0xC0,0x89,0x46, +0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B,0x76,0x70,0x89,0x76, +0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B,0x46,0x72,0x89,0x46, +0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56,0x06,0x89,0x56,0x0A, +0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B,0x4B,0xC1,0xE3,0x02, +0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03,0xFB,0x89,0x7E,0x42, +0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89,0x5E,0x32,0x89,0x5E, +0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8,0x3F,0xFF,0xE8,0x8B, +0xFF,0x58,0xC3,0xB8,0x10,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03,0xC3,0xA3,0xBA,0x13, +0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00,0x75,0x0E,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90,0xB8,0x30,0x7A,0xC1, +0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8,0x33,0xD2,0x8B,0xCA, +0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A,0x00,0x1F,0xC6,0x06, +0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF,0x07,0x72,0x03,0xB8, +0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33,0xF6,0xB8,0x00,0x09, +0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2,0xF3,0x8A,0x0E,0x94, +0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B,0xAC,0x44,0x00,0xE8, +0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E,0x8B,0xAD,0x44,0x00, +0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD, +0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47,0x47,0xFE,0xC4,0x80, +0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83,0xE9,0x10,0x74,0x05, +0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,0x44,0x00, +0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4,0x10,0x79,0x04,0x32, +0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0x99,0xFF, +0xC3,0xE8,0xD2,0xFF,0xC3,0x89,0x08,0x98,0x08,0xC6,0x08,0xF1,0x08,0x8B,0x0E,0x42, +0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48,0x12,0x8A,0x8C,0x4C, +0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB,0x75,0x02,0xB1,0x10, +0x2E,0xFF,0x97,0xF5,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01,0xCC,0x03,0xD0,0x00, +0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00,0xE8,0x04,0xD0,0xA8, +0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0xA8, +0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,0xD8,0x03,0xCC,0x03, +0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03, +0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0x00, +0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00, +0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F,0xBE,0x2B,0x09,0x33, +0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85,0xC0,0x74,0x05,0x8A, +0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0,0x74,0x16,0x78,0x14, +0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27,0x75,0x06,0xE4,0x11, +0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xB0, +0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE,0x83,0xC2,0x02,0xEE, +0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1,0x2E,0x2D,0x89,0x86, +0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE,0x83,0xC2,0x04,0xB0, +0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE,0x83,0xC2,0x02,0xB0, +0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4,0x38,0x89,0x46,0x1C, +0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88,0x86,0xA7,0x00,0xC3, +0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86,0xAF,0x00,0x75,0x24, +0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC,0x3C,0x13,0x75,0x14, +0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC,0x24,0xC0,0x3C,0xC0, +0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1,0x8A,0x0E,0x94,0x12, +0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x0E,0x8A, +0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA,0xFE,0x83,0xC6,0x08, +0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E, +0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x73, +0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94, +0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x16, +0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C, +0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3,0x33,0xC9,0x8B,0xF1, +0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x16, +0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C, +0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C,0x00,0x00,0x10,0x00, +0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00,0x00,0x2A,0x00,0x00, +0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00,0x34,0x00,0x11,0x36, +0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50,0x52,0xBE,0x2B,0x0B, +0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4,0x5A,0x58,0x5E,0xC3, +0x53,0x2E,0xA1,0x5C,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6,0xEC,0xE6,0xF8,0xE8, +0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38,0xE6,0x14,0xE8,0xAE, +0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A,0xE8,0xA0,0x15,0xB0, +0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4,0x16,0xA8,0x04,0x75, +0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A,0x00,0x1F,0xC6,0x06, +0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06,0x2B,0xC3,0x3D,0x24, +0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10,0x00,0x2E,0x8B,0xAC, +0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D,0x59,0x5E,0xE8,0x69, +0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B,0xC3,0x33,0xF6,0x8B, +0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8, +0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B,0xC2,0x05,0x04,0x00, +0x89,0x46,0x28,0x2E,0xA1,0x2E,0x2D,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89, +0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00,0x03,0x52,0x83,0xC2, +0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02,0xB0,0x05,0xEE,0x88, +0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42,0xE6,0x0A,0xF7,0x46, +0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x98,0x22,0xEB,0x04,0x2E,0xA1,0x68,0x22,0xC7, +0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00,0x89,0x86,0x8E,0x00, +0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4,0x8A,0xC4,0xE6,0xF8, +0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A,0xE6,0x0A,0xB0,0x10, +0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E, +0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x76,0x14,0xE8,0x5A, +0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B, +0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C,0x14,0xE8,0x74,0xFF, +0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75,0x14,0xB0,0x01,0xBA, +0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE,0xB8,0x00,0x02,0xEB, +0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E,0x0E,0x01,0xD3,0xE0, +0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20,0x00,0xA3,0x8A,0x12, +0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00,0xC7,0x06,0x80,0x12, +0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E,0x42,0x12,0x33,0xF6, +0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12,0x0C,0x04,0xE6,0xFE, +0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA, +0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0,0xBA,0x02,0x00,0xEE, +0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F,0xBA,0x00,0x00,0xEE, +0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0xD1, +0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA, +0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4,0x04,0x46,0xE2,0x90, +0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00,0xBA,0x32,0xFF,0xEF, +0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83,0x3E,0x44,0x12,0x00, +0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF, +0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8, +0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0xFC, +0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74,0x07,0xB8,0xCC,0x00, +0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF,0x2C,0xFF,0xFF,0x30, +0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x15,0x0E,0x2E,0xD7,0x3C, +0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3,0x83,0x3E,0x44,0x12, +0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80,0x3E,0x06,0x01,0x30, +0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8, +0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04,0x00,0xBF,0xC4,0x13, +0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC,0xAA,0xE2,0xF1,0xFA, +0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74,0x0E,0x6A,0x00,0x1F, +0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD,0x3C,0x0F,0x75,0xED, +0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6,0x06,0x8E,0x12,0x00, +0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06,0x8F,0x12,0x40,0x83, +0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90,0xB8,0x4C,0x00,0xBA, +0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3,0xA1,0x50,0x12,0x0B, +0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01,0x2A,0xE4,0x50,0xFF, +0x36,0xBA,0x13,0x1F,0xE8,0x36,0x56,0x83,0xC4,0x02,0x6A,0x00,0x1F,0x33,0xC0,0xA3, +0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13,0x8A,0x87,0x50,0x12, +0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE,0xCC,0x00,0xA0,0xBC, +0x13,0xE8,0x7A,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13,0x75,0xDA,0xC3,0x90, +0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x3A,0x3D,0x1F,0xC3,0x33,0xC9,0x8B,0xF1, +0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62,0x1A,0x44,0xC7,0x46, +0x7C,0xDE,0x3B,0xC7,0x46,0x7E,0xC4,0x3B,0xC7,0x86,0x80,0x00,0xCE,0x3C,0xE8,0xAB, +0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07,0x51,0x56,0xE8,0x19, +0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1,0x8B,0xF9,0x8A,0x0E, +0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00,0x8A,0x86,0x9E,0x00, +0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA,0xFC,0xB0,0xC0,0xBA, +0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF,0x16,0x01,0xB9,0xCC, +0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9,0x02,0xE8,0x56,0x3C, +0xBE,0xC8,0x0F,0xE8,0xD8,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0, +0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x17,0x55,0xE8,0xC1,0x3C,0xB0,0x01,0xE8, +0x92,0x3C,0xE8,0xB3,0x00,0xE8,0xFA,0xF5,0xE8,0x08,0xF8,0xE8,0x0F,0xF9,0xE8,0x85, +0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0xE9,0x3B,0xE8,0xB2,0xFD, +0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8,0xBB,0xFA,0xE8,0xEB, +0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F,0xFF,0xE8,0x58,0xFF, +0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8,0x70,0x3C,0xE8,0xA3, +0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0x86,0x44,0xE8,0x63,0x3C,0xE9,0xB0,0x2D,0x56,0x98, +0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52,0x01,0x00,0x53,0x36, +0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68,0x52,0x36,0x89,0xAC, +0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89,0xAC,0x1C,0x01,0x5B, +0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C,0x01,0xA8,0x01,0x75, +0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C,0x01,0xA8,0x01,0x74, +0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6,0xB8,0x01,0x00,0xB9, +0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46,0xE2,0xF4,0x59,0x5E, +0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A,0x8B,0xDD,0x8B,0x46, +0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00,0x74,0x45,0xF7,0x46, +0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24, +0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x6C,0x32,0x61,0xB0,0x02,0xE8, +0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17,0xE8,0x2A,0x10,0x81, +0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C, +0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21,0xFF,0x8B,0x46,0x48, +0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x2D,0x32,0x61,0x33,0xC0,0x87,0x46, +0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01,0x75,0x0D,0xE9,0x74, +0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89,0x1E,0x32,0x01,0xC3, +0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15,0xE8,0xD5,0x0F,0x80, +0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56,0xA8,0x01,0x74,0xE3, +0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46,0x26,0xB0,0x02,0xE8, +0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A,0x36,0x89,0x47,0x56, +0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75,0x02,0xEB,0xB4,0x89, +0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0,0x90,0x12,0x84,0xC0, +0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE,0xA1,0x20,0x01,0xA8, +0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05,0x74,0x45,0xA3,0xAC, +0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13,0xA1,0xB0,0x13,0x48, +0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78,0x03,0xA3,0x7E,0x12, +0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0,0x91,0x12,0x40,0x3C, +0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12,0xEB,0xA4,0xA2,0x91, +0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E,0x12,0x0A,0x06,0x1A, +0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E,0x84,0x12,0x10,0x72, +0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x39,0x37,0xBA,0x28,0xFF,0xED,0x24, +0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01,0xE8,0x25,0x37,0xC6, +0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF, +0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60,0xFF,0xEF,0xB8,0x01, +0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF,0xB8,0x09,0xC0,0xBA, +0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE,0x13,0x04,0x00,0xC6, +0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x05,0xD1, +0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A,0xC3,0x90,0x53,0x51, +0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75,0xF7,0x59,0x5B,0xC3, +0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90,0xB0,0x40,0xEB,0xF2, +0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E,0x16,0x2B,0xDB,0x8E, +0xDB,0x2E,0xA1,0x9C,0x4C,0x2E,0xA3,0x74,0x4C,0xA0,0x93,0x12,0x98,0x8B,0xE8,0x89, +0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x51,0x42,0xE8,0xC0,0xFF, +0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12,0x00,0xFF,0x16,0x7C, +0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8,0x90,0xFF,0xE8,0xAB, +0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74,0x0F,0xE8,0xA4,0xFF, +0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1,0xE8,0x95,0xFF,0xE8, +0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86,0xA5,0x00,0xC3, +0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7,0xC6,0x01,0x00,0x74, +0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89, +0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B,0x7E,0x2C,0x83,0xEA, +0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,0x12,0xF7,0xC6,0x20, +0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,0xA0,0xFC,0xC3,0xF7, +0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76,0x38,0x8A,0x86,0xA7, +0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83,0xEA,0x08,0x8B,0xC3, +0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0x02,0x8A,0x86, +0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02, +0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E,0x32,0xDB,0x8A,0xBE, +0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83,0xF9,0x08,0x72,0x2C, +0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83,0xC2,0x0A,0x84,0xE7, +0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32,0xFF,0x26,0x01,0x1C, +0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x3B,0x4E,0x3C,0x72, +0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xFD, +0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00, +0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2,0x02,0x3D,0x40,0x00, +0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09,0x26,0x89,0x1C,0x8B, +0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26,0x89,0x04,0xF6,0xC4, +0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,0x86,0xB2, +0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,0x68,0x26, +0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7,0x33,0xC0,0xAB,0x32, +0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17,0xE9,0x41,0xFF,0x81, +0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5, +0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86,0xAA,0x00,0xC0,0xE8, +0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B,0x5E,0x3E,0x84,0xE3, +0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05, +0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74, +0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86, +0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD,0xEB,0x06,0xA8,0x02, +0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x83,0xC2,0x0A,0x8B, +0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEE,0xFA, +0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72,0xE8,0x8A,0xA6,0xAA, +0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07, +0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83, +0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA,0x08,0xE9,0xB4,0xFD, +0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B,0x4E,0x1C,0xEC,0x88, +0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD,0x32,0xED,0x8B,0x46, +0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00, +0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30,0xC3,0x85,0xC0,0x74, +0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x80,0xCB,0x02, +0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83,0xC2,0x02,0xE8,0x53, +0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3,0xF6,0xC7,0x01,0x74, +0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74,0xDE,0x83,0xC2,0x02, +0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7,0xFE,0x80,0xCF,0x02, +0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0,0xC2,0xC8,0xCA,0xC4, +0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90,0xE9,0x0E,0x01,0xE4, +0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0,0x26,0x83,0x3F,0x00, +0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3,0x0F,0x2E,0x8A,0xA7, +0x2B,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE, +0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8, +0x86,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x89,0x7E,0x04,0x33, +0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1,0xEB,0x4E,0x90,0xEB, +0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03, +0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0x8B,0x4E,0x2E,0xC4, +0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07,0x3C,0x03,0x75,0xCF, +0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E, +0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72, +0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8, +0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9,0xC3,0xF7,0xC6,0x0A, +0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10,0x89,0x76,0x38,0xF7, +0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8,0x58,0xF7,0xC6,0x08, +0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0,0xE0,0xFA,0x84,0xC0, +0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73,0xB5,0x8A,0x86,0xA5, +0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10,0x04,0x89,0x76,0x38, +0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A,0x06,0x0E,0x03,0x0B, +0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50,0x90,0xD0,0x30,0x70, +0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E, +0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8,0x04,0x8B,0xD8,0x2E, +0x8A,0x87,0x62,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0xE4,0x98, +0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74, +0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08, +0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E, +0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08,0xA8,0x06,0x74,0x19, +0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75,0x04,0x0C,0x04,0xEB, +0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84,0xE7,0x75,0x09,0x8A, +0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8, +0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E,0x06,0x72,0xE0,0x8A, +0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32,0xC4,0x80,0xC9,0x0B, +0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA, +0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46, +0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1,0xF7,0xEB,0xA0,0x90, +0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E,0x26,0x83,0x66,0x48, +0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32, +0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E,0x26,0x8A,0x86,0xA5, +0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90,0xF6,0xC7,0x40,0x75, +0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x81,0xE6,0xC6,0x80, +0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71,0xF7,0x90,0x8A,0x86, +0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43,0xE4,0xD4,0xE6,0xD0, +0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x8B,0x5E, +0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA,0xC6,0x00,0x8B,0x4E, +0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A, +0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x3D,0x8B, +0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8,0x01,0x46,0x2A,0xC5, +0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26,0xE8,0xD9,0xED,0xF6, +0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00, +0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3,0xF6,0xC7,0x01,0x74, +0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x11, +0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB,0xC7,0x8A,0x86,0xA5, +0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x92,0x90,0xFD,0xF7, +0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, +0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, +0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, +0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, +0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, +0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, +0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, +0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, +0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, +0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE, +0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74,0x03,0xE9,0x2C,0xFE, +0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74,0x03,0xE9,0x1C,0xFE, +0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE9, +0xD0,0xFB,0x96,0x1A,0xC2,0x1A,0x00,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, +0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xD6,0x14,0x90,0x15,0x58,0x13,0xE2,0x13, +0xD6,0x1B,0xD6,0x1B,0xE2,0x13,0xD6,0x1B,0x8B,0x94,0x64,0x12,0xC1,0xE6,0x04,0xA8, +0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27, +0x8B,0xD8,0x2E,0x8A,0x9F,0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56, +0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF, +0x97,0xD8,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36,0x83,0xC6,0x10,0x33, +0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F, +0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75, +0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97,0xD8,0x1B,0x5E,0x5A, +0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A,0x9F,0x96,0x19,0x2E, +0x22,0x97,0x8E,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6,0x80,0xE3,0x04,0xD0, +0xEB,0x2E,0xFF,0x97,0xD2,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75,0xD9,0xC3,0x60,0x1E, +0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08, +0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00, +0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1, +0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,0x94,0xFF, +0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61, +0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00, +0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00, +0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD,0xA1,0x60,0x12,0xE6, +0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5C,0x12,0xE6, +0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90, +0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4, +0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22, +0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE, +0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5E,0x12,0xE6,0xFE, +0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E, +0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08, +0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07, +0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE,0xEB,0xED,0xB8,0x00, +0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, +0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8, +0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90, +0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4, +0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF, +0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12, +0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37,0xFE,0xA1,0x60,0x12, +0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0xAA,0xFD,0xEB,0xDD, +0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5C,0x12,0xE6,0xFE, +0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90, +0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4, +0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84, +0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04, +0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E, +0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x27, +0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8, +0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4, +0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E, +0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19, +0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74, +0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00, +0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF, +0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1,0x60,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC,0xEB,0xDD,0xA1,0x60, +0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,0x22, +0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC,0xA1,0x62,0x12,0xE6, +0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B,0xFC,0xEB,0xDC,0xA1, +0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0x2A,0xC0, +0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5,0xF6,0xEB,0xEF,0x90, +0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xF6,0x06,0x05,0x01, +0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0xE3,0xBB,0x04,0x00, +0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90, +0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33,0xDB,0xE8,0xCC,0xF8, +0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04, +0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, +0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x15,0xBB, +0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07, +0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8,0x24,0xF7,0xEB,0xD2, +0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B,0xF2,0x90,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90,0x6E,0x20,0x6E,0x20, +0x6E,0x20,0xCA,0x1D,0x8E,0x1C,0xE2,0x1C,0x16,0x1E,0x6E,0x20,0x7E,0x1D,0xAA,0x1E, +0x34,0x1F,0x6E,0x20,0x7E,0x1D,0x6E,0x20,0x6E,0x20,0x34,0x1F,0x6E,0x20,0x6E,0x20, +0x6E,0x20,0xF0,0x1D,0xB8,0x1C,0x30,0x1D,0x60,0x1E,0x6E,0x20,0xA4,0x1D,0xEE,0x1E, +0x74,0x1F,0x6E,0x20,0xA4,0x1D,0x6E,0x20,0x6E,0x20,0x74,0x1F,0xFC,0xB9,0x40,0x00, +0x8C,0xCB,0xB8,0x60,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2,0xFA,0xC7,0x06,0x4C, +0x00,0xA4,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06,0x3C,0x00,0xEA,0x4A, +0xC7,0x06,0x30,0x00,0xB6,0x1F,0xC7,0x06,0x34,0x00,0xF6,0x1F,0xF6,0x06,0x05,0x01, +0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2A,0x20,0xC3,0xC7,0x06,0x3C,0x00,0x38,0x4B, +0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56,0x12,0x2E,0x8B,0x87, +0x7C,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x57,0x12, +0x2E,0x8B,0x87,0x9C,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x86, +0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2,0x8A,0xD4,0xC3,0x51, +0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2,0xF6,0x59,0xF9,0xC3, +0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8,0xB8,0x01,0x00,0xD3, +0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10,0xE8,0xA9,0xE5,0x83, +0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0,0xF8,0xC3,0x84,0xC0, +0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0,0x59,0xF7,0xD0,0x21, +0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83,0xC2,0x04,0x8A,0x86, +0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF,0x72,0x04,0xB0,0x82, +0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86,0xA5,0x00,0xA8,0x06, +0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC4,0x01,0x74,0x0A, +0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02,0x75,0x0F,0x8A,0x86, +0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8,0xC3,0x8A,0x86,0xA5, +0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04,0x2E,0x8A,0x9F,0x62, +0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07, +0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x80,0x75,0x03, +0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0xFD,0x74,0x0D,0xA8, +0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC7,0x01,0x74, +0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04,0xEB,0xE7,0xC4,0x04, +0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03,0x82,0x03,0x41,0x03, +0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00,0x41,0x00,0x4E,0x02, +0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00,0x16,0x00,0xF4,0x04, +0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03,0xA3,0x03,0x51,0x03, +0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00,0x51,0x00,0x62,0x02, +0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00,0x1B,0x00,0x51,0x57, +0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB,0x07,0x90,0x51,0x56, +0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B,0xF0,0x8A,0x82,0xC4, +0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6,0x2E,0x8B,0x8C,0x4E, +0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x7E,0x22,0xF7,0xC7,0x02, +0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94,0x00,0x8A,0xC5,0xE6, +0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B,0x8E,0x96,0x00,0x74, +0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6,0xF0,0x5E,0x59,0xC3, +0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00,0xEB,0xBF,0xD5,0x03, +0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01,0x4D,0x00,0x14,0x00, +0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04,0x80,0x84,0x1E,0x00, +0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E,0xA1,0x4C,0x23,0x2E, +0x8B,0x16,0x4E,0x23,0xBB,0x2E,0x23,0xF7,0x46,0x38,0x80,0x00,0x74,0x0C,0x2E,0xA1, +0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x38,0x23,0xB9,0x05,0x00,0x2E,0x3B,0x31, +0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90,0xD1,0xEF,0x2E,0x8A, +0x8D,0x42,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7,0xF6,0x05,0x02,0x00, +0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x47,0x23,0x2E,0xA3,0x54,0x23,0x61,0x2E,0xA1,0x54, +0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09,0x08,0x00,0x20,0x00, +0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00, +0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03,0xB8,0x01,0x09,0xBF, +0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01,0x33,0xF6,0x2E,0x3B, +0x84,0xB2,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E,0x8B,0xBC,0xBC,0x23, +0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4,0xC6,0x23,0x5F,0x5E, +0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7,0x46,0x7A,0x20,0x00, +0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3,0x24,0x03,0x88,0x86, +0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00, +0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07,0xD1,0xE6,0x2E,0xFF, +0xA4,0x54,0x24,0x90,0x64,0x24,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24,0x83,0x24, +0x83,0x24,0x83,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A,0xB4,0x40,0xEB,0x06, +0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4,0xE6,0x10,0x80,0x8E, +0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0,0xE4,0x10,0x24,0xF3, +0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xC3,0x90,0x8B,0x5E, +0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08,0x8B,0x46,0x2E,0x3B, +0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6,0x0A,0x83,0xCB,0x10, +0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10,0x00,0x74,0xF5,0xE8, +0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xEB,0xE0, +0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77,0x0B,0x24,0xFE,0x80, +0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB,0x02,0xEB,0xF3,0x50, +0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A, +0xDC,0x2E,0x8A,0xA7,0x62,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50,0x33,0xDB,0xC1,0xE8, +0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,0xDC,0x2E,0x8A,0xA7, +0x62,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E,0x33,0xDB,0x8A,0xD8, +0x0A,0xDC,0x2E,0x8A,0x87,0x72,0x17,0xE6,0x2C,0x8A,0xE0,0xE4,0x2A,0x24,0x0F,0x0A, +0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8,0x80,0x74,0x11,0x24, +0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04,0x0C,0x80,0xEB,0xF1, +0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D,0xBE,0xFD,0x00,0x57, +0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F,0x78,0x09,0x38,0xA3, +0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46,0x5F,0x83,0xC7,0x09, +0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96,0x84,0x00,0x61,0x1F, +0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40,0x00,0x74,0x0D,0xB3, +0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00,0x32,0xDB,0xA9,0x02, +0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80,0xCB,0x02,0xA9,0x00, +0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80,0xCB,0xBC,0xA9,0x00, +0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80,0xCB,0x10,0xA9,0x08, +0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3,0x06,0x51,0x57,0x50, +0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA,0x40,0xE2,0xFC,0x8B, +0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58,0x5F,0x59,0x07,0xC3, +0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E,0x8A,0x87,0x62,0x17, +0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86,0xBA,0x00,0x01,0xB0, +0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36,0xA3,0xB6,0x13,0xAD, +0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13,0x0F,0x00,0xC3,0x8A, +0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88,0x86,0xBD,0x00,0x32, +0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80,0xE3,0xFE,0x3B,0x5E, +0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E,0xC5,0x5E,0x14,0x8B, +0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10,0x00,0x74,0x02,0x0C, +0x04,0xF7,0x46,0x7A,0x02,0x00,0x74,0x02,0x0C,0x08,0x88,0x86,0xBF,0x00,0xC3,0x90, +0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0x0B,0xEC,0x90,0xB0,0x02, +0xE6,0xDA,0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3, +0x33,0xC0,0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x68,0xFA,0xE8,0xBB,0xFA,0xF8,0xC3, +0xAC,0x49,0xE8,0xC9,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x2F,0xFD,0xF8,0xC3,0x90, +0xAC,0x49,0xE8,0x81,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x39,0xFD,0xF8,0xC3,0x90, +0xAC,0x49,0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02, +0x77,0x1F,0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F, +0xE6,0x12,0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0x04,0xFA,0x72,0x04,0xB0,0x18,0xE6, +0x0A,0xF8,0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6, +0xC4,0x01,0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x3F,0xFD,0xF8, +0xC3,0x90,0xB8,0x00,0x40,0xE8,0x97,0xFD,0xE8,0xCE,0xFD,0xE8,0xC2,0xFE,0xB0,0x01, +0xE8,0xD3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x9F,0xFD,0xE8,0xBA,0xFD,0xF8, +0xC3,0x90,0xB8,0x00,0x10,0xE8,0x77,0xFD,0xE8,0xAE,0xFD,0xE8,0xA2,0xFE,0xB0,0x08, +0xE8,0xB3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x7F,0xFD,0xE8,0x9A,0xFD,0xF8, +0xC3,0x90,0xB8,0x00,0x80,0xE8,0x57,0xFD,0xE8,0x8E,0xFD,0xE8,0x82,0xFE,0xB0,0x02, +0xE8,0x93,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x5F,0xFD,0xE8,0x7A,0xFD,0xF8, +0xC3,0x90,0xB8,0x00,0x20,0xE8,0x37,0xFD,0xE8,0x6E,0xFD,0xE8,0x62,0xFE,0xB0,0x04, +0xE8,0x73,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x3F,0xFD,0xE8,0x5A,0xFD,0xF8, +0xC3,0x90,0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8, +0xC3,0x90,0xB8,0xDE,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3, +0xE4,0x12,0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xCF, +0xFC,0xF8,0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06, +0x83,0x4E,0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xE5,0xFB,0xF8,0xC3,0x90, +0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E, +0x26,0x01,0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46, +0xF9,0xC3,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C, +0x81,0x4E,0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4, +0x3C,0x24,0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64, +0xA9,0x01,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74, +0x0F,0xE4,0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90, +0xE4,0x3E,0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0x02,0xFD,0xB8, +0x8C,0x40,0xEB,0xE6,0xE8,0x88,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90, +0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90, +0xE8,0x82,0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36, +0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01, +0x00,0x74,0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB, +0x02,0xB0,0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24, +0xF8,0x0A,0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8, +0xFA,0xFE,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x73,0xFB,0x32,0xC0,0x36,0x8A,0x26, +0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0, +0xE8,0xDB,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x71,0xF9,0x36,0xA1,0xB6, +0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0xD2,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8, +0x05,0x25,0x02,0x00,0xE8,0x1F,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04, +0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xC6,0xFA, +0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE, +0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE, +0xF8,0xC3,0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6, +0xE4,0x14,0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A, +0xF8,0xC3,0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14, +0xF8,0xC3,0xAD,0x49,0x49,0xE8,0x7E,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49, +0x49,0xE8,0x72,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xC2, +0xF7,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0xB8,0xF7,0xF8,0xC3,0x90,0xAC,0x49, +0x84,0xC0,0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8, +0xC3,0xE4,0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0, +0xC0,0xE0,0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24, +0xE7,0x0A,0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86, +0xC0,0x00,0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08, +0xE4,0x12,0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49, +0xE8,0xF0,0xF6,0x73,0x03,0xE8,0x41,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04, +0x24,0xFD,0xE6,0x12,0xB8,0xF0,0x00,0xE8,0xA1,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8, +0x71,0xF7,0xE8,0xB4,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x71,0xFA,0x80,0x4E, +0x27,0x08,0xE8,0x5E,0xF7,0xE8,0xA1,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x7B,0xFA, +0x81,0x66,0x26,0xFF,0xF7,0xE8,0x4B,0xF7,0xE8,0x8E,0xFA,0xF8,0xC3,0x90,0xB8,0x10, +0x00,0xE8,0x4B,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x38,0xF7,0xE8,0x7B,0xFA,0xF8,0xC3, +0xB8,0x10,0x00,0xE8,0x55,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x25,0xF7,0xE8,0x68, +0xFA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06, +0x3C,0x0C,0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00, +0x20,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83, +0x4E,0x26,0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C, +0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x1F,0xF6, +0x58,0x72,0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50, +0xAD,0xE8,0x9C,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C, +0x89,0x86,0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74, +0x10,0x39,0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6, +0xEC,0x83,0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0x00,0xFB,0x33, +0xDB,0xE4,0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB, +0x02,0xA8,0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8, +0xE4,0xDA,0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02, +0x75,0x09,0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00, +0x74,0x09,0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE, +0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x76,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41, +0x77,0x1F,0x50,0xE8,0x69,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6, +0x0A,0x80,0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8, +0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A, +0x86,0xA5,0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8, +0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF, +0xEB,0xE7,0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0, +0xE4,0x14,0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02, +0xE6,0x42,0xF8,0xC3,0xE8,0xE9,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xEE,0xE3, +0xF8,0xC3,0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2, +0x06,0xB0,0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2, +0x02,0xEE,0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5, +0x00,0x74,0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02, +0xEE,0x80,0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26, +0x84,0xC0,0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86, +0xA5,0x00,0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02, +0x75,0xF7,0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86, +0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75, +0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80, +0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24, +0xFD,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C, +0x02,0xEB,0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18, +0x00,0x12,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00, +0x30,0x00,0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00, +0x0C,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00, +0x01,0x00,0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00, +0x32,0xE4,0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77, +0x2F,0xD1,0xE6,0x2E,0x8B,0x8C,0x14,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E, +0x94,0x00,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA, +0x06,0x8A,0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE, +0x5E,0x59,0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8, +0x52,0x51,0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8, +0x00,0xD0,0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8, +0x20,0x74,0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE, +0x89,0x46,0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC, +0x80,0xE4,0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06, +0xEE,0x83,0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04, +0x77,0x23,0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x08,0x2E,0x8A,0xA6,0xA8,0x00,0x8A, +0xDC,0x80,0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2, +0x06,0xEE,0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00, +0x8A,0xDC,0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83, +0xC2,0x06,0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C, +0x02,0x74,0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B, +0x46,0x3C,0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2, +0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89, +0x5E,0x38,0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3, +0x10,0x00,0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04, +0x88,0x86,0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00, +0x8B,0xDA,0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE, +0xEB,0xEA,0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD, +0xEB,0xDA,0xB0,0xFF,0xE8,0x6C,0xF2,0xE8,0xB1,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61, +0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35, +0xFF,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06, +0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE, +0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB, +0xE6,0x90,0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00, +0x24,0xFD,0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01, +0xFD,0x5B,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF, +0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49, +0xE8,0xE5,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x83,0xF5,0xE8,0xF9,0xFC,0xE8, +0x24,0xFF,0xB0,0x01,0xE8,0xBF,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x8B,0xF5, +0xE8,0xE5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x63,0xF5,0xE8,0xD9,0xFC,0xE8, +0x04,0xFF,0xB0,0x08,0xE8,0x9F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x6B,0xF5, +0xE8,0xC5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x43,0xF5,0xE8,0xB9,0xFC,0xE8, +0xE4,0xFE,0xB0,0x02,0xE8,0x7F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x4B,0xF5, +0xE8,0xA5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x23,0xF5,0xE8,0x99,0xFC,0xE8, +0xC4,0xFE,0xB0,0x04,0xE8,0x5F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x2B,0xF5, +0xE8,0x85,0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xDE, +0x3B,0x89,0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8, +0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40, +0xE8,0x2F,0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49, +0xA8,0x01,0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8, +0x8A,0xFD,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8, +0x00,0xEE,0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01, +0x83,0x4E,0x48,0x08,0xB0,0x06,0xE8,0xD5,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2, +0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC, +0xB4,0x0A,0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89, +0x46,0x64,0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04, +0x00,0x74,0x0D,0xB8,0xC4,0x3F,0xEB,0x0B,0xE8,0x06,0xF5,0xB8,0x8C,0x40,0xEB,0x03, +0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A, +0x24,0xFD,0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81, +0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x76,0xF5,0x75, +0x05,0xE8,0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34, +0x10,0xE8,0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE, +0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE, +0x36,0xA1,0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01, +0x00,0xE8,0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36, +0x8A,0x26,0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02, +0xFE,0xC0,0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36, +0xA1,0xB6,0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13, +0xC1,0xE8,0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01, +0x75,0x04,0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8, +0x8C,0xFC,0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8, +0x94,0xFE,0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8, +0x70,0xFE,0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04, +0x00,0x89,0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83, +0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA, +0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9, +0x04,0x00,0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8, +0xBE,0xFB,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86, +0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66, +0x26,0xFB,0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E, +0xA3,0x00,0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2, +0x08,0x3C,0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7, +0x00,0x24,0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7, +0x00,0x0C,0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2, +0x04,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83, +0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3, +0xAC,0x49,0xE8,0xCE,0xEE,0x73,0x03,0xE8,0x11,0xEF,0xF8,0xC3,0x8A,0x86,0xAF,0x00, +0x24,0x7F,0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x80,0xF2,0x81,0x66,0x26,0xFF,0xF3, +0xE8,0x23,0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x51,0xF2,0x80,0x4E, +0x27,0x08,0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x5B,0xF2, +0x81,0x66,0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10, +0x00,0xE8,0x2B,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3, +0xB8,0x10,0x00,0xE8,0x19,0xF2,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3, +0xAC,0x49,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8, +0x00,0xEE,0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24, +0xBF,0xEB,0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8, +0x20,0x74,0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34, +0x49,0x89,0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA, +0x89,0x7E,0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5, +0x00,0xA8,0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80, +0xEA,0x02,0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25, +0x89,0x7E,0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9, +0x03,0x85,0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1, +0xE0,0x03,0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83, +0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3, +0xEE,0x83,0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3, +0xB0,0x88,0x88,0x86,0xBC,0x00,0xE8,0xA6,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8, +0x02,0x74,0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74, +0x03,0x80,0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86, +0xA9,0x00,0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8, +0x04,0x8A,0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03, +0x80,0xCB,0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74, +0x03,0x80,0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x0D, +0xDC,0xF8,0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x02,0xDC,0xF8,0xC3,0xAC,0x49, +0x3C,0x02,0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3, +0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9, +0x00,0x04,0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2, +0x02,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08, +0x8A,0x86,0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8, +0xC3,0x90,0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xA0,0xDB,0xF8,0xC3, +0xB0,0xFF,0xE8,0xD9,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x8D, +0xDB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x6D,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01, +0x36,0xA0,0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49, +0x32,0xE4,0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8, +0x36,0x89,0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03, +0xC3,0x2B,0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66, +0x7A,0xFD,0xB8,0x00,0x00,0xE8,0x36,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25, +0x0F,0x00,0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00, +0xAA,0x85,0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x41,0xF0, +0xE8,0x44,0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3, +0xB0,0x13,0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E, +0x7A,0x10,0xEB,0xF4,0xE8,0xB5,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C, +0x19,0x77,0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90, +0x83,0x4E,0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03, +0xC3,0x89,0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0xB1,0xDA,0x49,0x46,0xF9, +0xC3,0x90,0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0xA3,0xDA,0xF8,0xC3,0x90,0x33,0xC0, +0xAC,0x49,0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4, +0x3D,0x0A,0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8, +0x5A,0x00,0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9, +0x64,0x00,0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x9F,0xEB,0xF8, +0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81, +0x4E,0x38,0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88, +0x86,0xAA,0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90, +0xFE,0x86,0xB6,0x00,0xB0,0x0A,0xE8,0x25,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00, +0xB0,0x0A,0xE8,0x19,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0x0D, +0xDA,0xF8,0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x34,0x36,0x33,0xC9,0xAD, +0x8B,0xF9,0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83, +0x7E,0x08,0x00,0x74,0x18,0x2E,0x80,0x3E,0x34,0x36,0x01,0x74,0x09,0x60,0xB0,0x04, +0xE8,0xBB,0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1, +0xE8,0x75,0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46, +0x38,0x40,0x00,0x74,0x05,0xE8,0xA1,0xEA,0xF8,0xC3,0xE8,0xA7,0xEA,0xF8,0xC3,0x90, +0x36,0xC6,0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12, +0xAC,0x49,0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90, +0xC0,0x26,0xC0,0x26,0xCE,0x26,0xD4,0x26,0xDA,0x26,0xE0,0x26,0xE6,0x26,0xF0,0x26, +0xF8,0x26,0x00,0x27,0x08,0x27,0x10,0x27,0x16,0x27,0xA0,0x34,0xA8,0x34,0xB4,0x34, +0x1C,0x27,0x5A,0x27,0x62,0x27,0x76,0x27,0x82,0x27,0x96,0x27,0xA2,0x27,0xB6,0x27, +0xC2,0x27,0xD6,0x27,0xE2,0x27,0xF2,0x27,0xCE,0x34,0xC0,0x26,0x00,0x28,0x08,0x28, +0x0E,0x28,0x14,0x28,0x1A,0x28,0x30,0x28,0x6C,0x28,0xE8,0x34,0x0A,0x35,0x7A,0x28, +0xA0,0x28,0xB4,0x28,0xC0,0x28,0xC8,0x28,0x36,0x35,0x44,0x35,0x4E,0x35,0xD0,0x28, +0xA2,0x29,0xAA,0x29,0xB0,0x29,0xC2,0x29,0x54,0x35,0x5A,0x35,0xD2,0x29,0xDE,0x29, +0x70,0x35,0xEA,0x29,0xF4,0x29,0xFE,0x29,0x92,0x35,0x18,0x2A,0x9E,0x35,0x3C,0x2A, +0x44,0x2A,0x4A,0x2A,0xAC,0x35,0x5E,0x2A,0xDA,0x35,0x6A,0x2A,0x88,0x2A,0x9A,0x2A, +0xAE,0x2A,0xC0,0x2A,0xD4,0x2A,0xE2,0x35,0xEC,0x2A,0x06,0x2B,0x06,0x36,0x1A,0x2B, +0x2E,0x2B,0x66,0x2B,0x10,0x36,0x1C,0x36,0x28,0x36,0x36,0x36,0xCA,0x2B,0x90,0x36, +0x22,0x2C,0x44,0x2C,0x98,0x36,0x52,0x28,0xC0,0x26,0xC0,0x26,0xB6,0x2E,0xCA,0x2E, +0xD2,0x2E,0xDA,0x2E,0xE2,0x2E,0xEC,0x2E,0xF4,0x2E,0xFC,0x2E,0x04,0x2F,0x0C,0x2F, +0x24,0x2F,0xA0,0x34,0xA8,0x34,0xB4,0x34,0x32,0x2F,0x6E,0x2F,0x76,0x2F,0x8A,0x2F, +0x96,0x2F,0xAA,0x2F,0xB6,0x2F,0xCA,0x2F,0xD6,0x2F,0xEA,0x2F,0xF6,0x2F,0xFE,0x2F, +0xCE,0x34,0xC0,0x26,0x06,0x30,0x12,0x30,0x1A,0x30,0x26,0x30,0x2E,0x30,0x44,0x30, +0x86,0x30,0xE8,0x34,0x0A,0x35,0x8C,0x30,0xB0,0x30,0xB8,0x30,0xCC,0x30,0xD4,0x30, +0x36,0x35,0x44,0x35,0x4E,0x35,0xDC,0x30,0xA4,0x31,0xA4,0x31,0xA6,0x31,0xDC,0x31, +0x54,0x35,0x5A,0x35,0xEC,0x31,0xF8,0x31,0x70,0x35,0x04,0x32,0x0E,0x32,0x18,0x32, +0x92,0x35,0x2C,0x32,0x9E,0x35,0x56,0x32,0x6E,0x32,0x7C,0x32,0xAC,0x35,0x80,0x32, +0xDA,0x35,0x8C,0x32,0xA8,0x32,0xBA,0x32,0xCE,0x32,0xE0,0x32,0xF0,0x32,0xE2,0x35, +0xF4,0x32,0x08,0x33,0x06,0x36,0x14,0x33,0x7C,0x33,0xC0,0x33,0x10,0x36,0x1C,0x36, +0x28,0x36,0x36,0x36,0x3E,0x34,0x90,0x36,0x8C,0x34,0x92,0x34,0x98,0x36,0x6E,0x30, +0xE3,0x28,0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xFD,0xE8,0x33,0xC0,0xAC,0x49, +0x3D,0x5B,0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xB0,0x36,0x72,0x0B, +0x85,0xC9,0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x7D,0xDA,0xE8,0xD6,0xE8,0x33,0xC0, +0xAC,0x49,0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x68,0x37, +0x72,0xD9,0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE, +0x84,0x00,0x00,0x74,0x08,0xB8,0x2A,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80, +0x00,0xCE,0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xCE,0x3C,0xEB, +0xE7,0xF7,0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E, +0x74,0x77,0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D, +0x47,0x47,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01, +0x00,0x75,0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46, +0x74,0xB0,0x0C,0xE8,0x58,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC, +0xE3,0xE3,0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E, +0x88,0x00,0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED, +0x2B,0x86,0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B, +0xDF,0x26,0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75, +0x24,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7, +0x86,0x88,0x00,0x00,0x00,0xB0,0x0C,0xE8,0xF4,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0, +0x00,0xE8,0xEA,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB, +0xD2,0x90,0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00, +0x8B,0x96,0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4, +0x00,0xF3,0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6, +0xFD,0x00,0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D, +0xBE,0xF4,0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6, +0x8D,0xB6,0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5, +0x5E,0x10,0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76, +0xFF,0x4E,0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D, +0xB6,0xF4,0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C, +0x85,0xDB,0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00, +0x2B,0xC2,0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83, +0x4E,0x7A,0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61, +0x1F,0xC3,0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88, +0x00,0x76,0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB, +0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1, +0x83,0xBE,0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10, +0x03,0x1F,0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4, +0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58, +0x8B,0x5E,0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6, +0x2B,0x86,0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2, +0xAE,0x74,0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4, +0x00,0xC7,0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01, +0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE, +0x4A,0x75,0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86, +0x82,0x00,0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00, +0xA4,0xFF,0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9, +0x5B,0xFF,0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x2B,0xCC,0x8B,0x46,0x74,0x39, +0x46,0x72,0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78, +0x09,0x03,0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29, +0x4E,0x76,0x01,0x4E,0x78,0xE8,0x51,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E, +0x10,0x26,0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA, +0xB8,0x03,0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E, +0x10,0x26,0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF, +0x46,0x76,0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83, +0x86,0x87,0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x7A,0x3B, +0x08,0x86,0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0xA1,0xD4,0x5B,0x58,0xC3, +0x50,0x8A,0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00, +0xE8,0xAB,0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8, +0xB4,0xFF,0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8, +0x6C,0xFF,0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xDE, +0x3B,0xC4,0x3B,0xD4,0x3B,0xD4,0x3B,0xDE,0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE, +0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,0x3B,0xC4,0x3B,0xC4,0x3B,0xC4,0x3B,0x00, +0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51, +0x53,0x8B,0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01, +0x8A,0xE0,0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E, +0x8B,0x87,0xDF,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0xFF,0x3B,0x89,0x4E,0x38,0xD1, +0xEB,0x2E,0x8A,0xA7,0x1F,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74, +0x20,0x3C,0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72, +0x37,0x74,0x3A,0xBB,0xBC,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0x82,0x3B,0xEB, +0xF5,0xBB,0x76,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xDE,0x3B,0xB4,0x02,0xEB,0xE9,0xBB, +0xC4,0x3B,0xB4,0x03,0xEB,0xE2,0xBB,0xA0,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xAC,0x3B, +0xAC,0x49,0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xB4,0x3B,0xEB,0xF3,0xBB,0xDE,0x3B, +0xEB,0xC4,0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E, +0x74,0x8B,0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8, +0x8B,0xC1,0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46, +0x7A,0x01,0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3, +0xA5,0x73,0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74, +0xC3,0x50,0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3, +0xAA,0xD1,0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3, +0xAB,0x49,0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2, +0xE5,0x9D,0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xE8,0xC9,0x8B, +0x5E,0x38,0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8, +0xD2,0xE3,0xEB,0x03,0xE8,0xC2,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74, +0x3C,0xF6,0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74, +0x11,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83, +0xEA,0x08,0xF6,0xC3,0x08,0x74,0x0F,0xE8,0xA5,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00, +0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00, +0x08,0x75,0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC, +0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02, +0x0C,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x61,0xD2,0xEB,0x0F,0xB0, +0x02,0xE8,0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0, +0x8E,0xD8,0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06, +0x92,0x12,0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A, +0x01,0xA8,0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x51, +0xD2,0xFB,0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46, +0x78,0x3D,0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66, +0x38,0xDF,0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75, +0x0F,0xE8,0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E, +0x3B,0x76,0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E, +0x00,0x00,0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89, +0x76,0x2C,0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF, +0x56,0x7C,0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x9F,0xD1,0xEB, +0x86,0x89,0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C, +0xE8,0x8B,0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04, +0x10,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +0xC0,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0x80,0x30,0x41,0x5A,0x41,0xB2,0x41,0xD6,0x41,0xE8,0x41, +0xFA,0x41,0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27, +0xFD,0x8B,0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA, +0x76,0x02,0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F, +0x75,0x1E,0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B, +0x4A,0x4A,0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4, +0x2B,0xD9,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01, +0xA4,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80, +0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03, +0x61,0xC3,0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46, +0x6A,0x89,0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48, +0xB0,0x06,0xE8,0xD9,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29, +0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD, +0xE8,0xD5,0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40, +0x00,0x75,0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83, +0xEA,0x0A,0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00, +0xE3,0xB4,0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xB6,0x3E,0x93,0x22, +0xDF,0x75,0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87, +0xB6,0x3E,0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF, +0x46,0x66,0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3, +0x2E,0xFF,0xA7,0xB6,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C, +0x89,0x46,0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A, +0x29,0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01, +0xC3,0x60,0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90, +0x8B,0x5E,0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00, +0x20,0x75,0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00, +0xAA,0xE9,0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68, +0x83,0xC3,0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18, +0x81,0xFB,0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00, +0x75,0x18,0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0, +0x04,0xE9,0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA, +0xE9,0xE3,0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9, +0xD4,0xFE,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74, +0x10,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0, +0x0A,0xAA,0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0, +0x07,0xE9,0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06, +0xB8,0xD0,0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68, +0x85,0xDB,0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE, +0x8B,0x5E,0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00, +0x75,0x1F,0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75, +0x06,0xB8,0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE, +0xAA,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00, +0x74,0x19,0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06, +0x76,0x02,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81, +0xFB,0x00,0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00, +0xE9,0x79,0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83, +0xF9,0x32,0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF, +0xDC,0x12,0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F, +0xC3,0xB0,0x08,0xE8,0x88,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0xAD,0xC4,0xE8, +0xC8,0xFF,0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74, +0x09,0x80,0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40, +0x00,0x74,0x1D,0xE8,0x4E,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA, +0x08,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1, +0xE8,0x26,0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6, +0x0C,0x5A,0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46, +0x26,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1, +0x06,0x74,0x23,0xE8,0xF3,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C, +0x9D,0xC3,0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xEA,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24, +0xFD,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26, +0x74,0x01,0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38, +0x40,0x00,0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0xAD,0xDD,0x8A,0xC1,0x24,0xFD, +0x0C,0x04,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8, +0xA2,0xDD,0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C, +0x02,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C, +0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E, +0xC5,0x76,0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00, +0xEB,0xCD,0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3, +0x6E,0x1F,0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02, +0x89,0x5E,0x26,0xE8,0x22,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE, +0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x30,0xCC,0x9D,0xC3, +0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B, +0xC8,0x76,0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27, +0xFD,0x8E,0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1, +0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B, +0xCA,0x80,0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8, +0xF6,0xFE,0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84, +0xC0,0x74,0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF, +0x89,0x46,0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01, +0xFB,0xB0,0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xD6,0xCB,0xFB,0x85,0xED,0x74, +0xE5,0xFA,0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C, +0x75,0xDE,0xA8,0x20,0x74,0x1A,0x50,0xE8,0x6F,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10, +0xB0,0x02,0xE8,0x79,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90, +0xA8,0x01,0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC, +0xB3,0xF0,0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2, +0xFD,0x73,0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A, +0xF6,0xC4,0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40, +0xE3,0x93,0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B, +0xC8,0x90,0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0, +0xE9,0x04,0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76, +0x40,0xE9,0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A, +0x89,0x76,0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46, +0x46,0x77,0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC, +0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75, +0x12,0xB0,0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84, +0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06, +0x01,0xEC,0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80, +0x74,0xE1,0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7, +0x06,0x24,0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73, +0x26,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x91, +0xCA,0x85,0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9, +0x36,0x72,0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00, +0x75,0xF6,0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8, +0xBF,0x24,0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x57,0xCA,0x85,0xED,0x75,0x06,0xE9, +0x12,0x01,0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC, +0x78,0x0E,0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2, +0x8A,0xA6,0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08, +0xAB,0x83,0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE, +0xB0,0x00,0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7, +0xAB,0x83,0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6, +0xB4,0x00,0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB, +0x8B,0x86,0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6, +0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xF5, +0xCB,0xAB,0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6, +0xB7,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8, +0xD4,0xCB,0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A, +0xA6,0xB8,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB, +0xA1,0x50,0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C, +0x8A,0xA6,0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F, +0xAB,0x8B,0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F, +0x84,0xDB,0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0x12,0xC9,0xE9,0xE7,0xFE,0xB0, +0x0A,0xE8,0x0A,0xC9,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4, +0xA3,0x22,0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72, +0x11,0xA3,0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13, +0xF8,0xC3,0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00, +0x86,0xC4,0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01, +0x01,0x00,0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49, +0x49,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6, +0x34,0x3B,0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xC8,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46, +0x4C,0x8A,0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9, +0x00,0x80,0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x70,0xC8,0x8A,0xB6, +0xBA,0x00,0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56, +0x3F,0x8A,0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2, +0x74,0x4B,0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03, +0xAB,0x80,0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01, +0x75,0x02,0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4, +0x04,0xF6,0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6, +0x04,0x74,0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA, +0x00,0x00,0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72, +0x11,0xA3,0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13, +0xF8,0xC3,0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12, +0x8B,0xC1,0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90, +0xBE,0xDC,0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3, +0xF9,0xC3,0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90, +0x90,0x90,0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90, +0x90,0x90,0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84, +0x12,0xC3,0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0xA3,0xC7,0x85, +0xED,0x74,0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85, +0xC0,0x78,0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1, +0x77,0x02,0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A, +0x46,0x4C,0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90, +0x41,0x80,0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40, +0x24,0xFE,0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3, +0x72,0x13,0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E, +0x74,0x02,0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C, +0x39,0x76,0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8, +0x27,0xBE,0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xCF,0xC6,0x33, +0xC0,0x8E,0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B, +0x06,0x88,0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3, +0x0B,0xE8,0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13, +0xE3,0x0B,0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66, +0x13,0xE3,0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28, +0x01,0xA9,0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D, +0xA1,0x84,0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E, +0x12,0x3B,0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF, +0x16,0x7C,0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93, +0x12,0x17,0x9C,0x0E,0xE8,0xD1,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C, +0x0E,0xE8,0xC4,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0xB7, +0xC8,0x90,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01, +0xED,0x90,0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8, +0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4, +0xC0,0x75,0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90, +0x90,0x90,0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B, +0x5E,0x50,0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E, +0xD1,0xE9,0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4, +0xEF,0x89,0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05, +0xB0,0x02,0xE8,0x99,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41, +0x80,0xE1,0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9, +0x60,0xFF,0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9, +0xF3,0x6D,0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6, +0x06,0x93,0x12,0x1B,0x9C,0x0E,0xE8,0xEF,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E, +0xD8,0x8E,0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2, +0x8C,0x12,0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12, +0x00,0xE8,0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00, +0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93, +0x12,0x1B,0x9C,0x0E,0xE8,0xA1,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E, +0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12, +0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8, +0x12,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86, +0xE0,0xEC,0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90, +0x05,0x00,0x57,0x47,0x8A,0x4B,0x05,0x00,0x57,0x48,0x8A,0x4B,0x05,0x00,0x85,0x48, +0x8A,0x4B,0x05,0x00,0x17,0x49,0x8A,0x4B,0x06,0x00,0x7A,0x48,0x78,0x4B,0x06,0x00, +0x9C,0x48,0x78,0x4B,0x06,0x00,0xA5,0x48,0x78,0x4B,0x06,0x00,0xAD,0x48,0x78,0x4B, +0x06,0x00,0x02,0x49,0x78,0x4B,0x06,0x00,0x0A,0x49,0x78,0x4B,0x06,0x00,0x30,0x4A, +0x7E,0x4B,0x06,0x00,0x5D,0x4A,0x7E,0x4B,0x05,0x00,0x80,0x4A,0x84,0x4B,0x05,0x00, +0xCE,0x4A,0x84,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0, +0x06,0x01,0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0x90, +0x4B,0x8B,0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06, +0xEB,0xEF,0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40, +0x01,0x8B,0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77, +0xF6,0xA3,0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E, +0x00,0x3B,0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C, +0x01,0x89,0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08, +0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04, +0x61,0x07,0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06, +0x89,0x66,0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8, +0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06, +0x60,0x9C,0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B, +0x4E,0x00,0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60, +0x89,0x66,0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E, +0x01,0x85,0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B, +0xD8,0x89,0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F, +0xF9,0xC3,0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B, +0xE1,0xEB,0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20, +0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41, +0x4E,0x53,0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A, +0x32,0x29,0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61, +0x73,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F, +0x64,0x65,0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F, +0x6E,0x69,0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D, +0x0A,0x50,0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64, +0x64,0x72,0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00, +0x0D,0x0A,0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41, +0x54,0x41,0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E, +0x69,0x74,0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D, +0x0A,0x20,0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78, +0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F, +0x72,0x79,0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78, +0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73, +0x69,0x6E,0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45, +0x2C,0x65,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20, +0x2D,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20, +0x20,0x20,0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78, +0x78,0x5D,0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79, +0x20,0x70,0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20, +0x49,0x5B,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x2D,0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72, +0x6F,0x6D,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78, +0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62, +0x79,0x74,0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70, +0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75, +0x74,0x20,0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A, +0x20,0x20,0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74, +0x65,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B, +0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D, +0x20,0x67,0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20, +0x20,0x20,0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D, +0x20,0x20,0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72, +0x64,0x0D,0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75, +0x70,0x74,0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69, +0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20, +0x20,0x73,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D, +0x0A,0x20,0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E, +0x74,0x20,0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65, +0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20, +0x20,0x20,0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65, +0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72, +0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70, +0x74,0x0D,0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65, +0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48, +0x2C,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x2D,0x20,0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B, +0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65, +0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B, +0x4A,0x00,0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44, +0x20,0x1B,0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00, +0x3B,0x00,0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B, +0x7F,0x1B,0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F, +0x1B,0x7A,0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65, +0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A, +0x00,0x1E,0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00, +0x0D,0x00,0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F, +0x6F,0x43,0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x1E, +0x60,0xB6,0x57,0xB6,0x57,0x32,0x58,0x32,0x58,0xB8,0x59,0xB8,0x59,0x96,0x59,0x96, +0x59,0x1E,0x60,0x1E,0x60,0x4E,0x57,0x2A,0x57,0x08,0x57,0xE8,0x56,0x72,0x57,0x72, +0x57,0x7A,0x57,0x2A,0x5F,0xEE,0x5E,0x3A,0x5F,0x15,0x5F,0x22,0x5F,0x82,0x57,0x82, +0x57,0xE0,0x59,0xE0,0x59,0xBE,0x57,0xBE,0x57,0x6A,0x61,0x7A,0x61,0xA2,0x61,0xAE, +0x61,0xBA,0x61,0xD8,0x61,0xE4,0x61,0x04,0x62,0xDA,0x56,0x2C,0x62,0x3A,0x62,0x42, +0x59,0x20,0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00, +0x20,0x20,0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78, +0x3D,0x00,0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20, +0x65,0x73,0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00, +0x20,0x20,0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70, +0x3D,0x00,0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D, +0x00,0x20,0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74, +0x72,0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F, +0x6D,0x61,0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74, +0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00, +0x20,0x74,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67, +0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70, +0x63,0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69, +0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20, +0x72,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D, +0x00,0x20,0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69, +0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F, +0x74,0x6F,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74, +0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00, +0x20,0x74,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A, +0x3D,0x00,0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66, +0x6C,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68, +0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20, +0x72,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D, +0x00,0x20,0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73, +0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F, +0x66,0x6C,0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70, +0x74,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00, +0x20,0x72,0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E, +0x3D,0x00,0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72, +0x61,0x6E,0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20, +0x71,0x5F,0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20, +0x71,0x5F,0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D, +0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F, +0x62,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E, +0x64,0x5F,0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20, +0x74,0x69,0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00, +0x20,0x63,0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64, +0x3D,0x00,0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61, +0x74,0x65,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F, +0x61,0x64,0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20, +0x63,0x5F,0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D, +0x00,0x20,0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78, +0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F, +0x6C,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20, +0x63,0x5F,0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00, +0x20,0x20,0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73, +0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73, +0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63, +0x5F,0x63,0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20, +0x63,0x5F,0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D, +0x00,0x20,0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B, +0x63,0x3D,0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63, +0x63,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63, +0x5F,0x73,0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00, +0xE8,0xE5,0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xBE,0x56,0x8C,0x4D,0x02,0xBF,0x0C, +0x00,0xC7,0x05,0x50,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0x9C,0x5E,0x8C, +0x4D,0x02,0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5, +0x00,0xBE,0x9C,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09, +0xEB,0xE4,0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79, +0x3C,0x0D,0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F, +0xE1,0x88,0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B, +0xDB,0x74,0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB, +0xC1,0x90,0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E, +0xA0,0xD6,0x79,0xBF,0x42,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE, +0x07,0x75,0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x5F,0x51,0x90,0x33,0xC0, +0xA3,0xF8,0x79,0xBE,0x6B,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x6F,0x4D,0xE8,0x80,0x0B, +0xEB,0xEC,0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93, +0xEE,0xB0,0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC, +0x3C,0xAA,0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20, +0xEE,0xB0,0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE, +0xB0,0x07,0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA, +0x04,0x02,0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00, +0x00,0xC6,0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79, +0x00,0x00,0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06, +0xFC,0x79,0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00, +0xC7,0x06,0x02,0x7A,0xB0,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00, +0xC7,0x06,0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00, +0xC3,0x90,0xBE,0x04,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77, +0xF7,0xE8,0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x4C,0x4D,0xE8,0xAF, +0x0A,0x0E,0x58,0xE8,0xF8,0x0A,0xBE,0x5C,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1, +0xE3,0x83,0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0x99, +0x51,0x8B,0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75, +0x05,0xE8,0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE, +0xD7,0x79,0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05, +0xE8,0x23,0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE, +0xD7,0x79,0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04, +0xE9,0xB7,0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E, +0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A, +0xB0,0x20,0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16, +0x06,0x7A,0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B, +0xD0,0xA3,0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67, +0x0B,0xC3,0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB, +0xC3,0x90,0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47, +0x0B,0xB0,0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8, +0x01,0x00,0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA, +0x06,0x02,0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06, +0x08,0x7A,0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09, +0xE8,0x0B,0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0x94, +0x4D,0xE8,0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8, +0x0C,0x0A,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD, +0x09,0x43,0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90, +0x26,0x8A,0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3, +0x09,0x43,0xE2,0xEC,0xBE,0x94,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75, +0xB7,0xC3,0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E, +0xFE,0x79,0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06, +0x08,0x7A,0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00, +0x00,0xE8,0xDE,0x00,0xBE,0x97,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0, +0x3A,0xE8,0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90, +0xE8,0xB7,0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF, +0x10,0xEB,0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C, +0x75,0x04,0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79, +0x8B,0xC7,0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE, +0x20,0x90,0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E, +0x75,0x08,0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32, +0xC9,0x90,0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42, +0x3C,0x46,0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE, +0x0E,0x0A,0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0, +0x74,0xF6,0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A, +0xC1,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9, +0x70,0xFF,0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D, +0xFF,0x90,0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A, +0xE8,0x0D,0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01, +0x75,0x06,0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C, +0x7A,0xE8,0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01, +0x75,0x06,0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E, +0x7A,0xE8,0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8, +0x3C,0x07,0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3, +0xBE,0x79,0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07, +0x8B,0xD8,0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00, +0xB8,0xFF,0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90, +0x06,0xBE,0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00, +0xBE,0x08,0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73, +0xF2,0xE8,0xE0,0x08,0xBE,0x11,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08, +0xBE,0x59,0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x35,0x52,0xE8, +0xC5,0x08,0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x3E,0x52,0xE8,0xB9,0x08,0x8B,0x47, +0x20,0xE8,0xA4,0x08,0xBE,0x50,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08, +0xBE,0x62,0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE, +0x1A,0x52,0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x23,0x52,0xE8,0x87,0x08, +0x8B,0x47,0x1A,0xE8,0x72,0x08,0xBE,0x2C,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8, +0x66,0x08,0xBE,0x47,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63, +0x08,0xBE,0xB3,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0x8F,0x52, +0xE8,0x54,0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0x98,0x52,0xE8,0x48,0x08,0x8B, +0x47,0x32,0xE8,0x33,0x08,0xBE,0x86,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27, +0x08,0xBE,0xA1,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08, +0xBE,0x6B,0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x74,0x52,0xE8, +0x15,0x08,0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x7D,0x52,0xE8,0x09,0x08,0x8B,0x47, +0x2C,0xE8,0xF4,0x07,0xBE,0xAA,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07, +0xBE,0xBC,0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xC5,0x52,0xE8, +0xE5,0x07,0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0xFB,0x52,0xE8,0xD6, +0x07,0x8B,0x47,0x48,0xE8,0xC1,0x07,0xBE,0xE0,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42, +0xE8,0xB5,0x07,0xBE,0xE9,0x52,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE, +0x5E,0x53,0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x67,0x53,0xE8,0xA6, +0x07,0x8B,0x47,0x4E,0xE8,0x91,0x07,0xBE,0x70,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50, +0xE8,0x85,0x07,0xE8,0x8E,0x07,0xBE,0x04,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8, +0x76,0x07,0xBE,0xCE,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xD7, +0x52,0xE8,0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0xF2,0x52,0xE8,0x67,0x07, +0x8B,0x47,0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x4C,0x53,0xE8,0x58,0x07,0x8B, +0x47,0x7A,0xE8,0x43,0x07,0xBE,0x1F,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37, +0x07,0xBE,0x28,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x31,0x53, +0xE8,0x34,0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x0D,0x53,0xE8, +0x25,0x07,0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x16,0x53,0xE8,0x19,0x07,0x8B,0x47, +0x10,0xE8,0x04,0x07,0xBE,0x3A,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06, +0xBE,0x43,0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x55,0x53,0xE8, +0xF5,0x06,0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x79,0x53,0xE8,0xE6, +0x06,0x8B,0x47,0x52,0xE8,0xD1,0x06,0xBE,0x82,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54, +0xE8,0xC5,0x06,0xBE,0x8B,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE, +0x94,0x53,0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0x9D,0x53,0xE8,0xB6, +0x06,0x8B,0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xA6,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C, +0xE8,0x95,0x06,0xE8,0x9E,0x06,0xBE,0xAF,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8, +0x86,0x06,0xBE,0xB8,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xC1, +0x53,0xE8,0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xCA,0x53,0xE8,0x77,0x06, +0x8B,0x47,0x7C,0xE8,0x62,0x06,0xBE,0xD3,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8, +0x56,0x06,0xBE,0xDC,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8, +0x52,0x06,0xBE,0x24,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE, +0xE5,0x53,0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0xEE,0x53,0xE8,0x36, +0x06,0x8B,0x47,0x6E,0xE8,0x21,0x06,0xBE,0xF7,0x53,0xE8,0x2A,0x06,0x8B,0x87,0x8E, +0x00,0xE8,0x14,0x06,0xBE,0x00,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07, +0x06,0xBE,0x09,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03, +0x06,0xBE,0x12,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x1B, +0x54,0xE8,0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x51,0x54,0xE8,0xE6, +0x05,0x8B,0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x3F,0x54,0xE8,0xD9,0x05,0x8A,0x87, +0xA0,0x00,0xE8,0xA7,0x05,0xBE,0x36,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B, +0x05,0xBE,0x48,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3, +0x05,0xBE,0x5A,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x63, +0x54,0xE8,0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x6C,0x54,0xE8,0x96, +0x05,0x8A,0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x75,0x54,0xE8,0x89,0x05,0x8A,0x87, +0xA5,0x00,0xE8,0x57,0x05,0xBE,0x7E,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8, +0x4A,0x05,0xBE,0x87,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE, +0x90,0x54,0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE, +0x99,0x54,0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xA2,0x54,0xE8, +0x45,0x05,0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xAB,0x54,0xE8,0x38,0x05,0x8A, +0x87,0xAB,0x00,0xE8,0x06,0x05,0xBE,0xB4,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00, +0xE8,0xF9,0x04,0xBE,0xBD,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04, +0xBE,0xC6,0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xCF,0x54, +0xE8,0x04,0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xD8,0x54, +0xE8,0xF4,0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xE1,0x54,0xE8,0xE7,0x04, +0x8A,0x87,0xB2,0x00,0xE8,0xB5,0x04,0xBE,0xEA,0x54,0xE8,0xDA,0x04,0x8A,0x87,0xB3, +0x00,0xE8,0xA8,0x04,0xBE,0xF3,0x54,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B, +0x04,0xE8,0xC0,0x04,0xBE,0xFC,0x54,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B, +0x04,0xBE,0x05,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x0E, +0x55,0xE8,0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3, +0x60,0x06,0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01, +0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81, +0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0xE2,0x5E,0xA3, +0x2B,0x7A,0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00, +0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16, +0x8B,0xEC,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E, +0xC0,0x89,0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8, +0x92,0x00,0xB8,0xE2,0x5E,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00, +0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61, +0xCF,0x90,0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53, +0x56,0x80,0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25, +0x02,0x8B,0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88, +0x07,0x5E,0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A, +0xC3,0x90,0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8, +0x08,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00, +0x74,0x0F,0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A, +0x00,0x5F,0xC3,0x90,0xBE,0x94,0x4D,0xE8,0x06,0x02,0xBE,0xBA,0x51,0xE8,0x00,0x02, +0xFF,0x76,0x14,0x58,0xE8,0x47,0x02,0xBE,0xC0,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E, +0x58,0xE8,0x3A,0x02,0xBE,0xC6,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D, +0x02,0xBE,0xCC,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0xF6, +0x51,0xE8,0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0xFC,0x51,0xE8,0xBF, +0x01,0xFF,0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xB1,0x51,0xE8,0xB2,0x01,0xFF,0x76, +0x1A,0x58,0xE8,0xF9,0x01,0xBE,0x94,0x4D,0xE8,0xA5,0x01,0xBE,0xD2,0x51,0xE8,0x9F, +0x01,0xFF,0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xD8,0x51,0xE8,0x92,0x01,0xFF,0x76, +0x02,0x58,0xE8,0xD9,0x01,0xBE,0xDE,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8, +0xCC,0x01,0xBE,0xE4,0x51,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE, +0xEA,0x51,0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0xF0,0x51,0xE8, +0x5E,0x01,0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x02,0x52,0xE8,0x51,0x01,0xFF, +0x76,0x16,0x58,0xE8,0x98,0x01,0xBE,0x6B,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xAB, +0x4D,0xE8,0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06, +0x0C,0x7A,0xAF,0x50,0xC7,0x06,0x0E,0x7A,0xD2,0x50,0xC7,0x06,0x10,0x7A,0xCA,0x50, +0xC7,0x06,0x12,0x7A,0xCE,0x50,0xC7,0x06,0x14,0x7A,0xD6,0x50,0xC7,0x06,0x16,0x7A, +0xDD,0x50,0xC7,0x06,0x18,0x7A,0xE5,0x50,0xC7,0x06,0x1A,0x7A,0xED,0x50,0xC7,0x06, +0x1C,0x7A,0xF0,0x50,0xC7,0x06,0x1E,0x7A,0xF2,0x50,0xC7,0x06,0x20,0x7A,0xF4,0x50, +0xC7,0x06,0x22,0x7A,0xF8,0x50,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01, +0xC6,0x06,0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0xFC,0x50,0xC7,0x06,0x0E,0x7A, +0x2F,0x51,0xC7,0x06,0x10,0x7A,0x29,0x51,0xC7,0x06,0x12,0x7A,0x2C,0x51,0xC7,0x06, +0x14,0x7A,0x31,0x51,0xC7,0x06,0x16,0x7A,0x33,0x51,0xC7,0x06,0x18,0x7A,0x37,0x51, +0xC7,0x06,0x1A,0x7A,0x38,0x51,0xC7,0x06,0x1C,0x7A,0x3B,0x51,0xC7,0x06,0x1E,0x7A, +0x3C,0x51,0xC7,0x06,0x20,0x7A,0x3D,0x51,0xC7,0x06,0x22,0x7A,0x40,0x51,0xC6,0x06, +0x24,0x7A,0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8, +0x79,0x48,0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75, +0x07,0x8E,0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79, +0x8A,0xF0,0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04, +0x80,0xC6,0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00, +0x8B,0xC7,0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90, +0x0A,0xC0,0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A, +0x2C,0x07,0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A, +0x98,0xC1,0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90, +0x06,0x8C,0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0, +0x74,0x06,0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33, +0xD2,0xB9,0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64, +0x00,0xF6,0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00, +0x8A,0xC4,0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4, +0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00, +0xC1,0xC0,0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xAC,0x62,0x2E, +0xD7,0xE8,0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8, +0x02,0x00,0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30, +0xE8,0x11,0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20, +0xE8,0x01,0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6, +0xFF,0x01,0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01, +0x75,0x08,0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC, +0x24,0x01,0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74, +0x09,0x60,0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04, +0x74,0x28,0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0, +0x77,0x46,0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06, +0x02,0xEE,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA, +0x06,0x02,0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08, +0x58,0x5A,0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02, +0x02,0xEC,0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33, +0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0, +0x80,0xE4,0x0F,0xBB,0xAC,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4, +0x2E,0xD7,0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8, +0xDA,0xFF,0xC3,0x90,0xBE,0x94,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB, +0xFF,0xEB,0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF, +0x04,0x00,0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00, +0x00,0x83,0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05, +0x8B,0xC7,0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8, +0x01,0x00,0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89, +0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E, +0xFF,0xA7,0x94,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14, +0xC7,0x46,0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8, +0xC2,0x0F,0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56, +0xE8,0x9B,0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83, +0xFF,0x04,0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00, +0x75,0x03,0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01, +0x00,0xE9,0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1, +0xE3,0x2E,0xFF,0xA7,0x84,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C, +0x58,0x0F,0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56, +0xE8,0x7E,0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59, +0x59,0xC7,0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00, +0x00,0x56,0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74, +0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C, +0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46, +0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8, +0xDC,0x07,0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB, +0x2C,0xC7,0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C, +0x58,0x09,0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0, +0x0B,0x59,0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE, +0x5F,0x5E,0xC9,0xC3,0xC6,0x63,0x45,0x64,0x45,0x64,0x45,0x64,0x45,0x64,0xCB,0x63, +0x08,0x64,0x33,0x64,0x5A,0x63,0x9C,0x63,0xA8,0x63,0x78,0x64,0xB4,0x63,0x4C,0x64, +0x4C,0x64,0x51,0x64,0x54,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B, +0x7E,0x08,0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06, +0x04,0x80,0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E, +0xF8,0xEB,0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75, +0xF2,0x83,0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89, +0x46,0xFC,0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59, +0x59,0xFF,0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF, +0x47,0x8A,0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A, +0x02,0x56,0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00, +0x00,0x56,0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09, +0x01,0x8B,0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A, +0xC6,0x44,0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6, +0x44,0x19,0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6, +0x44,0x1E,0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6, +0x44,0x5B,0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6, +0x44,0x60,0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7, +0x40,0x30,0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC, +0x00,0x00,0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E, +0xFC,0x04,0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44, +0x5A,0x98,0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C, +0xFA,0x8A,0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88, +0x46,0xFC,0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C, +0x59,0x68,0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38, +0x02,0x56,0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8, +0x18,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59, +0x59,0x0B,0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0, +0x74,0x02,0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9, +0xEF,0xFE,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46, +0x04,0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74, +0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88, +0x44,0x5C,0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44, +0x54,0x8A,0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01, +0x56,0xE8,0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59, +0x59,0x0B,0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xCB, +0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03, +0x2E,0xFF,0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E, +0x04,0xD1,0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44, +0x54,0xE9,0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88, +0x44,0x60,0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75, +0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8, +0xF7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF, +0xB7,0xC4,0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75, +0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8, +0xC7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF, +0xB7,0xB4,0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59, +0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xC3,0x6A,0xBF, +0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24, +0x07,0x88,0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D, +0xEB,0x00,0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7, +0xFD,0x02,0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59, +0x59,0x6A,0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36, +0xD1,0xE3,0x2E,0xFF,0xA7,0xBB,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F, +0xEB,0x24,0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88, +0x44,0x5D,0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22, +0xC2,0x88,0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1, +0xE3,0x8B,0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85, +0xFC,0x83,0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02, +0x8B,0x5C,0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A, +0x01,0x56,0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F, +0x02,0xD1,0xE3,0x2E,0xFF,0xA7,0xB3,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44, +0x02,0x8B,0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4, +0x00,0x3B,0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B, +0x44,0x02,0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40, +0x08,0xE9,0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02, +0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04, +0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47, +0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01, +0xBF,0x01,0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8, +0xB9,0x0C,0x00,0xBB,0x83,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43, +0xE2,0xF4,0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C, +0x02,0x03,0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40, +0x08,0x8B,0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B, +0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C, +0x06,0xE9,0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6, +0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B, +0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D, +0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA, +0x30,0x40,0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44, +0x5F,0x88,0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07, +0x3D,0x03,0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44, +0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59, +0x6A,0x01,0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74, +0x06,0x83,0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A, +0x44,0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59, +0x59,0x56,0xE8,0x6B,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83, +0xFB,0x03,0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x7B,0x6A,0x68,0xAC,0x02,0x56,0xE8, +0x17,0x06,0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB, +0x18,0x68,0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56, +0xE8,0xF6,0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59, +0x59,0xBF,0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A, +0x01,0x56,0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B, +0xF8,0x89,0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B, +0xF8,0x89,0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02, +0xEB,0x00,0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0xFB,0x69,0x06,0x6A,0x11, +0x6A,0x1C,0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43, +0x00,0x44,0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0xF9,0x68,0x36,0x6A,0x5C, +0x6A,0x87,0x69,0x34,0x69,0x76,0x69,0x4C,0x6A,0x49,0x69,0x34,0x69,0x61,0x69,0x49, +0x69,0x2E,0x69,0xD6,0x68,0x58,0x68,0x94,0x68,0xD0,0x68,0xD7,0x67,0xE2,0x67,0xF4, +0x67,0xD7,0x67,0x7F,0x67,0x8A,0x67,0x96,0x67,0x7F,0x67,0x00,0x00,0x01,0x00,0xF0, +0x10,0xE0,0x20,0xD0,0x30,0x09,0x68,0xD4,0x66,0xA5,0x67,0x05,0x67,0xF4,0x66,0xC8, +0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A, +0x09,0x8B,0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B, +0xC7,0x25,0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0, +0x00,0x75,0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44, +0x04,0x3B,0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00, +0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7, +0x44,0x02,0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC, +0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7, +0x25,0x00,0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00, +0x75,0x48,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE, +0x08,0x7E,0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00, +0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C, +0x09,0x8A,0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7, +0x87,0xFC,0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D, +0x00,0x30,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7, +0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D, +0x04,0x33,0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B, +0x56,0xFE,0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE, +0x88,0x44,0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14, +0x09,0xB8,0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06, +0x00,0x00,0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44, +0x58,0x04,0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56, +0x75,0x0A,0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89, +0x44,0x56,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00, +0xC1,0xE0,0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00, +0x2B,0xD8,0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00, +0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89, +0x56,0xFC,0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A, +0x19,0xFF,0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07, +0x5E,0xC9,0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98, +0x8B,0xF0,0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6, +0x00,0x7D,0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04, +0x8B,0x47,0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04, +0x8A,0x46,0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47, +0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE, +0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F, +0x61,0x02,0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00, +0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, +0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA, +0x33,0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA, +0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F, +0x59,0x02,0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74, +0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE, +0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33, +0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB, +0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61, +0x02,0x88,0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF, +0x76,0x04,0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04, +0xE8,0xC3,0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x1F,0x93,0x59,0x59,0x89, +0x56,0xF2,0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x32,0x93,0x59,0x59,0x89,0x56, +0xEE,0x89,0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4, +0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D, +0xC7,0x46,0xE4,0x01,0x00,0xE8,0x08,0xA1,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B, +0x46,0xFC,0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA, +0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4, +0x5E,0xF0,0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B, +0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4, +0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE, +0x9D,0x81,0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76, +0x01,0x59,0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59, +0x59,0x89,0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59, +0x02,0xC6,0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47, +0x83,0xFF,0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D, +0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6, +0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E, +0x00,0xEB,0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81, +0x7E,0xF6,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8, +0xEB,0x25,0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, +0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6, +0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4, +0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E, +0x00,0xEB,0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81, +0x7E,0xF4,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8, +0xEB,0x25,0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, +0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4, +0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1, +0xE3,0xFF,0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1, +0xE3,0xFF,0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF, +0x76,0x04,0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3, +0x2E,0xFF,0xA7,0xFD,0x6F,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB, +0x0C,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4, +0x00,0x74,0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xD5,0x6F,0xD7, +0x6F,0xE1,0x6F,0xD5,0x6F,0xEB,0x6F,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03, +0xF7,0xE1,0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06, +0xEB,0x0E,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59, +0x80,0x3C,0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76, +0x06,0xEB,0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59, +0x59,0x0B,0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D, +0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE, +0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74, +0x06,0x9D,0xE8,0xAB,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB, +0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98, +0x89,0x46,0xFE,0xE8,0x00,0xA2,0x89,0x46,0xFC,0xE8,0xFA,0xA1,0x2B,0x46,0xFC,0x3D, +0xB8,0x0B,0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE, +0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x62,0x9E,0xEB,0xD9, +0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8, +0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8, +0x03,0x01,0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF, +0x08,0x77,0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB, +0x79,0x90,0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77, +0x67,0xD1,0xE3,0x2E,0xFF,0xA7,0x91,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00, +0x59,0xB4,0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00, +0x8B,0xF8,0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0, +0x8B,0xFA,0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00, +0x59,0x88,0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8, +0x29,0x00,0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8, +0x19,0x00,0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9, +0xC3,0x28,0x71,0x88,0x71,0x2C,0x71,0x5C,0x71,0x66,0x71,0xC8,0x04,0x00,0x00,0x56, +0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA, +0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x71,0x9D,0xEB, +0xE9,0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9, +0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE, +0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24, +0x01,0x9D,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A, +0x98,0x89,0x46,0xFE,0xE8,0x9F,0xA0,0x89,0x46,0xFA,0xE8,0x99,0xA0,0x2B,0x46,0xFA, +0x3D,0xB8,0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE, +0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x02,0x9D,0xEB,0xDA, +0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3, +0x55,0x8B,0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50, +0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B, +0x56,0x04,0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14, +0x7C,0xF8,0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57, +0x8B,0x76,0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE, +0xBA,0x86,0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01, +0x83,0xC4,0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01, +0x50,0xE8,0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00, +0x89,0x46,0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2, +0x0C,0x3B,0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE, +0x83,0xF2,0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83, +0xF2,0x09,0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46, +0xFE,0x07,0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00, +0xF7,0xEA,0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6, +0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00, +0x5F,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B, +0xC6,0xC1,0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6, +0x83,0xF2,0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89, +0x46,0xFE,0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00, +0x52,0x50,0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50, +0xE8,0x9A,0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B, +0xEC,0x56,0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1, +0x10,0x2A,0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80, +0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59, +0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01, +0xE8,0x6D,0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6, +0xEB,0x24,0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01, +0x68,0x86,0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98, +0x25,0x01,0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01, +0xE8,0x2D,0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC, +0x56,0x57,0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8, +0x20,0x00,0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4, +0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80, +0x72,0x0C,0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00, +0x50,0x68,0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF, +0xFD,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF, +0x76,0x06,0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46, +0x04,0x46,0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59, +0x6A,0x00,0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B, +0xEC,0x56,0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00, +0x68,0x88,0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64, +0x00,0x7C,0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3, +0xC8,0x04,0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1, +0xE0,0xD1,0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46, +0xFC,0xEB,0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x50,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x4D,0x65,0x6E,0x75,0x00,0x42,0x65, +0x67,0x69,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x6F,0x72,0x74, +0x20,0x30,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x00,0x50,0x6F,0x72,0x74,0x20,0x32, +0x00,0x50,0x6F,0x72,0x74,0x20,0x33,0x00,0x50,0x6F,0x72,0x74,0x20,0x34,0x00,0x50, +0x6F,0x72,0x74,0x20,0x35,0x00,0x50,0x6F,0x72,0x74,0x20,0x36,0x00,0x50,0x6F,0x72, +0x74,0x20,0x37,0x00,0x50,0x6F,0x72,0x74,0x20,0x38,0x00,0x50,0x6F,0x72,0x74,0x20, +0x39,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x30,0x00,0x50,0x6F,0x72,0x74,0x20,0x31, +0x31,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x32,0x00,0x50,0x6F,0x72,0x74,0x20,0x31, +0x33,0x00,0x50,0x6F,0x72,0x74,0x20,0x31,0x34,0x00,0x50,0x6F,0x72,0x74,0x20,0x31, +0x35,0x00,0x9C,0x01,0xA3,0x01,0xAA,0x01,0xB1,0x01,0xB8,0x01,0xBF,0x01,0xC6,0x01, +0xCD,0x01,0xD4,0x01,0xDB,0x01,0xE2,0x01,0xEA,0x01,0xF2,0x01,0xFA,0x01,0x02,0x02, +0x0A,0x02,0x08,0x00,0x00,0x07,0x81,0x00,0x03,0x80,0x80,0x80,0x9F,0x91,0x95,0x91, +0x9F,0x00,0x03,0x81,0x84,0x8E,0x95,0x84,0x84,0x84,0x84,0x00,0x03,0x82,0x84,0x84, +0x84,0x84,0x95,0x8E,0x84,0x00,0x04,0x88,0x00,0xB2,0x0B,0xC6,0x0B,0xDA,0x0B,0xEE, +0x0B,0x02,0x0C,0x16,0x0C,0x2A,0x0C,0x3E,0x0C,0x52,0x0C,0x77,0x0C,0x9C,0x0C,0xBE, +0x0C,0xE0,0x0C,0x02,0x0D,0x01,0x80,0x20,0x54,0x65,0x73,0x74,0x20,0x50,0x61,0x73, +0x73,0x65,0x64,0x20,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01, +0x80,0x20,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67,0x20,0x52,0x78,0x20,0x44,0x61,0x74, +0x61,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20,0x42, +0x61,0x64,0x20,0x52,0x78,0x20,0x44,0x61,0x74,0x61,0x20,0x1F,0x20,0x50,0x72,0x65, +0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20,0x58,0x6D,0x74,0x72,0x20,0x42,0x75, +0x73,0x79,0x1F,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x02,0x00,0x01,0x80,0x20, +0x6E,0x6F,0x74,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x6C,0x79,0x1F,0x20,0x20, +0x69,0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x65,0x64,0x02,0x00,0x24,0x0D,0x2F, +0x0D,0x3A,0x0D,0x45,0x0D,0x50,0x0D,0x5B,0x0D,0x66,0x0D,0x71,0x0D,0x7C,0x0D,0x87, +0x0D,0x92,0x0D,0x9D,0x0D,0xA8,0x0D,0xB3,0x0D,0xBE,0x0D,0xC9,0x0D,0x53,0x80,0x2C, +0x32,0x54,0x44,0x20,0x53,0x86,0x2C,0x33,0x44,0x54,0x52,0x20,0x53,0x82,0x2C,0x33, +0x52,0x54,0x53,0x20,0x1F,0x53,0x81,0x2C,0x32,0x52,0x44,0x20,0x53,0x85,0x2C,0x32, +0x43,0x44,0x20,0x53,0x83,0x2C,0x33,0x43,0x54,0x53,0x20,0x53,0x84,0x2C,0x33,0x44, +0x53,0x52,0x20,0x53,0x87,0x2C,0x32,0x52,0x49,0x27,0x02,0x00,0x01,0x80,0x20,0x20, +0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x30,0x1F,0x27,0x53,0x85, +0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89, +0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x53,0x52, +0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x31,0x1F,0x27,0x53,0x84,0x2E,0x31,0x81, +0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C, +0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x43,0x54,0x53,0x20,0x2D,0x20, +0x70,0x69,0x6E,0x20,0x34,0x1F,0x27,0x53,0x83,0x2E,0x31,0x81,0x82,0x63,0x90,0x80, +0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27, +0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32, +0x32,0x1F,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84, +0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80, +0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x2F,0x38,0x1F, +0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86, +0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20, +0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x27,0x53,0x82,0x2E, +0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A, +0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F,0x27,0x53,0x81,0x2E,0x30,0x53,0x4D,0x81, +0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C, +0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,0x44,0x20,0x2D,0x20, +0x70,0x69,0x6E,0x20,0x33,0x1F,0x27,0x53,0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63, +0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E, +0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69, +0x6E,0x20,0x35,0x1F,0x27,0x53,0x85,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F, +0x27,0x53,0x84,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86, +0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20, +0x43,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x1F,0x27,0x53,0x83,0x2E, +0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A, +0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D, +0x20,0x28,0x6E,0x2E,0x63,0x2E,0x29,0x1F,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63, +0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E, +0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69, +0x6E,0x20,0x32,0x1F,0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x37,0x1F, +0x27,0x53,0x82,0x2E,0x31,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86, +0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20, +0x52,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x1F,0x27,0x53,0x81,0x2E, +0x30,0x53,0x4D,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88, +0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78, +0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x33,0x1F,0x27,0x53,0x80,0x2E,0x30,0x53, +0x4D,0x81,0x82,0x63,0x90,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A, +0x8B,0x8C,0x8D,0x8E,0x8F,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x43,0x44,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x85,0x2E, +0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F, +0x20,0x20,0x20,0x20,0x27,0x53,0x84,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x43,0x54,0x53,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x31,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x83,0x2E, +0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x28,0x6E,0x2E,0x63,0x2E,0x29,0x1F, +0x20,0x20,0x20,0x20,0x27,0x53,0x87,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x54,0x52,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x86,0x2E, +0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x37,0x1F, +0x20,0x20,0x20,0x20,0x27,0x53,0x82,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x81,0x2E, +0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27, +0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20, +0x33,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63, +0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20, +0x44,0x43,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x30,0x1F,0x20,0x20,0x20, +0x20,0x27,0x53,0x85,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85, +0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x44,0x53,0x52,0x20,0x2D,0x20,0x70, +0x69,0x6E,0x20,0x31,0x31,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x84,0x2E,0x31,0x81, +0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80, +0x20,0x20,0x43,0x54,0x53,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x34,0x1F,0x20,0x20, +0x20,0x20,0x27,0x53,0x83,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84, +0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x49,0x20,0x2D,0x20,0x70, +0x69,0x6E,0x20,0x32,0x32,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x87,0x2E,0x31,0x81, +0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80, +0x20,0x20,0x44,0x54,0x52,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x36,0x2F,0x38,0x1F, +0x20,0x20,0x20,0x20,0x27,0x53,0x86,0x2E,0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82, +0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x52,0x54,0x53,0x20, +0x2D,0x20,0x70,0x69,0x6E,0x20,0x35,0x1F,0x20,0x20,0x20,0x20,0x27,0x53,0x82,0x2E, +0x31,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00, +0x01,0x80,0x20,0x20,0x52,0x78,0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x32,0x1F, +0x20,0x20,0x20,0x20,0x27,0x53,0x81,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80, +0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x27,0x02,0x00,0x01,0x80,0x20,0x20,0x54,0x78, +0x44,0x20,0x2D,0x20,0x70,0x69,0x6E,0x20,0x33,0x1F,0x20,0x20,0x20,0x20,0x27,0x53, +0x80,0x2E,0x30,0x53,0x4D,0x81,0x82,0x63,0x88,0x80,0x81,0x82,0x83,0x84,0x85,0x86, +0x87,0x27,0x02,0x00,0x68,0x04,0x96,0x04,0xB6,0x03,0x3C,0x04,0x0E,0x04,0x89,0x03, +0x5C,0x03,0xE2,0x03,0x60,0x08,0x8A,0x08,0xBE,0x07,0x38,0x08,0x0E,0x08,0x95,0x07, +0x6C,0x07,0xE6,0x07,0x1C,0x05,0x74,0x05,0xFA,0x05,0xC4,0x04,0xF0,0x04,0xCC,0x05, +0xA0,0x05,0x48,0x05,0x78,0x06,0xC8,0x06,0x42,0x07,0x28,0x06,0x50,0x06,0x18,0x07, +0xF0,0x06,0xA0,0x06,0x00,0x00,0xF4,0x08,0xF4,0x08,0xD4,0x0D,0x04,0x09,0x04,0x09, +0x04,0x09,0x04,0x09,0x42,0x00,0x0C,0x09,0x1C,0x09,0xE5,0x0D,0x02,0x00,0x14,0x09, +0x04,0x09,0xF4,0x0D,0x43,0x00,0x1C,0x09,0x0C,0x09,0x05,0x0E,0x00,0x04,0x04,0x09, +0x14,0x09,0x12,0x0E,0x2C,0x09,0x2C,0x09,0x2C,0x09,0x2C,0x09,0x00,0x00,0x3C,0x09, +0x6C,0x09,0x1E,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x01,0x4C,0x09, +0x2C,0x09,0x2D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x02,0x5C,0x09, +0x3C,0x09,0x3D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0x00,0x03,0x6C,0x09, +0x4C,0x09,0x4D,0x0E,0x74,0x09,0x74,0x09,0x74,0x09,0x74,0x09,0xFF,0x00,0x2C,0x09, +0x5C,0x09,0x00,0x00,0x00,0x05,0x84,0x09,0xEC,0x09,0x5E,0x0E,0xF4,0x09,0xF4,0x09, +0xF4,0x09,0xF4,0x09,0x00,0x06,0x94,0x09,0x74,0x09,0x68,0x0E,0xAC,0x0A,0xAC,0x0A, +0xAC,0x0A,0xAC,0x0A,0x00,0x07,0xA4,0x09,0x84,0x09,0x72,0x0E,0xBC,0x0A,0xBC,0x0A, +0xBC,0x0A,0xBC,0x0A,0x00,0x08,0xB4,0x09,0x94,0x09,0x7C,0x0E,0xD4,0x0A,0xD4,0x0A, +0xD4,0x0A,0xD4,0x0A,0x00,0x0B,0xC4,0x09,0xA4,0x09,0x83,0x0E,0xFC,0x0A,0xFC,0x0A, +0xFC,0x0A,0xFC,0x0A,0x00,0x0C,0xD4,0x09,0xB4,0x09,0x90,0x0E,0x14,0x0B,0x14,0x0B, +0x14,0x0B,0x14,0x0B,0x00,0x02,0xE4,0x09,0xC4,0x09,0xA0,0x0E,0x2C,0x0B,0x2C,0x0B, +0x2C,0x0B,0x2C,0x0B,0x04,0x00,0xEC,0x09,0xD4,0x09,0x0E,0x00,0xFF,0x00,0x74,0x09, +0xE4,0x09,0x00,0x00,0x82,0x01,0xFC,0x09,0xA4,0x0A,0xAC,0x0E,0x82,0x02,0x04,0x0A, +0xF4,0x09,0xAF,0x0E,0x82,0x03,0x0C,0x0A,0xFC,0x09,0xB2,0x0E,0x82,0x04,0x14,0x0A, +0x04,0x0A,0xB6,0x0E,0x82,0x05,0x1C,0x0A,0x0C,0x0A,0xBC,0x0E,0x82,0x06,0x24,0x0A, +0x14,0x0A,0xC0,0x0E,0x82,0x07,0x2C,0x0A,0x1C,0x0A,0xC4,0x0E,0x82,0x08,0x34,0x0A, +0x24,0x0A,0xC8,0x0E,0x82,0x09,0x3C,0x0A,0x2C,0x0A,0xCC,0x0E,0x82,0x0A,0x44,0x0A, +0x34,0x0A,0xD1,0x0E,0x82,0x10,0x4C,0x0A,0x3C,0x0A,0xD6,0x0E,0x82,0x0B,0x54,0x0A, +0x44,0x0A,0xDB,0x0E,0x82,0x11,0x5C,0x0A,0x4C,0x0A,0xE0,0x0E,0x82,0x0C,0x64,0x0A, +0x54,0x0A,0xE5,0x0E,0x82,0x12,0x6C,0x0A,0x5C,0x0A,0xEA,0x0E,0x82,0x0D,0x74,0x0A, +0x64,0x0A,0xEF,0x0E,0x82,0x0E,0x7C,0x0A,0x6C,0x0A,0xF4,0x0E,0x82,0x0F,0x84,0x0A, +0x74,0x0A,0xFB,0x0E,0x82,0x13,0x8C,0x0A,0x7C,0x0A,0x02,0x0F,0x82,0x14,0x94,0x0A, +0x84,0x0A,0x09,0x0F,0x82,0x15,0x9C,0x0A,0x8C,0x0A,0x10,0x0F,0x82,0x16,0xA4,0x0A, +0x94,0x0A,0x17,0x0F,0x82,0x17,0xF4,0x09,0x9C,0x0A,0x1E,0x0F,0x82,0x02,0xB4,0x0A, +0xB4,0x0A,0x26,0x0F,0x82,0x03,0xAC,0x0A,0xAC,0x0A,0x2D,0x0F,0x82,0x00,0xC4,0x0A, +0xCC,0x0A,0x34,0x0F,0x82,0x01,0xCC,0x0A,0xBC,0x0A,0x3F,0x0F,0x82,0x02,0xBC,0x0A, +0xC4,0x0A,0x4D,0x0F,0x82,0x00,0xDC,0x0A,0xF4,0x0A,0x59,0x0F,0x82,0x01,0xE4,0x0A, +0xD4,0x0A,0x63,0x0F,0x82,0x02,0xEC,0x0A,0xDC,0x0A,0x6E,0x0F,0x82,0x03,0xF4,0x0A, +0xE4,0x0A,0x7A,0x0F,0x82,0x04,0xD4,0x0A,0xEC,0x0A,0x87,0x0F,0x82,0x00,0x04,0x0B, +0x0C,0x0B,0x93,0x0F,0x82,0x01,0x0C,0x0B,0xFC,0x0A,0x9B,0x0F,0x82,0x02,0xFC,0x0A, +0x04,0x0B,0xA7,0x0F,0x82,0x00,0x1C,0x0B,0x24,0x0B,0xB0,0x0F,0x82,0x01,0x24,0x0B, +0x14,0x0B,0xB5,0x0F,0x82,0x02,0x14,0x0B,0x1C,0x0B,0xBE,0x0F,0x44,0x00,0x34,0x0B, +0xA4,0x0B,0x9C,0x01,0x44,0x01,0x3C,0x0B,0x2C,0x0B,0xA3,0x01,0x44,0x02,0x44,0x0B, +0x34,0x0B,0xAA,0x01,0x44,0x03,0x4C,0x0B,0x3C,0x0B,0xB1,0x01,0x44,0x04,0x54,0x0B, +0x44,0x0B,0xB8,0x01,0x44,0x05,0x5C,0x0B,0x4C,0x0B,0xBF,0x01,0x44,0x06,0x64,0x0B, +0x54,0x0B,0xC6,0x01,0x44,0x07,0x6C,0x0B,0x5C,0x0B,0xCD,0x01,0x44,0x08,0x74,0x0B, +0x64,0x0B,0xD4,0x01,0x44,0x09,0x7C,0x0B,0x6C,0x0B,0xDB,0x01,0x44,0x0A,0x84,0x0B, +0x74,0x0B,0xE2,0x01,0x44,0x0B,0x8C,0x0B,0x7C,0x0B,0xEA,0x01,0x44,0x0C,0x94,0x0B, +0x84,0x0B,0xF2,0x01,0x44,0x0D,0x9C,0x0B,0x8C,0x0B,0xFA,0x01,0x44,0x0E,0xA4,0x0B, +0x94,0x0B,0x02,0x02,0x44,0x0F,0x2C,0x0B,0x9C,0x0B,0x0A,0x02,0x17,0x1F,0x0F,0x2F, +0x00,0x00,0x01,0x80,0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A, +0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80,0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63, +0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80,0x78,0x78,0x3A,0x20, +0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0x80, +0x78,0x78,0x3A,0x20,0x74,0x78,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A, +0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A, +0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63, +0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0,0x78,0x78,0x3A,0x20, +0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A,0x02,0x00,0x01,0xC0, +0x78,0x78,0x3A,0x20,0x72,0x63,0x20,0x63,0x70,0x73,0x20,0x2A,0x2A,0x2A,0x2A,0x2A, +0x02,0x00,0x01,0x80,0x49,0x6E,0x73,0x74,0x61,0x6C,0x6C,0x20,0x4C,0x6F,0x6F,0x70, +0x62,0x61,0x63,0x6B,0x1F,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x74,0x6F,0x20, +0x73,0x74,0x61,0x72,0x74,0x02,0x00,0x01,0x80,0x20,0x43,0x61,0x62,0x6C,0x65,0x20, +0x74,0x6F,0x20,0x52,0x65,0x6D,0x6F,0x74,0x65,0x1F,0x50,0x72,0x65,0x73,0x73,0x20, +0x80,0x20,0x74,0x6F,0x20,0x73,0x74,0x61,0x72,0x74,0x02,0x00,0x01,0x80,0x20,0x4C, +0x6F,0x63,0x61,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x20,0x1F,0x20, +0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E,0x02,0x00,0x01,0x80, +0x52,0x65,0x6D,0x6F,0x74,0x65,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x20, +0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E,0x02,0x00, +0x01,0x80,0x20,0x49,0x6E,0x74,0x72,0x6E,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61, +0x63,0x6B,0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E,0x2E,0x2E, +0x02,0x00,0x01,0x80,0x54,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x20,0x50,0x61,0x74, +0x74,0x65,0x72,0x6E,0x1F,0x20,0x20,0x52,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x2E, +0x2E,0x2E,0x02,0x00,0x01,0x80,0x20,0x20,0x30,0x3A,0x20,0x27,0x43,0x80,0x00,0x01, +0x80,0x20,0x20,0x31,0x3A,0x20,0x27,0x43,0x81,0x00,0x01,0x80,0x20,0x20,0x32,0x3A, +0x20,0x27,0x43,0x82,0x00,0x01,0x80,0x20,0x20,0x33,0x3A,0x20,0x27,0x43,0x83,0x00, +0x01,0x80,0x20,0x20,0x34,0x3A,0x20,0x27,0x43,0x84,0x00,0x01,0x80,0x20,0x20,0x35, +0x3A,0x20,0x27,0x43,0x85,0x00,0x01,0x80,0x20,0x20,0x36,0x3A,0x20,0x27,0x43,0x86, +0x00,0x01,0x80,0x20,0x20,0x37,0x3A,0x20,0x27,0x43,0x87,0x00,0x01,0x80,0x20,0x20, +0x38,0x3A,0x20,0x27,0x43,0x88,0x00,0x01,0x80,0x20,0x20,0x39,0x3A,0x20,0x27,0x43, +0x89,0x00,0x01,0x80,0x20,0x31,0x30,0x3A,0x20,0x27,0x43,0x8A,0x00,0x01,0x80,0x20, +0x31,0x31,0x3A,0x20,0x27,0x43,0x8B,0x00,0x01,0x80,0x20,0x31,0x32,0x3A,0x20,0x27, +0x43,0x8C,0x00,0x01,0x80,0x20,0x31,0x33,0x3A,0x20,0x27,0x43,0x8D,0x00,0x01,0x80, +0x20,0x31,0x34,0x3A,0x20,0x27,0x43,0x8E,0x00,0x01,0x80,0x20,0x31,0x35,0x3A,0x20, +0x27,0x43,0x8F,0x00,0x2A,0x2A,0x20,0x4D,0x61,0x69,0x6E,0x20,0x20,0x4D,0x65,0x6E, +0x75,0x20,0x2A,0x2A,0x00,0x4D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x20,0x50, +0x6F,0x72,0x74,0x00,0x4D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x20,0x53,0x69, +0x67,0x6E,0x61,0x6C,0x00,0x45,0x73,0x74,0x69,0x6D,0x61,0x74,0x65,0x20,0x43,0x50, +0x53,0x00,0x44,0x69,0x61,0x67,0x6E,0x6F,0x73,0x74,0x69,0x63,0x73,0x00,0x4C,0x6F, +0x63,0x61,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x52,0x65,0x6D, +0x6F,0x74,0x65,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x49,0x6E,0x74, +0x72,0x6E,0x6C,0x20,0x4C,0x6F,0x6F,0x70,0x62,0x61,0x63,0x6B,0x00,0x54,0x72,0x61, +0x6E,0x73,0x6D,0x69,0x74,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x00,0x42,0x61, +0x75,0x64,0x20,0x52,0x61,0x74,0x65,0x00,0x44,0x61,0x74,0x61,0x20,0x42,0x69,0x74, +0x73,0x00,0x53,0x74,0x6F,0x70,0x20,0x42,0x69,0x74,0x73,0x00,0x50,0x61,0x72,0x69, +0x74,0x79,0x00,0x44,0x61,0x74,0x61,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x00, +0x54,0x78,0x20,0x46,0x6C,0x6F,0x77,0x20,0x43,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x00, +0x50,0x6F,0x72,0x74,0x20,0x4E,0x75,0x6D,0x62,0x65,0x72,0x00,0x35,0x30,0x00,0x37, +0x35,0x00,0x31,0x31,0x30,0x00,0x31,0x33,0x34,0x2E,0x35,0x00,0x31,0x35,0x30,0x00, +0x32,0x30,0x30,0x00,0x33,0x30,0x30,0x00,0x36,0x30,0x30,0x00,0x31,0x32,0x30,0x30, +0x00,0x31,0x38,0x30,0x30,0x00,0x32,0x30,0x30,0x30,0x00,0x32,0x34,0x30,0x30,0x00, +0x33,0x36,0x30,0x30,0x00,0x34,0x38,0x30,0x30,0x00,0x37,0x32,0x30,0x30,0x00,0x39, +0x36,0x30,0x30,0x00,0x31,0x39,0x2C,0x32,0x30,0x30,0x00,0x33,0x38,0x2C,0x34,0x30, +0x30,0x00,0x35,0x36,0x2C,0x30,0x30,0x30,0x00,0x35,0x37,0x2C,0x36,0x30,0x30,0x00, +0x36,0x34,0x2C,0x30,0x30,0x30,0x00,0x37,0x36,0x2C,0x38,0x30,0x30,0x00,0x31,0x31, +0x35,0x2C,0x32,0x30,0x30,0x00,0x37,0x20,0x62,0x69,0x74,0x73,0x00,0x38,0x20,0x62, +0x69,0x74,0x73,0x00,0x31,0x20,0x73,0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x00,0x31, +0x2E,0x35,0x20,0x73,0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x73,0x00,0x32,0x20,0x73, +0x74,0x6F,0x70,0x20,0x62,0x69,0x74,0x73,0x00,0x6E,0x6F,0x20,0x70,0x61,0x72,0x69, +0x74,0x79,0x00,0x6F,0x64,0x64,0x20,0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x65,0x76, +0x65,0x6E,0x20,0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x73,0x70,0x61,0x63,0x65,0x20, +0x70,0x61,0x72,0x69,0x74,0x79,0x00,0x6D,0x61,0x72,0x6B,0x20,0x70,0x61,0x72,0x69, +0x74,0x79,0x00,0x43,0x6F,0x6C,0x75,0x6D,0x6E,0x73,0x00,0x42,0x61,0x72,0x62,0x65, +0x72,0x20,0x50,0x6F,0x6C,0x65,0x00,0x55,0x55,0x55,0x55,0x55,0x2E,0x2E,0x2E,0x00, +0x4E,0x6F,0x6E,0x65,0x00,0x58,0x6F,0x6E,0x2F,0x58,0x6F,0x66,0x66,0x00,0x43,0x54, +0x53,0x00,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x66,0x6F,0x72,0x20,0x6D,0x65, +0x6E,0x75,0x00,0x28,0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x2E,0x2E,0x2E,0x29, +0x00,0x00,0x65,0x4E,0x64,0x20,0x4F,0x66,0x20,0x43,0x6F,0x44,0x65,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c --- v2.3.14/linux/drivers/char/ip2/i2cmd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2cmd.c Mon Aug 23 10:23:23 1999 @@ -0,0 +1,264 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Definition table for In-line and Bypass commands. Applicable +* only when the standard loadware is active. (This is included +* source code, not a separate compilation module.) +* +*******************************************************************************/ + +//------------------------------------------------------------------------------ +// +// Revision History: +// +// 10 October 1991 MAG First Draft +// 7 November 1991 MAG Reflects additional commands. +// 24 February 1992 MAG Additional commands for 1.4.x loadware +// 11 March 1992 MAG Additional commands +// 30 March 1992 MAG Additional command: CMD_DSS_NOW +// 18 May 1992 MAG Discovered commands 39 & 40 must be at the end of a +// packet: affects implementation. +//------------------------------------------------------------------------------ + +//************ +//* Includes * +//************ + +#include "i2cmd.h" /* To get some bit-defines */ + +//------------------------------------------------------------------------------ +// Here is the table of global arrays which represent each type of command +// supported in the IntelliPort standard loadware. See also i2cmd.h +// for a more complete explanation of what is going on. +//------------------------------------------------------------------------------ + +// Here are the various globals: note that the names are not used except through +// the macros defined in i2cmd.h. Also note that although they are character +// arrays here (for extendability) they are cast to structure pointers in the +// i2cmd.h macros. See i2cmd.h for flags definitions. + +// Length Flags Command +static UCHAR ct02[] = { 1, BTH, 0x02 }; // DTR UP +static UCHAR ct03[] = { 1, BTH, 0x03 }; // DTR DN +static UCHAR ct04[] = { 1, BTH, 0x04 }; // RTS UP +static UCHAR ct05[] = { 1, BTH, 0x05 }; // RTS DN +static UCHAR ct06[] = { 1, BYP, 0x06 }; // START FL +static UCHAR ct07[] = { 2, BTH, 0x07,0 }; // BAUD +static UCHAR ct08[] = { 2, BTH, 0x08,0 }; // BITS +static UCHAR ct09[] = { 2, BTH, 0x09,0 }; // STOP +static UCHAR ct10[] = { 2, BTH, 0x0A,0 }; // PARITY +static UCHAR ct11[] = { 2, BTH, 0x0B,0 }; // XON +static UCHAR ct12[] = { 2, BTH, 0x0C,0 }; // XOFF +static UCHAR ct13[] = { 1, BTH, 0x0D }; // STOP FL +static UCHAR ct14[] = { 1, BYP|VIP, 0x0E }; // ACK HOTK +//static UCHAR ct15[]={ 2, BTH|VIP, 0x0F,0 }; // IRQ SET +static UCHAR ct16[] = { 2, INL, 0x10,0 }; // IXONOPTS +static UCHAR ct17[] = { 2, INL, 0x11,0 }; // OXONOPTS +static UCHAR ct18[] = { 1, INL, 0x12 }; // CTSENAB +static UCHAR ct19[] = { 1, BTH, 0x13 }; // CTSDSAB +static UCHAR ct20[] = { 1, INL, 0x14 }; // DCDENAB +static UCHAR ct21[] = { 1, BTH, 0x15 }; // DCDDSAB +static UCHAR ct22[] = { 1, BTH, 0x16 }; // DSRENAB +static UCHAR ct23[] = { 1, BTH, 0x17 }; // DSRDSAB +static UCHAR ct24[] = { 1, BTH, 0x18 }; // RIENAB +static UCHAR ct25[] = { 1, BTH, 0x19 }; // RIDSAB +static UCHAR ct26[] = { 2, BTH, 0x1A,0 }; // BRKENAB +static UCHAR ct27[] = { 1, BTH, 0x1B }; // BRKDSAB +//static UCHAR ct28[]={ 2, BTH, 0x1C,0 }; // MAXBLOKSIZE +//static UCHAR ct29[]={ 2, 0, 0x1D,0 }; // reserved +static UCHAR ct30[] = { 1, INL, 0x1E }; // CTSFLOWENAB +static UCHAR ct31[] = { 1, INL, 0x1F }; // CTSFLOWDSAB +static UCHAR ct32[] = { 1, INL, 0x20 }; // RTSFLOWENAB +static UCHAR ct33[] = { 1, INL, 0x21 }; // RTSFLOWDSAB +static UCHAR ct34[] = { 2, BTH, 0x22,0 }; // ISTRIPMODE +static UCHAR ct35[] = { 2, BTH|END, 0x23,0 }; // SENDBREAK +static UCHAR ct36[] = { 2, BTH, 0x24,0 }; // SETERRMODE +//static UCHAR ct36a[]={ 3, INL, 0x24,0,0 }; // SET_REPLACE + +// The following is listed for completeness, but should never be sent directly +// by user-level code. It is sent only by library routines in response to data +// movement. +//static UCHAR ct37[]={ 5, BYP|VIP, 0x25,0,0,0,0 }; // FLOW PACKET + +// Back to normal +static UCHAR ct38[] = {11, BTH|VAR, 0x26,0,0,0,0,0,0,0,0,0,0 }; // DEF KEY SEQ +//static UCHAR ct39[]={ 3, BTH|END, 0x27,0,0 }; // OPOSTON +//static UCHAR ct40[]={ 1, BTH|END, 0x28 }; // OPOSTOFF +static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME +//static UCHAR ct42[]={ 2, BTH, 0x2A,0 }; // TXBAUD +//static UCHAR ct43[]={ 2, BTH, 0x2B,0 }; // RXBAUD +//static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING +//static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB +//static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB +static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS +//static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB +//static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB +//static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB +//static UCHAR ct51[]={ 1, BTH, 0x33 }; // DTRFLOWDSAB +//static UCHAR ct52[]={ 1, BTH, 0x34 }; // BAUDTABRESET +static UCHAR ct53[] = { 3, BTH, 0x35,0,0 }; // BAUDREMAP +static UCHAR ct54[] = { 3, BTH, 0x36,0,0 }; // CUSTOMBAUD1 +static UCHAR ct55[] = { 3, BTH, 0x37,0,0 }; // CUSTOMBAUD2 +static UCHAR ct56[] = { 2, BTH|END, 0x38,0 }; // PAUSE +static UCHAR ct57[] = { 1, BYP, 0x39 }; // SUSPEND +static UCHAR ct58[] = { 1, BYP, 0x3A }; // UNSUSPEND +static UCHAR ct59[] = { 2, BTH, 0x3B,0 }; // PARITYCHK +static UCHAR ct60[] = { 1, INL|VIP, 0x3C }; // BOOKMARKREQ +//static UCHAR ct61[]={ 2, BTH, 0x3D,0 }; // INTERNALLOOP +//static UCHAR ct62[]={ 2, BTH, 0x3E,0 }; // HOTKTIMEOUT +static UCHAR ct63[] = { 2, INL, 0x3F,0 }; // SETTXON +static UCHAR ct64[] = { 2, INL, 0x40,0 }; // SETTXOFF +//static UCHAR ct65[]={ 2, BTH, 0x41,0 }; // SETAUTORTS +//static UCHAR ct66[]={ 2, BTH, 0x42,0 }; // SETHIGHWAT +//static UCHAR ct67[]={ 2, BYP, 0x43,0 }; // STARTSELFL +//static UCHAR ct68[]={ 2, INL, 0x44,0 }; // ENDSELFL +//static UCHAR ct69[]={ 1, BYP, 0x45 }; // HWFLOW_OFF +//static UCHAR ct70[]={ 1, BTH, 0x46 }; // ODSRFL_ENAB +//static UCHAR ct71[]={ 1, BTH, 0x47 }; // ODSRFL_DSAB +//static UCHAR ct72[]={ 1, BTH, 0x48 }; // ODCDFL_ENAB +//static UCHAR ct73[]={ 1, BTH, 0x49 }; // ODCDFL_DSAB +//static UCHAR ct74[]={ 2, BTH, 0x4A,0 }; // LOADLEVEL +//static UCHAR ct75[]={ 2, BTH, 0x4B,0 }; // STATDATA +//static UCHAR ct76[]={ 1, BYP, 0x4C }; // BREAK_ON +//static UCHAR ct77[]={ 1, BYP, 0x4D }; // BREAK_OFF +//static UCHAR ct78[]={ 1, BYP, 0x4E }; // GETFC +static UCHAR ct79[] = { 2, BYP, 0x4F,0 }; // XMIT_NOW +//static UCHAR ct80[]={ 4, BTH, 0x50,0,0,0 }; // DIVISOR_LATCH +//static UCHAR ct81[]={ 1, BYP, 0x51 }; // GET_STATUS +//static UCHAR ct82[]={ 1, BYP, 0x52 }; // GET_TXCNT +//static UCHAR ct83[]={ 1, BYP, 0x53 }; // GET_RXCNT +//static UCHAR ct84[]={ 1, BYP, 0x54 }; // GET_BOXIDS +//static UCHAR ct85[]={10, BYP, 0x55,0,0,0,0,0,0,0,0,0 }; // ENAB_MULT +//static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE +static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST +//static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD +//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +//static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO +//static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break + +// Some composite commands as well +//static UCHAR cc01[]={ 2, BTH, 0x02,0x04 }; // DTR & RTS UP +//static UCHAR cc02[]={ 2, BTH, 0x03,0x05 }; // DTR & RTS DN + +//******** +//* Code * +//******** + +//****************************************************************************** +// Function: i2cmdSetSeq(type, size, string) +// Parameters: type - sequence number +// size - length of sequence +// string - substitution string +// +// Returns: Pointer to command structure +// +// Description: +// +// This routine sets the parameters of command 38 Define Hot Key sequence (alias +// "special receive sequence"). Returns a pointer to the structure. Endeavours +// to be bullet-proof in that the sequence number is forced in range, and any +// out-of-range sizes are forced to zero. +//****************************************************************************** +cmdSyntaxPtr +i2cmdSetSeq(unsigned char type, unsigned char size, unsigned char *string) +{ + cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct38; + unsigned char *pc; + + pCM->cmd[1] = ((type > 0xf) ? 0xf : type); // Sequence number + size = ((size > 0x8) ? 0 : size); // size + pCM->cmd[2] = size; + pCM->length = 3 + size; // UPDATES THE LENGTH! + + pc = &(pCM->cmd[3]); + + while(size--) { + *pc++ = *string++; + } + return pCM; +} + +//****************************************************************************** +// Function: i2cmdUnixFlags(iflag, cflag, lflag) +// Parameters: Unix tty flags +// +// Returns: Pointer to command structure +// +// Description: +// +// This routine sets the parameters of command 47 and returns a pointer to the +// appropriate structure. +//****************************************************************************** +cmdSyntaxPtr +i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) +{ + cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct47; + + pCM->cmd[1] = (unsigned char) iflag; + pCM->cmd[2] = (unsigned char) (iflag >> 8); + pCM->cmd[3] = (unsigned char) cflag; + pCM->cmd[4] = (unsigned char) (cflag >> 8); + pCM->cmd[5] = (unsigned char) lflag; + pCM->cmd[6] = (unsigned char) (lflag >> 8); + return pCM; +} + +//****************************************************************************** +// Function: i2cmdBaudRemap(dest,src) +// Parameters: ? +// +// Returns: Pointer to command structure +// +// Description: +// +// This routine sets the parameters of command 53 and returns a pointer to the +// appropriate structure. +//****************************************************************************** +cmdSyntaxPtr +i2cmdBaudRemap(unsigned char dest, unsigned char src) +{ + cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct53; + + pCM->cmd[1] = dest; + pCM->cmd[2] = src; + return pCM; +} + +//****************************************************************************** +// Function: i2cmdBaudDef(which, rate) +// Parameters: ? +// +// Returns: Pointer to command structure +// +// Description: +// +// This routine sets the parameters of commands 54 or 55 (according to the +// argument which), and returns a pointer to the appropriate structure. +//****************************************************************************** +cmdSyntaxPtr +i2cmdBaudDef(int which, unsigned short rate) +{ + cmdSyntaxPtr pCM; + + switch(which) + { + case 1: + pCM = (cmdSyntaxPtr) ct54; + break; + default: + case 2: + pCM = (cmdSyntaxPtr) ct55; + break; + } + pCM->cmd[1] = (unsigned char) rate; + pCM->cmd[2] = (unsigned char) (rate >> 8); + return pCM; +} + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2cmd.h linux/drivers/char/ip2/i2cmd.h --- v2.3.14/linux/drivers/char/ip2/i2cmd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2cmd.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,660 @@ +/******************************************************************************* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Definitions and support for In-line and Bypass commands. +* Applicable only when the standard loadware is active. +* +*******************************************************************************/ +//------------------------------------------------------------------------------ +// Revision History: +// +// 10 October 1991 MAG First Draft +// 7 November 1991 MAG Reflects some new commands +// 20 February 1992 MAG CMD_HOTACK corrected: no argument. +// 24 February 1992 MAG Support added for new commands for 1.4.x loadware. +// 11 March 1992 MAG Additional commands. +// 16 March 1992 MAG Additional commands. +// 30 March 1992 MAG Additional command: CMD_DSS_NOW +// 18 May 1992 MAG Changed CMD_OPOST +// +//------------------------------------------------------------------------------ +#ifndef I2CMD_H // To prevent multiple includes +#define I2CMD_H 1 + +#include "ip2types.h" + +// This module is designed to provide a uniform method of sending commands to +// the board through command packets. The difficulty is, some commands take +// parameters, others do not. Furthermore, it is often useful to send several +// commands to the same channel as part of the same packet. (See also i2pack.h.) +// +// This module is designed so that the caller should not be responsible for +// remembering the exact syntax of each command, or at least so that the +// compiler could check things somewhat. I'll explain as we go... +// +// First, a structure which can embody the syntax of each type of command. +// +typedef struct _cmdSyntax +{ + UCHAR length; // Number of bytes in the command + UCHAR flags; // Information about the command (see below) + + // The command and its parameters, which may be of arbitrary length. Don't + // worry yet how the parameters will be initialized; macros later take care + // of it. Also, don't worry about the arbitrary length issue; this structure + // is never used to allocate space (see i2cmd.c). + UCHAR cmd[2]; +} cmdSyntax, *cmdSyntaxPtr; + +// Bit assignments for flags + +#define INL 1 // Set if suitable for inline commands +#define BYP 2 // Set if suitable for bypass commands +#define BTH (INL|BYP) // suitable for either! +#define END 4 // Set if this must be the last command in a block +#define VIP 8 // Set if this command is special in some way and really + // should only be sent from the library-level and not + // directly from user-level +#define VAR 0x10 // This command is of variable length! + +//----------------------------------- +// External declarations for i2cmd.c +//----------------------------------- +// Routine to set up parameters for the "define hot-key sequence" command. Since +// there is more than one parameter to assign, we must use a function rather +// than a macro (used usually). +// +extern cmdSyntaxPtr i2cmdSetSeq(UCHAR seqno, UCHAR size, UCHAR *string); +extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag); +extern cmdSyntaxPtr i2cmdBaudRemap(UCHAR dest, UCHAR src); +extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate); + +// Declarations for the global arrays used to bear the commands and their +// arguments. +// +// Note: Since these are globals and the arguments might change, it is important +// that the library routine COPY these into buffers from whence they would be +// sent, rather than merely storing the pointers. In multi-threaded +// environments, important that the copy should obtain before any context switch +// is allowed. Also, for parameterized commands, DO NOT ISSUE THE SAME COMMAND +// MORE THAN ONCE WITH THE SAME PARAMETERS in the same call. +// +static UCHAR ct02[]; +static UCHAR ct03[]; +static UCHAR ct04[]; +static UCHAR ct05[]; +static UCHAR ct06[]; +static UCHAR ct07[]; +static UCHAR ct08[]; +static UCHAR ct09[]; +static UCHAR ct10[]; +static UCHAR ct11[]; +static UCHAR ct12[]; +static UCHAR ct13[]; +static UCHAR ct14[]; +static UCHAR ct15[]; +static UCHAR ct16[]; +static UCHAR ct17[]; +static UCHAR ct18[]; +static UCHAR ct19[]; +static UCHAR ct20[]; +static UCHAR ct21[]; +static UCHAR ct22[]; +static UCHAR ct23[]; +static UCHAR ct24[]; +static UCHAR ct25[]; +static UCHAR ct26[]; +static UCHAR ct27[]; +static UCHAR ct28[]; +static UCHAR ct29[]; +static UCHAR ct30[]; +static UCHAR ct31[]; +static UCHAR ct32[]; +static UCHAR ct33[]; +static UCHAR ct34[]; +static UCHAR ct35[]; +static UCHAR ct36[]; +static UCHAR ct36a[]; +static UCHAR ct41[]; +static UCHAR ct42[]; +static UCHAR ct43[]; +static UCHAR ct44[]; +static UCHAR ct45[]; +static UCHAR ct46[]; +static UCHAR ct48[]; +static UCHAR ct49[]; +static UCHAR ct50[]; +static UCHAR ct51[]; +static UCHAR ct52[]; +static UCHAR ct56[]; +static UCHAR ct57[]; +static UCHAR ct58[]; +static UCHAR ct59[]; +static UCHAR ct60[]; +static UCHAR ct61[]; +static UCHAR ct62[]; +static UCHAR ct63[]; +static UCHAR ct64[]; +static UCHAR ct65[]; +static UCHAR ct66[]; +static UCHAR ct67[]; +static UCHAR ct68[]; +static UCHAR ct69[]; +static UCHAR ct70[]; +static UCHAR ct71[]; +static UCHAR ct72[]; +static UCHAR ct73[]; +static UCHAR ct74[]; +static UCHAR ct75[]; +static UCHAR ct76[]; +static UCHAR ct77[]; +static UCHAR ct78[]; +static UCHAR ct79[]; +static UCHAR ct80[]; +static UCHAR ct81[]; +static UCHAR ct82[]; +static UCHAR ct83[]; +static UCHAR ct84[]; +static UCHAR ct85[]; +static UCHAR ct86[]; +static UCHAR ct87[]; +static UCHAR ct88[]; +static UCHAR ct89[]; +static UCHAR ct90[]; +static UCHAR ct91[]; +static UCHAR cc01[]; +static UCHAR cc02[]; + +// Now, refer to i2cmd.c, and see the character arrays defined there. They are +// cast here to cmdSyntaxPtr. +// +// There are library functions for issuing bypass or inline commands. These +// functions take one or more arguments of the type cmdSyntaxPtr. The routine +// then can figure out how long each command is supposed to be and easily add it +// to the list. +// +// For ease of use, we define manifests which return pointers to appropriate +// cmdSyntaxPtr things. But some commands also take arguments. If a single +// argument is used, we define a macro which performs the single assignment and +// (through the expedient of a comma expression) references the appropriate +// pointer. For commands requiring several arguments, we actually define a +// function to perform the assignments. + +#define CMD_DTRUP (cmdSyntaxPtr)(ct02) // Raise DTR +#define CMD_DTRDN (cmdSyntaxPtr)(ct03) // Lower DTR +#define CMD_RTSUP (cmdSyntaxPtr)(ct04) // Raise RTS +#define CMD_RTSDN (cmdSyntaxPtr)(ct05) // Lower RTS +#define CMD_STARTFL (cmdSyntaxPtr)(ct06) // Start Flushing Data + +#define CMD_DTRRTS_UP (cmdSyntaxPtr)(cc01) // Raise DTR and RTS +#define CMD_DTRRTS_DN (cmdSyntaxPtr)(cc02) // Lower DTR and RTS + +// Set Baud Rate for transmit and receive +#define CMD_SETBAUD(arg) \ + (((cmdSyntaxPtr)(ct07))->cmd[1] = (arg),(cmdSyntaxPtr)(ct07)) + +#define CBR_50 1 +#define CBR_75 2 +#define CBR_110 3 +#define CBR_134 4 +#define CBR_150 5 +#define CBR_200 6 +#define CBR_300 7 +#define CBR_600 8 +#define CBR_1200 9 +#define CBR_1800 10 +#define CBR_2400 11 +#define CBR_4800 12 +#define CBR_9600 13 +#define CBR_19200 14 +#define CBR_38400 15 +#define CBR_2000 16 +#define CBR_3600 17 +#define CBR_7200 18 +#define CBR_56000 19 +#define CBR_57600 20 +#define CBR_64000 21 +#define CBR_76800 22 +#define CBR_115200 23 +#define CBR_C1 24 // Custom baud rate 1 +#define CBR_C2 25 // Custom baud rate 2 +#define CBR_153600 26 +#define CBR_230400 27 +#define CBR_307200 28 +#define CBR_460800 29 +#define CBR_921600 30 + +// Set Character size +// +#define CMD_SETBITS(arg) \ + (((cmdSyntaxPtr)(ct08))->cmd[1] = (arg),(cmdSyntaxPtr)(ct08)) + +#define CSZ_5 0 +#define CSZ_6 1 +#define CSZ_7 2 +#define CSZ_8 3 + +// Set number of stop bits +// +#define CMD_SETSTOP(arg) \ + (((cmdSyntaxPtr)(ct09))->cmd[1] = (arg),(cmdSyntaxPtr)(ct09)) + +#define CST_1 0 +#define CST_15 1 // 1.5 stop bits +#define CST_2 2 + +// Set parity option +// +#define CMD_SETPAR(arg) \ + (((cmdSyntaxPtr)(ct10))->cmd[1] = (arg),(cmdSyntaxPtr)(ct10)) + +#define CSP_NP 0 // no parity +#define CSP_OD 1 // odd parity +#define CSP_EV 2 // Even parity +#define CSP_SP 3 // Space parity +#define CSP_MK 4 // Mark parity + +// Define xon char for transmitter flow control +// +#define CMD_DEF_IXON(arg) \ + (((cmdSyntaxPtr)(ct11))->cmd[1] = (arg),(cmdSyntaxPtr)(ct11)) + +// Define xoff char for transmitter flow control +// +#define CMD_DEF_IXOFF(arg) \ + (((cmdSyntaxPtr)(ct12))->cmd[1] = (arg),(cmdSyntaxPtr)(ct12)) + +#define CMD_STOPFL (cmdSyntaxPtr)(ct13) // Stop Flushing data + +// Acknowledge receipt of hotkey signal +// +#define CMD_HOTACK (cmdSyntaxPtr)(ct14) + +// Define irq level to use. Should actually be sent by library-level code, not +// directly from user... +// +#define CMDVALUE_IRQ 15 // For library use at initialization. Until this command + // is sent, board processing doesn't really start. +#define CMD_SET_IRQ(arg) \ + (((cmdSyntaxPtr)(ct15))->cmd[1] = (arg),(cmdSyntaxPtr)(ct15)) + +#define CIR_POLL 0 // No IRQ - Poll +#define CIR_3 3 // IRQ 3 +#define CIR_4 4 // IRQ 4 +#define CIR_5 5 // IRQ 5 +#define CIR_7 7 // IRQ 7 +#define CIR_10 10 // IRQ 10 +#define CIR_11 11 // IRQ 11 +#define CIR_12 12 // IRQ 12 +#define CIR_15 15 // IRQ 15 + +// Select transmit flow xon/xoff options +// +#define CMD_IXON_OPT(arg) \ + (((cmdSyntaxPtr)(ct16))->cmd[1] = (arg),(cmdSyntaxPtr)(ct16)) + +#define CIX_NONE 0 // Incoming Xon/Xoff characters not special +#define CIX_XON 1 // Xoff disable, Xon enable +#define CIX_XANY 2 // Xoff disable, any key enable + +// Select receive flow xon/xoff options +// +#define CMD_OXON_OPT(arg) \ + (((cmdSyntaxPtr)(ct17))->cmd[1] = (arg),(cmdSyntaxPtr)(ct17)) + +#define COX_NONE 0 // Don't send Xon/Xoff +#define COX_XON 1 // Send xon/xoff to start/stop incoming data + + +#define CMD_CTS_REP (cmdSyntaxPtr)(ct18) // Enable CTS reporting +#define CMD_CTS_NREP (cmdSyntaxPtr)(ct19) // Disable CTS reporting + +#define CMD_DCD_REP (cmdSyntaxPtr)(ct20) // Enable DCD reporting +#define CMD_DCD_NREP (cmdSyntaxPtr)(ct21) // Disable DCD reporting + +#define CMD_DSR_REP (cmdSyntaxPtr)(ct22) // Enable DSR reporting +#define CMD_DSR_NREP (cmdSyntaxPtr)(ct23) // Disable DSR reporting + +#define CMD_RI_REP (cmdSyntaxPtr)(ct24) // Enable RI reporting +#define CMD_RI_NREP (cmdSyntaxPtr)(ct25) // Disable RI reporting + +// Enable break reporting and select style +// +#define CMD_BRK_REP(arg) \ + (((cmdSyntaxPtr)(ct26))->cmd[1] = (arg),(cmdSyntaxPtr)(ct26)) + +#define CBK_STAT 0x00 // Report breaks as a status (exception,irq) +#define CBK_NULL 0x01 // Report breaks as a good null +#define CBK_STAT_SEQ 0x02 // Report breaks as a status AND as in-band character + // sequence FFh, 01h, 10h +#define CBK_SEQ 0x03 // Report breaks as the in-band + //sequence FFh, 01h, 10h ONLY. +#define CBK_FLSH 0x04 // if this bit set also flush input data +#define CBK_POSIX 0x08 // if this bit set report as FF,0,0 sequence +#define CBK_SINGLE 0x10 // if this bit set with CBK_SEQ or CBK_STAT_SEQ + //then reports single null instead of triple + +#define CMD_BRK_NREP (cmdSyntaxPtr)(ct27) // Disable break reporting + +// Specify maximum block size for received data +// +#define CMD_MAX_BLOCK(arg) \ + (((cmdSyntaxPtr)(ct28))->cmd[1] = (arg),(cmdSyntaxPtr)(ct28)) + +// -- COMMAND 29 is reserved -- + +#define CMD_CTSFL_ENAB (cmdSyntaxPtr)(ct30) // Enable CTS flow control +#define CMD_CTSFL_DSAB (cmdSyntaxPtr)(ct31) // Disable CTS flow control +#define CMD_RTSFL_ENAB (cmdSyntaxPtr)(ct32) // Enable RTS flow control +#define CMD_RTSFL_DSAB (cmdSyntaxPtr)(ct33) // Disable RTS flow control + +// Specify istrip option +// +#define CMD_ISTRIP_OPT(arg) \ + (((cmdSyntaxPtr)(ct34))->cmd[1] = (arg),(cmdSyntaxPtr)(ct34)) + +#define CIS_NOSTRIP 0 // Strip characters to character size +#define CIS_STRIP 1 // Strip any 8-bit characters to 7 bits + +// Send a break of arg milliseconds +// +#define CMD_SEND_BRK(arg) \ + (((cmdSyntaxPtr)(ct35))->cmd[1] = (arg),(cmdSyntaxPtr)(ct35)) + +// Set error reporting mode +// +#define CMD_SET_ERROR(arg) \ + (((cmdSyntaxPtr)(ct36))->cmd[1] = (arg),(cmdSyntaxPtr)(ct36)) + +#define CSE_ESTAT 0 // Report error in a status packet +#define CSE_NOREP 1 // Treat character as though it were good +#define CSE_DROP 2 // Discard the character +#define CSE_NULL 3 // Replace with a null +#define CSE_MARK 4 // Replace with a 3-character sequence (as Unix) + +#define CMD_SET_REPLACEMENT(arg,ch) \ + (((cmdSyntaxPtr)(ct36a))->cmd[1] = (arg), \ + (((cmdSyntaxPtr)(ct36a))->cmd[2] = (ch), \ + (cmdSyntaxPtr)(ct36a)) + +#define CSE_REPLACE 0x8 // Replace the errored character with the + // replacement character defined here + +#define CSE_STAT_REPLACE 0x18 // Replace the errored character with the + // replacement character defined here AND + // report the error as a status packet (as in + // CSE_ESTAT). + + +// COMMAND 37, to send flow control packets, is handled only by low-level +// library code in response to data movement and shouldn't ever be sent by the +// user code. See i2pack.h and the body of i2lib.c for details. + +// COMMAND 38: Define the hot-key sequence +// seqno: sequence number 0-15 +// size: number of characters in sequence (1-8) +// string: pointer to the characters +// (if size == 0, "undefines" this sequence +// +#define CMD_SET_SEQ(seqno,size,string) i2cmdSetSeq(seqno,size,string) + +// Enable on-board post-processing, using options given in oflag argument. +// Formerly, this command was automatically preceded by a CMD_OPOST_OFF command +// because the loadware does not permit sending back-to-back CMD_OPOST_ON +// commands without an intervening CMD_OPOST_OFF. BUT, WE LEARN 18 MAY 92, that +// CMD_OPOST_ON and CMD_OPOST_OFF must each be at the end of a packet (or in a +// solo packet). This means the caller must specify separately CMD_OPOST_OFF, +// CMD_OPOST_ON(parm) when he calls i2QueueCommands(). That function will ensure +// each gets a separate packet. Extra CMD_OPOST_OFF's are always ok. +// +#define CMD_OPOST_ON(oflag) \ + (*(USHORT *)(((cmdSyntaxPtr)(ct39))->cmd[1]) = (oflag), \ + (cmdSyntaxPtr)(ct39)) + +#define CMD_OPOST_OFF (cmdSyntaxPtr)(ct40) // Disable on-board post-proc + +#define CMD_RESUME (cmdSyntaxPtr)(ct41) // Resume: behave as though an XON + // were received; + +// Set Transmit baud rate (see command 7 for arguments) +// +#define CMD_SETBAUD_TX(arg) \ + (((cmdSyntaxPtr)(ct42))->cmd[1] = (arg),(cmdSyntaxPtr)(ct42)) + +// Set Receive baud rate (see command 7 for arguments) +// +#define CMD_SETBAUD_RX(arg) \ + (((cmdSyntaxPtr)(ct43))->cmd[1] = (arg),(cmdSyntaxPtr)(ct43)) + +// Request interrupt from board each arg milliseconds. Interrupt will specify +// "received data", even though there may be no data present. If arg == 0, +// disables any such interrupts. +// +#define CMD_PING_REQ(arg) \ + (((cmdSyntaxPtr)(ct44))->cmd[1] = (arg),(cmdSyntaxPtr)(ct44)) + +#define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking +#define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking + +// COMMAND 47: Send Protocol info via Unix flags: +// iflag = Unix tty t_iflag +// cflag = Unix tty t_cflag +// lflag = Unix tty t_lflag +// See System V Unix/Xenix documentation for the meanings of the bit fields +// within these flags +// +#define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag) + +#define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl +#define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl +#define CMD_DTRFL_ENAB (cmdSyntaxPtr)(ct50) // Enable DTR flow control +#define CMD_DTRFL_DSAB (cmdSyntaxPtr)(ct51) // Disable DTR flow control +#define CMD_BAUD_RESET (cmdSyntaxPtr)(ct52) // Reset baudrate table + +// COMMAND 53: Remap baud rate table +// dest = index of table entry to be changed +// src = index value to substitute. +// at default mapping table is f(x) = x +// +#define CMD_BAUD_REMAP(dest,src) i2cmdBaudRemap(dest,src) + +// COMMAND 54: Define custom rate #1 +// rate = (short) 1/10 of the desired baud rate +// +#define CMD_BAUD_DEF1(rate) i2cmdBaudDef(1,rate) + +// COMMAND 55: Define custom rate #2 +// rate = (short) 1/10 of the desired baud rate +// +#define CMD_BAUD_DEF2(rate) i2cmdBaudDef(2,rate) + +// Pause arg hundredths of seconds. (Note, this is NOT milliseconds.) +// +#define CMD_PAUSE(arg) \ + (((cmdSyntaxPtr)(ct56))->cmd[1] = (arg),(cmdSyntaxPtr)(ct56)) + +#define CMD_SUSPEND (cmdSyntaxPtr)(ct57) // Suspend output +#define CMD_UNSUSPEND (cmdSyntaxPtr)(ct58) // Un-Suspend output + +// Set parity-checking options +// +#define CMD_PARCHK(arg) \ + (((cmdSyntaxPtr)(ct59))->cmd[1] = (arg),(cmdSyntaxPtr)(ct59)) + +#define CPK_ENAB 0 // Enable parity checking on input +#define CPK_DSAB 1 // Disable parity checking on input + +#define CMD_BMARK_REQ (cmdSyntaxPtr)(ct60) // Bookmark request + + +// Enable/Disable internal loopback mode +// +#define CMD_INLOOP(arg) \ + (((cmdSyntaxPtr)(ct61))->cmd[1] = (arg),(cmdSyntaxPtr)(ct61)) + +#define CIN_DISABLE 0 // Normal operation (default) +#define CIN_ENABLE 1 // Internal (local) loopback +#define CIN_REMOTE 2 // Remote loopback + +// Specify timeout for hotkeys: Delay will be (arg x 10) milliseconds, arg == 0 +// --> no timeout: wait forever. +// +#define CMD_HOT_TIME(arg) \ + (((cmdSyntaxPtr)(ct62))->cmd[1] = (arg),(cmdSyntaxPtr)(ct62)) + + +// Define (outgoing) xon for receive flow control +// +#define CMD_DEF_OXON(arg) \ + (((cmdSyntaxPtr)(ct63))->cmd[1] = (arg),(cmdSyntaxPtr)(ct63)) + +// Define (outgoing) xoff for receiver flow control +// +#define CMD_DEF_OXOFF(arg) \ + (((cmdSyntaxPtr)(ct64))->cmd[1] = (arg),(cmdSyntaxPtr)(ct64)) + +// Enable/Disable RTS on transmit (1/2 duplex-style) +// +#define CMD_RTS_XMIT(arg) \ + (((cmdSyntaxPtr)(ct65))->cmd[1] = (arg),(cmdSyntaxPtr)(ct65)) + +#define CHD_DISABLE 0 +#define CHD_ENABLE 1 + +// Set high-water-mark level (debugging use only) +// +#define CMD_SETHIGHWAT(arg) \ + (((cmdSyntaxPtr)(ct66))->cmd[1] = (arg),(cmdSyntaxPtr)(ct66)) + +// Start flushing tagged data (tag = 0-14) +// +#define CMD_START_SELFL(tag) \ + (((cmdSyntaxPtr)(ct67))->cmd[1] = (tag),(cmdSyntaxPtr)(ct67)) + +// End flushing tagged data (tag = 0-14) +// +#define CMD_END_SELFL(tag) \ + (((cmdSyntaxPtr)(ct68))->cmd[1] = (tag),(cmdSyntaxPtr)(ct68)) + +#define CMD_HWFLOW_OFF (cmdSyntaxPtr)(ct69) // Disable HW TX flow control +#define CMD_ODSRFL_ENAB (cmdSyntaxPtr)(ct70) // Enable DSR output f/c +#define CMD_ODSRFL_DSAB (cmdSyntaxPtr)(ct71) // Disable DSR output f/c +#define CMD_ODCDFL_ENAB (cmdSyntaxPtr)(ct72) // Enable DCD output f/c +#define CMD_ODCDFL_DSAB (cmdSyntaxPtr)(ct73) // Disable DCD output f/c + +// Set transmit interrupt load level. Count should be an even value 2-12 +// +#define CMD_LOADLEVEL(count) \ + (((cmdSyntaxPtr)(ct74))->cmd[1] = (count),(cmdSyntaxPtr)(ct74)) + +// If reporting DSS changes, map to character sequence FFh, 2, MSR +// +#define CMD_STATDATA(arg) \ + (((cmdSyntaxPtr)(ct75))->cmd[1] = (arg),(cmdSyntaxPtr)(ct75)) + +#define CSTD_DISABLE// Report DSS changes as status packets only (default) +#define CSTD_ENABLE // Report DSS changes as in-band data sequence as well as + // by status packet. + +#define CMD_BREAK_ON (cmdSyntaxPtr)(ct76)// Set break and stop xmit +#define CMD_BREAK_OFF (cmdSyntaxPtr)(ct77)// End break and restart xmit +#define CMD_GETFC (cmdSyntaxPtr)(ct78)// Request for flow control packet + // from board. + +// Transmit this character immediately +// +#define CMD_XMIT_NOW(ch) \ + (((cmdSyntaxPtr)(ct79))->cmd[1] = (ch),(cmdSyntaxPtr)(ct79)) + +// Set baud rate via "divisor latch" +// +#define CMD_DIVISOR_LATCH(which,value) \ + (((cmdSyntaxPtr)(ct80))->cmd[1] = (which), \ + *(USHORT *)(((cmdSyntaxPtr)(ct80))->cmd[2]) = (value), \ + (cmdSyntaxPtr)(ct80)) + +#define CDL_RX 1 // Set receiver rate +#define CDL_TX 2 // Set transmit rate + // (CDL_TX | CDL_RX) Set both rates + +// Request for special diagnostic status pkt from the board. +// +#define CMD_GET_STATUS (cmdSyntaxPtr)(ct81) + +// Request time-stamped transmit character count packet. +// +#define CMD_GET_TXCNT (cmdSyntaxPtr)(ct82) + +// Request time-stamped receive character count packet. +// +#define CMD_GET_RXCNT (cmdSyntaxPtr)(ct83) + +// Request for box/board I.D. packet. +#define CMD_GET_BOXIDS (cmdSyntaxPtr)(ct84) + +// Enable or disable multiple channels according to bit-mapped ushorts box 1-4 +// +#define CMD_ENAB_MULT(enable, box1, box2, box3, box4) \ + (((cmdSytaxPtr)(ct85))->cmd[1] = (enable), \ + *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[2]) = (box1), \ + *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[4]) = (box2), \ + *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[6]) = (box3), \ + *(USHORT *)(((cmdSyntaxPtr)(ct85))->cmd[8]) = (box4), \ + (cmdSyntaxPtr)(ct85)) + +#define CEM_DISABLE 0 +#define CEM_ENABLE 1 + +// Enable or disable receiver or receiver interrupts (default both enabled) +// +#define CMD_RCV_ENABLE(ch) \ + (((cmdSyntaxPtr)(ct86))->cmd[1] = (ch),(cmdSyntaxPtr)(ct86)) + +#define CRE_OFF 0 // Disable the receiver +#define CRE_ON 1 // Enable the receiver +#define CRE_INTOFF 2 // Disable receiver interrupts (to loadware) +#define CRE_INTON 3 // Enable receiver interrupts (to loadware) + +// Starts up a hardware test process, which runs transparently, and sends a +// STAT_HWFAIL packet in case a hardware failure is detected. +// +#define CMD_HW_TEST (cmdSyntaxPtr)(ct87) + +// Change receiver threshold and timeout value: +// Defaults: timeout = 20mS +// threshold count = 8 when DTRflow not in use, +// threshold count = 5 when DTRflow in use. +// +#define CMD_RCV_THRESHOLD(count,ms) \ + (((cmdSyntaxPtr)(ct88))->cmd[1] = (count), \ + ((cmdSyntaxPtr)(ct88))->cmd[2] = (ms), \ + (cmdSyntaxPtr)(ct88)) + +// Makes the loadware report DSS signals for this channel immediately. +// +#define CMD_DSS_NOW (cmdSyntaxPtr)(ct89) + +// Set the receive silo parameters +// timeout is ms idle wait until delivery (~VTIME) +// threshold is max characters cause interrupt (~VMIN) +// +#define CMD_SET_SILO(timeout,threshold) \ + (((cmdSyntaxPtr)(ct90))->cmd[1] = (timeout), \ + ((cmdSyntaxPtr)(ct90))->cmd[2] = (threshold), \ + (cmdSyntaxPtr)(ct90)) + +// Set timed break in decisecond (1/10s) +// +#define CMD_LBREAK(ds) \ + (((cmdSyntaxPtr)(ct91))->cmd[1] = (ds),(cmdSyntaxPtr)(ct66)) + + + +#endif // I2CMD_H diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2ellis.c linux/drivers/char/ip2/i2ellis.c --- v2.3.14/linux/drivers/char/ip2/i2ellis.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2ellis.c Mon Aug 23 10:23:23 1999 @@ -0,0 +1,1470 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Low-level interface code for the device driver +* (This is included source code, not a separate compilation +* module.) +* +*******************************************************************************/ +//--------------------------------------------- +// Function declarations private to this module +//--------------------------------------------- +// Functions called only indirectly through i2eBordStr entries. + +static int iiWriteBuf16(i2eBordStrPtr, unsigned char *, int); +static int iiWriteBuf8(i2eBordStrPtr, unsigned char *, int); +static int iiReadBuf16(i2eBordStrPtr, unsigned char *, int); +static int iiReadBuf8(i2eBordStrPtr, unsigned char *, int); + +static unsigned short iiReadWord16(i2eBordStrPtr); +static unsigned short iiReadWord8(i2eBordStrPtr); +static void iiWriteWord16(i2eBordStrPtr, unsigned short); +static void iiWriteWord8(i2eBordStrPtr, unsigned short); + +static int iiWaitForTxEmptyII(i2eBordStrPtr, int); +static int iiWaitForTxEmptyIIEX(i2eBordStrPtr, int); +static int iiTxMailEmptyII(i2eBordStrPtr); +static int iiTxMailEmptyIIEX(i2eBordStrPtr); +static int iiTrySendMailII(i2eBordStrPtr, unsigned char); +static int iiTrySendMailIIEX(i2eBordStrPtr, unsigned char); + +static unsigned short iiGetMailII(i2eBordStrPtr); +static unsigned short iiGetMailIIEX(i2eBordStrPtr); + +static void iiEnableMailIrqII(i2eBordStrPtr); +static void iiEnableMailIrqIIEX(i2eBordStrPtr); +static void iiWriteMaskII(i2eBordStrPtr, unsigned char); +static void iiWriteMaskIIEX(i2eBordStrPtr, unsigned char); + +static void ii2DelayTimer(unsigned int); +static void ii2DelayWakeup(unsigned long id); +static void ii2Nop(void); + +//*************** +//* Static Data * +//*************** + +static int ii2Safe = 0; // Safe I/O address for delay routine + +static int iiDelayed = 0; // Set when the iiResetDelay function is + // called. Cleared when ANY board is reset. +static struct timer_list * pDelayTimer; // Used by iiDelayTimer +static wait_queue_head_t pDelayWait; // Used by iiDelayTimer +static spinlock_t Dl_spinlock; + +//******** +//* Code * +//******** + +//======================================================= +// Initialization Routines +// +// iiSetAddress +// iiReset +// iiResetDelay +// iiInitialize +//======================================================= + +//****************************************************************************** +// Function: iiEllisInit() +// Parameters: None +// +// Returns: Nothing +// +// Description: +// +// This routine performs any required initialization of the iiEllis subsystem. +// +//****************************************************************************** +static void +iiEllisInit(void) +{ + pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL ); + init_waitqueue_head(&pDelayWait); + LOCK_INIT(&Dl_spinlock); +} + +//****************************************************************************** +// Function: iiEllisCleanup() +// Parameters: None +// +// Returns: Nothing +// +// Description: +// +// This routine performs any required cleanup of the iiEllis subsystem. +// +//****************************************************************************** +static void +iiEllisCleanup(void) +{ + if ( pDelayTimer != NULL ) { + kfree ( pDelayTimer ); + } +} + +//****************************************************************************** +// Function: iiSetAddress(pB, address, delay) +// Parameters: pB - pointer to the board structure +// address - the purported I/O address of the board +// delay - pointer to the 1-ms delay function to use +// in this and any future operations to this board +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// This routine (roughly) checks for address validity, sets the i2eValid OK and +// sets the state to II_STATE_COLD which means that we haven't even sent a reset +// yet. +// +//****************************************************************************** +static int +iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay ) +{ + // Should any failure occur before init is finished... + pB->i2eValid = I2E_INCOMPLETE; + + // Cannot check upper limit except extremely: Might be microchannel + // Address must be on an 8-byte boundary + + if ((unsigned int)address <= 0x100 + || (unsigned int)address >= 0xfff8 + || (address & 0x7) + ) + { + COMPLETE(pB,I2EE_BADADDR); + } + + // Initialize accelerators + pB->i2eBase = address; + pB->i2eData = address + FIFO_DATA; + pB->i2eStatus = address + FIFO_STATUS; + pB->i2ePointer = address + FIFO_PTR; + pB->i2eXMail = address + FIFO_MAIL; + pB->i2eXMask = address + FIFO_MASK; + + // Initialize i/o address for ii2DelayIO + ii2Safe = address + FIFO_NOP; + + // Initialize the delay routine + pB->i2eDelay = ((delay != (delayFunc_t)NULL) ? delay : (delayFunc_t)ii2Nop); + + pB->i2eValid = I2E_MAGIC; + pB->i2eState = II_STATE_COLD; + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiReset(pB) +// Parameters: pB - pointer to the board structure +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Attempts to reset the board (see also i2hw.h). Normally, we would use this to +// reset a board immediately after iiSetAddress(), but it is valid to reset a +// board from any state, say, in order to change or re-load loadware. (Under +// such circumstances, no reason to re-run iiSetAddress(), which is why it is a +// separate routine and not included in this routine. +// +//****************************************************************************** +static int +iiReset(i2eBordStrPtr pB) +{ + // Magic number should be set, else even the address is suspect + if (pB->i2eValid != I2E_MAGIC) + { + COMPLETE(pB, I2EE_BADMAGIC); + } + + OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do + iiDelay(pB, 50); // Pause between resets + OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset + + // We must wait before even attempting to read anything from the FIFO: the + // board's P.O.S.T may actually attempt to read and write its end of the + // FIFO in order to check flags, loop back (where supported), etc. On + // completion of this testing it would reset the FIFO, and on completion + // of all // P.O.S.T., write the message. We must not mistake data which + // might have been sent for testing as part of the reset message. To + // better utilize time, say, when resetting several boards, we allow the + // delay to be performed externally; in this way the caller can reset + // several boards, delay a single time, then call the initialization + // routine for all. + + pB->i2eState = II_STATE_RESET; + + iiDelayed = 0; // i.e., the delay routine hasn't been called since the most + // recent reset. + + // Ensure anything which would have been of use to standard loadware is + // blanked out, since board has now forgotten everything!. + + pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet + pB->i2eWaitingForEmptyFifo = 0; + pB->i2eOutMailWaiting = 0; + pB->i2eChannelPtr = NULL; + pB->i2eChannelCnt = 0; + + pB->i2eLeadoffWord[0] = 0; + pB->i2eFifoInInts = 0; + pB->i2eFifoOutInts = 0; + pB->i2eFatalTrap = NULL; + pB->i2eFatal = 0; + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiResetDelay(pB) +// Parameters: pB - pointer to the board structure +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Using the delay defined in board structure, waits two seconds (for board to +// reset). +// +//****************************************************************************** +static int +iiResetDelay(i2eBordStrPtr pB) +{ + if (pB->i2eValid != I2E_MAGIC) { + COMPLETE(pB, I2EE_BADMAGIC); + } + if (pB->i2eState != II_STATE_RESET) { + COMPLETE(pB, I2EE_BADSTATE); + } + iiDelay(pB,2000); /* Now we wait for two seconds. */ + iiDelayed = 1; /* Delay has been called: ok to initialize */ + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiInitialize(pB) +// Parameters: pB - pointer to the board structure +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Attempts to read the Power-on reset message. Initializes any remaining fields +// in the pB structure. +// +// This should be called as the third step of a process beginning with +// iiReset(), then iiResetDelay(). This routine checks to see that the structure +// is "valid" and in the reset state, also confirms that the delay routine has +// been called since the latest reset (to any board! overly strong!). +// +//****************************************************************************** +static int +iiInitialize(i2eBordStrPtr pB) +{ + int itemp; + unsigned char c; + unsigned short utemp; + unsigned int ilimit; + + if (pB->i2eValid != I2E_MAGIC) + { + COMPLETE(pB, I2EE_BADMAGIC); + } + + if (pB->i2eState != II_STATE_RESET || !iiDelayed) + { + COMPLETE(pB, I2EE_BADSTATE); + } + + // In case there is a failure short of our completely reading the power-up + // message. + pB->i2eValid = I2E_INCOMPLETE; + + + // Now attempt to read the message. + + for (itemp = 0; itemp < sizeof(porStr); itemp++) + { + // We expect the entire message is ready. + if (HAS_NO_INPUT(pB)) + { + pB->i2ePomSize = itemp; + COMPLETE(pB, I2EE_PORM_SHORT); + } + + pB->i2ePom.c[itemp] = c = BYTE_FROM(pB); + + // We check the magic numbers as soon as they are supposed to be read + // (rather than after) to minimize effect of reading something we + // already suspect can't be "us". + if ( (itemp == POR_1_INDEX && c != POR_MAGIC_1) || + (itemp == POR_2_INDEX && c != POR_MAGIC_2)) + { + pB->i2ePomSize = itemp+1; + COMPLETE(pB, I2EE_BADMAGIC); + } + } + + pB->i2ePomSize = itemp; + + // Ensure that this was all the data... + if (HAS_INPUT(pB)) + COMPLETE(pB, I2EE_PORM_LONG); + + // For now, we'll fail to initialize if P.O.S.T reports bad chip mapper: + // Implying we will not be able to download any code either: That's ok: the + // condition is pretty explicit. + if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER) + { + COMPLETE(pB, I2EE_POSTERR); + } + + // Determine anything which must be done differently depending on the family + // of boards! + switch (pB->i2ePom.e.porID & POR_ID_FAMILY) + { + case POR_ID_FII: // IntelliPort-II + + pB->i2eFifoStyle = FIFO_II; + pB->i2eFifoSize = 512; // 512 bytes, always + pB->i2eDataWidth16 = NO; + + pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit + // slot, we do allow it to be done (documentation!) + + pB->i2eGoodMap[1] = + pB->i2eGoodMap[2] = + pB->i2eGoodMap[3] = + pB->i2eChannelMap[1] = + pB->i2eChannelMap[2] = + pB->i2eChannelMap[3] = 0; + + switch (pB->i2ePom.e.porID & POR_ID_SIZE) + { + case POR_ID_II_4: + pB->i2eGoodMap[0] = + pB->i2eChannelMap[0] = 0x0f; // four-port + + // Since porPorts1 is based on the Hardware ID register, the numbers + // should always be consistent for IntelliPort-II. Ditto below... + if (pB->i2ePom.e.porPorts1 != 4) + { + COMPLETE(pB, I2EE_INCONSIST); + } + break; + + case POR_ID_II_8: + case POR_ID_II_8R: + pB->i2eGoodMap[0] = + pB->i2eChannelMap[0] = 0xff; // Eight port + if (pB->i2ePom.e.porPorts1 != 8) + { + COMPLETE(pB, I2EE_INCONSIST); + } + break; + + case POR_ID_II_6: + pB->i2eGoodMap[0] = + pB->i2eChannelMap[0] = 0x3f; // Six Port + if (pB->i2ePom.e.porPorts1 != 6) + { + COMPLETE(pB, I2EE_INCONSIST); + } + break; + } + + // Fix up the "good channel list based on any errors reported. + if (pB->i2ePom.e.porDiag1 & POR_BAD_UART1) + { + pB->i2eGoodMap[0] &= ~0x0f; + } + + if (pB->i2ePom.e.porDiag1 & POR_BAD_UART2) + { + pB->i2eGoodMap[0] &= ~0xf0; + } + + break; // POR_ID_FII case + + case POR_ID_FIIEX: // IntelliPort-IIEX + + pB->i2eFifoStyle = FIFO_IIEX; + + itemp = pB->i2ePom.e.porFifoSize; + + // Implicit assumption that fifo would not grow beyond 32k, + // nor would ever be less than 256. + + if (itemp < 8 || itemp > 15) + { + COMPLETE(pB, I2EE_INCONSIST); + } + pB->i2eFifoSize = (1 << itemp); + + // These are based on what P.O.S.T thinks should be there, based on + // box ID registers + ilimit = pB->i2ePom.e.porNumBoxes; + if (ilimit > ABS_MAX_BOXES) + { + ilimit = ABS_MAX_BOXES; + } + + // For as many boxes as EXIST, gives the type of box. + // Added 8/6/93: check for the ISA-4 (asic) which looks like an + // expandable but for whom "8 or 16?" is not the right question. + + utemp = pB->i2ePom.e.porFlags; + if (utemp & POR_CEX4) + { + pB->i2eChannelMap[0] = 0x000f; + } else { + utemp &= POR_BOXES; + for (itemp = 0; itemp < ilimit; itemp++) + { + pB->i2eChannelMap[itemp] = + ((utemp & POR_BOX_16) ? 0xffff : 0x00ff); + utemp >>= 1; + } + } + + // These are based on what P.O.S.T actually found. + + utemp = (pB->i2ePom.e.porPorts2 << 8) + pB->i2ePom.e.porPorts1; + + for (itemp = 0; itemp < ilimit; itemp++) + { + pB->i2eGoodMap[itemp] = 0; + if (utemp & 1) pB->i2eGoodMap[itemp] |= 0x000f; + if (utemp & 2) pB->i2eGoodMap[itemp] |= 0x00f0; + if (utemp & 4) pB->i2eGoodMap[itemp] |= 0x0f00; + if (utemp & 8) pB->i2eGoodMap[itemp] |= 0xf000; + utemp >>= 4; + } + + // Now determine whether we should transfer in 8 or 16-bit mode. + switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) ) + { + case POR_BUS_SLOT16 | POR_BUS_DIP16: + pB->i2eDataWidth16 = YES; + pB->i2eMaxIrq = 15; + break; + + case POR_BUS_SLOT16: + pB->i2eDataWidth16 = NO; + pB->i2eMaxIrq = 15; + break; + + case 0: + case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care. + default: + pB->i2eDataWidth16 = NO; + pB->i2eMaxIrq = 7; + break; + } + break; // POR_ID_FIIEX case + + default: // Unknown type of board + COMPLETE(pB, I2EE_BAD_FAMILY); + break; + } // End the switch based on family + + // Temporarily, claim there is no room in the outbound fifo. + // We will maintain this whenever we check for an empty outbound FIFO. + pB->i2eFifoRemains = 0; + + // Now, based on the bus type, should we expect to be able to re-configure + // interrupts (say, for testing purposes). + switch (pB->i2ePom.e.porBus & POR_BUS_TYPE) + { + case POR_BUS_T_ISA: + case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok. + pB->i2eChangeIrq = YES; + break; + case POR_BUS_T_MCA: + case POR_BUS_T_EISA: + pB->i2eChangeIrq = NO; + break; + default: + COMPLETE(pB, I2EE_BADBUS); + } + + if (pB->i2eDataWidth16 == YES) + { + pB->i2eWriteBuf = iiWriteBuf16; + pB->i2eReadBuf = iiReadBuf16; + pB->i2eWriteWord = iiWriteWord16; + pB->i2eReadWord = iiReadWord16; + } else { + pB->i2eWriteBuf = iiWriteBuf8; + pB->i2eReadBuf = iiReadBuf8; + pB->i2eWriteWord = iiWriteWord8; + pB->i2eReadWord = iiReadWord8; + } + + switch(pB->i2eFifoStyle) + { + case FIFO_II: + pB->i2eWaitForTxEmpty = iiWaitForTxEmptyII; + pB->i2eTxMailEmpty = iiTxMailEmptyII; + pB->i2eTrySendMail = iiTrySendMailII; + pB->i2eGetMail = iiGetMailII; + pB->i2eEnableMailIrq = iiEnableMailIrqII; + pB->i2eWriteMask = iiWriteMaskII; + + break; + + case FIFO_IIEX: + pB->i2eWaitForTxEmpty = iiWaitForTxEmptyIIEX; + pB->i2eTxMailEmpty = iiTxMailEmptyIIEX; + pB->i2eTrySendMail = iiTrySendMailIIEX; + pB->i2eGetMail = iiGetMailIIEX; + pB->i2eEnableMailIrq = iiEnableMailIrqIIEX; + pB->i2eWriteMask = iiWriteMaskIIEX; + + break; + + default: + COMPLETE(pB, I2EE_INCONSIST); + } + + // Initialize state information. + pB->i2eState = II_STATE_READY; // Ready to load loadware. + + // Some Final cleanup: + // For some boards, the bootstrap firmware may perform some sort of test + // resulting in a stray character pending in the incoming mailbox. If one is + // there, it should be read and discarded, especially since for the standard + // firmware, it's the mailbox that interrupts the host. + + pB->i2eStartMail = iiGetMail(pB); + + // Everything is ok now, return with good status/ + + pB->i2eValid = I2E_MAGIC; + COMPLETE(pB, I2EE_GOOD); +} + +//======================================================= +// Delay Routines +// +// iiDelayIO +// iiNop +//======================================================= + +static void +ii2DelayWakeup(unsigned long id) +{ + wake_up_interruptible ( &pDelayWait ); +} + +//****************************************************************************** +// Function: ii2DelayTimer(mseconds) +// Parameters: mseconds - number of milliseconds to delay +// +// Returns: Nothing +// +// Description: +// +// This routine delays for approximately mseconds milliseconds and is intended +// to be called indirectly through i2Delay field in i2eBordStr. It uses the +// Linux timer_list mechanism. +// +// The Linux timers use a unit called "jiffies" which are 10mS in the Intel +// architecture. This function rounds the delay period up to the next "jiffy". +// In the Alpha architecture the "jiffy" is 1mS, but this driver is not intended +// for Alpha platforms at this time. +// +//****************************************************************************** +static void +ii2DelayTimer(unsigned int mseconds) +{ + init_timer ( pDelayTimer ); + + pDelayTimer->expires = jiffies + ( mseconds + 9 ) / 10; + pDelayTimer->function = ii2DelayWakeup; + pDelayTimer->data = 0; + + add_timer ( pDelayTimer ); + interruptible_sleep_on ( &pDelayWait ); + del_timer ( pDelayTimer ); +} + +#if 0 +//static void ii2DelayIO(unsigned int); +//****************************************************************************** +// !!! Not Used, this is DOS crap, some of you young folks may be interested in +// in how things were done in the stone age of caculating machines !!! +// Function: ii2DelayIO(mseconds) +// Parameters: mseconds - number of milliseconds to delay +// +// Returns: Nothing +// +// Description: +// +// This routine delays for approximately mseconds milliseconds and is intended +// to be called indirectly through i2Delay field in i2eBordStr. It is intended +// for use where a clock-based function is impossible: for example, DOS drivers. +// +// This function uses the IN instruction to place bounds on the timing and +// assumes that ii2Safe has been set. This is because I/O instructions are not +// subject to caching and will therefore take a certain minimum time. To ensure +// the delay is at least long enough on fast machines, it is based on some +// fastest-case calculations. On slower machines this may cause VERY long +// delays. (3 x fastest case). In the fastest case, everything is cached except +// the I/O instruction itself. +// +// Timing calculations: +// The fastest bus speed for I/O operations is likely to be 10 MHz. The I/O +// operation in question is a byte operation to an odd address. For 8-bit +// operations, the architecture generally enforces two wait states. At 10 MHz, a +// single cycle time is 100nS. A read operation at two wait states takes 6 +// cycles for a total time of 600nS. Therefore approximately 1666 iterations +// would be required to generate a single millisecond delay. The worst +// (reasonable) case would be an 8MHz system with no cacheing. In this case, the +// I/O instruction would take 125nS x 6 cyles = 750 nS. More importantly, code +// fetch of other instructions in the loop would take time (zero wait states, +// however) and would be hard to estimate. This is minimized by using in-line +// assembler for the in inner loop of IN instructions. This consists of just a +// few bytes. So we'll guess about four code fetches per loop. Each code fetch +// should take four cycles, so we have 125nS * 8 = 1000nS. Worst case then is +// that what should have taken 1 mS takes instead 1666 * (1750) = 2.9 mS. +// +// So much for theoretical timings: results using 1666 value on some actual +// machines: +// IBM 286 6MHz 3.15 mS +// Zenith 386 33MHz 2.45 mS +// (brandX) 386 33MHz 1.90 mS (has cache) +// (brandY) 486 33MHz 2.35 mS +// NCR 486 ?? 1.65 mS (microchannel) +// +// For most machines, it is probably safe to scale this number back (remember, +// for robust operation use an actual timed delay if possible), so we are using +// a value of 1190. This yields 1.17 mS for the fastest machine in our sample, +// 1.75 mS for typical 386 machines, and 2.25 mS the absolute slowest machine. +// +// 1/29/93: +// The above timings are too slow. Actual cycle times might be faster. ISA cycle +// times could approach 500 nS, and ... +// The IBM model 77 being microchannel has no wait states for 8-bit reads and +// seems to be accessing the I/O at 440 nS per access (from start of one to +// start of next). This would imply we need 1000/.440 = 2272 iterations to +// guarantee we are fast enough. In actual testing, we see that 2 * 1190 are in +// fact enough. For diagnostics, we keep the level at 1190, but developers note +// this needs tuning. +// +// Safe assumption: 2270 i/o reads = 1 millisecond +// +//****************************************************************************** + + +static int ii2DelValue = 1190; // See timing calculations below + // 1666 for fastest theoretical machine + // 1190 safe for most fast 386 machines + // 1000 for fastest machine tested here + // 540 (sic) for AT286/6Mhz +static void +ii2DelayIO(unsigned int mseconds) +{ + if (!ii2Safe) + return; /* Do nothing if this variable uninitialized */ + + while(mseconds--) { + int i = ii2DelValue; + while ( i-- ) { + INB ( ii2Safe ); + } + } +} +#endif + +//****************************************************************************** +// Function: ii2Nop() +// Parameters: None +// +// Returns: Nothing +// +// Description: +// +// iiInitialize will set i2eDelay to this if the delay parameter is NULL. This +// saves checking for a NULL pointer at every call. +//****************************************************************************** +static void +ii2Nop(void) +{ + return; // no mystery here +} + +//======================================================= +// Routines which are available in 8/16-bit versions, or +// in different fifo styles. These are ALL called +// indirectly through the board structure. +//======================================================= + +//****************************************************************************** +// Function: iiWriteBuf16(pB, address, count) +// Parameters: pB - pointer to board structure +// address - address of data to write +// count - number of data bytes to write +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Writes 'count' bytes from 'address' to the data fifo specified by the board +// structure pointer pB. Should count happen to be odd, an extra pad byte is +// sent (identity unknown...). Uses 16-bit (word) operations. Is called +// indirectly through pB->i2eWriteBuf. +// +//****************************************************************************** +static int +iiWriteBuf16(i2eBordStrPtr pB, unsigned char *address, int count) +{ + // Rudimentary sanity checking here. + if (pB->i2eValid != I2E_MAGIC) + COMPLETE(pB, I2EE_INVALID); + + OUTSW ( pB->i2eData, address, count); + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiWriteBuf8(pB, address, count) +// Parameters: pB - pointer to board structure +// address - address of data to write +// count - number of data bytes to write +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Writes 'count' bytes from 'address' to the data fifo specified by the board +// structure pointer pB. Should count happen to be odd, an extra pad byte is +// sent (identity unknown...). This is to be consistant with the 16-bit version. +// Uses 8-bit (byte) operations. Is called indirectly through pB->i2eWriteBuf. +// +//****************************************************************************** +static int +iiWriteBuf8(i2eBordStrPtr pB, unsigned char *address, int count) +{ + /* Rudimentary sanity checking here */ + if (pB->i2eValid != I2E_MAGIC) + COMPLETE(pB, I2EE_INVALID); + + OUTSB ( pB->i2eData, address, count ); + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiReadBuf16(pB, address, count) +// Parameters: pB - pointer to board structure +// address - address to put data read +// count - number of data bytes to read +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Reads 'count' bytes into 'address' from the data fifo specified by the board +// structure pointer pB. Should count happen to be odd, an extra pad byte is +// received (identity unknown...). Uses 16-bit (word) operations. Is called +// indirectly through pB->i2eReadBuf. +// +//****************************************************************************** +static int +iiReadBuf16(i2eBordStrPtr pB, unsigned char *address, int count) +{ + // Rudimentary sanity checking here. + if (pB->i2eValid != I2E_MAGIC) + COMPLETE(pB, I2EE_INVALID); + + INSW ( pB->i2eData, address, count); + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiReadBuf8(pB, address, count) +// Parameters: pB - pointer to board structure +// address - address to put data read +// count - number of data bytes to read +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Reads 'count' bytes into 'address' from the data fifo specified by the board +// structure pointer pB. Should count happen to be odd, an extra pad byte is +// received (identity unknown...). This to match the 16-bit behaviour. Uses +// 8-bit (byte) operations. Is called indirectly through pB->i2eReadBuf. +// +//****************************************************************************** +static int +iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count) +{ + // Rudimentary sanity checking here. + if (pB->i2eValid != I2E_MAGIC) + COMPLETE(pB, I2EE_INVALID); + + INSB ( pB->i2eData, address, count); + + COMPLETE(pB, I2EE_GOOD); +} + +//****************************************************************************** +// Function: iiReadWord16(pB) +// Parameters: pB - pointer to board structure +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Returns the word read from the data fifo specified by the board-structure +// pointer pB. Uses a 16-bit operation. Is called indirectly through +// pB->i2eReadWord. +// +//****************************************************************************** +static unsigned short +iiReadWord16(i2eBordStrPtr pB) +{ + return (unsigned short)( INW(pB->i2eData) ); +} + +//****************************************************************************** +// Function: iiReadWord8(pB) +// Parameters: pB - pointer to board structure +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Returns the word read from the data fifo specified by the board-structure +// pointer pB. Uses two 8-bit operations. Bytes are assumed to be LSB first. Is +// called indirectly through pB->i2eReadWord. +// +//****************************************************************************** +static unsigned short +iiReadWord8(i2eBordStrPtr pB) +{ + unsigned short urs; + + urs = INB ( pB->i2eData ); + + return ( ( INB ( pB->i2eData ) << 8 ) | urs ); +} + +//****************************************************************************** +// Function: iiWriteWord16(pB, value) +// Parameters: pB - pointer to board structure +// value - data to write +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Writes the word 'value' to the data fifo specified by the board-structure +// pointer pB. Uses 16-bit operation. Is called indirectly through +// pB->i2eWriteWord. +// +//****************************************************************************** +static void +iiWriteWord16(i2eBordStrPtr pB, unsigned short value) +{ + WORD_TO(pB, (int)value); +} + +//****************************************************************************** +// Function: iiWriteWord8(pB, value) +// Parameters: pB - pointer to board structure +// value - data to write +// +// Returns: True if everything appears copacetic. +// False if there is any error: the pB->i2eError field has the error +// +// Description: +// +// Writes the word 'value' to the data fifo specified by the board-structure +// pointer pB. Uses two 8-bit operations (writes LSB first). Is called +// indirectly through pB->i2eWriteWord. +// +//****************************************************************************** +static void +iiWriteWord8(i2eBordStrPtr pB, unsigned short value) +{ + BYTE_TO(pB, (char)value); + BYTE_TO(pB, (char)(value >> 8) ); +} + +//****************************************************************************** +// Function: iiWaitForTxEmptyII(pB, mSdelay) +// Parameters: pB - pointer to board structure +// mSdelay - period to wait before returning +// +// Returns: True if the FIFO is empty. +// False if it not empty in the required time: the pB->i2eError +// field has the error. +// +// Description: +// +// Waits up to "mSdelay" milliseconds for the outgoing FIFO to become empty; if +// not empty by the required time, returns false and error in pB->i2eError, +// otherwise returns true. +// +// mSdelay == 0 is taken to mean must be empty on the first test. +// +// This version operates on IntelliPort-II - style FIFO's +// +// Note this routine is organized so that if status is ok there is no delay at +// all called either before or after the test. Is called indirectly through +// pB->i2eWaitForTxEmpty. +// +//****************************************************************************** +static int +iiWaitForTxEmptyII(i2eBordStrPtr pB, int mSdelay) +{ + unsigned long flags; + int itemp; + + for (;;) + { + // This routine hinges on being able to see the "other" status register + // (as seen by the local processor). His incoming fifo is our outgoing + // FIFO. + // + // By the nature of this routine, you would be using this as part of a + // larger atomic context: i.e., you would use this routine to ensure the + // fifo empty, then act on this information. Between these two halves, + // you will generally not want to service interrupts or in any way + // disrupt the assumptions implicit in the larger context. + // + // Even worse, however, this routine "shifts" the status register to + // point to the local status register which is not the usual situation. + // Therefore for extra safety, we force the critical section to be + // completely atomic, and pick up after ourselves before allowing any + // interrupts of any kind. + + + WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags) + OUTB(pB->i2ePointer, SEL_COMMAND); + OUTB(pB->i2ePointer, SEL_CMD_SH); + + itemp = INB(pB->i2eStatus); + + OUTB(pB->i2ePointer, SEL_COMMAND); + OUTB(pB->i2ePointer, SEL_CMD_UNSH); + + if (itemp & ST_IN_EMPTY) + { + UPDATE_FIFO_ROOM(pB); + WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + COMPLETE(pB, I2EE_GOOD); + } + + WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + + if (mSdelay-- == 0) + break; + + iiDelay(pB, 1); /* 1 mS granularity on checking condition */ + } + COMPLETE(pB, I2EE_TXE_TIME); +} + +//****************************************************************************** +// Function: iiWaitForTxEmptyIIEX(pB, mSdelay) +// Parameters: pB - pointer to board structure +// mSdelay - period to wait before returning +// +// Returns: True if the FIFO is empty. +// False if it not empty in the required time: the pB->i2eError +// field has the error. +// +// Description: +// +// Waits up to "mSdelay" milliseconds for the outgoing FIFO to become empty; if +// not empty by the required time, returns false and error in pB->i2eError, +// otherwise returns true. +// +// mSdelay == 0 is taken to mean must be empty on the first test. +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +// Note this routine is organized so that if status is ok there is no delay at +// all called either before or after the test. Is called indirectly through +// pB->i2eWaitForTxEmpty. +// +//****************************************************************************** +static int +iiWaitForTxEmptyIIEX(i2eBordStrPtr pB, int mSdelay) +{ + unsigned long flags; + + for (;;) + { + // By the nature of this routine, you would be using this as part of a + // larger atomic context: i.e., you would use this routine to ensure the + // fifo empty, then act on this information. Between these two halves, + // you will generally not want to service interrupts or in any way + // disrupt the assumptions implicit in the larger context. + + WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags) + + if (INB(pB->i2eStatus) & STE_OUT_MT) { + UPDATE_FIFO_ROOM(pB); + WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + COMPLETE(pB, I2EE_GOOD); + } + WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + + if (mSdelay-- == 0) + break; + + iiDelay(pB, 1); // 1 mS granularity on checking condition + } + COMPLETE(pB, I2EE_TXE_TIME); +} + +//****************************************************************************** +// Function: iiTxMailEmptyII(pB) +// Parameters: pB - pointer to board structure +// +// Returns: True if the transmit mailbox is empty. +// False if it not empty. +// +// Description: +// +// Returns true or false according to whether the transmit mailbox is empty (and +// therefore able to accept more mail) +// +// This version operates on IntelliPort-II - style FIFO's +// +//****************************************************************************** +static int +iiTxMailEmptyII(i2eBordStrPtr pB) +{ + int port = pB->i2ePointer; + OUTB ( port, SEL_OUTMAIL ); + return ( INB(port) == 0 ); +} + +//****************************************************************************** +// Function: iiTxMailEmptyIIEX(pB) +// Parameters: pB - pointer to board structure +// +// Returns: True if the transmit mailbox is empty. +// False if it not empty. +// +// Description: +// +// Returns true or false according to whether the transmit mailbox is empty (and +// therefore able to accept more mail) +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +//****************************************************************************** +static int +iiTxMailEmptyIIEX(i2eBordStrPtr pB) +{ + return !(INB(pB->i2eStatus) & STE_OUT_MAIL); +} + +//****************************************************************************** +// Function: iiTrySendMailII(pB,mail) +// Parameters: pB - pointer to board structure +// mail - value to write to mailbox +// +// Returns: True if the transmit mailbox is empty, and mail is sent. +// False if it not empty. +// +// Description: +// +// If outgoing mailbox is empty, sends mail and returns true. If outgoing +// mailbox is not empty, returns false. +// +// This version operates on IntelliPort-II - style FIFO's +// +//****************************************************************************** +static int +iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail) +{ + int port = pB->i2ePointer; + + OUTB(port, SEL_OUTMAIL); + if (INB(port) == 0) { + OUTB(port, SEL_OUTMAIL); + OUTB(port, mail); + return 1; + } + return 0; +} + +//****************************************************************************** +// Function: iiTrySendMailIIEX(pB,mail) +// Parameters: pB - pointer to board structure +// mail - value to write to mailbox +// +// Returns: True if the transmit mailbox is empty, and mail is sent. +// False if it not empty. +// +// Description: +// +// If outgoing mailbox is empty, sends mail and returns true. If outgoing +// mailbox is not empty, returns false. +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +//****************************************************************************** +static int +iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail) +{ + if(INB(pB->i2eStatus) & STE_OUT_MAIL) { + return 0; + } + OUTB(pB->i2eXMail, mail); + return 1; +} + +//****************************************************************************** +// Function: iiGetMailII(pB,mail) +// Parameters: pB - pointer to board structure +// +// Returns: Mailbox data or NO_MAIL_HERE. +// +// Description: +// +// If no mail available, returns NO_MAIL_HERE otherwise returns the data from +// the mailbox, which is guaranteed != NO_MAIL_HERE. +// +// This version operates on IntelliPort-II - style FIFO's +// +//****************************************************************************** +static unsigned short +iiGetMailII(i2eBordStrPtr pB) +{ + if (HAS_MAIL(pB)) { + OUTB(pB->i2ePointer, SEL_INMAIL); + return INB(pB->i2ePointer); + } else { + return NO_MAIL_HERE; + } +} + +//****************************************************************************** +// Function: iiGetMailIIEX(pB,mail) +// Parameters: pB - pointer to board structure +// +// Returns: Mailbox data or NO_MAIL_HERE. +// +// Description: +// +// If no mail available, returns NO_MAIL_HERE otherwise returns the data from +// the mailbox, which is guaranteed != NO_MAIL_HERE. +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +//****************************************************************************** +static unsigned short +iiGetMailIIEX(i2eBordStrPtr pB) +{ + if (HAS_MAIL(pB)) { + return INB(pB->i2eXMail); + } else { + return NO_MAIL_HERE; + } +} + +//****************************************************************************** +// Function: iiEnableMailIrqII(pB) +// Parameters: pB - pointer to board structure +// +// Returns: Nothing +// +// Description: +// +// Enables board to interrupt host (only) by writing to host's in-bound mailbox. +// +// This version operates on IntelliPort-II - style FIFO's +// +//****************************************************************************** +static void +iiEnableMailIrqII(i2eBordStrPtr pB) +{ + OUTB(pB->i2ePointer, SEL_MASK); + OUTB(pB->i2ePointer, ST_IN_MAIL); +} + +//****************************************************************************** +// Function: iiEnableMailIrqIIEX(pB) +// Parameters: pB - pointer to board structure +// +// Returns: Nothing +// +// Description: +// +// Enables board to interrupt host (only) by writing to host's in-bound mailbox. +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +//****************************************************************************** +static void +iiEnableMailIrqIIEX(i2eBordStrPtr pB) +{ + OUTB(pB->i2eXMask, MX_IN_MAIL); +} + +//****************************************************************************** +// Function: iiWriteMaskII(pB) +// Parameters: pB - pointer to board structure +// +// Returns: Nothing +// +// Description: +// +// Writes arbitrary value to the mask register. +// +// This version operates on IntelliPort-II - style FIFO's +// +//****************************************************************************** +static void +iiWriteMaskII(i2eBordStrPtr pB, unsigned char value) +{ + OUTB(pB->i2ePointer, SEL_MASK); + OUTB(pB->i2ePointer, value); +} + +//****************************************************************************** +// Function: iiWriteMaskIIEX(pB) +// Parameters: pB - pointer to board structure +// +// Returns: Nothing +// +// Description: +// +// Writes arbitrary value to the mask register. +// +// This version operates on IntelliPort-IIEX - style FIFO's +// +//****************************************************************************** +static void +iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value) +{ + OUTB(pB->i2eXMask, value); +} + +//****************************************************************************** +// Function: iiDownloadBlock(pB, pSource, isStandard) +// Parameters: pB - pointer to board structure +// pSource - loadware block to download +// isStandard - True if "standard" loadware, else false. +// +// Returns: Success or Failure +// +// Description: +// +// Downloads a single block (at pSource)to the board referenced by pB. Caller +// sets isStandard to true/false according to whether the "standard" loadware is +// what's being loaded. The normal process, then, is to perform an iiInitialize +// to the board, then perform some number of iiDownloadBlocks using the returned +// state to determine when download is complete. +// +// Possible return values: (see I2ELLIS.H) +// II_DOWN_BADVALID +// II_DOWN_BADFILE +// II_DOWN_CONTINUING +// II_DOWN_GOOD +// II_DOWN_BAD +// II_DOWN_BADSTATE +// II_DOWN_TIMEOUT +// +// Uses the i2eState and i2eToLoad fields (initialized at iiInitialize) to +// determine whether this is the first block, whether to check for magic +// numbers, how many blocks there are to go... +// +//****************************************************************************** +static int +iiDownloadBlock ( i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard) +{ + int itemp; + int loadedFirst; + + if (pB->i2eValid != I2E_MAGIC) return II_DOWN_BADVALID; + + switch(pB->i2eState) + { + case II_STATE_READY: + + // Loading the first block after reset. Must check the magic number of the + // loadfile, store the number of blocks we expect to load. + if (pSource->e.loadMagic != MAGIC_LOADFILE) + { + return II_DOWN_BADFILE; + } + + // Next we store the total number of blocks to load, including this one. + pB->i2eToLoad = 1 + pSource->e.loadBlocksMore; + + // Set the state, store the version numbers. ('Cause this may have come + // from a file - we might want to report these versions and revisions in + // case of an error! + pB->i2eState = II_STATE_LOADING; + pB->i2eLVersion = pSource->e.loadVersion; + pB->i2eLRevision = pSource->e.loadRevision; + pB->i2eLSub = pSource->e.loadSubRevision; + + // The time and date of compilation is also available but don't bother + // storing it for normal purposes. + loadedFirst = 1; + break; + + case II_STATE_LOADING: + loadedFirst = 0; + break; + + default: + return II_DOWN_BADSTATE; + } + + // Now we must be in the II_STATE_LOADING state, and we assume i2eToLoad + // must be positive still, because otherwise we would have cleaned up last + // time and set the state to II_STATE_LOADED. + if (!iiWaitForTxEmpty(pB, MAX_DLOAD_READ_TIME)) { + return II_DOWN_TIMEOUT; + } + + if (!iiWriteBuf(pB, pSource->c, LOADWARE_BLOCK_SIZE)) { + return II_DOWN_BADVALID; + } + + // If we just loaded the first block, wait for the fifo to empty an extra + // long time to allow for any special startup code in the firmware, like + // sending status messages to the LCD's. + + if (loadedFirst) { + if (!iiWaitForTxEmpty(pB, MAX_DLOAD_START_TIME)) { + return II_DOWN_TIMEOUT; + } + } + + // Determine whether this was our last block! + if (--(pB->i2eToLoad)) { + return II_DOWN_CONTINUING; // more to come... + } + + // It WAS our last block: Clean up operations... + // ...Wait for last buffer to drain from the board... + if (!iiWaitForTxEmpty(pB, MAX_DLOAD_READ_TIME)) { + return II_DOWN_TIMEOUT; + } + // If there were only a single block written, this would come back + // immediately and be harmless, though not strictly necessary. + itemp = MAX_DLOAD_ACK_TIME/10; + while (--itemp) { + if (HAS_INPUT(pB)) { + switch(BYTE_FROM(pB)) + { + case LOADWARE_OK: + pB->i2eState = + isStandard ? II_STATE_STDLOADED :II_STATE_LOADED; + + // Some revisions of the bootstrap firmware (e.g. ISA-8 1.0.2) + // will, // if there is a debug port attached, require some + // time to send information to the debug port now. It will do + // this before // executing any of the code we just downloaded. + // It may take up to 700 milliseconds. + if (pB->i2ePom.e.porDiag2 & POR_DEBUG_PORT) { + iiDelay(pB, 700); + } + + return II_DOWN_GOOD; + + case LOADWARE_BAD: + default: + return II_DOWN_BAD; + } + } + + iiDelay(pB, 10); // 10 mS granularity on checking condition + } + + // Drop-through --> timed out waiting for firmware confirmation + + pB->i2eState = II_STATE_BADLOAD; + return II_DOWN_TIMEOUT; +} + +//****************************************************************************** +// Function: iiDownloadAll(pB, pSource, isStandard, size) +// Parameters: pB - pointer to board structure +// pSource - loadware block to download +// isStandard - True if "standard" loadware, else false. +// size - size of data to download (in bytes) +// +// Returns: Success or Failure +// +// Description: +// +// Given a pointer to a board structure, a pointer to the beginning of some +// loadware, whether it is considered the "standard loadware", and the size of +// the array in bytes loads the entire array to the board as loadware. +// +// Assumes the board has been freshly reset and the power-up reset message read. +// (i.e., in II_STATE_READY). Complains if state is bad, or if there seems to be +// too much or too little data to load, or if iiDownloadBlock complains. +//****************************************************************************** +static int +iiDownloadAll(i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard, int size) +{ + int status; + + // We know (from context) board should be ready for the first block of + // download. Complain if not. + if (pB->i2eState != II_STATE_READY) return II_DOWN_BADSTATE; + + while (size > 0) { + size -= LOADWARE_BLOCK_SIZE; // How much data should there be left to + // load after the following operation ? + + // Note we just bump pSource by "one", because its size is actually that + // of an entire block, same as LOADWARE_BLOCK_SIZE. + status = iiDownloadBlock(pB, pSource++, isStandard); + + switch(status) + { + case II_DOWN_GOOD: + return ( (size > 0) ? II_DOWN_OVER : II_DOWN_GOOD); + + case II_DOWN_CONTINUING: + break; + + default: + return status; + } + } + + // We shouldn't drop out: it means "while" caught us with nothing left to + // download, yet the previous DownloadBlock did not return complete. Ergo, + // not enough data to match the size byte in the header. + return II_DOWN_UNDER; +} diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2ellis.h linux/drivers/char/ip2/i2ellis.h --- v2.3.14/linux/drivers/char/ip2/i2ellis.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2ellis.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,609 @@ +/******************************************************************************* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Mainline code for the device driver +* +*******************************************************************************/ +//------------------------------------------------------------------------------ +// i2ellis.h +// +// IntelliPort-II and IntelliPort-IIEX +// +// Extremely +// Low +// Level +// Interface +// Services +// +// Structure Definitions and declarations for "ELLIS" service routines found in +// i2ellis.c +// +// These routines are based on properties of the IntelliPort-II and -IIEX +// hardware and bootstrap firmware, and are not sensitive to particular +// conventions of any particular loadware. +// +// Unlike i2hw.h, which provides IRONCLAD hardware definitions, the material +// here and in i2ellis.c is intended to provice a useful, but not required, +// layer of insulation from the hardware specifics. +//------------------------------------------------------------------------------ +#ifndef I2ELLIS_H /* To prevent multiple includes */ +#define I2ELLIS_H 1 +//------------------------------------------------ +// Revision History: +// +// 30 September 1991 MAG First Draft Started +// 12 October 1991 ...continued... +// +// 20 December 1996 AKM Linux version +//------------------------------------------------- + +//---------------------- +// Mandatory Includes: +//---------------------- +#include "ip2types.h" +#include "i2hw.h" // The hardware definitions + +//------------------------------------------ +// STAT_BOXIDS packets +//------------------------------------------ +#define MAX_BOX 4 + +typedef struct _bidStat +{ + unsigned char bid_value[MAX_BOX]; +} bidStat, *bidStatPtr; + +// This packet is sent in response to a CMD_GET_BOXIDS bypass command. For -IIEX +// boards, reports the hardware-specific "asynchronous resource register" on +// each expansion box. Boxes not present report 0xff. For -II boards, the first +// element contains 0x80 for 8-port, 0x40 for 4-port boards. + +// Box IDs aka ARR or Async Resource Register (more than you want to know) +// 7 6 5 4 3 2 1 0 +// F F N N L S S S +// ============================= +// F F - Product Family Designator +// =====+++++++++++++++++++++++++++++++ +// 0 0 - Intelliport II EX / ISA-8 +// 1 0 - IntelliServer +// 0 1 - SAC - Port Device (Intelliport III ??? ) +// =====+++++++++++++++++++++++++++++++++++++++ +// N N - Number of Ports +// 0 0 - 8 (eight) +// 0 1 - 4 (four) +// 1 0 - 12 (twelve) +// 1 1 - 16 (sixteen) +// =++++++++++++++++++++++++++++++++++ +// L - LCD Display Module Present +// 0 - No +// 1 - LCD module present +// =========+++++++++++++++++++++++++++++++++++++ +// S S S - Async Signals Supported Designator +// 0 0 0 - 8dss, Mod DCE DB25 Female +// 0 0 1 - 6dss, RJ-45 +// 0 1 0 - RS-232/422 dss, DB25 Female +// 0 1 1 - RS-232/422 dss, separate 232/422 DB25 Female +// 1 0 0 - 6dss, 921.6 I/F with ST654's +// 1 0 1 - RS-423/232 8dss, RJ-45 10Pin +// 1 1 0 - 6dss, Mod DCE DB25 Female +// 1 1 1 - NO BOX PRESENT + +#define FF(c) ((c & 0xC0) >> 6) +#define NN(c) ((c & 0x30) >> 4) +#define L(c) ((c & 0x08) >> 3) +#define SSS(c) (c & 0x07) + +#define BID_HAS_654(x) (SSS(x) == 0x04) +#define BID_NO_BOX 0xff /* no box */ +#define BID_8PORT 0x80 /* IP2-8 port */ +#define BID_4PORT 0x81 /* IP2-4 port */ +#define BID_EXP_MASK 0x30 /* IP2-EX */ +#define BID_EXP_8PORT 0x00 /* 8, */ +#define BID_EXP_4PORT 0x10 /* 4, */ +#define BID_EXP_UNDEF 0x20 /* UNDEF, */ +#define BID_EXP_16PORT 0x30 /* 16, */ +#define BID_LCD_CTRL 0x08 /* LCD Controller */ +#define BID_LCD_NONE 0x00 /* - no controller present */ +#define BID_LCD_PRES 0x08 /* - controller present */ +#define BID_CON_MASK 0x07 /* - connector pinouts */ +#define BID_CON_DB25 0x00 /* - DB-25 F */ +#define BID_CON_RJ45 0x01 /* - rj45 */ + +//------------------------------------------------------------------------------ +// i2eBordStr +// +// This structure contains all the information the ELLIS routines require in +// dealing with a particular board. +//------------------------------------------------------------------------------ +// There are some queues here which are guaranteed to never contain the entry +// for a single channel twice. So they must be slightly larger to allow +// unambiguous full/empty management +// +#define CH_QUEUE_SIZE ABS_MOST_PORTS+2 + +typedef struct _i2eBordStr +{ + porStr i2ePom; // Structure containing the power-on message. + + unsigned short i2ePomSize; + // The number of bytes actually read if + // different from sizeof i2ePom, indicates + // there is an error! + + unsigned short i2eStartMail; + // Contains whatever inbound mailbox data + // present at startup. NO_MAIL_HERE indicates + // nothing was present. No special + // significance as of this writing, but may be + // useful for diagnostic reasons. + + unsigned short i2eValid; + // Indicates validity of the structure; if + // i2eValid == I2E_MAGIC, then we can trust + // the other fields. Some (especially + // initialization) functions are good about + // checking for validity. Many functions do + // not, it being assumed that the larger + // context assures we are using a valid + // i2eBordStrPtr. + + unsigned short i2eError; + // Used for returning an error condition from + // several functions which use i2eBordStrPtr + // as an argument. + + // Accelerators to characterize separate features of a board, derived from a + // number of sources. + + unsigned short i2eFifoSize; + // Always, the size of the FIFO. For + // IntelliPort-II, always the same, for -IIEX + // taken from the Power-On reset message. + + volatile + unsigned short i2eFifoRemains; + // Used during normal operation to indicate a + // lower bound on the amount of data which + // might be in the outbound fifo. + + unsigned char i2eFifoStyle; + // Accelerator which tells which style (-II or + // -IIEX) FIFO we are using. + + unsigned char i2eDataWidth16; + // Accelerator which tells whether we should + // do 8 or 16-bit data transfers. + + unsigned char i2eMaxIrq; + // The highest allowable IRQ, based on the + // slot size. + + unsigned char i2eChangeIrq; + // Whether tis valid to change IRQ's + // ISA = ok, EISA, MicroChannel, no + + // Accelerators for various addresses on the board + int i2eBase; // I/O Address of the Board + int i2eData; // From here data transfers happen + int i2eStatus; // From here status reads happen + int i2ePointer; // (IntelliPort-II: pointer/commands) + int i2eXMail; // (IntelliPOrt-IIEX: mailboxes + int i2eXMask; // (IntelliPort-IIEX: mask write + + //------------------------------------------------------- + // Information presented in a common format across boards + // For each box, bit map of the channels present. Box closest to + // the host is box 0. LSB is channel 0. IntelliPort-II (non-expandable) + // is taken to be box 0. These are derived from product i.d. registers. + + unsigned short i2eChannelMap[ABS_MAX_BOXES]; + + // Same as above, except each is derived from firmware attempting to detect + // the uart presence (by reading a valid GFRCR register). If bits are set in + // i2eChannelMap and not in i2eGoodMap, there is a potential problem. + + unsigned short i2eGoodMap[ABS_MAX_BOXES]; + + // --------------------------- + // For indirect function calls + + // Routine to cause an N-millisecond delay: Patched by the ii2Initialize + // function. + + void (*i2eDelay)(unsigned int); + + // Routine to write N bytes to the board through the FIFO. Returns true if + // all copacetic, otherwise returns false and error is in i2eError field. + // IF COUNT IS ODD, ROUNDS UP TO THE NEXT EVEN NUMBER. + + int (*i2eWriteBuf)(struct _i2eBordStr *, unsigned char *, int); + + // Routine to read N bytes from the board through the FIFO. Returns true if + // copacetic, otherwise returns false and error in i2eError. + // IF COUNT IS ODD, ROUNDS UP TO THE NEXT EVEN NUMBER. + + int (*i2eReadBuf)(struct _i2eBordStr *, unsigned char *, int); + + // Returns a word from FIFO. Will use 2 byte operations if needed. + + unsigned short (*i2eReadWord)(struct _i2eBordStr *); + + // Writes a word to FIFO. Will use 2 byte operations if needed. + + void (*i2eWriteWord)(struct _i2eBordStr *, unsigned short); + + // Waits specified time for the Transmit FIFO to go empty. Returns true if + // ok, otherwise returns false and error in i2eError. + + int (*i2eWaitForTxEmpty)(struct _i2eBordStr *, int); + + // Returns true or false according to whether the outgoing mailbox is empty. + + int (*i2eTxMailEmpty)(struct _i2eBordStr *); + + // Checks whether outgoing mailbox is empty. If so, sends mail and returns + // true. Otherwise returns false. + + int (*i2eTrySendMail)(struct _i2eBordStr *, unsigned char); + + // If no mail available, returns NO_MAIL_HERE, else returns the value in the + // mailbox (guaranteed can't be NO_MAIL_HERE). + + unsigned short (*i2eGetMail)(struct _i2eBordStr *); + + // Enables the board to interrupt the host when it writes to the mailbox. + // Irqs will not occur, however, until the loadware separately enables + // interrupt generation to the host. The standard loadware does this in + // response to a command packet sent by the host. (Also, disables + // any other potential interrupt sources from the board -- other than the + // inbound mailbox). + + void (*i2eEnableMailIrq)(struct _i2eBordStr *); + + // Writes an arbitrary value to the mask register. + + void (*i2eWriteMask)(struct _i2eBordStr *, unsigned char); + + + // State information + + // During downloading, indicates the number of blocks remaining to download + // to the board. + + short i2eToLoad; + + // State of board (see manifests below) (e.g., whether in reset condition, + // whether standard loadware is installed, etc. + + unsigned char i2eState; + + // These three fields are only valid when there is loadware running on the + // board. (i2eState == II_STATE_LOADED or i2eState == II_STATE_STDLOADED ) + + unsigned char i2eLVersion; // Loadware version + unsigned char i2eLRevision; // Loadware revision + unsigned char i2eLSub; // Loadware subrevision + + // Flags which only have meaning in the context of the standard loadware. + // Somewhat violates the layering concept, but there is so little additional + // needed at the board level (while much additional at the channel level), + // that this beats maintaining two different per-board structures. + + // Indicates which IRQ the board has been initialized (from software) to use + // For MicroChannel boards, any value different from IRQ_UNDEFINED means + // that the software command has been sent to enable interrupts (or specify + // they are disabled). Special value: IRQ_UNDEFINED indicates that the + // software command to select the interrupt has not yet been sent, therefore + // (since the standard loadware insists that it be sent before any other + // packets are sent) no other packets should be sent yet. + + unsigned short i2eUsingIrq; + + // This is set when we hit the MB_OUT_STUFFED mailbox, which prevents us + // putting more in the mailbox until an appropriate mailbox message is + // received. + + unsigned char i2eWaitingForEmptyFifo; + + // Any mailbox bits waiting to be sent to the board are OR'ed in here. + + unsigned char i2eOutMailWaiting; + + // The head of any incoming packet is read into here, is then examined and + // we dispatch accordingly. + + unsigned short i2eLeadoffWord[1]; + + // Running counter of interrupts where the mailbox indicated incoming data. + + unsigned short i2eFifoInInts; + + // Running counter of interrupts where the mailbox indicated outgoing data + // had been stripped. + + unsigned short i2eFifoOutInts; + + // If not void, gives the address of a routine to call if fatal board error + // is found (only applies to standard l/w). + + void (*i2eFatalTrap)(struct _i2eBordStr *); + + // Will point to an array of some sort of channel structures (whose format + // is unknown at this level, being a function of what loadware is + // installed and the code configuration (max sizes of buffers, etc.)). + + void *i2eChannelPtr; + + // Set indicates that the board has gone fatal. + + unsigned short i2eFatal; + + // The number of elements pointed to by i2eChannelPtr. + + unsigned short i2eChannelCnt; + + // Ring-buffers of channel structures whose channels have particular needs. + + spinlock_t Fbuf_spinlock; + volatile + unsigned short i2Fbuf_strip; // Strip index + volatile + unsigned short i2Fbuf_stuff; // Stuff index + void *i2Fbuf[CH_QUEUE_SIZE]; // An array of channel pointers + // of channels who need to send + // flow control packets. + spinlock_t Dbuf_spinlock; + volatile + unsigned short i2Dbuf_strip; // Strip index + volatile + unsigned short i2Dbuf_stuff; // Stuff index + void *i2Dbuf[CH_QUEUE_SIZE]; // An array of channel pointers + // of channels who need to send + // data or in-line command packets. + spinlock_t Bbuf_spinlock; + volatile + unsigned short i2Bbuf_strip; // Strip index + volatile + unsigned short i2Bbuf_stuff; // Stuff index + void *i2Bbuf[CH_QUEUE_SIZE]; // An array of channel pointers + // of channels who need to send + // bypass command packets. + + /* + * A set of flags to indicate that certain events have occurred on at least + * one of the ports on this board. We use this to decide whether to spin + * through the channels looking for breaks, etc. + */ + int got_input; + int status_change; + bidStat channelBtypes; + + /* + * Debugging counters, etc. + */ + unsigned long debugFlowQueued; + unsigned long debugInlineQueued; + unsigned long debugDataQueued; + unsigned long debugBypassQueued; + unsigned long debugFlowCount; + unsigned long debugInlineCount; + unsigned long debugBypassCount; + + spinlock_t read_fifo_spinlock; + spinlock_t write_fifo_spinlock; + +} i2eBordStr, *i2eBordStrPtr; + +//------------------------------------------------------------------- +// Macro Definitions for the indirect calls defined in the i2eBordStr +//------------------------------------------------------------------- +// +#define iiDelay(a,b) (*(a)->i2eDelay)(b) +#define iiWriteBuf(a,b,c) (*(a)->i2eWriteBuf)(a,b,c) +#define iiReadBuf(a,b,c) (*(a)->i2eReadBuf)(a,b,c) + +#define iiWriteWord(a,b) (*(a)->i2eWriteWord)(a,b) +#define iiReadWord(a) (*(a)->i2eReadWord)(a) + +#define iiWaitForTxEmpty(a,b) (*(a)->i2eWaitForTxEmpty)(a,b) + +#define iiTxMailEmpty(a) (*(a)->i2eTxMailEmpty)(a) +#define iiTrySendMail(a,b) (*(a)->i2eTrySendMail)(a,b) + +#define iiGetMail(a) (*(a)->i2eGetMail)(a) +#define iiEnableMailIrq(a) (*(a)->i2eEnableMailIrq)(a) +#define iiDisableMailIrq(a) (*(a)->i2eWriteMask)(a,0) +#define iiWriteMask(a,b) (*(a)->i2eWriteMask)(a,b) + +//------------------------------------------- +// Manifests for i2eBordStr: +//------------------------------------------- + +#define YES 1 +#define NO 0 + +#define NULLFUNC (void (*)(void))0 +#define NULLPTR (void *)0 + +typedef void (*delayFunc_t)(unsigned int); + +// i2eValid +// +#define I2E_MAGIC 0x4251 // Structure is valid. +#define I2E_INCOMPLETE 0x1122 // Structure failed during init. + + +// i2eError +// +#define I2EE_GOOD 0 // Operation successful +#define I2EE_BADADDR 1 // Address out of range +#define I2EE_BADSTATE 2 // Attempt to perform a function when the board + // structure was in the incorrect state +#define I2EE_BADMAGIC 3 // Bad magic number from Power On test (i2ePomSize + // reflects what was read +#define I2EE_PORM_SHORT 4 // Power On message too short +#define I2EE_PORM_LONG 5 // Power On message too long +#define I2EE_BAD_FAMILY 6 // Un-supported board family type +#define I2EE_INCONSIST 7 // Firmware reports something impossible, + // e.g. unexpected number of ports... Almost no + // excuse other than bad FIFO... +#define I2EE_POSTERR 8 // Power-On self test reported a bad error +#define I2EE_BADBUS 9 // Unknown Bus type declared in message +#define I2EE_TXE_TIME 10 // Timed out waiting for TX Fifo to empty +#define I2EE_INVALID 11 // i2eValid field does not indicate a valid and + // complete board structure (for functions which + // require this be so.) +#define I2EE_BAD_PORT 12 // Discrepancy between channels actually found and + // what the product is supposed to have. Check + // i2eGoodMap vs i2eChannelMap for details. +#define I2EE_BAD_IRQ 13 // Someone specified an unsupported IRQ +#define I2EE_NOCHANNELS 14 // No channel structures have been defined (for + // functions requiring this). + +// i2eFifoStyle +// +#define FIFO_II 0 /* IntelliPort-II style: see also i2hw.h */ +#define FIFO_IIEX 1 /* IntelliPort-IIEX style */ + +// i2eGetMail +// +#define NO_MAIL_HERE 0x1111 // Since mail is unsigned char, cannot possibly + // promote to 0x1111. +// i2eState +// +#define II_STATE_COLD 0 // Addresses have been defined, but board not even + // reset yet. +#define II_STATE_RESET 1 // Board,if it exists, has just been reset +#define II_STATE_READY 2 // Board ready for its first block +#define II_STATE_LOADING 3 // Board continuing load +#define II_STATE_LOADED 4 // Board has finished load: status ok +#define II_STATE_BADLOAD 5 // Board has finished load: failed! +#define II_STATE_STDLOADED 6 // Board has finished load: standard firmware + +// i2eUsingIrq +// +#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever + // promote to this! +//------------------------------------------ +// Handy Macros for i2ellis.c and others +// Note these are common to -II and -IIEX +//------------------------------------------ + +// Given a pointer to the board structure, does the input FIFO have any data or +// not? +// +#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY) +#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY) + +// Given a pointer to board structure, read a byte or word from the fifo +// +#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData) +#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData) + +// Given a pointer to board structure, is there room for any data to be written +// to the data fifo? +// +#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL) +#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL) + +// Given a pointer to board structure, write a single byte to the fifo +// structure. Note that for 16-bit interfaces, the high order byte is undefined +// and unknown. +// +#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c)) + +// Write a word to the fifo structure. For 8-bit interfaces, this may have +// unknown results. +// +#define WORD_TO(pB, c) OUTW(pB->i2eData,(c)) + +// Given a pointer to the board structure, is there anything in the incoming +// mailbox? +// +#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL) + +#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize + +// Handy macro to round up a number (like the buffer write and read routines do) +// +#define ROUNDUP(number) (((number)+1) & (~1)) + +//------------------------------------------ +// Function Declarations for i2ellis.c +//------------------------------------------ +// +// Functions called directly +// +// Initialization of a board & structure is in four (five!) parts: +// +// 0) iiEllisInit() - Initialize iiEllis subsystem. +// 1) iiSetAddress() - Define the board address & delay function for a board. +// 2) iiReset() - Reset the board (provided it exists) +// -- Note you may do this to several boards -- +// 3) iiResetDelay() - Delay for 2 seconds (once for all boards) +// 4) iiInitialize() - Attempt to read Power-up message; further initialize +// accelerators +// +// Then you may use iiDownloadAll() or iiDownloadFile() (in i2file.c) to write +// loadware. To change loadware, you must begin again with step 2, resetting +// the board again (step 1 not needed). + +static void iiEllisInit(void); +static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t ); +static int iiReset(i2eBordStrPtr); +static int iiResetDelay(i2eBordStrPtr); +static int iiInitialize(i2eBordStrPtr); + +// Routine to validate that all channels expected are there. +// +extern int iiValidateChannels(i2eBordStrPtr); + +// Routine used to download a block of loadware. +// +static int iiDownloadBlock(i2eBordStrPtr, loadHdrStrPtr, int); + +// Return values given by iiDownloadBlock, iiDownloadAll, iiDownloadFile: +// +#define II_DOWN_BADVALID 0 // board structure is invalid +#define II_DOWN_CONTINUING 1 // So far, so good, firmware expects more +#define II_DOWN_GOOD 2 // Download complete, CRC good +#define II_DOWN_BAD 3 // Download complete, but CRC bad +#define II_DOWN_BADFILE 4 // Bad magic number in loadware file +#define II_DOWN_BADSTATE 5 // Board is in an inappropriate state for + // downloading loadware. (see i2eState) +#define II_DOWN_TIMEOUT 6 // Timeout waiting for firmware +#define II_DOWN_OVER 7 // Too much data +#define II_DOWN_UNDER 8 // Not enough data +#define II_DOWN_NOFILE 9 // Loadware file not found + +// Routine to download an entire loadware module: Return values are a subset of +// iiDownloadBlock's, excluding, of course, II_DOWN_CONTINUING +// +static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int); + +// Called indirectly always. Needed externally so the routine might be +// SPECIFIED as an argument to iiReset() +// +//static void ii2DelayIO(unsigned int); // N-millisecond delay using + //hardware spin +//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux + //timer + +// Many functions defined here return True if good, False otherwise, with an +// error code in i2eError field. Here is a handy macro for setting the error +// code and returning. +// +#define COMPLETE(pB,code) \ + if(1){ \ + pB->i2eError = code; \ + return (code == I2EE_GOOD);\ + } + +#endif // I2ELLIS_H diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2hw.h linux/drivers/char/ip2/i2hw.h --- v2.3.14/linux/drivers/char/ip2/i2hw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2hw.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,648 @@ +/******************************************************************************* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Definitions limited to properties of the hardware or the +* bootstrap firmware. As such, they are applicable regardless of +* operating system or loadware (standard or diagnostic). +* +*******************************************************************************/ +#ifndef I2HW_H +#define I2HW_H 1 +//------------------------------------------------------------------------------ +// Revision History: +// +// 23 September 1991 MAG First Draft Started...through... +// 11 October 1991 ... Continuing development... +// 6 August 1993 Added support for ISA-4 (asic) which is architected +// as an ISA-CEX with a single 4-port box. +// +// 20 December 1996 AKM Version for Linux +// +//------------------------------------------------------------------------------ +/*------------------------------------------------------------------------------ + +HARDWARE DESCRIPTION: + +Introduction: + +The IntelliPort-II and IntelliPort-IIEX products occupy a block of eight (8) +addresses in the host's I/O space. + +Some addresses are used to transfer data to/from the board, some to transfer +so-called "mailbox" messages, and some to read bit-mapped status information. +While all the products in the line are functionally similar, some use a 16-bit +data path to transfer data while others use an 8-bit path. Also, the use of +command /status/mailbox registers differs slightly between the II and IIEX +branches of the family. + +The host determines what type of board it is dealing with by reading a string of +sixteen characters from the board. These characters are always placed in the +fifo by the board's local processor whenever the board is reset (either from +power-on or under software control) and are known as the "Power-on Reset +Message." In order that this message can be read from either type of board, the +hardware registers used in reading this message are the same. Once this message +has been read by the host, then it has the information required to operate. + +General Differences between boards: + +The greatest structural difference is between the -II and -IIEX families of +product. The -II boards use the Am4701 dual 512x8 bidirectional fifo to support +the data path, mailbox registers, and status registers. This chip contains some +features which are not used in the IntelliPort-II products; a description of +these is omitted here. Because of these many features, it contains many +registers, too many to access directly within a small address space. They are +accessed by first writing a value to a "pointer" register. This value selects +the register to be accessed. The next read or write to that address accesses +the selected register rather than the pointer register. + +The -IIEX boards use a proprietary design similar to the Am4701 in function. But +because of a simpler, more streamlined design it doesn't require so many +registers. This means they can be accessed directly in single operations rather +than through a pointer register. + +Besides these differences, there are differences in whether 8-bit or 16-bit +transfers are used to move data to the board. + +The -II boards are capable only of 8-bit data transfers, while the -IIEX boards +may be configured for either 8-bit or 16-bit data transfers. If the on-board DIP +switch #8 is ON, and the card has been installed in a 16-bit slot, 16-bit +transfers are supported (and will be expected by the standard loadware). The +on-board firmware can determine the position of the switch, and whether the +board is installed in a 16-bit slot; it supplies this information to the host as +part of the power-up reset message. + +The configuration switch (#8) and slot selection do not directly configure the +hardware. It is up to the on-board loadware and host-based drivers to act +according to the selected options. That is, loadware and drivers could be +written to perform 8-bit transfers regardless of the state of the DIP switch or +slot (and in a diagnostic environment might well do so). Likewise, 16-bit +transfers could be performed as long as the card is in a 16-bit slot. + +Note the slot selection and DIP switch selection are provided separately: a +board running in 8-bit mode in a 16-bit slot has a greater range of possible +interrupts to choose from; information of potential use to the host. + +All 8-bit data transfers are done in the same way, regardless of whether on a +-II board or a -IIEX board. + +The host must consider two things then: 1) whether a -II or -IIEX product is +being used, and 2) whether an 8-bit or 16-bit data path is used. + +A further difference is that -II boards always have a 512-byte fifo operating in +each direction. -IIEX boards may use fifos of varying size; this size is +reported as part of the power-up message. + +I/O Map Of IntelliPort-II and IntelliPort-IIEX boards: +(Relative to the chosen base address) + +Addr R/W IntelliPort-II IntelliPort-IIEX +---- --- -------------- ---------------- +0 R/W Data Port (byte) Data Port (byte or word) +1 R/W (Not used) (MSB of word-wide data written to Data Port) +2 R Status Register Status Register +2 W Pointer Register Interrupt Mask Register +3 R/W (Not used) Mailbox Registers (6 bits: 11111100) +4,5 -- Reserved for future products +6 -- Reserved for future products +7 R Guaranteed to have no effect +7 W Hardware reset of board. + + +Rules: +All data transfers are performed using the even i/o address. If byte-wide data +transfers are being used, do INB/OUTB operations on the data port. If word-wide +transfers are used, do INW/OUTW operations. In some circumstances (such as +reading the power-up message) you will do INB from the data port, but in this +case the MSB of each word read is lost. When accessing all other unreserved +registers, use byte operations only. +------------------------------------------------------------------------------*/ + +//------------------------------------------------ +// Mandatory Includes: +//------------------------------------------------ +// +#include "ip2types.h" +#include "i2os.h" /* For any o.s., compiler, or host-related issues */ + +//------------------------------------------------------------------------- +// Manifests for the I/O map: +//------------------------------------------------------------------------- +// R/W: Data port (byte) for IntelliPort-II, +// R/W: Data port (byte or word) for IntelliPort-IIEX +// Incoming or outgoing data passes through a FIFO, the status of which is +// available in some of the bits in FIFO_STATUS. This (bidirectional) FIFO is +// the primary means of transferring data, commands, flow-control, and status +// information between the host and board. +// +#define FIFO_DATA 0 + +// Another way of passing information between the the board and the host is +// through "mailboxes". Unlike a FIFO, a mailbox holds only a single byte of +// data. Writing data to the mailbox causes a status bit to be set, and +// potentially interrupting the intended receiver. The sender has some way to +// determine whether the data has been read yet; as soon as it has, it may send +// more. The mailboxes are handled differently on -II and -IIEX products, as +// suggested below. +//------------------------------------------------------------------------------ +// Read: Status Register for IntelliPort-II or -IIEX +// The presence of any bit set here will cause an interrupt to the host, +// provided the corresponding bit has been unmasked in the interrupt mask +// register. Furthermore, interrupts to the host are disabled globally until the +// loadware selects the irq line to use. With the exception of STN_MR, the bits +// remain set so long as the associated condition is true. +// +#define FIFO_STATUS 2 + +// Bit map of status bits which are identical for -II and -IIEX +// +#define ST_OUT_FULL 0x40 // Outbound FIFO full +#define ST_IN_EMPTY 0x20 // Inbound FIFO empty +#define ST_IN_MAIL 0x04 // Inbound Mailbox full + +// The following exists only on the Intelliport-IIEX, and indicates that the +// board has not read the last outgoing mailbox data yet. In the IntelliPort-II, +// the outgoing mailbox may be read back: a zero indicates the board has read +// the data. +// +#define STE_OUT_MAIL 0x80 // Outbound mailbox full (!) + +// The following bits are defined differently for -II and -IIEX boards. Code +// which relies on these bits will need to be functionally different for the two +// types of boards and should be generally avoided because of the additional +// complexity this creates: + +// Bit map of status bits only on -II + +// Fifo has been RESET (cleared when the status register is read). Note that +// this condition cannot be masked and would always interrupt the host, except +// that the hardware reset also disables interrupts globally from the board +// until re-enabled by loadware. This could also arise from the +// Am4701-supported command to reset the chip, but this command is generally not +// used here. +// +#define STN_MR 0x80 + +// See the AMD Am4701 data sheet for details on the following four bits. They +// are not presently used by Computone drivers. +// +#define STN_OUT_AF 0x10 // Outbound FIFO almost full (programmable) +#define STN_IN_AE 0x08 // Inbound FIFO almost empty (programmable) +#define STN_BD 0x02 // Inbound byte detected +#define STN_PE 0x01 // Parity/Framing condition detected + +// Bit-map of status bits only on -IIEX +// +#define STE_OUT_HF 0x10 // Outbound FIFO half full +#define STE_IN_HF 0x08 // Inbound FIFO half full +#define STE_IN_FULL 0x02 // Inbound FIFO full +#define STE_OUT_MT 0x01 // Outbound FIFO empty + +//------------------------------------------------------------------------------ + +// Intelliport-II -- Write Only: the pointer register. +// Values are written to this register to select the Am4701 internal register to +// be accessed on the next operation. +// +#define FIFO_PTR 0x02 + +// Values for the pointer register +// +#define SEL_COMMAND 0x1 // Selects the Am4701 command register + +// Some possible commands: +// +#define SEL_CMD_MR 0x80 // Am4701 command to reset the chip +#define SEL_CMD_SH 0x40 // Am4701 command to map the "other" port into the + // status register. +#define SEL_CMD_UNSH 0 // Am4701 command to "unshift": port maps into its + // own status register. +#define SEL_MASK 0x2 // Selects the Am4701 interrupt mask register. The + // interrupt mask register is bit-mapped to match + // the status register (FIFO_STATUS) except for + // STN_MR. (See above.) +#define SEL_BYTE_DET 0x3 // Selects the Am4701 byte-detect register. (Not + // normally used except in diagnostics.) +#define SEL_OUTMAIL 0x4 // Selects the outbound mailbox (R/W). Reading back + // a value of zero indicates that the mailbox has + // been read by the board and is available for more + // data./ Writing to the mailbox optionally + // interrupts the board, depending on the loadware's + // setting of its interrupt mask register. +#define SEL_AEAF 0x5 // Selects AE/AF threshold register. +#define SEL_INMAIL 0x6 // Selects the inbound mailbox (Read) + +//------------------------------------------------------------------------------ +// IntelliPort-IIEX -- Write Only: interrupt mask (and misc flags) register: +// Unlike IntelliPort-II, bit assignments do NOT match those of the status +// register. +// +#define FIFO_MASK 0x2 + +// Mailbox readback select: +// If set, reads to FIFO_MAIL will read the OUTBOUND mailbox (host to board). If +// clear (default on reset) reads to FIFO_MAIL will read the INBOUND mailbox. +// This is the normal situation. The clearing of a mailbox is determined on +// -IIEX boards by waiting for the STE_OUT_MAIL bit to clear. Readback +// capability is provided for diagnostic purposes only. +// +#define MX_OUTMAIL_RSEL 0x80 + +#define MX_IN_MAIL 0x40 // Enables interrupts when incoming mailbox goes + // full (ST_IN_MAIL set). +#define MX_IN_FULL 0x20 // Enables interrupts when incoming FIFO goes full + // (STE_IN_FULL). +#define MX_IN_MT 0x08 // Enables interrupts when incoming FIFO goes empty + // (ST_IN_MT). +#define MX_OUT_FULL 0x04 // Enables interrupts when outgoing FIFO goes full + // (ST_OUT_FULL). +#define MX_OUT_MT 0x01 // Enables interrupts when outgoing FIFO goes empty + // (STE_OUT_MT). + +// Any remaining bits are reserved, and should be written to ZERO for +// compatibility with future Computone products. + +//------------------------------------------------------------------------------ +// IntelliPort-IIEX: -- These are only 6-bit mailboxes !!! -- 11111100 (low two +// bits always read back 0). +// Read: One of the mailboxes, usually Inbound. +// Inbound Mailbox (MX_OUTMAIL_RSEL = 0) +// Outbound Mailbox (MX_OUTMAIL_RSEL = 1) +// Write: Outbound Mailbox +// For the IntelliPort-II boards, the outbound mailbox is read back to determine +// whether the board has read the data (0 --> data has been read). For the +// IntelliPort-IIEX, this is done by reading a status register. To determine +// whether mailbox is available for more outbound data, use the STE_OUT_MAIL bit +// in FIFO_STATUS. Moreover, although the Outbound Mailbox can be read back by +// setting MX_OUTMAIL_RSEL, it is NOT cleared when the board reads it, as is the +// case with the -II boards. For this reason, FIFO_MAIL is normally used to read +// the inbound FIFO, and MX_OUTMAIL_RSEL kept clear. (See above for +// MX_OUTMAIL_RSEL description.) +// +#define FIFO_MAIL 0x3 + +//------------------------------------------------------------------------------ +// WRITE ONLY: Resets the board. (Data doesn't matter). +// +#define FIFO_RESET 0x7 + +//------------------------------------------------------------------------------ +// READ ONLY: Will have no effect. (Data is undefined.) +// Actually, there will be an effect, in that the operation is sure to generate +// a bus cycle: viz., an I/O byte Read. This fact can be used to enforce short +// delays when no comparable time constant is available. +// +#define FIFO_NOP 0x7 + +//------------------------------------------------------------------------------ +// RESET & POWER-ON RESET MESSAGE +/*------------------------------------------------------------------------------ +RESET: + +The IntelliPort-II and -IIEX boards are reset in three ways: Power-up, channel +reset, and via a write to the reset register described above. For products using +the ISA bus, these three sources of reset are equvalent. For MCA and EISA buses, +the Power-up and channel reset sources cause additional hardware initialization +which should only occur at system startup time. + +The third type of reset, called a "command reset", is done by writing any data +to the FIFO_RESET address described above. This resets the on-board processor, +FIFO, UARTS, and associated hardware. + +This passes control of the board to the bootstrap firmware, which performs a +Power-On Self Test and which detects its current configuration. For example, +-IIEX products determine the size of FIFO which has been installed, and the +number and type of expansion boxes attached. + +This and other information is then written to the FIFO in a 16-byte data block +to be read by the host. This block is guaranteed to be present within two (2) +seconds of having received the command reset. The firmware is now ready to +receive loadware from the host. + +It is good practice to perform a command reset to the board explicitly as part +of your software initialization. This allows your code to properly restart from +a soft boot. (Many systems do not issue channel reset on soft boot). + +Because of a hardware reset problem on some of the Cirrus Logic 1400's which are +used on the product, it is recommended that you reset the board twice, separated +by an approximately 50 milliseconds delay. (VERY approximately: probably ok to +be off by a factor of five. The important point is that the first command reset +in fact generates a reset pulse on the board. This pulse is guaranteed to last +less than 10 milliseconds. The additional delay ensures the 1400 has had the +chance to respond sufficiently to the first reset. Why not a longer delay? Much +more than 50 milliseconds gets to be noticable, but the board would still work. + +Once all 16 bytes of the Power-on Reset Message have been read, the bootstrap +firmware is ready to receive loadware. + +Note on Power-on Reset Message format: +The various fields have been designed with future expansion in view. +Combinations of bitfields and values have been defined which define products +which may not currently exist. This has been done to allow drivers to anticipate +the possible introduction of products in a systematic fashion. This is not +intended to suggest that each potential product is actually under consideration. +------------------------------------------------------------------------------*/ + +//---------------------------------------- +// Format of Power-on Reset Message +//---------------------------------------- + +typedef union _porStr // "por" stands for Power On Reset +{ + unsigned char c[16]; // array used when considering the message as a + // string of undifferentiated characters + + struct // Elements used when considering values + { + // The first two bytes out of the FIFO are two magic numbers. These are + // intended to establish that there is indeed a member of the + // IntelliPort-II(EX) family present. The remaining bytes may be + // expected // to be valid. When reading the Power-on Reset message, + // if the magic numbers do not match it is probably best to stop + // reading immediately. You are certainly not reading our board (unless + // hardware is faulty), and may in fact be reading some other piece of + // hardware. + + unsigned char porMagic1; // magic number: first byte == POR_MAGIC_1 + unsigned char porMagic2; // magic number: second byte == POR_MAGIC_2 + + // The Version, Revision, and Subrevision are stored as absolute numbers + // and would normally be displayed in the format V.R.S (e.g. 1.0.2) + + unsigned char porVersion; // Bootstrap firmware version number + unsigned char porRevision; // Bootstrap firmware revision number + unsigned char porSubRev; // Bootstrap firmware sub-revision number + + unsigned char porID; // Product ID: Bit-mapped according to + // conventions described below. Among other + // things, this allows us to distinguish + // IntelliPort-II boards from IntelliPort-IIEX + // boards. + + unsigned char porBus; // IntelliPort-II: Unused + // IntelliPort-IIEX: Bus Information: + // Bit-mapped below + + unsigned char porMemory; // On-board DRAM size: in 32k blocks + + // porPorts1 (and porPorts2) are used to determine the ports which are + // available to the board. For non-expandable product, a single number + // is sufficient. For expandable product, the board may be connected + // to as many as four boxes. Each box may be (so far) either a 16-port + // or an 8-port size. Whenever an 8-port box is used, the remaining 8 + // ports leave gaps between existing channels. For that reason, + // expandable products must report a MAP of available channels. Since + // each UART supports four ports, we represent each UART found by a + // single bit. Using two bytes to supply the mapping information we + // report the presense or absense of up to 16 UARTS, or 64 ports in + // steps of 4 ports. For -IIEX products, the ports are numbered + // starting at the box closest to the controller in the "chain". + + // Interpreted Differently for IntelliPort-II and -IIEX. + // -II: Number of ports (Derived actually from product ID). See + // Diag1&2 to indicate if uart was actually detected. + // -IIEX: Bit-map of UARTS found, LSB (see below for MSB of this). This + // bitmap is based on detecting the uarts themselves; + // see porFlags for information from the box i.d's. + unsigned char porPorts1; + + unsigned char porDiag1; // Results of on-board P.O.S.T, 1st byte + unsigned char porDiag2; // Results of on-board P.O.S.T, 2nd byte + unsigned char porSpeed; // Speed of local CPU: given as MHz x10 + // e.g., 16.0 MHz CPU is reported as 160 + unsigned char porFlags; // Misc information (see manifests below) + // Bit-mapped: CPU type, UART's present + + unsigned char porPorts2; // -II: Undefined + // -IIEX: Bit-map of UARTS found, MSB (see + // above for LSB) + + // IntelliPort-II: undefined + // IntelliPort-IIEX: 1 << porFifoSize gives the size, in bytes, of the + // host interface FIFO, in each direction. When running the -IIEX in + // 8-bit mode, fifo capacity is halved. The bootstrap firmware will + // have already accounted for this fact in generating this number. + unsigned char porFifoSize; + + // IntelliPort-II: undefined + // IntelliPort-IIEX: The number of boxes connected. (Presently 1-4) + unsigned char porNumBoxes; + } e; +} porStr, *porStrPtr; + +//-------------------------- +// Values for porStr fields +//-------------------------- + +//--------------------- +// porMagic1, porMagic2 +//---------------------- +// +#define POR_MAGIC_1 0x96 // The only valid value for porMagic1 +#define POR_MAGIC_2 0x35 // The only valid value for porMagic2 +#define POR_1_INDEX 0 // Byte position of POR_MAGIC_1 +#define POR_2_INDEX 1 // Ditto for POR_MAGIC_2 + +//---------------------- +// porID +//---------------------- +// +#define POR_ID_FAMILY 0xc0 // These bits indicate the general family of + // product. +#define POR_ID_FII 0x00 // Family is "IntelliPort-II" +#define POR_ID_FIIEX 0x40 // Family is "IntelliPort-IIEX" + +// These bits are reserved, presently zero. May be used at a later date to +// convey other product information. +// +#define POR_ID_RESERVED 0x3c + +#define POR_ID_SIZE 0x03 // Remaining bits indicate number of ports & + // Connector information. +#define POR_ID_II_8 0x00 // For IntelliPort-II, indicates 8-port using + // standard brick. +#define POR_ID_II_8R 0x01 // For IntelliPort-II, indicates 8-port using + // RJ11's (no CTS) +#define POR_ID_II_6 0x02 // For IntelliPort-II, indicates 6-port using + // RJ45's +#define POR_ID_II_4 0x03 // For IntelliPort-II, indicates 4-port using + // 4xRJ45 connectors +#define POR_ID_EX 0x00 // For IntelliPort-IIEX, indicates standard + // expandable controller (other values reserved) + +//---------------------- +// porBus +//---------------------- + +// IntelliPort-IIEX only: Board is installed in a 16-bit slot +// +#define POR_BUS_SLOT16 0x20 + +// IntelliPort-IIEX only: DIP switch #8 is on, selecting 16-bit host interface +// operation. +// +#define POR_BUS_DIP16 0x10 + +// Bits 0-2 indicate type of bus: This information is stored in the bootstrap +// loadware, different loadware being used on different products for different +// buses. For most situations, the drivers do not need this information; but it +// is handy in a diagnostic environment. For example, on microchannel boards, +// you would not want to try to test several interrupts, only the one for which +// you were configured. +// +#define POR_BUS_TYPE 0x07 + +// Unknown: this product doesn't know what bus it is running in. (e.g. if same +// bootstrap firmware were wanted for two different buses.) +// +#define POR_BUS_T_UNK 0 + +// Note: existing firmware for ISA-8 and MC-8 currently report the POR_BUS_T_UNK +// state, since the same bootstrap firmware is used for each. + +#define POR_BUS_T_MCA 1 // MCA BUS */ +#define POR_BUS_T_EISA 2 // EISA BUS */ +#define POR_BUS_T_ISA 3 // ISA BUS */ + +// Values 4-7 Reserved + +// Remaining bits are reserved + +//---------------------- +// porDiag1 +//---------------------- + +#define POR_BAD_MAPPER 0x80 // HW failure on P.O.S.T: Chip mapper failed + +// These two bits valid only for the IntelliPort-II +// +#define POR_BAD_UART1 0x01 // First 1400 bad +#define POR_BAD_UART2 0x02 // Second 1400 bad + +//---------------------- +// porDiag2 +//---------------------- + +#define POR_DEBUG_PORT 0x80 // debug port was detected by the P.O.S.T +#define POR_DIAG_OK 0x00 // Indicates passage: Failure codes not yet + // available. + // Other bits undefined. +//---------------------- +// porFlags +//---------------------- + +#define POR_CPU 0x03 // These bits indicate supposed CPU type +#define POR_CPU_8 0x01 // Board uses an 80188 (no such thing yet) +#define POR_CPU_6 0x02 // Board uses an 80186 (all existing products) +#define POR_CEX4 0x04 // If set, this is an ISA-CEX/4: An ISA-4 (asic) + // which is architected like an ISA-CEX connected + // to a (hitherto impossible) 4-port box. +#define POR_BOXES 0xf0 // Valid for IntelliPort-IIEX only: Map of Box + // sizes based on box I.D. +#define POR_BOX_16 0x10 // Set indicates 16-port, clear 8-port + +//------------------------------------- +// LOADWARE and DOWNLOADING CODE +//------------------------------------- + +/* +Loadware may be sent to the board in two ways: +1) It may be read from a (binary image) data file block by block as each block + is sent to the board. This is only possible when the initialization is + performed by code which can access your file system. This is most suitable + for diagnostics and appications which use the interface library directly. + +2) It may be hard-coded into your source by including a .h file (typically + supplied by Computone), which declares a data array and initializes every + element. This acheives the same result as if an entire loadware file had + been read into the array. + + This requires more data space in your program, but access to the file system + is not required. This method is more suited to driver code, which typically + is running at a level too low to access the file system directly. + +At present, loadware can only be generated at Computone. + +All Loadware begins with a header area which has a particular format. This +includes a magic number which identifies the file as being (purportedly) +loadware, CRC (for the loader), and version information. +*/ + + +//----------------------------------------------------------------------------- +// Format of loadware block +// +// This is defined as a union so we can pass a pointer to one of these items +// and (if it is the first block) pick out the version information, etc. +// +// Otherwise, to deal with this as a simple character array +//------------------------------------------------------------------------------ + +#define LOADWARE_BLOCK_SIZE 512 // Number of bytes in each block of loadware + +typedef union _loadHdrStr +{ + unsigned char c[LOADWARE_BLOCK_SIZE]; // Valid for every block + + struct // These fields are valid for only the first block of loadware. + { + unsigned char loadMagic; // Magic number: see below + unsigned char loadBlocksMore; // How many more blocks? + unsigned char loadCRC[2]; // Two CRC bytes: used by loader + unsigned char loadVersion; // Version number + unsigned char loadRevision; // Revision number + unsigned char loadSubRevision; // Sub-revision number + unsigned char loadSpares[9]; // Presently unused + unsigned char loadDates[32]; // Null-terminated string which can give + // date and time of compilation + } e; +} loadHdrStr, *loadHdrStrPtr; + +//------------------------------------ +// Defines for downloading code: +//------------------------------------ + +// The loadMagic field in the first block of the loadfile must be this, else the +// file is not valid. +// +#define MAGIC_LOADFILE 0x3c + +// How do we know the load was successful? On completion of the load, the +// bootstrap firmware returns a code to indicate whether it thought the download +// was valid and intends to execute it. These are the only possible valid codes: +// +#define LOADWARE_OK 0xc3 // Download was ok +#define LOADWARE_BAD 0x5a // Download was bad (CRC error) + +// Constants applicable to writing blocks of loadware: +// The first block of loadware might take 600 mS to load, in extreme cases. +// (Expandable board: worst case for sending startup messages to the LCD's). +// The 600mS figure is not really a calculation, but a conservative +// guess/guarantee. Usually this will be within 100 mS, like subsequent blocks. +// +#define MAX_DLOAD_START_TIME 1000 // 1000 mS +#define MAX_DLOAD_READ_TIME 100 // 100 mS + +// Firmware should respond with status (see above) within this long of host +// having sent the final block. +// +#define MAX_DLOAD_ACK_TIME 100 // 100 mS, again! + +//------------------------------------------------------ +// MAXIMUM NUMBER OF PORTS PER BOARD: +// This is fixed for now (with the expandable), but may +// be expanding according to even newer products. +//------------------------------------------------------ +// +#define ABS_MAX_BOXES 4 // Absolute most boxes per board +#define ABS_BIGGEST_BOX 16 // Absolute the most ports per box +#define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX) + +#endif // I2HW_H + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2lib.c linux/drivers/char/ip2/i2lib.c --- v2.3.14/linux/drivers/char/ip2/i2lib.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2lib.c Mon Aug 23 10:23:23 1999 @@ -0,0 +1,2255 @@ +/******************************************************************************* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: High-level interface code for the device driver. Uses the +* Extremely Low Level Interface Support (i2ellis.c). Provides an +* interface to the standard loadware, to support drivers or +* application code. (This is included source code, not a separate +* compilation module.) +* +*******************************************************************************/ +//------------------------------------------------------------------------------ +// Note on Strategy: +// Once the board has been initialized, it will interrupt us when: +// 1) It has something in the fifo for us to read (incoming data, flow control +// packets, or whatever). +// 2) It has stripped whatever we have sent last time in the FIFO (and +// consequently is ready for more). +// +// Note also that the buffer sizes declared in i2lib.h are VERY SMALL. This +// worsens performance considerably, but is done so that a great many channels +// might use only a little memory. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Revision History: +// +// 0.00 - 4/16/91 --- First Draft +// 0.01 - 4/29/91 --- 1st beta release +// 0.02 - 6/14/91 --- Changes to allow small model compilation +// 0.03 - 6/17/91 MAG Break reporting protected from interrupts routines with +// in-line asm added for moving data to/from ring buffers, +// replacing a variety of methods used previously. +// 0.04 - 6/21/91 MAG Initial flow-control packets not queued until +// i2_enable_interrupts time. Former versions would enqueue +// them at i2_init_channel time, before we knew how many +// channels were supposed to exist! +// 0.05 - 10/12/91 MAG Major changes: works through the ellis.c routines now; +// supports new 16-bit protocol and expandable boards. +// - 10/24/91 MAG Most changes in place and stable. +// 0.06 - 2/20/92 MAG Format of CMD_HOTACK corrected: the command takes no +// argument. +// 0.07 -- 3/11/92 MAG Support added to store special packet types at interrupt +// level (mostly responses to specific commands.) +// 0.08 -- 3/30/92 MAG Support added for STAT_MODEM packet +// 0.09 -- 6/24/93 MAG i2Link... needed to update number of boards BEFORE +// turning on the interrupt. +// 0.10 -- 6/25/93 MAG To avoid gruesome death from a bad board, we sanity check +// some incoming. +// +// 1.1 - 12/25/96 AKM Linux version. +// - 10/09/98 DMC Revised Linux version. +//------------------------------------------------------------------------------ + +//************ +//* Includes * +//************ + +#include +#include "i2lib.h" + + +//*********************** +//* Function Prototypes * +//*********************** +static void i2QueueNeeds(i2eBordStrPtr, i2ChanStrPtr, int); +static i2ChanStrPtr i2DeQueueNeeds(i2eBordStrPtr, int ); +static void i2StripFifo(i2eBordStrPtr); +static void i2StuffFifoBypass(i2eBordStrPtr); +static void i2StuffFifoFlow(i2eBordStrPtr); +static void i2StuffFifoInline(i2eBordStrPtr); +static int i2RetryFlushOutput(i2ChanStrPtr); + +// Not a documented part of the library routines (careful...) but the Diagnostic +// i2diag.c finds them useful to help the throughput in certain limited +// single-threaded operations. +static void iiSendPendingMail(i2eBordStrPtr); +static void serviceOutgoingFifo(i2eBordStrPtr); + +// Functions defined in ip2.c as part of interrupt handling +static void do_input(i2ChanStrPtr); +static void do_status(i2ChanStrPtr); + +//*************** +//* Debug Data * +//*************** +#ifdef DEBUG_FIFO + +unsigned char DBGBuf[0x4000]; +unsigned short I = 0; + +static void +WriteDBGBuf(char *s, unsigned char *src, unsigned short n ) +{ + char *p = src; + + // XXX: We need a spin lock here if we ever use this again + + while (*s) { // copy label + DBGBuf[I] = *s++; + I = I++ & 0x3fff; + } + while (n--) { // copy data + DBGBuf[I] = *p++; + I = I++ & 0x3fff; + } +} + +static void +fatality(i2eBordStrPtr pB ) +{ + int i; + + for (i=0;i= ' ' && DBGBuf[i] <= '~') { + printk(" %c ",DBGBuf[i]); + } else { + printk(" . "); + } + } + printk("\n"); + printk("Last index %x\n",I); +} +#endif /* DEBUG_FIFO */ + +//******** +//* Code * +//******** + +inline int +i2Validate ( i2ChanStrPtr pCh ) +{ + //ip2trace(pCh->port_index, ITRC_VERIFY,ITRC_ENTER,2,pCh->validity, + // (CHANNEL_MAGIC | CHANNEL_SUPPORT)); + return ((pCh->validity & (CHANNEL_MAGIC_BITS | CHANNEL_SUPPORT)) + == (CHANNEL_MAGIC | CHANNEL_SUPPORT)); +} + +//****************************************************************************** +// Function: iiSendPendingMail(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// If any outgoing mail bits are set and there is outgoing mailbox is empty, +// send the mail and clear the bits. +//****************************************************************************** +static inline void +iiSendPendingMail(i2eBordStrPtr pB) +{ + if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) ) + { + if (iiTrySendMail(pB, pB->i2eOutMailWaiting)) + { + /* If we were already waiting for fifo to empty, + * or just sent MB_OUT_STUFFED, then we are + * still waiting for it to empty, until we should + * receive an MB_IN_STRIPPED from the board. + */ + pB->i2eWaitingForEmptyFifo |= + (pB->i2eOutMailWaiting & MB_OUT_STUFFED); + pB->i2eOutMailWaiting = 0; + } + } +} + +//****************************************************************************** +// Function: i2InitChannels(pB, nChannels, pCh) +// Parameters: Pointer to Ellis Board structure +// Number of channels to initialize +// Pointer to first element in an array of channel structures +// Returns: Success or failure +// +// Description: +// +// This function patches pointers, back-pointers, and initializes all the +// elements in the channel structure array. +// +// This should be run after the board structure is initialized, through having +// loaded the standard loadware (otherwise it complains). +// +// In any case, it must be done before any serious work begins initializing the +// irq's or sending commands... +// +//****************************************************************************** +static int +i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) +{ + int index, stuffIndex; + i2ChanStrPtr *ppCh; + + if (pB->i2eValid != I2E_MAGIC) { + COMPLETE(pB, I2EE_BADMAGIC); + } + if (pB->i2eState != II_STATE_STDLOADED) { + COMPLETE(pB, I2EE_BADSTATE); + } + + LOCK_INIT(&pB->read_fifo_spinlock); + LOCK_INIT(&pB->write_fifo_spinlock); + LOCK_INIT(&pB->Dbuf_spinlock); + LOCK_INIT(&pB->Bbuf_spinlock); + LOCK_INIT(&pB->Fbuf_spinlock); + + // NO LOCK needed yet - this is init + + pB->i2eChannelPtr = pCh; + pB->i2eChannelCnt = nChannels; + + pB->i2Fbuf_strip = pB->i2Fbuf_stuff = 0; + pB->i2Dbuf_strip = pB->i2Dbuf_stuff = 0; + pB->i2Bbuf_strip = pB->i2Bbuf_stuff = 0; + + memset ( pCh, 0, sizeof (i2ChanStr) * nChannels ); + + for (index = stuffIndex = 0, ppCh = (i2ChanStrPtr *)(pB->i2Fbuf); + nChannels && index < ABS_MOST_PORTS; + index++) + { + if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) { + continue; + } + LOCK_INIT(&pCh->Ibuf_spinlock); + LOCK_INIT(&pCh->Obuf_spinlock); + LOCK_INIT(&pCh->Cbuf_spinlock); + LOCK_INIT(&pCh->Pbuf_spinlock); + // NO LOCK needed yet - this is init + // Set up validity flag according to support level + if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) { + pCh->validity = CHANNEL_MAGIC | CHANNEL_SUPPORT; + } else { + pCh->validity = CHANNEL_MAGIC; + } + pCh->pMyBord = pB; /* Back-pointer */ + + // Prepare an outgoing flow-control packet to send as soon as the chance + // occurs. + if ( pCh->validity & CHANNEL_SUPPORT ) { + pCh->infl.hd.i2sChannel = index; + pCh->infl.hd.i2sCount = 5; + pCh->infl.hd.i2sType = PTYPE_BYPASS; + pCh->infl.fcmd = 37; + pCh->infl.asof = 0; + pCh->infl.room = IBUF_SIZE - 1; + + pCh->whenSendFlow = (IBUF_SIZE/5)*4; // when 80% full + + // The following is similar to calling i2QueueNeeds, except that this + // is done in longhand, since we are setting up initial conditions on + // many channels at once. + pCh->channelNeeds = NEED_FLOW; // Since starting from scratch + pCh->sinceLastFlow = 0; // No bytes received since last flow + // control packet was queued + stuffIndex++; + *ppCh++ = pCh; // List this channel as needing + // initial flow control packet sent + } + + // Don't allow anything to be sent until the status packets come in from + // the board. + + pCh->outfl.asof = 0; + pCh->outfl.room = 0; + + // Initialize all the ring buffers + + pCh->Ibuf_stuff = pCh->Ibuf_strip = 0; + pCh->Obuf_stuff = pCh->Obuf_strip = 0; + pCh->Cbuf_stuff = pCh->Cbuf_strip = 0; + + memset( &pCh->icount, 0, sizeof (struct async_icount) ); + pCh->hotKeyIn = HOT_CLEAR; + pCh->channelOptions = 0; + pCh->bookMarks = 0; + init_waitqueue_head(&pCh->pBookmarkWait); + + init_waitqueue_head(&pCh->open_wait); + init_waitqueue_head(&pCh->close_wait); + init_waitqueue_head(&pCh->delta_msr_wait); + + // Set base and divisor so default custom rate is 9600 + pCh->BaudBase = 921600; // MAX for ST654, changed after we get + pCh->BaudDivisor = 96; // the boxids (UART types) later + + pCh->dataSetIn = 0; + pCh->dataSetOut = 0; + + pCh->wopen = 0; + pCh->throttled = 0; + + pCh->speed = CBR_9600; + + pCh->flags = 0; + pCh->session = 0; + pCh->pgrp = 0; + + pCh->ClosingDelay = 5*HZ/10; + pCh->ClosingWaitTime = 30*HZ; + +#ifdef USE_IQ + // Initialize task queue objects + pCh->tqueue_input.routine = (void(*)(void*)) do_input; + pCh->tqueue_input.data = pCh; + pCh->tqueue_status.routine = (void(*)(void*)) do_status; + pCh->tqueue_status.data = pCh; +#endif + + pCh->trace = ip2trace; + + ++pCh; + --nChannels; + } + // No need to check for wrap here; this is initialization. + pB->i2Fbuf_stuff = stuffIndex; + COMPLETE(pB, I2EE_GOOD); + +} + +//****************************************************************************** +// Function: i2DeQueueNeeds(pB, type) +// Parameters: Pointer to a board structure +// type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW +// Returns: +// Pointer to a channel structure +// +// Description: Returns pointer struct of next channel that needs service of +// the type specified. Otherwise returns a NULL reference. +// +//****************************************************************************** +static i2ChanStrPtr +i2DeQueueNeeds(i2eBordStrPtr pB, int type) +{ + unsigned short queueIndex; + unsigned long flags; + + i2ChanStrPtr pCh = NULL; + + switch(type) { + + case NEED_INLINE: + + WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); + if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip) + { + queueIndex = pB->i2Dbuf_strip; + pCh = pB->i2Dbuf[queueIndex]; + queueIndex++; + if (queueIndex >= CH_QUEUE_SIZE) { + queueIndex = 0; + } + pB->i2Dbuf_strip = queueIndex; + pCh->channelNeeds &= ~NEED_INLINE; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); + break; + + case NEED_BYPASS: + + WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); + if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip) + { + queueIndex = pB->i2Bbuf_strip; + pCh = pB->i2Bbuf[queueIndex]; + queueIndex++; + if (queueIndex >= CH_QUEUE_SIZE) { + queueIndex = 0; + } + pB->i2Bbuf_strip = queueIndex; + pCh->channelNeeds &= ~NEED_BYPASS; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); + break; + + case NEED_FLOW: + + WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); + if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip) + { + queueIndex = pB->i2Fbuf_strip; + pCh = pB->i2Fbuf[queueIndex]; + queueIndex++; + if (queueIndex >= CH_QUEUE_SIZE) { + queueIndex = 0; + } + pB->i2Fbuf_strip = queueIndex; + pCh->channelNeeds &= ~NEED_FLOW; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); + break; + default: + printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type); + break; + } + return pCh; +} + +//****************************************************************************** +// Function: i2QueueNeeds(pB, pCh, type) +// Parameters: Pointer to a board structure +// Pointer to a channel structure +// type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW +// Returns: Nothing +// +// Description: +// For each type of need selected, if the given channel is not already in the +// queue, adds it, and sets the flag indicating it is in the queue. +//****************************************************************************** +static void +i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) +{ + unsigned short queueIndex; + unsigned long flags; + + // We turn off all the interrupts during this brief process, since the + // interrupt-level code might want to put things on the queue as well. + + switch (type) { + + case NEED_INLINE: + + WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); + if ( !(pCh->channelNeeds & NEED_INLINE) ) + { + pCh->channelNeeds |= NEED_INLINE; + queueIndex = pB->i2Dbuf_stuff; + pB->i2Dbuf[queueIndex++] = pCh; + if (queueIndex >= CH_QUEUE_SIZE) + queueIndex = 0; + pB->i2Dbuf_stuff = queueIndex; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); + break; + + case NEED_BYPASS: + + WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); + if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS)) + { + pCh->channelNeeds |= NEED_BYPASS; + queueIndex = pB->i2Bbuf_stuff; + pB->i2Bbuf[queueIndex++] = pCh; + if (queueIndex >= CH_QUEUE_SIZE) + queueIndex = 0; + pB->i2Bbuf_stuff = queueIndex; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); + break; + + case NEED_FLOW: + + WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); + if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW)) + { + pCh->channelNeeds |= NEED_FLOW; + queueIndex = pB->i2Fbuf_stuff; + pB->i2Fbuf[queueIndex++] = pCh; + if (queueIndex >= CH_QUEUE_SIZE) + queueIndex = 0; + pB->i2Fbuf_stuff = queueIndex; + } + WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); + break; + + case NEED_CREDIT: + pCh->channelNeeds |= NEED_CREDIT; + break; + default: + printk(KERN_ERR "i2QueueNeeds called with bad type:%x\n",type); + break; + } + return; +} + +//****************************************************************************** +// Function: i2QueueCommands(type, pCh, timeout, nCommands, pCs,...) +// Parameters: type - PTYPE_BYPASS or PTYPE_INLINE +// pointer to the channel structure +// maximum period to wait +// number of commands (n) +// n commands +// Returns: Number of commands sent, or -1 for error +// +// get board lock before calling +// +// Description: +// Queues up some commands to be sent to a channel. To send possibly several +// bypass or inline commands to the given channel. The timeout parameter +// indicates how many HUNDREDTHS OF SECONDS to wait until there is room: +// 0 = return immediately if no room, -ive = wait forever, +ive = number of +// 1/100 seconds to wait. Return values: +// -1 Some kind of nasty error: bad channel structure or invalid arguments. +// 0 No room to send all the commands +// (+) Number of commands sent +//****************************************************************************** +static int +i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, + cmdSyntaxPtr pCs0,...) +{ + int totalsize = 0; + int blocksize; + int lastended; + cmdSyntaxPtr *ppCs; + cmdSyntaxPtr pCs; + int count; + int flag; + i2eBordStrPtr pB; + + unsigned short maxBlock; + unsigned short maxBuff; + short bufroom; + unsigned short stuffIndex; + unsigned char *pBuf; + unsigned char *pInsert; + unsigned char *pDest, *pSource; + unsigned short channel; + int cnt; + unsigned long flags = 0; + spinlock_t *lock_var_p = NULL; + + // Make sure the channel exists, otherwise do nothing + if ( !i2Validate ( pCh ) ) { + return -1; + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, ITRC_ENTER, 0 ); +#endif + pB = pCh->pMyBord; + + // Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT + if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) { + return -2; + } + // If the board has gone fatal, return bad, and also hit the trap routine if + // it exists. + if (pB->i2eFatal) { + if ( pB->i2eFatalTrap ) { + (*(pB)->i2eFatalTrap)(pB); + } + return -3; + } + // Set up some variables, Which buffers are we using? How big are they? + switch(type) + { + case PTYPE_INLINE: + flag = INL; + maxBlock = MAX_OBUF_BLOCK; + maxBuff = OBUF_SIZE; + pBuf = pCh->Obuf; + break; + case PTYPE_BYPASS: + flag = BYP; + maxBlock = MAX_CBUF_BLOCK; + maxBuff = CBUF_SIZE; + pBuf = pCh->Cbuf; + break; + default: + return -4; + } + // Determine the total size required for all the commands + totalsize = blocksize = sizeof(i2CmdHeader); + lastended = 0; + ppCs = &pCs0; + for ( count = nCommands; count; count--, ppCs++) + { + pCs = *ppCs; + cnt = pCs->length; + // Will a new block be needed for this one? + // Two possible reasons: too + // big or previous command has to be at the end of a packet. + if ((blocksize + cnt > maxBlock) || lastended) { + blocksize = sizeof(i2CmdHeader); + totalsize += sizeof(i2CmdHeader); + } + totalsize += cnt; + blocksize += cnt; + + // If this command had to end a block, then we will make sure to + // account for it should there be any more blocks. + lastended = pCs->flags & END; + } + for (;;) { + // Make sure any pending flush commands go out before we add more data. + if ( !( pCh->flush_flags && i2RetryFlushOutput( pCh ) ) ) { + // How much room (this time through) ? + switch(type) { + case PTYPE_INLINE: + lock_var_p = &pCh->Obuf_spinlock; + WRITE_LOCK_IRQSAVE(lock_var_p,flags); + stuffIndex = pCh->Obuf_stuff; + bufroom = pCh->Obuf_strip - stuffIndex; + break; + case PTYPE_BYPASS: + lock_var_p = &pCh->Cbuf_spinlock; + WRITE_LOCK_IRQSAVE(lock_var_p,flags); + stuffIndex = pCh->Cbuf_stuff; + bufroom = pCh->Cbuf_strip - stuffIndex; + break; + default: + return -5; + } + if (--bufroom < 0) { + bufroom += maxBuff; + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, 2, 1, bufroom ); +#endif + // Check for overflow + if (totalsize <= bufroom) { + // Normal Expected path - We still hold LOCK + break; /* from for()- Enough room: goto proceed */ + } + } + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, 3, 1, totalsize ); +#endif + // Prepare to wait for buffers to empty + WRITE_UNLOCK_IRQRESTORE(lock_var_p,flags); + serviceOutgoingFifo(pB); // Dump what we got + + if (timeout == 0) { + return 0; // Tired of waiting + } + if (timeout > 0) + timeout--; // So negative values == forever + + if (!in_interrupt()) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + schedule_timeout(1); // short nap + } else { + // we cannot sched/sleep in interrrupt silly + return 0; + } + if (signal_pending(current)) { + return 0; // Wake up! Time to die!!! + } + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, 4, 0 ); +#endif + } // end of for(;;) + + // At this point we have room and the lock - stick them in. + channel = pCh->infl.hd.i2sChannel; + pInsert = &pBuf[stuffIndex]; // Pointer to start of packet + pDest = CMD_OF(pInsert); // Pointer to start of command + + // When we start counting, the block is the size of the header + for (blocksize = sizeof(i2CmdHeader), count = nCommands, + lastended = 0, ppCs = &pCs0; + count; + count--, ppCs++) + { + pCs = *ppCs; // Points to command protocol structure + + // If this is a bookmark request command, post the fact that a bookmark + // request is pending. NOTE THIS TRICK ONLY WORKS BECAUSE CMD_BMARK_REQ + // has no parameters! The more general solution would be to reference + // pCs->cmd[0]. + if (pCs == CMD_BMARK_REQ) { + pCh->bookMarks++; +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, 30, 1, pCh->bookMarks ); +#endif + } + cnt = pCs->length; + + // If this command would put us over the maximum block size or + // if the last command had to be at the end of a block, we end + // the existing block here and start a new one. + if ((blocksize + cnt > maxBlock) || lastended) { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, 5, 0 ); +#endif + PTYPE_OF(pInsert) = type; + CHANNEL_OF(pInsert) = channel; + // count here does not include the header + CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader); + stuffIndex += blocksize; + if(stuffIndex >= maxBuff) { + stuffIndex = 0; + pInsert = pBuf; + } + pInsert = &pBuf[stuffIndex]; // Pointer to start of next pkt + pDest = CMD_OF(pInsert); + blocksize = sizeof(i2CmdHeader); + } + // Now we know there is room for this one in the current block + + blocksize += cnt; // Total bytes in this command + pSource = pCs->cmd; // Copy the command into the buffer + while (cnt--) { + *pDest++ = *pSource++; + } + // If this command had to end a block, then we will make sure to account + // for it should there be any more blocks. + lastended = pCs->flags & END; + } // end for + // Clean up the final block by writing header, etc + + PTYPE_OF(pInsert) = type; + CHANNEL_OF(pInsert) = channel; + // count here does not include the header + CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader); + stuffIndex += blocksize; + if(stuffIndex >= maxBuff) { + stuffIndex = 0; + pInsert = pBuf; + } + // Updates the index, and post the need for service. When adding these to + // the queue of channels, we turn off the interrupt while doing so, + // because at interrupt level we might want to push a channel back to the + // end of the queue. + switch(type) + { + case PTYPE_INLINE: + pCh->Obuf_stuff = stuffIndex; // Store buffer pointer + WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + + pB->debugInlineQueued++; + // Add the channel pointer to list of channels needing service (first + // come...), if it's not already there. + i2QueueNeeds(pB, pCh, NEED_INLINE); + break; + + case PTYPE_BYPASS: + pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer + WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); + + pB->debugBypassQueued++; + // Add the channel pointer to list of channels needing service (first + // come...), if it's not already there. + i2QueueNeeds(pB, pCh, NEED_BYPASS); + break; + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_QUEUE, ITRC_RETURN, 1, nCommands ); +#endif + return nCommands; // Good status: number of commands sent +} + +//****************************************************************************** +// Function: i2GetStatus(pCh,resetBits) +// Parameters: Pointer to a channel structure +// Bit map of status bits to clear +// Returns: Bit map of current status bits +// +// Description: +// Returns the state of data set signals, and whether a break has been received, +// (see i2lib.h for bit-mapped result). resetBits is a bit-map of any status +// bits to be cleared: I2_BRK, I2_PAR, I2_FRA, I2_OVR,... These are cleared +// AFTER the condition is passed. If pCh does not point to a valid channel, +// returns -1 (which would be impossible otherwise. +//****************************************************************************** +static int +i2GetStatus(i2ChanStrPtr pCh, int resetBits) +{ + unsigned short status; + i2eBordStrPtr pB; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_STATUS, ITRC_ENTER, 2, pCh->dataSetIn, resetBits ); +#endif + + // Make sure the channel exists, otherwise do nothing */ + if ( !i2Validate ( pCh ) ) + return -1; + + pB = pCh->pMyBord; + + status = pCh->dataSetIn; + + // Clear any specified error bits: but note that only actual error bits can + // be cleared, regardless of the value passed. + if (resetBits) + { + pCh->dataSetIn &= ~(resetBits & (I2_BRK | I2_PAR | I2_FRA | I2_OVR)); + pCh->dataSetIn &= ~(I2_DDCD | I2_DCTS | I2_DDSR | I2_DRI); + } + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_STATUS, ITRC_RETURN, 1, pCh->dataSetIn ); +#endif + + return status; +} + +//****************************************************************************** +// Function: i2Input(pChpDest,count) +// Parameters: Pointer to a channel structure +// Pointer to data buffer +// Number of bytes to read +// Returns: Number of bytes read, or -1 for error +// +// Description: +// Strips data from the input buffer and writes it to pDest. If there is a +// collosal blunder, (invalid structure pointers or the like), returns -1. +// Otherwise, returns the number of bytes read. +//****************************************************************************** +static int +i2Input(i2ChanStrPtr pCh) +{ + int amountToMove; + unsigned short stripIndex; + int count; + unsigned long flags = 0; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_INPUT, ITRC_ENTER, 0); +#endif + + // Ensure channel structure seems real + if ( !i2Validate( pCh ) ) { + count = -1; + goto i2Input_exit; + } + WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + + // initialize some accelerators and private copies + stripIndex = pCh->Ibuf_strip; + + count = pCh->Ibuf_stuff - stripIndex; + + // If buffer is empty or requested data count was 0, (trivial case) return + // without any further thought. + if ( count == 0 ) { + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + goto i2Input_exit; + } + // Adjust for buffer wrap + if ( count < 0 ) { + count += IBUF_SIZE; + } + // Don't give more than can be taken by the line discipline + amountToMove = pCh->pTTY->ldisc.receive_room( pCh->pTTY ); + if (count > amountToMove) { + count = amountToMove; + } + // How much could we copy without a wrap? + amountToMove = IBUF_SIZE - stripIndex; + + if (amountToMove > count) { + amountToMove = count; + } + // Move the first block + pCh->pTTY->ldisc.receive_buf( pCh->pTTY, + &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); + // If we needed to wrap, do the second data move + if (count > amountToMove) { + pCh->pTTY->ldisc.receive_buf( pCh->pTTY, + pCh->Ibuf, NULL, count - amountToMove ); + } + // Bump and wrap the stripIndex all at once by the amount of data read. This + // method is good regardless of whether the data was in one or two pieces. + stripIndex += count; + if (stripIndex >= IBUF_SIZE) { + stripIndex -= IBUF_SIZE; + } + pCh->Ibuf_strip = stripIndex; + + // Update our flow control information and possibly queue ourselves to send + // it, depending on how much data has been stripped since the last time a + // packet was sent. + pCh->infl.asof += count; + + if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) { + pCh->sinceLastFlow -= pCh->whenSendFlow; + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); + } else { + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + } + +i2Input_exit: + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_INPUT, ITRC_RETURN, 1, count); +#endif + return count; +} + +//****************************************************************************** +// Function: i2InputFlush(pCh) +// Parameters: Pointer to a channel structure +// Returns: Number of bytes stripped, or -1 for error +// +// Description: +// Strips any data from the input buffer. If there is a collosal blunder, +// (invalid structure pointers or the like), returns -1. Otherwise, returns the +// number of bytes stripped. +//****************************************************************************** +static int +i2InputFlush(i2ChanStrPtr pCh) +{ + int count; + unsigned long flags; + + // Ensure channel structure seems real + if ( !i2Validate ( pCh ) ) + return -1; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_INPUT, 10, 0); +#endif + + WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + count = pCh->Ibuf_stuff - pCh->Ibuf_strip; + + // Adjust for buffer wrap + if (count < 0) { + count += IBUF_SIZE; + } + + // Expedient way to zero out the buffer + pCh->Ibuf_strip = pCh->Ibuf_stuff; + + + // Update our flow control information and possibly queue ourselves to send + // it, depending on how much data has been stripped since the last time a + // packet was sent. + + pCh->infl.asof += count; + + if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow ) + { + pCh->sinceLastFlow -= pCh->whenSendFlow; + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); + } else { + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_INPUT, 19, 1, count); +#endif + return count; +} + +//****************************************************************************** +// Function: i2InputAvailable(pCh) +// Parameters: Pointer to a channel structure +// Returns: Number of bytes available, or -1 for error +// +// Description: +// If there is a collosal blunder, (invalid structure pointers or the like), +// returns -1. Otherwise, returns the number of bytes stripped. Otherwise, +// returns the number of bytes available in the buffer. +//****************************************************************************** +#if 0 +static int +i2InputAvailable(i2ChanStrPtr pCh) +{ + int count; + + // Ensure channel structure seems real + if ( !i2Validate ( pCh ) ) return -1; + + + // initialize some accelerators and private copies + READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + count = pCh->Ibuf_stuff - pCh->Ibuf_strip; + READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + + // Adjust for buffer wrap + if (count < 0) + { + count += IBUF_SIZE; + } + + return count; +} +#endif + +//****************************************************************************** +// Function: i2Output(pCh, pSource, count) +// Parameters: Pointer to channel structure +// Pointer to source data +// Number of bytes to send +// Returns: Number of bytes sent, or -1 for error +// +// Description: +// Queues the data at pSource to be sent as data packets to the board. If there +// is a collosal blunder, (invalid structure pointers or the like), returns -1. +// Otherwise, returns the number of bytes written. What if there is not enough +// room for all the data? If pCh->channelOptions & CO_NBLOCK_WRITE is set, then +// we transfer as many characters as we can now, then return. If this bit is +// clear (default), routine will spin along until all the data is buffered. +// Should this occur, the 1-ms delay routine is called while waiting to avoid +// applications that one cannot break out of. +//****************************************************************************** +static int +i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) +{ + i2eBordStrPtr pB; + unsigned char *pInsert; + int amountToMove; + int countOriginal = count; + unsigned short channel; + unsigned short stuffIndex; + unsigned long flags; + int rc = 0; + + int bailout = 10; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user ); +#endif + + // Ensure channel structure seems real + if ( !i2Validate ( pCh ) ) + return -1; + + // initialize some accelerators and private copies + pB = pCh->pMyBord; + channel = pCh->infl.hd.i2sChannel; + + // If the board has gone fatal, return bad, and also hit the trap routine if + // it exists. + if (pB->i2eFatal) { + if (pB->i2eFatalTrap) { + (*(pB)->i2eFatalTrap)(pB); + } + return -1; + } + // Proceed as though we would do everything + while ( count > 0 ) { + + // How much room in output buffer is there? + READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; + READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + if (amountToMove < 0) { + amountToMove += OBUF_SIZE; + } + // Subtract off the headers size and see how much room there is for real + // data. If this is negative, we will discover later. + amountToMove -= sizeof (i2DataHeader); + + // Don't move more (now) than can go in a single packet + if ( amountToMove > (int)(MAX_OBUF_BLOCK - sizeof(i2DataHeader)) ) { + amountToMove = MAX_OBUF_BLOCK - sizeof(i2DataHeader); + } + // Don't move more than the count we were given + if (amountToMove > count) { + amountToMove = count; + } + // Now we know how much we must move: NB because the ring buffers have + // an overflow area at the end, we needn't worry about wrapping in the + // middle of a packet. + +// Small WINDOW here with no LOCK but I can't call Flush with LOCK +// We would be flushing (or ending flush) anyway + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 10, 1, amountToMove ); +#endif + if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) ) + && amountToMove > 0 ) + { + WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + stuffIndex = pCh->Obuf_stuff; + + // Had room to move some data: don't know whether the block size, + // buffer space, or what was the limiting factor... + pInsert = &(pCh->Obuf[stuffIndex]); + + // Set up the header + CHANNEL_OF(pInsert) = channel; + PTYPE_OF(pInsert) = PTYPE_DATA; + TAG_OF(pInsert) = 0; + ID_OF(pInsert) = ID_ORDINARY_DATA; + DATA_COUNT_OF(pInsert) = amountToMove; + + // Move the data + if ( user ) { + rc=copy_from_user((char*)(DATA_OF(pInsert)), pSource, + amountToMove ); + } else { + memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); + } + // Adjust pointers and indices + pSource += amountToMove; + pCh->Obuf_char_count += amountToMove; + stuffIndex += amountToMove + sizeof(i2DataHeader); + count -= amountToMove; + + if (stuffIndex >= OBUF_SIZE) { + stuffIndex = 0; + } + pCh->Obuf_stuff = stuffIndex; + + WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex ); +#endif + + } else { + + // Cannot move data + // becuz we need to stuff a flush + // or amount to move is <= 0 + +#ifdef IP2DEBUG_TRACE + ip2trace(CHANN, ITRC_OUTPUT, 14, 3, + amountToMove, pB->i2eFifoRemains, pB->i2eWaitingForEmptyFifo ); +#endif + // Put this channel back on queue + // this ultimatly gets more data or wakes write output + i2QueueNeeds(pB, pCh, NEED_INLINE); + + if ( pB->i2eWaitingForEmptyFifo ) { + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 16, 0 ); +#endif + // or schedule + if (!in_interrupt()) { + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 61, 0 ); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + schedule_timeout(2); + if (signal_pending(current)) { + break; + } + continue; + } else { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 62, 0 ); +#endif + // let interrupt in = WAS restore_flags() + // We hold no lock nor is irq off anymore??? + + break; + } + break; // from while(count) + } + else if ( pB->i2eFifoRemains < 32 && !pB->i2eTxMailEmpty ( pB ) ) + { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 19, 2, pB->i2eFifoRemains, + pB->i2eTxMailEmpty ); +#endif + break; // from while(count) + } else if ( pCh->channelNeeds & NEED_CREDIT ) { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 22, 0 ); +#endif + break; // from while(count) + } else if ( --bailout) { + + // Try to throw more things (maybe not us) in the fifo if we're + // not already waiting for it. + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 20, 0 ); +#endif + serviceOutgoingFifo(pB); + //break; CONTINUE; + } else { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 21, 3, pB->i2eFifoRemains, + pB->i2eOutMailWaiting, pB->i2eWaitingForEmptyFifo ); +#endif + break; // from while(count) + } + } + } // End of while(count) + + i2QueueNeeds(pB, pCh, NEED_INLINE); + + // We drop through either when the count expires, or when there is some + // count left, but there was a non-blocking write. + if (countOriginal > count) { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, 17, 2, countOriginal, count ); +#endif + serviceOutgoingFifo( pB ); + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_OUTPUT, ITRC_RETURN, 2, countOriginal, count ); +#endif + + return countOriginal - count; +} + +//****************************************************************************** +// Function: i2FlushOutput(pCh) +// Parameters: Pointer to a channel structure +// Returns: Nothing +// +// Description: +// Sends bypass command to start flushing (waiting possibly forever until there +// is room), then sends inline command to stop flushing output, (again waiting +// possibly forever). +//****************************************************************************** +static inline void +i2FlushOutput(i2ChanStrPtr pCh) +{ + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 1, 1, pCh->flush_flags ); +#endif + + if (pCh->flush_flags) + return; + + if ( 1 != i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { + pCh->flush_flags = STARTFL_FLAG; // Failed - flag for later +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 2, 0 ); +#endif + } else if ( 1 != i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) ) { + pCh->flush_flags = STOPFL_FLAG; // Failed - flag for later +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 3, 0 ); +#endif + } +} + +static int +i2RetryFlushOutput(i2ChanStrPtr pCh) +{ + int old_flags = pCh->flush_flags; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 14, 1, old_flags ); +#endif + + pCh->flush_flags = 0; // Clear flag so we can avoid recursion + // and queue the commands + + if ( old_flags & STARTFL_FLAG ) { + if ( 1 == i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { + old_flags = STOPFL_FLAG; //Success - send stop flush + } else { + old_flags = STARTFL_FLAG; //Failure - Flag for retry later + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 15, 1, old_flags ); +#endif + } + if ( old_flags & STOPFL_FLAG ) { + if ( 1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) > 0 ) { + old_flags = 0; // Success - clear flags + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 16, 1, old_flags ); +#endif + } + pCh->flush_flags = old_flags; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_FLUSH, 17, 1, old_flags ); +#endif + return old_flags; +} + +//****************************************************************************** +// Function: i2DrainOutput(pCh,timeout) +// Parameters: Pointer to a channel structure +// Maximum period to wait +// Returns: ? +// +// Description: +// Uses the bookmark request command to ask the board to send a bookmark back as +// soon as all the data is completely sent. +//****************************************************************************** +static void +i2DrainWakeup(i2ChanStrPtr pCh) +{ +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires ); +#endif + pCh->BookmarkTimer.expires = 0; + wake_up_interruptible( &pCh->pBookmarkWait ); +} + +static void +i2DrainOutput(i2ChanStrPtr pCh, int timeout) +{ + i2eBordStrPtr pB; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, ITRC_ENTER, 1, pCh->BookmarkTimer.expires); +#endif + pB = pCh->pMyBord; + // If the board has gone fatal, return bad, + // and also hit the trap routine if it exists. + if (pB->i2eFatal) { + if (pB->i2eFatalTrap) { + (*(pB)->i2eFatalTrap)(pB); + } + return; + } + if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) { + // One per customer (channel) + init_timer( &(pCh->BookmarkTimer) ); + pCh->BookmarkTimer.expires = jiffies + timeout; + pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup; + pCh->BookmarkTimer.data = (unsigned long)pCh; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires ); +#endif + + add_timer( &(pCh->BookmarkTimer) ); + } + + i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ ); + serviceOutgoingFifo( pB ); + + interruptible_sleep_on( &(pCh->pBookmarkWait) ); + + // if expires == 0 then timer poped, then do not need to del_timer + if ((timeout > 0) && pCh->BookmarkTimer.expires && + (pCh->BookmarkTimer.expires > jiffies)) { + del_timer( &(pCh->BookmarkTimer) ); + pCh->BookmarkTimer.expires = 0; +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, 3, 1, pCh->BookmarkTimer.expires ); +#endif + + } +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_DRAIN, ITRC_RETURN, 1, pCh->BookmarkTimer.expires ); +#endif + return; +} + +//****************************************************************************** +// Function: i2OutputFree(pCh) +// Parameters: Pointer to a channel structure +// Returns: Space in output buffer +// +// Description: +// Returns -1 if very gross error. Otherwise returns the amount of bytes still +// free in the output buffer. +//****************************************************************************** +static int +i2OutputFree(i2ChanStrPtr pCh) +{ + int amountToMove; + unsigned long flags; + + // Ensure channel structure seems real + if ( !i2Validate ( pCh ) ) { + return -1; + } + READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; + READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + + if (amountToMove < 0) { + amountToMove += OBUF_SIZE; + } + // If this is negative, we will discover later + amountToMove -= sizeof(i2DataHeader); + + return (amountToMove < 0) ? 0 : amountToMove; +} +static void + +ip2_owake( PTTY tp) +{ + i2ChanStrPtr pCh; + + if (tp == NULL) return; + + pCh = tp->driver_data; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags, (1 << TTY_DO_WRITE_WAKEUP) ); +#endif + wake_up_interruptible ( &tp->write_wait ); + if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) + && tp->ldisc.write_wakeup ) + { + (tp->ldisc.write_wakeup) ( tp ); +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 11, 0 ); +#endif + } +} + +static inline void +set_baud_params(i2eBordStrPtr pB) +{ + int i,j; + i2ChanStrPtr *pCh; + + pCh = (i2ChanStrPtr *) pB->i2eChannelPtr; + + for (i = 0; i < ABS_MAX_BOXES; i++) { + if (pB->channelBtypes.bid_value[i]) { + if (BID_HAS_654(pB->channelBtypes.bid_value[i])) { + for (j = 0; j < ABS_BIGGEST_BOX; j++) { + if (pCh[i*16+j] == NULL) + break; + (pCh[i*16+j])->BaudBase = 921600; // MAX for ST654 + (pCh[i*16+j])->BaudDivisor = 96; + } + } else { // has cirrus cd1400 + for (j = 0; j < ABS_BIGGEST_BOX; j++) { + if (pCh[i*16+j] == NULL) + break; + (pCh[i*16+j])->BaudBase = 115200; // MAX for CD1400 + (pCh[i*16+j])->BaudDivisor = 12; + } + } + } + } +} + +//****************************************************************************** +// Function: i2StripFifo(pB) +// Parameters: Pointer to a board structure +// Returns: ? +// +// Description: +// Strips all the available data from the incoming FIFO, identifies the type of +// packet, and either buffers the data or does what needs to be done. +// +// Note there is no overflow checking here: if the board sends more data than it +// ought to, we will not detect it here, but blindly overflow... +//****************************************************************************** + +// A buffer for reading in blocks for unknown channels +static unsigned char junkBuffer[IBUF_SIZE]; + +// A buffer to read in a status packet. Because of the size of the count field +// for these things, the maximum packet size must be less than MAX_CMD_PACK_SIZE +static unsigned char cmdBuffer[MAX_CMD_PACK_SIZE + 4]; + +// This table changes the bit order from MSR order given by STAT_MODEM packet to +// status bits used in our library. +static char xlatDss[16] = { +0 | 0 | 0 | 0 , +0 | 0 | 0 | I2_CTS , +0 | 0 | I2_DSR | 0 , +0 | 0 | I2_DSR | I2_CTS , +0 | I2_RI | 0 | 0 , +0 | I2_RI | 0 | I2_CTS , +0 | I2_RI | I2_DSR | 0 , +0 | I2_RI | I2_DSR | I2_CTS , +I2_DCD | 0 | 0 | 0 , +I2_DCD | 0 | 0 | I2_CTS , +I2_DCD | 0 | I2_DSR | 0 , +I2_DCD | 0 | I2_DSR | I2_CTS , +I2_DCD | I2_RI | 0 | 0 , +I2_DCD | I2_RI | 0 | I2_CTS , +I2_DCD | I2_RI | I2_DSR | 0 , +I2_DCD | I2_RI | I2_DSR | I2_CTS }; + +static inline void +i2StripFifo(i2eBordStrPtr pB) +{ + i2ChanStrPtr pCh; + int channel; + int count; + unsigned short stuffIndex; + int amountToRead; + unsigned char *pc, *pcLimit; + unsigned char uc; + unsigned char dss_change; + unsigned long bflags,cflags; + +#ifdef IP2DEBUG_TRACE + //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 ); +#endif + + while (HAS_INPUT(pB)) { +#ifdef IP2DEBUG_TRACE + //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 ); +#endif + // Process packet from fifo a one atomic unit + WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags); + + // The first word (or two bytes) will have channel number and type of + // packet, possibly other information + pB->i2eLeadoffWord[0] = iiReadWord(pB); + + switch(PTYPE_OF(pB->i2eLeadoffWord)) + { + case PTYPE_DATA: + pB->got_input = 1; + +#ifdef IP2DEBUG_TRACE + //ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 3, 0 ); +#endif + channel = CHANNEL_OF(pB->i2eLeadoffWord); /* Store channel */ + count = iiReadWord(pB); /* Count is in the next word */ + +// NEW: Check the count for sanity! Should the hardware fail, our death +// is more pleasant. While an oversize channel is acceptable (just more +// than the driver supports), an over-length count clearly means we are +// sick! + if ( ((unsigned int)count) > IBUF_SIZE ) { + pB->i2eFatal = 2; + WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + return; /* Bail out ASAP */ + } + // Channel is illegally big ? + if (channel >= pB->i2eChannelCnt || + (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) == NULL) + { + iiReadBuf(pB, junkBuffer, count); + WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + break; /* From switch: ready for next packet */ + } + + // Channel should be valid, then + + // If this is a hot-key, merely post its receipt for now. These are + // always supposed to be 1-byte packets, so we won't even check the + // count. Also we will post an acknowledgement to the board so that + // more data can be forthcoming. Note that we are not trying to use + // these sequences in this driver, merely to robustly ignore them. + if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY) + { + pCh->hotKeyIn = iiReadWord(pB) & 0xff; + WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK); + break; /* From the switch: ready for next packet */ + } + + // Normal data! We crudely assume there is room for the data in our + // buffer because the board wouldn't have exceeded his credit limit. + WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);// We have 2 locks now + stuffIndex = pCh->Ibuf_stuff; + amountToRead = IBUF_SIZE - stuffIndex; + if (amountToRead > count) + amountToRead = count; + + // stuffIndex would have been already adjusted so there would + // always be room for at least one, and count is always at least + // one. + + iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); + + // Update the stuffIndex by the amount of data moved. Note we could + // never ask for more data than would just fit. However, we might + // have read in one more byte than we wanted because the read + // rounds up to even bytes. If this byte is on the end of the + // packet, and is padding, we ignore it. If the byte is part of + // the actual data, we need to move it. + + stuffIndex += amountToRead; + + if (stuffIndex >= IBUF_SIZE) { + if ((amountToRead & 1) && (count > amountToRead)) { + pCh->Ibuf[0] = pCh->Ibuf[IBUF_SIZE]; + amountToRead++; + stuffIndex = 1; + } else { + stuffIndex = 0; + } + } + + // If there is anything left over, read it as well + if (count > amountToRead) { + amountToRead = count - amountToRead; + iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); + stuffIndex += amountToRead; + } + + // Update stuff index + pCh->Ibuf_stuff = stuffIndex; + WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags); + WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + +#ifdef USE_IQ + queue_task(&pCh->tqueue_input, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + do_input(pCh); +#endif + + // Note we do not need to maintain any flow-control credits at this + // time: if we were to increment .asof and decrement .room, there + // would be no net effect. Instead, when we strip data, we will + // increment .asof and leave .room unchanged. + + break; // From switch: ready for next packet + + case PTYPE_STATUS: +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 4, 0 ); +#endif + + count = CMD_COUNT_OF(pB->i2eLeadoffWord); + + iiReadBuf(pB, cmdBuffer, count); + // We can release early with buffer grab + WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + + pc = cmdBuffer; + pcLimit = &(cmdBuffer[count]); + + while (pc < pcLimit) { + channel = *pc++; +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_SFIFO, 7, 2, channel, *pc ); +#endif + /* check for valid channel */ + if (channel < pB->i2eChannelCnt + && + (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) != NULL + ) + { + dss_change = 0; + + switch (uc = *pc++) + { + /* Breaks and modem signals are easy: just update status */ + case STAT_CTS_UP: + if ( !(pCh->dataSetIn & I2_CTS) ) + { + pCh->dataSetIn |= I2_DCTS; + ++pCh->icount.cts; + dss_change = 1; + } + pCh->dataSetIn |= I2_CTS; + break; + + case STAT_CTS_DN: + if ( pCh->dataSetIn & I2_CTS ) + { + pCh->dataSetIn |= I2_DCTS; + ++pCh->icount.cts; + dss_change = 1; + } + pCh->dataSetIn &= ~I2_CTS; + break; + + case STAT_DCD_UP: +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_MODEM, 1, 1, pCh->dataSetIn ); +#endif + if ( !(pCh->dataSetIn & I2_DCD) ) + { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_MODEM, 2, 0 ); +#endif + pCh->dataSetIn |= I2_DDCD; + ++pCh->icount.dcd; + dss_change = 1; + } + pCh->dataSetIn |= I2_DCD; +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_MODEM, 3, 1, pCh->dataSetIn ); +#endif + break; + + case STAT_DCD_DN: +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_MODEM, 4, 1, pCh->dataSetIn ); +#endif + if ( pCh->dataSetIn & I2_DCD ) + { +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_MODEM, 5, 0 ); +#endif + pCh->dataSetIn |= I2_DDCD; + ++pCh->icount.dcd; + dss_change = 1; + } + pCh->dataSetIn &= ~I2_DCD; +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_MODEM, 6, 1, pCh->dataSetIn ); +#endif + break; + + case STAT_DSR_UP: + if ( !(pCh->dataSetIn & I2_DSR) ) + { + pCh->dataSetIn |= I2_DDSR; + ++pCh->icount.dsr; + dss_change = 1; + } + pCh->dataSetIn |= I2_DSR; + break; + + case STAT_DSR_DN: + if ( pCh->dataSetIn & I2_DSR ) + { + pCh->dataSetIn |= I2_DDSR; + ++pCh->icount.dsr; + dss_change = 1; + } + pCh->dataSetIn &= ~I2_DSR; + break; + + case STAT_RI_UP: + if ( !(pCh->dataSetIn & I2_RI) ) + { + pCh->dataSetIn |= I2_DRI; + ++pCh->icount.rng; + dss_change = 1; + } + pCh->dataSetIn |= I2_RI ; + break; + + case STAT_RI_DN: + if ( pCh->dataSetIn & I2_RI ) + { + pCh->dataSetIn |= I2_DRI; + dss_change = 1; + } + pCh->dataSetIn &= ~I2_RI ; + break; + + case STAT_BRK_DET: + pCh->dataSetIn |= I2_BRK; + dss_change = 1; + break; + + // Bookmarks? one less request we're waiting for + case STAT_BMARK: + pCh->bookMarks--; + if (pCh->bookMarks <= 0 ) { + pCh->bookMarks = 0; + wake_up_interruptible( &pCh->pBookmarkWait ); +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_DRAIN, 20, 1, pCh->BookmarkTimer.expires ); +#endif + } + break; + + // Flow control packets? Update the new credits, and if + // someone was waiting for output, queue him up again. + case STAT_FLOW: + pCh->outfl.room = + ((flowStatPtr)pc)->room - + (pCh->outfl.asof - ((flowStatPtr)pc)->asof); +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_STFLW, 1, 1, pCh->outfl.room ); +#endif + if (pCh->channelNeeds & NEED_CREDIT) + { +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_STFLW, 2, 1, pCh->channelNeeds); +#endif + pCh->channelNeeds &= ~NEED_CREDIT; + i2QueueNeeds(pB, pCh, NEED_INLINE); + if ( pCh->pTTY ) + ip2_owake(pCh->pTTY); + } +#ifdef IP2DEBUG_TRACE + ip2trace (channel, ITRC_STFLW, 3, 1, pCh->channelNeeds); +#endif + pc += sizeof(flowStat); + break; + + /* Special packets: */ + /* Just copy the information into the channel structure */ + + case STAT_STATUS: + + pCh->channelStatus = *((debugStatPtr)pc); + pc += sizeof(debugStat); + break; + + case STAT_TXCNT: + + pCh->channelTcount = *((cntStatPtr)pc); + pc += sizeof(cntStat); + break; + + case STAT_RXCNT: + + pCh->channelRcount = *((cntStatPtr)pc); + pc += sizeof(cntStat); + break; + + case STAT_BOXIDS: + pB->channelBtypes = *((bidStatPtr)pc); + pc += sizeof(bidStat); +//printk("boxids: %x %x %x %x\n", +// pB->channelBtypes.bid_value[0],pB->channelBtypes.bid_value[1], +// pB->channelBtypes.bid_value[2],pB->channelBtypes.bid_value[3]); + set_baud_params(pB); + break; + + case STAT_HWFAIL: + i2QueueCommands (PTYPE_INLINE, pCh, 0, 1, CMD_HW_TEST); + pCh->channelFail = *((failStatPtr)pc); + pc += sizeof(failStat); + break; + + /* No explicit match? then + * Might be an error packet... + */ + default: + switch (uc & STAT_MOD_ERROR) + { + case STAT_ERROR: + if (uc & STAT_E_PARITY) + pCh->dataSetIn |= I2_PAR; + if (uc & STAT_E_FRAMING) + pCh->dataSetIn |= I2_FRA; + if (uc & STAT_E_OVERRUN) + pCh->dataSetIn |= I2_OVR; + break; + + case STAT_MODEM: + pCh->dataSetIn = (pCh->dataSetIn + & ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) ) + | xlatDss[uc & 0xf]; + default: + break; + } + } /* End of switch on status type */ + if (dss_change) { +#ifdef USE_IQ + queue_task(&pCh->tqueue_status, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + do_status(pCh); +#endif + } + } + else /* Or else, channel is invalid */ + { + // Even though the channel is invalid, we must test the + // status to see how much additional data it has (to be + // skipped) + switch (*pc++) + { + case STAT_FLOW: + pc += 4; /* Skip the data */ + break; + + case STAT_CTS_UP: + case STAT_CTS_DN: + case STAT_DCD_UP: + case STAT_DCD_DN: + case STAT_DSR_UP: + case STAT_DSR_DN: + case STAT_RI_UP: + case STAT_RI_DN: + case STAT_BRK_DET: + case STAT_BMARK: + default: + break; + } + } + } // End of while (there is still some status packet left) + break; + + default: // Neither packet? should be impossible +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1, + PTYPE_OF(pB->i2eLeadoffWord) ); +#endif + break; + } // End of switch on type of packets + } //while(board HAS_INPUT) +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 ); +#endif + // Send acknowledgement to the board even if there was no data! + pB->i2eOutMailWaiting |= MB_IN_STRIPPED; + return; +} + +//****************************************************************************** +// Function: i2Write2Fifo(pB,address,count) +// Parameters: Pointer to a board structure, source address, byte count +// Returns: bytes written +// +// Description: +// Writes count bytes to board io address(implied) from source +// Adjusts count, leaves reserve for next time around bypass cmds +//****************************************************************************** +static int +i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve) +{ + int rc = 0; + unsigned long flags; + WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + if (!pB->i2eWaitingForEmptyFifo) { + if (pB->i2eFifoRemains > (count+reserve)) { + pB->i2eFifoRemains -= count; + iiWriteBuf(pB, source, count); + pB->i2eOutMailWaiting |= MB_OUT_STUFFED; + rc = count; + } + } + WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + return rc; +} +//****************************************************************************** +// Function: i2StuffFifoBypass(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// Stuffs as many bypass commands into the fifo as possible. This is simpler +// than stuffing data or inline commands to fifo, since we do not have +// flow-control to deal with. +//****************************************************************************** +static inline void +i2StuffFifoBypass(i2eBordStrPtr pB) +{ + i2ChanStrPtr pCh; + unsigned char *pRemove; + unsigned short stripIndex; + unsigned short packetSize; + unsigned short paddedSize; + unsigned short notClogged = 1; + unsigned long flags; + + int bailout = 1000; + + // Continue processing so long as there are entries, or there is room in the + // fifo. Each entry represents a channel with something to do. + while ( --bailout && notClogged && + (NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS)))) + { + WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags); + stripIndex = pCh->Cbuf_strip; + + // as long as there are packets for this channel... + + while (stripIndex != pCh->Cbuf_stuff) { + pRemove = &(pCh->Cbuf[stripIndex]); + packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader); + paddedSize = ROUNDUP(packetSize); + + if (paddedSize > 0) { + if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) { + notClogged = 0; /* fifo full */ + i2QueueNeeds(pB, pCh, NEED_BYPASS); // Put back on queue + break; // Break from the channel + } + } +#ifdef DEBUG_FIFO +WriteDBGBuf("BYPS", pRemove, paddedSize); +#endif /* DEBUG_FIFO */ + pB->debugBypassCount++; + + pRemove += packetSize; + stripIndex += packetSize; + if (stripIndex >= CBUF_SIZE) { + stripIndex = 0; + pRemove = pCh->Cbuf; + } + } + // Done with this channel. Move to next, removing this one from + // the queue of channels if we cleaned it out (i.e., didn't get clogged. + pCh->Cbuf_strip = stripIndex; + WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); + } // Either clogged or finished all the work + +#ifdef IP2DEBUG_TRACE + if ( !bailout ) { + ip2trace (ITRC_NO_PORT, ITRC_ERROR, 1, 0 ); + } +#endif +} + +//****************************************************************************** +// Function: i2StuffFifoFlow(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// Stuffs as many flow control packets into the fifo as possible. This is easier +// even than doing normal bypass commands, because there is always at most one +// packet, already assembled, for each channel. +//****************************************************************************** +static inline void +i2StuffFifoFlow(i2eBordStrPtr pB) +{ + i2ChanStrPtr pCh; + unsigned short paddedSize = ROUNDUP(sizeof(flowIn)); + +#ifdef IP2DEBUG_TRACE +ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2, pB->i2eFifoRemains, paddedSize ); +#endif + + // Continue processing so long as there are entries, or there is room in the + // fifo. Each entry represents a channel with something to do. + while ( (NULL != (pCh = i2DeQueueNeeds(pB,NEED_FLOW)))) { + pB->debugFlowCount++; + + // NO Chan LOCK needed ??? + if ( 0 == i2Write2Fifo(pB,(unsigned char *)&(pCh->infl),paddedSize,0)) { + break; + } +#ifdef DEBUG_FIFO +WriteDBGBuf("FLOW",(unsigned char *) &(pCh->infl), paddedSize); +#endif /* DEBUG_FIFO */ + + } // Either clogged or finished all the work + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_RETURN, 0 ); +#endif +} + +//****************************************************************************** +// Function: i2StuffFifoInline(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// Stuffs as much data and inline commands into the fifo as possible. This is +// the most complex fifo-stuffing operation, since there if now the channel +// flow-control issue to deal with. +//****************************************************************************** +static inline void +i2StuffFifoInline(i2eBordStrPtr pB) +{ + i2ChanStrPtr pCh; + unsigned char *pRemove; + unsigned short stripIndex; + unsigned short packetSize; + unsigned short paddedSize; + unsigned short notClogged = 1; + unsigned short flowsize; + unsigned long flags; + + int bailout = 1000; + int bailout2; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_ENTER, 3, pB->i2eFifoRemains, + pB->i2Dbuf_strip, pB->i2Dbuf_stuff ); +#endif + + // Continue processing so long as there are entries, or there is room in the + // fifo. Each entry represents a channel with something to do. + while ( --bailout && notClogged && + (NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) ) + { + WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + stripIndex = pCh->Obuf_strip; + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff ); +#endif + // as long as there are packets for this channel... + bailout2 = 1000; + while ( --bailout2 && stripIndex != pCh->Obuf_stuff) { + pRemove = &(pCh->Obuf[stripIndex]); + + // Must determine whether this be a data or command packet to + // calculate correctly the header size and the amount of + // flow-control credit this type of packet will use. + if (PTYPE_OF(pRemove) == PTYPE_DATA) { + flowsize = DATA_COUNT_OF(pRemove); + packetSize = flowsize + sizeof(i2DataHeader); + } else { + flowsize = CMD_COUNT_OF(pRemove); + packetSize = flowsize + sizeof(i2CmdHeader); + } + flowsize = CREDIT_USAGE(flowsize); + paddedSize = ROUNDUP(packetSize); + +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize ); +#endif + // If we don't have enough credits from the board to send the data, + // flag the channel that we are waiting for flow control credit, and + // break out. This will clean up this channel and remove us from the + // queue of hot things to do. +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 5, 2, pCh->outfl.room, flowsize ); +#endif + if (pCh->outfl.room <= flowsize) { + // Do Not have the credits to send this packet. + i2QueueNeeds(pB, pCh, NEED_CREDIT); + notClogged = 0; + break; // So to do next channel + } + if ( (paddedSize > 0) + && ( 0 == i2Write2Fifo(pB, pRemove, paddedSize, 128))) { + // Do Not have room in fifo to send this packet. + notClogged = 0; + i2QueueNeeds(pB, pCh, NEED_INLINE); + break; // Break from the channel + } +#ifdef DEBUG_FIFO +WriteDBGBuf("DATA", pRemove, paddedSize); +#endif /* DEBUG_FIFO */ + pB->debugInlineCount++; + + // Update current credits + pCh->outfl.room -= flowsize; + pCh->outfl.asof += flowsize; + if (PTYPE_OF(pRemove) == PTYPE_DATA) { + pCh->Obuf_char_count -= DATA_COUNT_OF(pRemove); + } + pRemove += packetSize; + stripIndex += packetSize; +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 6, 2, stripIndex, pCh->Obuf_strip); +#endif + if (stripIndex >= OBUF_SIZE) { + stripIndex = 0; + pRemove = pCh->Obuf; +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 7, 1, stripIndex ); +#endif + } + } /* while */ + if ( !bailout2 ) { + ip2trace (CHANN, ITRC_ERROR, 3, 0 ); + } + // Done with this channel. Move to next, removing this one from the + // queue of channels if we cleaned it out (i.e., didn't get clogged. + pCh->Obuf_strip = stripIndex; + WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + if ( notClogged ) + { +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_SICMD, 8, 0 ); +#endif + if ( pCh->pTTY ) { + ip2_owake(pCh->pTTY); + } + } + } // Either clogged or finished all the work +#ifdef IP2DEBUG_TRACE + if ( !bailout ) { + ip2trace (ITRC_NO_PORT, ITRC_ERROR, 4, 0 ); + } +#endif + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_RETURN, 1,pB->i2Dbuf_strip); +#endif +} + +//****************************************************************************** +// Function: serviceOutgoingFifo(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// Helper routine to put data in the outgoing fifo, if we aren't already waiting +// for something to be there. If the fifo has only room for a very little data, +// go head and hit the board with a mailbox hit immediately. Otherwise, it will +// have to happen later in the interrupt processing. Since this routine may be +// called both at interrupt and foreground time, we must turn off interrupts +// during the entire process. +//****************************************************************************** +static void +serviceOutgoingFifo(i2eBordStrPtr pB) +{ + // If we aren't currently waiting for the board to empty our fifo, service + // everything that is pending, in priority order (especially, Bypass before + // Inline). + if ( ! pB->i2eWaitingForEmptyFifo ) + { + i2StuffFifoFlow(pB); + i2StuffFifoBypass(pB); + i2StuffFifoInline(pB); + + iiSendPendingMail(pB); + } +} + +//****************************************************************************** +// Function: i2ServiceBoard(pB) +// Parameters: Pointer to a board structure +// Returns: Nothing +// +// Description: +// Normally this is called from interrupt level, but there is deliberately +// nothing in here specific to being called from interrupt level. All the +// hardware-specific, interrupt-specific things happen at the outer levels. +// +// For example, a timer interrupt could drive this routine for some sort of +// polled operation. The only requirement is that the programmer deal with any +// atomiticity/concurrency issues that result. +// +// This routine responds to the board's having sent mailbox information to the +// host (which would normally cause an interrupt). This routine reads the +// incoming mailbox. If there is no data in it, this board did not create the +// interrupt and/or has nothing to be done to it. (Except, if we have been +// waiting to write mailbox data to it, we may do so. +// +// Based on the value in the mailbox, we may take various actions. +// +// No checking here of pB validity: after all, it shouldn't have been called by +// the handler unless pB were on the list. +//****************************************************************************** +static inline int +i2ServiceBoard ( i2eBordStrPtr pB ) +{ + unsigned inmail; + unsigned long flags; + + + inmail = iiGetMail(pB); + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, 2, 1, inmail ); +#endif + + if (inmail != NO_MAIL_HERE) { + // If the board has gone fatal, nothing to do but hit a bit that will + // alert foreground tasks to protest! + if ( inmail & MB_FATAL_ERROR ) { + pB->i2eFatal = 1; + goto exit_i2ServiceBoard; + } + + /* Assuming no fatal condition, we proceed to do work */ + if ( inmail & MB_IN_STUFFED ) { + pB->i2eFifoInInts++; + i2StripFifo(pB); /* There might be incoming packets */ + } + + if (inmail & MB_OUT_STRIPPED) { + pB->i2eFifoOutInts++; + WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + pB->i2eFifoRemains = pB->i2eFifoSize; + pB->i2eWaitingForEmptyFifo = 0; + WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains ); +#endif + } + serviceOutgoingFifo(pB); + } + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, 8, 0 ); +#endif + +exit_i2ServiceBoard: + + return 0; +} diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2lib.h linux/drivers/char/ip2/i2lib.h --- v2.3.14/linux/drivers/char/ip2/i2lib.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2lib.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,350 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Header file for high level library functions +* +*******************************************************************************/ +#ifndef I2LIB_H +#define I2LIB_H 1 +//------------------------------------------------------------------------------ +// I2LIB.H +// +// IntelliPort-II and IntelliPort-IIEX +// +// Defines, structure definitions, and external declarations for i2lib.c +//------------------------------------------------------------------------------ +//-------------------------------------- +// Mandatory Includes: +//-------------------------------------- +#include "ip2types.h" +#include "i2ellis.h" +#include "i2pack.h" +#include "i2cmd.h" + +//------------------------------------------------------------------------------ +// i2ChanStr -- Channel Structure: +// Used to track per-channel information for the library routines using standard +// loadware. Note also, a pointer to an array of these structures is patched +// into the i2eBordStr (see i2ellis.h) +//------------------------------------------------------------------------------ +// +// If we make some limits on the maximum block sizes, we can avoid dealing with +// buffer wrap. The wrapping of the buffer is based on where the start of the +// packet is. Then there is always room for the packet contiguously. +// +// Maximum total length of an outgoing data or in-line command block. The limit +// of 36 on data is quite arbitrary and based more on DOS memory limitations +// than the board interface. However, for commands, the maximum packet length is +// MAX_CMD_PACK_SIZE, because the field size for the count is only a few bits +// (see I2PACK.H) in such packets. For data packets, the count field size is not +// the limiting factor. As of this writing, MAX_OBUF_BLOCK < MAX_CMD_PACK_SIZE, +// but be careful if wanting to modify either. +// +#define MAX_OBUF_BLOCK 36 + +// Another note on maximum block sizes: we are buffering packets here. Data is +// put into the buffer (if there is room) regardless of the credits from the +// board. The board sends new credits whenever it has removed from his buffers a +// number of characters equal to 80% of total buffer size. (Of course, the total +// buffer size is what is reported when the very first set of flow control +// status packets are received from the board. Therefore, to be robust, you must +// always fill the board to at least 80% of the current credit limit, else you +// might not give it enough to trigger a new report. These conditions are +// obtained here so long as the maximum output block size is less than 20% the +// size of the board's output buffers. This is true at present by "coincidence" +// or "infernal knowledge": the board's output buffers are at least 700 bytes +// long (20% = 140 bytes, at least). The 80% figure is "official", so the safest +// strategy might be to trap the first flow control report and guarantee that +// the effective maxObufBlock is the minimum of MAX_OBUF_BLOCK and 20% of first +// reported buffer credit. +// +#define MAX_CBUF_BLOCK 6 // Maximum total length of a bypass command block + +#define IBUF_SIZE 500 // character capacity of input buffer per channel +#define OBUF_SIZE 2048// character capacity of output buffer per channel +#define CBUF_SIZE 10 // character capacity of output bypass buffer + +typedef struct _i2ChanStr +{ + // First, back-pointers so that given a pointer to this structure, you can + // determine the correct board and channel number to reference, (say, when + // issuing commands, etc. (Note, channel number is in infl.hd.i2sChannel.) + + int port_index; // Index of port in channel structure array attached + // to board structure. + PTTY pTTY; // Pointer to tty structure for port (OS specific) + USHORT validity; // Indicates whether the given channel has been + // initialized, really exists (or is a missing + // channel, e.g. channel 9 on an 8-port box.) + + i2eBordStrPtr pMyBord; // Back-pointer to this channel's board structure + + int wopen; // waiting fer carrier + + int throttled; // Set if upper layer can take no data + + int flags; // Defined in tty.h + int session; // Defined in tty.h + int pgrp; // Defined in tty.h + + PWAITQ open_wait; // Pointer for OS sleep function. + PWAITQ close_wait; // Pointer for OS sleep function. + PWAITQ delta_msr_wait;// Pointer for OS sleep function. + + struct timer_list BookmarkTimer; // Used by i2DrainOutput + wait_queue_head_t pBookmarkWait; // Used by i2DrainOutput + + struct termios NormalTermios; + struct termios CalloutTermios; + + int BaudBase; + int BaudDivisor; + + USHORT ClosingDelay; + USHORT ClosingWaitTime; + + volatile + flowIn infl; // This structure is initialized as a completely + // formed flow-control command packet, and as such + // has the channel number, also the capacity and + // "as-of" data needed continuously. + + USHORT sinceLastFlow; // Counts the number of characters read from input + // buffers, since the last time flow control info + // was sent. + + USHORT whenSendFlow; // Determines when new flow control is to be sent to + // the board. Note unlike earlier manifestations of + // the driver, these packets can be sent from + // in-place. + + USHORT channelNeeds; // Bit map of important things which must be done + // for this channel. (See bits below ) + + volatile + flowStat outfl; // Same type of structure is used to hold current + // flow control information used to control our + // output. "asof" is kept updated as data is sent, + // and "room" never goes to zero. + + // The incoming ring buffer + // Unlike the outgoing buffers, this holds raw data, not packets. The two + // extra bytes are used to hold the byte-padding when there is room for an + // odd number of bytes before we must wrap. + // + UCHAR Ibuf[IBUF_SIZE + 2]; + volatile + USHORT Ibuf_stuff; // Stuffing index + volatile + USHORT Ibuf_strip; // Stripping index + + // The outgoing ring-buffer: Holds Data and command packets. N.B., even + // though these are in the channel structure, the channel is also written + // here, the easier to send it to the fifo when ready. HOWEVER, individual + // packets here are NOT padded to even length: the routines for writing + // blocks to the the fifo will pad to even byte counts. + // + UCHAR Obuf[OBUF_SIZE+MAX_OBUF_BLOCK+4]; + volatile + USHORT Obuf_stuff; // Stuffing index + volatile + USHORT Obuf_strip; // Stripping index + int Obuf_char_count; + + // The outgoing bypass-command buffer. Unlike earlier manifestations, the + // flow control packets are sent directly from the structures. As above, the + // channel number is included in the packet, but they are NOT padded to even + // size. + // + UCHAR Cbuf[CBUF_SIZE+MAX_CBUF_BLOCK+2]; + volatile + USHORT Cbuf_stuff; // Stuffing index + volatile + USHORT Cbuf_strip; // Stripping index + + // The temporary buffer for the Linux tty driver PutChar entry. + // + UCHAR Pbuf[MAX_OBUF_BLOCK - sizeof (i2DataHeader)]; + volatile + USHORT Pbuf_stuff; // Stuffing index + + // The state of incoming data-set signals + // + USHORT dataSetIn; // Bit-mapped according to below. Also indicates + // whether a break has been detected since last + // inquiry. + + // The state of outcoming data-set signals (as far as we can tell!) + // + USHORT dataSetOut; // Bit-mapped according to below. + + // Most recent hot-key identifier detected + // + USHORT hotKeyIn; // Hot key as sent by the board, HOT_CLEAR indicates + // no hot key detected since last examined. + + // Counter of outstanding requests for bookmarks + // + short bookMarks; // Number of outstanding bookmark requests, (+ive + // whenever a bookmark request if queued up, -ive + // whenever a bookmark is received). + + // Misc options + // + USHORT channelOptions; // See below + + // To store various incoming special packets + // + debugStat channelStatus; + cntStat channelRcount; + cntStat channelTcount; + failStat channelFail; + + // To store the last values for line characteristics we sent to the board. + // + int speed; + + int flush_flags; + + void (*trace)(unsigned short,unsigned char,unsigned char,unsigned long,...); + +#ifdef __KERNEL__ + /* + * Kernel counters for the 4 input interrupts + */ + struct async_icount icount; + + /* + * Task queues for processing input packets from the board. + */ + struct tq_struct tqueue_input; + struct tq_struct tqueue_status; + struct tq_struct tqueue_hangup; +#endif + + spinlock_t Ibuf_spinlock; + spinlock_t Obuf_spinlock; + spinlock_t Cbuf_spinlock; + spinlock_t Pbuf_spinlock; + +} i2ChanStr, *i2ChanStrPtr; + +//--------------------------------------------------- +// Manifests and bit-maps for elements in i2ChanStr +//--------------------------------------------------- +// +// flush flags +// +#define STARTFL_FLAG 1 +#define STOPFL_FLAG 2 + +// validity +// +#define CHANNEL_MAGIC_BITS 0xff00 +#define CHANNEL_MAGIC 0x5300 // (validity & CHANNEL_MAGIC_BITS) == + // CHANNEL_MAGIC --> structure good + +#define CHANNEL_SUPPORT 0x0001 // Indicates channel is supported, exists, + // and passed P.O.S.T. + +// channelNeeds +// +#define NEED_FLOW 1 // Indicates flow control has been queued +#define NEED_INLINE 2 // Indicates inline commands or data queued +#define NEED_BYPASS 4 // Indicates bypass commands queued +#define NEED_CREDIT 8 // Indicates would be sending except has not sufficient + // credit. The data is still in the channel structure, + // but the channel is not enqueued in the board + // structure again until there is a credit received from + // the board. + +// dataSetIn (Also the bits for i2GetStatus return value) +// +#define I2_DCD 1 +#define I2_CTS 2 +#define I2_DSR 4 +#define I2_RI 8 + +// dataSetOut (Also the bits for i2GetStatus return value) +// +#define I2_DTR 1 +#define I2_RTS 2 + +// i2GetStatus() can optionally clear these bits +// +#define I2_BRK 0x10 // A break was detected +#define I2_PAR 0x20 // A parity error was received +#define I2_FRA 0x40 // A framing error was received +#define I2_OVR 0x80 // An overrun error was received + +// i2GetStatus() automatically clears these bits */ +// +#define I2_DDCD 0x100 // DCD changed from its former value +#define I2_DCTS 0x200 // CTS changed from its former value +#define I2_DDSR 0x400 // DSR changed from its former value +#define I2_DRI 0x800 // RI changed from its former value + +// hotKeyIn +// +#define HOT_CLEAR 0x1322 // Indicates that no hot-key has been detected + +// channelOptions +// +#define CO_NBLOCK_WRITE 1 // Writes don't block waiting for buffer. (Default + // is, they do wait.) + +// fcmodes +// +#define I2_OUTFLOW_CTS 0x0001 +#define I2_INFLOW_RTS 0x0002 +#define I2_INFLOW_DSR 0x0004 +#define I2_INFLOW_DTR 0x0008 +#define I2_OUTFLOW_DSR 0x0010 +#define I2_OUTFLOW_DTR 0x0020 +#define I2_OUTFLOW_XON 0x0040 +#define I2_OUTFLOW_XANY 0x0080 +#define I2_INFLOW_XON 0x0100 + +#define I2_CRTSCTS (I2_OUTFLOW_CTS|I2_INFLOW_RTS) +#define I2_IXANY_MODE (I2_OUTFLOW_XON|I2_OUTFLOW_XANY) + +//------------------------------------------- +// Macros used from user level like functions +//------------------------------------------- + +// Macros to set and clear channel options +// +#define i2SetOption(pCh, option) pCh->channelOptions |= option +#define i2ClrOption(pCh, option) pCh->channelOptions &= ~option + +// Macro to set fatal-error trap +// +#define i2SetFatalTrap(pB, routine) pB->i2eFatalTrap = routine + +//-------------------------------------------- +// Declarations and prototypes for i2lib.c +//-------------------------------------------- +// +static int i2InitChannels(i2eBordStrPtr, int, i2ChanStrPtr); +static int i2QueueCommands(int, i2ChanStrPtr, int, int, cmdSyntaxPtr,...); +static int i2GetStatus(i2ChanStrPtr, int); +static int i2Input(i2ChanStrPtr); +static int i2InputFlush(i2ChanStrPtr); +static int i2Output(i2ChanStrPtr, const char *, int, int); +static int i2OutputFree(i2ChanStrPtr); +static int i2ServiceBoard(i2eBordStrPtr); +static void i2DrainOutput(i2ChanStrPtr, int); + +// Argument to i2QueueCommands +// +#define C_IN_LINE 1 +#define C_BYPASS 0 + +#endif // I2LIB_H diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2os.h linux/drivers/char/ip2/i2os.h --- v2.3.14/linux/drivers/char/ip2/i2os.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2os.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,145 @@ +/******************************************************************************* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Defines, definitions and includes which are heavily dependant +* on O/S, host, compiler, etc. This file is tailored for: +* Linux v2.0.0 and later +* Gnu gcc c2.7.2 +* 80x86 architecture +* +*******************************************************************************/ + +#ifndef I2OS_H /* To prevent multiple includes */ +#define I2OS_H 1 + +#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) + +//------------------------------------------------- +// Required Includes +//------------------------------------------------- + +#include "ip2types.h" +#include /* For inb, etc */ + +//------------------------------------ +// Defines for I/O instructions: +//------------------------------------ + +#define INB(port) inb(port) +#define OUTB(port,value) outb((value),(port)) +#define INW(port) inw(port) +#define OUTW(port,value) outw((value),(port)) +#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2)) +#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2) +#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2)) +#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2) + +//-------------------------------------------- +// Interrupt control +//-------------------------------------------- + +#if LINUX_VERSION_CODE < 0x00020100 +typedef int spinlock_t; +#define spin_lock_init() +#define spin_lock(a) +#define spin_unlock(a) +#define spin_lock_irqsave(a,b) {save_flags((b));cli();} +#define spin_unlock_irqrestore(a,b) {restore_flags((b));} +#define write_lock_irqsave(a,b) spin_lock_irqsave(a,b) +#define write_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) +#define read_lock_irqsave(a,b) spin_lock_irqsave(a,b) +#define read_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) +#endif + +//#define SAVE_AND_DISABLE_INTS(a,b) spin_lock_irqsave(a,b) +//#define RESTORE_INTS(a,b) spin_unlock_irqrestore(a,b) + +#define LOCK_INIT(a) spin_lock_init(a) + +#define SAVE_AND_DISABLE_INTS(a,b) { \ + /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + spin_lock_irqsave(a,b); \ +} + +#define RESTORE_INTS(a,b) { \ + /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + spin_unlock_irqrestore(a,b); \ +} + +#define READ_LOCK_IRQSAVE(a,b) { \ + /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + read_lock_irqsave(a,b); \ +} + +#define READ_UNLOCK_IRQRESTORE(a,b) { \ + /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + read_unlock_irqrestore(a,b); \ +} + +#define WRITE_LOCK_IRQSAVE(a,b) { \ + /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + write_lock_irqsave(a,b); \ +} + +#define WRITE_UNLOCK_IRQRESTORE(a,b) { \ + /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ + write_unlock_irqrestore(a,b); \ +} + + +//------------------------------------------------------------------------------ +// Hardware-delay loop +// +// Probably used in only one place (see i2ellis.c) but this helps keep things +// together. Note we have unwound the IN instructions. On machines with a +// reasonable cache, the eight instructions (1 byte each) should fit in cache +// nicely, and on un-cached machines, the code-fetch would tend not to dominate. +// Note that cx is shifted so that "count" still reflects the total number of +// iterations assuming no unwinding. +//------------------------------------------------------------------------------ + +//#define DELAY1MS(port,count,label) + +//------------------------------------------------------------------------------ +// Macros to switch to a new stack, saving stack pointers, and to restore the +// old stack (Used, for example, in i2lib.c) "heap" is the address of some +// buffer which will become the new stack (working down from highest address). +// The two words at the two lowest addresses in this stack are for storing the +// SS and SP. +//------------------------------------------------------------------------------ + +//#define TO_NEW_STACK(heap,size) +//#define TO_OLD_STACK(heap) + +//------------------------------------------------------------------------------ +// Macros to save the original IRQ vectors and masks, and to patch in new ones. +//------------------------------------------------------------------------------ + +//#define SAVE_IRQ_MASKS(dest) +//#define WRITE_IRQ_MASKS(src) +//#define SAVE_IRQ_VECTOR(value,dest) +//#define WRITE_IRQ_VECTOR(value,src) + +//------------------------------------------------------------------------------ +// Macro to copy data from one far pointer to another. +//------------------------------------------------------------------------------ + +#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count); + +//------------------------------------------------------------------------------ +// Macros to issue eoi's to host interrupt control (IBM AT 8259-style). +//------------------------------------------------------------------------------ + +//#define MASTER_EOI +//#define SLAVE_EOI + +#endif /* I2OS_H */ + + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/i2pack.h linux/drivers/char/ip2/i2pack.h --- v2.3.14/linux/drivers/char/ip2/i2pack.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/i2pack.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,364 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Definitions of the packets used to transfer data and commands +* Host <--> Board. Information provided here is only applicable +* when the standard loadware is active. +* +*******************************************************************************/ +#ifndef I2PACK_H +#define I2PACK_H 1 + +//----------------------------------------------- +// Revision History: +// +// 10 October 1991 MAG First draft +// 24 February 1992 MAG Additions for 1.4.x loadware +// 11 March 1992 MAG New status packets +// +//----------------------------------------------- + +//------------------------------------------------------------------------------ +// Packet Formats: +// +// Information passes between the host and board through the FIFO in packets. +// These have headers which indicate the type of packet. Because the fifo data +// path may be 16-bits wide, the protocol is constrained such that each packet +// is always padded to an even byte count. (The lower-level interface routines +// -- i2ellis.c -- are designed to do this). +// +// The sender (be it host or board) must place some number of complete packets +// in the fifo, then place a message in the mailbox that packets are available. +// Placing such a message interrupts the "receiver" (be it board or host), who +// reads the mailbox message and determines that there are incoming packets +// ready. Since there are no partial packets, and the length of a packet is +// given in the header, the remainder of the packet can be read without checking +// for FIFO empty condition. The process is repeated, packet by packet, until +// the incoming FIFO is empty. Then the receiver uses the outbound mailbox to +// signal the board that it has read the data. Only then can the sender place +// additional data in the fifo. +//------------------------------------------------------------------------------ +// +//------------------------------------------------ +// Definition of Packet Header Area +//------------------------------------------------ +// +// Caution: these only define header areas. In actual use the data runs off +// beyond the end of these structures. +// +// Since these structures are based on sequences of bytes which go to the board, +// there cannot be ANY padding between the elements. +#pragma pack(1) + +//---------------------------- +// DATA PACKETS +//---------------------------- + +typedef struct _i2DataHeader +{ + unsigned char i2sChannel; /* The channel number: 0-255 */ + + // -- Bitfields are allocated LSB first -- + + // For incoming data, indicates whether this is an ordinary packet or a + // special one (e.g., hot key hit). + unsigned i2sId : 2 __attribute__ ((__packed__)); + + // For tagging data packets. There are flush commands which flush only data + // packets bearing a particular tag. (used in implementing IntelliView and + // IntelliPrint). THE TAG VALUE 0xf is RESERVED and must not be used (it has + // meaning internally to the loadware). + unsigned i2sTag : 4; + + // These two bits determine the type of packet sent/received. + unsigned i2sType : 2; + + // The count of data to follow: does not include the possible additional + // padding byte. MAXIMUM COUNT: 4094. The top four bits must be 0. + unsigned short i2sCount; + +} i2DataHeader, *i2DataHeaderPtr; + +// Structure is immediately followed by the data, proper. + +//---------------------------- +// NON-DATA PACKETS +//---------------------------- + +typedef struct _i2CmdHeader +{ + unsigned char i2sChannel; // The channel number: 0-255 (Except where noted + // - see below + + // Number of bytes of commands, status or whatever to follow + unsigned i2sCount : 6; + + // These two bits determine the type of packet sent/received. + unsigned i2sType : 2; + +} i2CmdHeader, *i2CmdHeaderPtr; + +// Structure is immediately followed by the applicable data. + +//--------------------------------------- +// Flow Control Packets (Outbound) +//--------------------------------------- + +// One type of outbound command packet is so important that the entire structure +// is explicitly defined here. That is the flow-control packet. This is never +// sent by user-level code (as would be the commands to raise/lower DTR, for +// example). These are only sent by the library routines in response to reading +// incoming data into the buffers. +// +// The parameters inside the command block are maintained in place, then the +// block is sent at the appropriate time. + +typedef struct _flowIn +{ + i2CmdHeader hd; // Channel #, count, type (see above) + unsigned char fcmd; // The flow control command (37) + unsigned short asof; // As of byte number "asof" (LSB first!) I have room + // for "room" bytes + unsigned short room; +} flowIn, *flowInPtr; + +//---------------------------------------- +// (Incoming) Status Packets +//---------------------------------------- + +// Incoming packets which are non-data packets are status packets. In this case, +// the channel number in the header is unimportant. What follows are one or more +// sub-packets, the first word of which consists of the channel (first or low +// byte) and the status indicator (second or high byte), followed by possibly +// more data. + +#define STAT_CTS_UP 0 /* CTS raised (no other bytes) */ +#define STAT_CTS_DN 1 /* CTS dropped (no other bytes) */ +#define STAT_DCD_UP 2 /* DCD raised (no other bytes) */ +#define STAT_DCD_DN 3 /* DCD dropped (no other bytes) */ +#define STAT_DSR_UP 4 /* DSR raised (no other bytes) */ +#define STAT_DSR_DN 5 /* DSR dropped (no other bytes) */ +#define STAT_RI_UP 6 /* RI raised (no other bytes) */ +#define STAT_RI_DN 7 /* RI dropped (no other bytes) */ +#define STAT_BRK_DET 8 /* BRK detect (no other bytes) */ +#define STAT_FLOW 9 /* Flow control(-- more: see below */ +#define STAT_BMARK 10 /* Bookmark (no other bytes) + * Bookmark is sent as a response to + * a command 60: request for bookmark + */ +#define STAT_STATUS 11 /* Special packet: see below */ +#define STAT_TXCNT 12 /* Special packet: see below */ +#define STAT_RXCNT 13 /* Special packet: see below */ +#define STAT_BOXIDS 14 /* Special packet: see below */ +#define STAT_HWFAIL 15 /* Special packet: see below */ + +#define STAT_MOD_ERROR 0xc0 +#define STAT_MODEM 0xc0/* If status & STAT_MOD_ERROR: + * == STAT_MODEM, then this is a modem + * status packet, given in response to a + * CMD_DSS_NOW command. + * The low nibble has each data signal: + */ +#define STAT_MOD_DCD 0x8 +#define STAT_MOD_RI 0x4 +#define STAT_MOD_DSR 0x2 +#define STAT_MOD_CTS 0x1 + +#define STAT_ERROR 0x80/* If status & STAT_MOD_ERROR + * == STAT_ERROR, then + * sort of error on the channel. + * The remaining seven bits indicate + * what sort of error it is. + */ +/* The low three bits indicate parity, framing, or overrun errors */ + +#define STAT_E_PARITY 4 /* Parity error */ +#define STAT_E_FRAMING 2 /* Framing error */ +#define STAT_E_OVERRUN 1 /* (uxart) overrun error */ + +//--------------------------------------- +// STAT_FLOW packets +//--------------------------------------- + +typedef struct _flowStat +{ + unsigned short asof; + unsigned short room; +}flowStat, *flowStatPtr; + +// flowStat packets are received from the board to regulate the flow of outgoing +// data. A local copy of this structure is also kept to track the amount of +// credits used and credits remaining. "room" is the amount of space in the +// board's buffers, "as of" having received a certain byte number. When sending +// data to the fifo, you must calculate how much buffer space your packet will +// use. Add this to the current "asof" and subtract it from the current "room". +// +// The calculation for the board's buffer is given by CREDIT_USAGE, where size +// is the un-rounded count of either data characters or command characters. +// (Which is to say, the count rounded up, plus two). + +#define CREDIT_USAGE(size) (((size) + 3) & ~1) + +//--------------------------------------- +// STAT_STATUS packets +//--------------------------------------- + +typedef struct _debugStat +{ + unsigned char d_ccsr; + unsigned char d_txinh; + unsigned char d_stat1; + unsigned char d_stat2; +} debugStat, *debugStatPtr; + +// debugStat packets are sent to the host in response to a CMD_GET_STATUS +// command. Each byte is bit-mapped as described below: + +#define D_CCSR_XON 2 /* Has received XON, ready to transmit */ +#define D_CCSR_XOFF 4 /* Has received XOFF, not transmitting */ +#define D_CCSR_TXENAB 8 /* Transmitter is enabled */ +#define D_CCSR_RXENAB 0x80 /* Receiver is enabled */ + +#define D_TXINH_BREAK 1 /* We are sending a break */ +#define D_TXINH_EMPTY 2 /* No data to send */ +#define D_TXINH_SUSP 4 /* Output suspended via command 57 */ +#define D_TXINH_CMD 8 /* We are processing an in-line command */ +#define D_TXINH_LCD 0x10 /* LCD diagnostics are running */ +#define D_TXINH_PAUSE 0x20 /* We are processing a PAUSE command */ +#define D_TXINH_DCD 0x40 /* DCD is low, preventing transmission */ +#define D_TXINH_DSR 0x80 /* DSR is low, preventing transmission */ + +#define D_STAT1_TXEN 1 /* Transmit INTERRUPTS enabled */ +#define D_STAT1_RXEN 2 /* Receiver INTERRUPTS enabled */ +#define D_STAT1_MDEN 4 /* Modem (data set sigs) interrupts enabled */ +#define D_STAT1_RLM 8 /* Remote loopback mode selected */ +#define D_STAT1_LLM 0x10 /* Local internal loopback mode selected */ +#define D_STAT1_CTS 0x20 /* CTS is low, preventing transmission */ +#define D_STAT1_DTR 0x40 /* DTR is low, to stop remote transmission */ +#define D_STAT1_RTS 0x80 /* RTS is low, to stop remote transmission */ + +#define D_STAT2_TXMT 1 /* Transmit buffers are all empty */ +#define D_STAT2_RXMT 2 /* Receive buffers are all empty */ +#define D_STAT2_RXINH 4 /* Loadware has tried to inhibit remote + * transmission: dropped DTR, sent XOFF, + * whatever... + */ +#define D_STAT2_RXFLO 8 /* Loadware can send no more data to host + * until it receives a flow-control packet + */ +//----------------------------------------- +// STAT_TXCNT and STAT_RXCNT packets +//---------------------------------------- + +typedef struct _cntStat +{ + unsigned short cs_time; // (Assumes host is little-endian!) + unsigned short cs_count; +} cntStat, *cntStatPtr; + +// These packets are sent in response to a CMD_GET_RXCNT or a CMD_GET_TXCNT +// bypass command. cs_time is a running 1 Millisecond counter which acts as a +// time stamp. cs_count is a running counter of data sent or received from the +// uxarts. (Not including data added by the chip itself, as with CRLF +// processing). +//------------------------------------------ +// STAT_HWFAIL packets +//------------------------------------------ + +typedef struct _failStat +{ + unsigned char fs_written; + unsigned char fs_read; + unsigned short fs_address; +} failStat, *failStatPtr; + +// This packet is sent whenever the on-board diagnostic process detects an +// error. At startup, this process is dormant. The host can wake it up by +// issuing the bypass command CMD_HW_TEST. The process runs at low priority and +// performs continuous hardware verification; writing data to certain on-board +// registers, reading it back, and comparing. If it detects an error, this +// packet is sent to the host, and the process goes dormant again until the host +// sends another CMD_HW_TEST. It then continues with the next register to be +// tested. + +//------------------------------------------------------------------------------ +// Macros to deal with the headers more easily! Note that these are defined so +// they may be used as "left" as well as "right" expressions. +//------------------------------------------------------------------------------ + +// Given a pointer to the packet, reference the channel number +// +#define CHANNEL_OF(pP) ((i2DataHeaderPtr)(pP))->i2sChannel + +// Given a pointer to the packet, reference the Packet type +// +#define PTYPE_OF(pP) ((i2DataHeaderPtr)(pP))->i2sType + +// The possible types of packets +// +#define PTYPE_DATA 0 /* Host <--> Board */ +#define PTYPE_BYPASS 1 /* Host ---> Board */ +#define PTYPE_INLINE 2 /* Host ---> Board */ +#define PTYPE_STATUS 2 /* Host <--- Board */ + +// Given a pointer to a Data packet, reference the Tag +// +#define TAG_OF(pP) ((i2DataHeaderPtr)(pP))->i2sTag + +// Given a pointer to a Data packet, reference the data i.d. +// +#define ID_OF(pP) ((i2DataHeaderPtr)(pP))->i2sId + +// The possible types of ID's +// +#define ID_ORDINARY_DATA 0 +#define ID_HOT_KEY 1 + +// Given a pointer to a Data packet, reference the count +// +#define DATA_COUNT_OF(pP) ((i2DataHeaderPtr)(pP))->i2sCount + +// Given a pointer to a Data packet, reference the beginning of data +// +#define DATA_OF(pP) &((unsigned char *)(pP))[4] // 4 = size of header + +// Given a pointer to a Non-Data packet, reference the count +// +#define CMD_COUNT_OF(pP) ((i2CmdHeaderPtr)(pP))->i2sCount + +#define MAX_CMD_PACK_SIZE 62 // Maximum size of such a count + +// Given a pointer to a Non-Data packet, reference the beginning of data +// +#define CMD_OF(pP) &((unsigned char *)(pP))[2] // 2 = size of header + +//-------------------------------- +// MailBox Bits: +//-------------------------------- + +//-------------------------- +// Outgoing (host to board) +//-------------------------- +// +#define MB_OUT_STUFFED 0x80 // Host has placed output in fifo +#define MB_IN_STRIPPED 0x40 // Host has read in all input from fifo + +//-------------------------- +// Incoming (board to host) +//-------------------------- +// +#define MB_IN_STUFFED 0x80 // Board has placed input in fifo +#define MB_OUT_STRIPPED 0x40 // Board has read all output from fifo +#define MB_FATAL_ERROR 0x20 // Board has encountered a fatal error + +#pragma pack(4) // Reset padding to command-line default + +#endif // I2PACK_H + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/ip2.h linux/drivers/char/ip2/ip2.h --- v2.3.14/linux/drivers/char/ip2/ip2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,109 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Driver constants for configuration and tuning +* +* NOTES: +* +*******************************************************************************/ +#ifndef IP2_H +#define IP2_H + +#include "ip2types.h" +#include "i2cmd.h" + +/*************/ +/* Constants */ +/*************/ + +/* Device major numbers + * The first set are the major numbers allocated from the Linux Device Registry. + * This was expanded from 64 to 128 with version 2.0.26. If this code is built + * under earlier versions we use majors from the LOCAL/EXPERIMENTAL range. + */ +#if MAX_CHRDEV > 64 +# define IP2_TTY_MAJOR 71 +# define IP2_CALLOUT_MAJOR 72 +# define IP2_IPL_MAJOR 73 +#else +# define IP2_TTY_MAJOR 60 +# define IP2_CALLOUT_MAJOR 61 +# define IP2_IPL_MAJOR 62 +#endif + + +/* Board configuration array. + * This array defines the hardware irq and address for up to IP2_MAX_BOARDS + * (4 supported per ip2_types.h) ISA board addresses and irqs MUST be specified, + * PCI and EISA boards are probed for and automagicly configed + * iff the addresses are set to 1 and 2 respectivily. + * 0x0100 - 0x03f0 == ISA + * 1 == PCI + * 2 == EISA + * 0 == (skip this board) + * This array defines the hardware addresses for them. Special + * addresses are EISA and PCI which go sniffing for boards. + + * In a multiboard system the position in the array determines which port + * devices are assigned to each board: + * board 0 is assigned ttyF0.. to ttyF63, + * board 1 is assigned ttyF64 to ttyF127, + * board 2 is assigned ttyF128 to ttyF191, + * board 3 is assigned ttyF192 to ttyF255. + * + * In PCI and EISA bus systems each range is mapped to card in + * monotonically increasing slot number order, ISA position is as specified + * here. + + * If the irqs are ALL set to 0,0,0,0 all boards operate in + * polled mode. For interrupt operation ISA boards require that the IRQ be + * specified, while PCI and EISA boards any nonzero entry + * will enable interrupts using the BIOS configured irq for the board. + * An invalid irq entry will default to polled mode for that card and print + * console warning. + + * When the driver is loaded as a module these setting can be overridden on the + * modprobe command line or on an option line in /etc/conf.modules + * or /etc/modules.conf depending on your distrubution. + * If the driver is built-in the configuration must be + * set here for ISA cards and address set to 1 and 2 for PCI and EISA. + * + * Here is an example that shows most if not all possibe combinations: + + *static ip2config_t ip2config = + *{ + * {11,1,0,0}, // irqs + * { // Addresses + * 0x0308, // Board 0, ttyF0 - ttyF63// ISA card at io=0x308, irq=11 + * 0x0001, // Board 1, ttyF64 - ttyF127//PCI card configured by BIOS + * 0x0000, // Board 2, ttyF128 - ttyF191// Slot skipped + * 0x0002 // Board 3, ttyF192 - ttyF255//EISA card configured by BIOS + * // but polled not irq driven + * } + *}; + */ + + /* this structure is zeroed out because the suggested method is to configure + * the driver as a module, set up the parameters with an options line in + * /etc/modules.conf or /etc/conf.modules and load with modprobe, kerneld or + * kmod, the kernel module loader + */ +static ip2config_t ip2config = +{ + {0,0,0,0}, // irqs + { // Addresses + 0x0000, // Board 0, ttyF0 - ttyF63 + 0x0000, // Board 1, ttyF64 - ttyF127 + 0x0000, // Board 2, ttyF128 - ttyF191 + 0x0000 // Board 3, ttyF192 - ttyF255 + } +}; + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/ip2ioctl.h linux/drivers/char/ip2/ip2ioctl.h --- v2.3.14/linux/drivers/char/ip2/ip2ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2ioctl.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,35 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Driver constants for configuration and tuning +* +* NOTES: +* +*******************************************************************************/ + +#ifndef IP2IOCTL_H +#define IP2IOCTL_H + +//************* +//* Constants * +//************* + +// High baud rates (if not defined elsewhere. +#ifndef B153600 +# define B153600 0010005 +#endif +#ifndef B307200 +# define B307200 0010006 +#endif +#ifndef B921600 +# define B921600 0010007 +#endif + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/ip2trace.h linux/drivers/char/ip2/ip2trace.h --- v2.3.14/linux/drivers/char/ip2/ip2trace.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2trace.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,43 @@ + +// +union ip2breadcrumb +{ + struct { + unsigned char port, cat, codes, label; + } __attribute__ ((packed)) hdr; + unsigned long value; +}; + +#define ITRC_NO_PORT 0xFF +#define PORTN (port->port_index) +#define CHANN (pCh->port_index) + +#define ITRC_ERROR '!' +#define ITRC_INIT 'A' +#define ITRC_OPEN 'B' +#define ITRC_CLOSE 'C' +#define ITRC_DRAIN 'D' +#define ITRC_IOCTL 'E' +#define ITRC_FLUSH 'F' +#define ITRC_STATUS 'G' +#define ITRC_HANGUP 'H' +#define ITRC_INTR 'I' +#define ITRC_SFLOW 'J' +#define ITRC_SBCMD 'K' +#define ITRC_SICMD 'L' +#define ITRC_MODEM 'M' +#define ITRC_INPUT 'N' +#define ITRC_OUTPUT 'O' +#define ITRC_PUTC 'P' +#define ITRC_QUEUE 'Q' +#define ITRC_STFLW 'R' +#define ITRC_SFIFO 'S' +#define ITRC_VERIFY 'V' +#define ITRC_WRITE 'W' + +#define ITRC_ENTER 0x00 +#define ITRC_RETURN 0xFF + +#define ITRC_QUEUE_ROOM 2 +#define ITRC_QUEUE_CMD 6 + diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2/ip2types.h linux/drivers/char/ip2/ip2types.h --- v2.3.14/linux/drivers/char/ip2/ip2types.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2types.h Mon Aug 23 10:23:23 1999 @@ -0,0 +1,54 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Driver constants and type definitions. +* +* NOTES: +* +*******************************************************************************/ +#ifndef IP2TYPES_H +#define IP2TYPES_H + +//************* +//* Constants * +//************* + +// Define some limits for this driver. Ports per board is a hardware limitation +// that will not change. Current hardware limits this to 64 ports per board. +// Boards per driver is a self-imposed limit. +// +#define IP2_MAX_BOARDS 4 +#define IP2_PORTS_PER_BOARD ABS_MOST_PORTS +#define IP2_MAX_PORTS (IP2_MAX_BOARDS*IP2_PORTS_PER_BOARD) + +#define ISA 0 +#define PCI 1 +#define EISA 2 + +//******************** +//* Type Definitions * +//******************** + +typedef struct tty_struct * PTTY; +typedef wait_queue_head_t PWAITQ; + +typedef unsigned char UCHAR; +typedef unsigned int UINT; +typedef unsigned short USHORT; +typedef unsigned long ULONG; + +typedef struct +{ + short irq[IP2_MAX_BOARDS]; + unsigned short addr[IP2_MAX_BOARDS]; + int type[IP2_MAX_BOARDS]; +} ip2config_t; + +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2.c linux/drivers/char/ip2.c --- v2.3.14/linux/drivers/char/ip2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,71 @@ +// ip2.c +// This is a dummy module to make the firmware available when needed +// and allows it to be unloaded when not. Rumor is the __initdata +// macro doesn't always works on all platforms so we use this kludge. +// If not compiled as a module it just makes fip_firm avaliable then +// __initdata should work as advertized +// + +#include +#include +#include + +#include "./ip2/ip2types.h" +#include "./ip2/fip_firm.h" // the meat + +int +ip2_loadmain(int *, int *, unsigned char *, int ); // ref into ip2main.c + +#ifdef MODULE +static int io[IP2_MAX_BOARDS]= { 0,}; +static int irq[IP2_MAX_BOARDS] = { 0,}; + +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); +MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); +MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); +MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); + + +//====================================================================== +int +init_module(void) +{ + int rc; + + MOD_INC_USE_COUNT; // hold till done + + rc = ip2_loadmain(io,irq,(unsigned char *)fip_firm,sizeof(fip_firm)); + // The call to lock and load main, create dep + + MOD_DEC_USE_COUNT; //done - kerneld now can unload us + return rc; +} + +//====================================================================== +int +ip2_init(void) +{ + // call to this is int tty_io.c so we need this + return 0; +} + +//====================================================================== +void +cleanup_module(void) +{ +} + +#else // !MODULE + +#ifndef NULL +# define NULL ((void *) 0) +#endif + +int +ip2_init(void) { + return ip2_loadmain(NULL,NULL,(unsigned char *)fip_firm,sizeof(fip_firm)); +} + +#endif /* !MODULE */ diff -u --recursive --new-file v2.3.14/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c --- v2.3.14/linux/drivers/char/ip2main.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2main.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,3236 @@ +/* +* +* (c) 1999 by Computone Corporation +* +******************************************************************************** +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Mainline code for the device driver +* +*******************************************************************************/ +/************/ +/* Includes */ +/************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#define pcibios_strerror(status) \ + printk( KERN_ERR "IP2: PCI error 0x%x \n", status ); + +#include "./ip2/ip2types.h" +#include "./ip2/ip2trace.h" +#include "./ip2/ip2ioctl.h" +#include "./ip2/ip2.h" +#include "./ip2/i2ellis.h" +#include "./ip2/i2lib.h" + +/***************** + * /proc/ip2mem * + *****************/ + +#include + +int ip2_read_procmem(char *, char **, off_t, int, int ); +int ip2_read_proc(char *, char **, off_t, int, int *, void * ); + +struct proc_dir_entry ip2_proc_entry = { + 0, + 6,"ip2mem", + S_IFREG | S_IRUGO, + 1, 0, 0, + 0, + NULL, + ip2_read_procmem +}; + +/********************/ +/* Type Definitions */ +/********************/ + +/*************/ +/* Constants */ +/*************/ + +/* String constants to identify ourselves */ +static char *pcName = "Computone IntelliPort Plus multiport driver"; +static char *pcVersion = "1.2.4"; + +/* String constants for port names */ +static char *pcDriver_name = "ip2"; +static char *pcTty = "ttyf"; +static char *pcCallout = "cuf"; +static char *pcIpl = "ip2ipl"; + +/* Serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +// cheezy kludge or genius - you decide? +int ip2_loadmain(int *, int *, unsigned char *, int); +static unsigned char *Fip_firmware; +static int Fip_firmware_size; + +/***********************/ +/* Function Prototypes */ +/***********************/ + +/* Global module entry functions */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif + +int old_ip2_init(void); + +/* Private (static) functions */ +static int ip2_open(PTTY, struct file *); +static void ip2_close(PTTY, struct file *); +static int ip2_write(PTTY, int, const unsigned char *, int); +static void ip2_putchar(PTTY, unsigned char); +static void ip2_flush_chars(PTTY); +static int ip2_write_room(PTTY); +static int ip2_chars_in_buf(PTTY); +static void ip2_flush_buffer(PTTY); +static int ip2_ioctl(PTTY, struct file *, UINT, ULONG); +static void ip2_set_termios(PTTY, struct termios *); +static void ip2_set_line_discipline(PTTY); +static void ip2_throttle(PTTY); +static void ip2_unthrottle(PTTY); +static void ip2_stop(PTTY); +static void ip2_start(PTTY); +static void ip2_hangup(PTTY); + +static void set_irq(int, int); +static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void ip2_poll(unsigned long arg); +static inline void service_all_boards(void); +static inline void do_input(i2ChanStrPtr pCh); +static inline void do_status(i2ChanStrPtr pCh); + +static void ip2_wait_until_sent(PTTY,int); + +static void set_params (i2ChanStrPtr, struct termios *); +static int get_modem_info(i2ChanStrPtr, unsigned int *); +static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *); +static int get_serial_info(i2ChanStrPtr, struct serial_struct *); +static int set_serial_info(i2ChanStrPtr, struct serial_struct *); + +static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ; +static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *); +static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG); +static int ip2_ipl_open(struct inode *, struct file *); + +void ip2trace(unsigned short,unsigned char,unsigned char,unsigned long,...); +static int DumpTraceBuffer(char *, int); +static int DumpFifoBuffer( char *, int); + +static void ip2_init_board(int); +static unsigned short find_eisa_board(int); + +/***************/ +/* Static Data */ +/***************/ + +static struct tty_driver ip2_tty_driver; +static struct tty_driver ip2_callout_driver; + +static int ref_count; + +/* Here, then is a table of board pointers which the interrupt routine should + * scan through to determine who it must service. + */ +static unsigned short i2nBoards = 0; // Number of boards here + +static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS]; + +static i2ChanStrPtr DevTable[IP2_MAX_PORTS]; +//DevTableMem just used to save addresses for kfree +static void *DevTableMem[IP2_MAX_BOARDS] = {NULL,NULL,NULL,NULL}; + +static struct tty_struct * TtyTable[IP2_MAX_PORTS]; +static struct termios * Termios[IP2_MAX_PORTS]; +static struct termios * TermiosLocked[IP2_MAX_PORTS]; + +/* This is the driver descriptor for the ip2ipl device, which is used to + * download the loadware to the boards. + */ +static struct file_operations +ip2_ipl = { + NULL, + ip2_ipl_read, + ip2_ipl_write, + NULL, + NULL, + ip2_ipl_ioctl, + NULL, + ip2_ipl_open, + NULL, + NULL, + NULL, + NULL, + NULL, + /* NULL, NULL 2.2 */ +}; + +static long irq_counter = 0; +static long bh_counter = 0; + +// Use immediate queue to service interrupts +//#define USE_IQI // PCI&2.2 needs work +//#define USE_IQ // PCI&2.2 needs work + +/* The timer_list entry for our poll routine. If interrupt operation is not + * selected, the board is serviced periodically to see if anything needs doing. + */ +#define POLL_TIMEOUT (jiffies + 1) +static struct timer_list PollTimer = { NULL, NULL, 0, 0, ip2_poll }; +// next, prev, expires,data, func() +static char TimerOn = 0; + +#ifdef IP2DEBUG_TRACE +/* Trace (debug) buffer data */ +#define TRACEMAX 1000 +static unsigned long tracebuf[TRACEMAX]; +static int tracestuff = 0; +static int tracestrip = 0; +static int tracewrap = 0; +#endif + +/**********/ +/* Macros */ +/**********/ + +#if defined(MODULE) && defined(IP2DEBUG_OPEN) +#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ + kdevname(tty->device),(pCh->flags),ref_count, \ + tty->count,/*GET_USE_COUNT(module)*/0,s) +#else +#define DBG_CNT(s) +#endif + +#define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) ) +#define MAX(a,b) ( ( (a) > (b) ) ? (a) : (b) ) + +/********/ +/* Code */ +/********/ + +#include "./ip2/i2ellis.c" /* Extremely low-level interface services */ +#include "./ip2/i2cmd.c" /* Standard loadware command definitions */ +#include "./ip2/i2lib.c" /* High level interface services */ + +/* Configuration area for modprobe */ +#ifdef MODULE +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +#endif /* MODULE */ + +static int poll_only = 0; + +static int Pci_index = 0; +static int Eisa_irq = 0; +static int Eisa_slot = 0; + +static int iindx = 0; +static char rirqs[IP2_MAX_BOARDS] = {0,}; +static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; + +/******************************************************************************/ +/* Initialisation Section */ +/******************************************************************************/ +int +ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) +{ + int i; + /* process command line arguments to modprobe or insmod i.e. iop & irqp */ + /* otherwise ip2config is initialized by what's in ip2/ip2.h */ + /* command line trumps initialization in ip2.h */ + /* first two args are null if builtin to kernel */ + if ((irqp != NULL) || (iop != NULL)) { + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if (irqp && irqp[i]) { + ip2config.irq[i] = irqp[i]; + } + if (iop && iop[i]) { + ip2config.addr[i] = iop[i]; + } + } + } + Fip_firmware = firmware; + Fip_firmware_size = firmsize; + return old_ip2_init(); +} + +// Some functions to keep track of what irq's we have + +__initfunc(static int +is_valid_irq(int irq) ) +{ + int *i = Valid_Irqs; + + while ((*i != 0) && (*i != irq)) { + i++; + } + return (*i); +} + +__initfunc( static void +mark_requested_irq( char irq )) +{ + rirqs[iindx++] = irq; +} + +__initfunc( static int +clear_requested_irq( char irq )) +{ + int i; + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if (rirqs[i] == irq) { + rirqs[i] = 0; + return 1; + } + } + return 0; +} + +__initfunc( static int +have_requested_irq( char irq )) +{ + // array init to zeros so 0 irq will not be requested as a side effect + int i; + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if (rirqs[i] == irq) + return 1; + } + return 0; +} + +/******************************************************************************/ +/* Function: init_module() */ +/* Parameters: None */ +/* Returns: Success (0) */ +/* */ +/* Description: */ +/* This is a required entry point for an installable module. It simply calls */ +/* the driver initialisation function and returns what it returns. */ +/******************************************************************************/ +#ifdef MODULE +int +init_module(void) +{ +#ifdef IP2DEBUG_INIT + printk (KERN_DEBUG "Loading module ...\n" ); +#endif + //was return old_ip2_init(); + return 0; +} +#endif /* MODULE */ + +/******************************************************************************/ +/* Function: cleanup_module() */ +/* Parameters: None */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This is a required entry point for an installable module. It has to return */ +/* the device and the driver to a passive state. It should not be necessary */ +/* to reset the board fully, especially as the loadware is downloaded */ +/* externally rather than in the driver. We just want to disable the board */ +/* and clear the loadware to a reset state. To allow this there has to be a */ +/* way to detect whether the board has the loadware running at init time to */ +/* handle subsequent installations of the driver. All memory allocated by the */ +/* driver should be returned since it may be unloaded from memory. */ +/******************************************************************************/ +#ifdef MODULE +void +cleanup_module(void) +{ + int err; + int i; + +#ifdef IP2DEBUG_INIT + printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); +#endif + + + /* Stop poll timer if we had one. */ + if ( TimerOn ) { + del_timer ( &PollTimer ); + TimerOn = 0; + } + + /* Reset the boards we have. */ + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + iiReset ( i2BoardPtrTable[i] ); + } + } + + /* The following is done at most once, if any boards were installed. */ + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + iiResetDelay( i2BoardPtrTable[i] ); + /* free io addresses and Tibet */ + release_region( ip2config.addr[i], 8 ); + } + /* Disable and remove interrupt handler. */ + if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { + free_irq ( ip2config.irq[i], (void *)&pcName); + clear_requested_irq( ip2config.irq[i]); + } + } + if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) { + printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); + } + if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) { + printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err); + } + if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { + printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); + } + if ( ( err = proc_unregister( &proc_root, ip2_proc_entry.low_ino ) ) ) { + printk(KERN_ERR "IP2: failed to unregister read_procmem (%d)\n", err); + } + + // free memory + for (i = 0; i < IP2_MAX_BOARDS; i++) { + void *pB; + if ((pB = i2BoardPtrTable[i]) != 0 ) { + kfree ( pB ); + i2BoardPtrTable[i] = NULL; + } + if ((DevTableMem[i]) != NULL ) { + kfree ( DevTableMem[i] ); + DevTableMem[i] = NULL; + } + } + + /* Cleanup the iiEllis subsystem. */ + iiEllisCleanup(); +#ifdef IP2DEBUG_INIT + printk (KERN_DEBUG "IP2 Unloaded\n" ); +#endif +} +#endif /* MODULE */ + +/******************************************************************************/ +/* Function: old_ip2_init() */ +/* Parameters: irq, io from command line of insmod et. al. */ +/* Returns: Success (0) */ +/* */ +/* Description: */ +/* This was the required entry point for all drivers (now in ip2.c) */ +/* It performs all */ +/* initialisation of the devices and driver structures, and registers itself */ +/* with the relevant kernel modules. */ +/******************************************************************************/ +/* SA_INTERRUPT- if set blocks all interrupts else only this line */ +/* SA_SHIRQ - for shared irq PCI or maybe EISA only */ +/* SA_RANDOM - can be source for cert. random number generators */ +#define IP2_SA_FLAGS 0 + +__initfunc( int +old_ip2_init(void)) +{ + int i; + int err; + int status = 0; + i2eBordStrPtr pB = NULL; + int rc = -1; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); +#endif + + /* Announce our presence */ + printk( KERN_INFO "%s version %s\n", pcName, pcVersion ); + + /* if all irq config is zero we shall poll_only */ + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + poll_only |= ip2config.irq[i]; + } + poll_only = !poll_only; + + /* Initialise the iiEllis subsystem. */ + iiEllisInit(); + + /* Initialize arrays. */ + memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable ); + memset( DevTable, 0, sizeof DevTable ); + memset( TtyTable, 0, sizeof TtyTable ); + memset( Termios, 0, sizeof Termios ); + memset( TermiosLocked, 0, sizeof TermiosLocked ); + + /* Initialise all the boards we can find (up to the maximum). */ + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + switch ( ip2config.addr[i] ) { + case 0: /* skip this slot even if card is present */ + break; + default: /* ISA */ + /* ISA address must be specified */ + if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) { + printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n", + i, ip2config.addr[i] ); + ip2config.addr[i] = 0; + } else { + ip2config.type[i] = ISA; + + /* Check for valid irq argument, set for polling if invalid */ + if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) { + printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]); + ip2config.irq[i] = 0;// 0 is polling and is valid in that sense + } + } + break; + case PCI: +#ifdef CONFIG_PCI + if (pci_present()) { + struct pci_dev *pci_dev_i = NULL; + pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE, + PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); + if (pci_dev_i != NULL) { + unsigned int addr; + unsigned char pci_irq; + + ip2config.type[i] = PCI; + /* + * Update Pci_index, so that the next time we go + * searching for a PCI board we find a different + * one. + */ + ++Pci_index; + status = + pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); + if ( addr & 1 ) { + ip2config.addr[i]=(USHORT)(addr&0xfffe); + } else { + printk( KERN_ERR "IP2: PCI I/O address error\n"); + } + status = + pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq); + + if (!is_valid_irq(pci_irq)) { + printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); + pci_irq = 0; + } + ip2config.irq[i] = pci_irq; + } else { // ann error + ip2config.addr[i] = 0; + if (status == PCIBIOS_DEVICE_NOT_FOUND) { + printk( KERN_ERR "IP2: PCI board %d not found\n", i ); + } else { + pcibios_strerror(status); + } + } + } +#else + printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); + printk( KERN_ERR "IP2: configured in this kernel.\n"); + printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n"); +#endif /* CONFIG_PCI */ + break; + case EISA: + if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) { + /* Eisa_irq set as side effect, boo */ + ip2config.type[i] = EISA; + } + ip2config.irq[i] = Eisa_irq; + break; + } /* switch */ + } /* for */ + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( ip2config.addr[i] ) { + pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL); + if ( pB != NULL ) { + i2BoardPtrTable[i] = pB; + memset( pB, 0, sizeof(i2eBordStr) ); + iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer ); + iiReset( pB ); + } else { + printk(KERN_ERR "IP2: board memory allocation error\n"); + } + } + } + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( ( pB = i2BoardPtrTable[i] ) != NULL ) { + iiResetDelay( pB ); + break; + } + } + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] != NULL ) { + ip2_init_board( i ); + } + } + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 ); +#endif + + /* Zero out the normal tty device structure. */ + memset ( &ip2_tty_driver, 0, sizeof ip2_tty_driver ); + + /* Initialise the relevant fields. */ + ip2_tty_driver.magic = TTY_DRIVER_MAGIC; + ip2_tty_driver.name = pcTty; + ip2_tty_driver.driver_name = pcDriver_name; + ip2_tty_driver.read_proc = ip2_read_proc; + ip2_tty_driver.major = IP2_TTY_MAJOR; + ip2_tty_driver.minor_start = 0; + ip2_tty_driver.num = IP2_MAX_PORTS; + ip2_tty_driver.type = TTY_DRIVER_TYPE_SERIAL; + ip2_tty_driver.subtype = SERIAL_TYPE_NORMAL; + ip2_tty_driver.init_termios = tty_std_termios; + ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; + ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW; + ip2_tty_driver.refcount = &ref_count; + ip2_tty_driver.table = TtyTable; + ip2_tty_driver.termios = Termios; + ip2_tty_driver.termios_locked = TermiosLocked; + + /* Setup the pointers to the implemented functions. */ + ip2_tty_driver.open = ip2_open; + ip2_tty_driver.close = ip2_close; + ip2_tty_driver.write = ip2_write; + ip2_tty_driver.put_char = ip2_putchar; + ip2_tty_driver.flush_chars = ip2_flush_chars; + ip2_tty_driver.write_room = ip2_write_room; + ip2_tty_driver.chars_in_buffer = ip2_chars_in_buf; + ip2_tty_driver.flush_buffer = ip2_flush_buffer; + ip2_tty_driver.ioctl = ip2_ioctl; + ip2_tty_driver.throttle = ip2_throttle; + ip2_tty_driver.unthrottle = ip2_unthrottle; + ip2_tty_driver.set_termios = ip2_set_termios; + ip2_tty_driver.set_ldisc = ip2_set_line_discipline; + ip2_tty_driver.stop = ip2_stop; + ip2_tty_driver.start = ip2_start; + ip2_tty_driver.hangup = ip2_hangup; + + /* Initialise the callout driver structure from the tty driver, and + * make the needed adjustments. + */ + ip2_callout_driver = ip2_tty_driver; + ip2_callout_driver.name = pcCallout; + ip2_callout_driver.driver_name = pcDriver_name; + ip2_callout_driver.read_proc = NULL; + ip2_callout_driver.major = IP2_CALLOUT_MAJOR; + ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); +#endif + + /* Register the tty devices. */ + if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) { + printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); + } else + if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) { + printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err); + } else + /* Register the IPL driver. */ + if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { + printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); + } else + /* Register the read_procmem thing */ + if ( ( err = proc_register( &proc_root, &ip2_proc_entry ) ) ) { + printk(KERN_ERR "IP2: failed to register read_procmem (%d)\n", err ); + } else { + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 ); +#endif + /* Register the interrupt handler or poll handler, depending upon the + * specified interrupt. + */ + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( 0 == ip2config.addr[i] ) { + continue; + } + if (poll_only) { + ip2config.irq[i] = CIR_POLL; + } + if ( ip2config.irq[i] == CIR_POLL ) { +retry: + if (!TimerOn) { + PollTimer.expires = POLL_TIMEOUT; + add_timer ( &PollTimer ); + TimerOn = 1; + printk( KERN_INFO "IP2: polling\n"); + } + } else { + if (have_requested_irq(ip2config.irq[i])) + continue; + rc = request_irq( ip2config.irq[i], ip2_interrupt, + IP2_SA_FLAGS | (ip2config.type[i] == PCI ? SA_SHIRQ : 0), + pcName, (void *)&pcName); + if (rc) { + printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc); + ip2config.irq[i] = CIR_POLL; + printk( KERN_INFO "IP2: Polling %ld/sec.\n", + (POLL_TIMEOUT - jiffies)); + goto retry; + } + mark_requested_irq(ip2config.irq[i]); + /* Initialise the interrupt handler bottom half (aka slih). */ + } + } + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */ + } + } + } +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); +#endif + + return 0; +} + +/******************************************************************************/ +/* Function: ip2_init_board() */ +/* Parameters: Index of board in configuration structure */ +/* Returns: Success (0) */ +/* */ +/* Description: */ +/* This function initializes the specified board. The loadware is copied to */ +/* the board, the channel structures are initialized, and the board details */ +/* are reported on the console. */ +/******************************************************************************/ +__initfunc( static void +ip2_init_board( int boardnum )) +{ + int i,rc; + int nports = 0, nboxes = 0; + i2ChanStrPtr pCh; + i2eBordStrPtr pB = i2BoardPtrTable[boardnum]; + + if ( !iiInitialize ( pB ) ) { + printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n", + pB->i2eBase, pB->i2eError ); + kfree ( pB ); + i2BoardPtrTable[boardnum] = NULL; + return; + } + printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1, + ip2config.addr[boardnum], ip2config.irq[boardnum] ); + + if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) { + i2BoardPtrTable[boardnum] = NULL; + printk(KERN_ERR "bad addr=0x%x rc = %d\n", + ip2config.addr[boardnum], rc ); + return; + } + request_region( ip2config.addr[boardnum], 8, pcName ); + + if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size ) + != II_DOWN_GOOD ) { + printk ( KERN_ERR "IP2:failed to download loadware " ); + } else { + printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n", + pB->i2ePom.e.porVersion, + pB->i2ePom.e.porRevision, + pB->i2ePom.e.porSubRev, pB->i2eLVersion, + pB->i2eLRevision, pB->i2eLSub ); + } + + switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) { + + default: + printk( KERN_ERR "IP2: Unknown board type, ID = %x", + pB->i2ePom.e.porID ); + nports = 0; + goto ex_exit; + break; + + case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */ + printk ( KERN_INFO "ISA-4" ); + nports = 4; + break; + + case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */ + printk ( KERN_INFO "ISA-8 std" ); + nports = 8; + break; + + case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */ + printk ( KERN_INFO "ISA-8 RJ11" ); + nports = 8; + break; + + case POR_ID_FIIEX: /* IntelliPort IIEX */ + { + int portnum = IP2_PORTS_PER_BOARD * boardnum; + int box; + + for( box = 0; box < ABS_MAX_BOXES; ++box ) { + if ( pB->i2eChannelMap[box] != 0 ) { + ++nboxes; + } + for( i = 0; i < ABS_BIGGEST_BOX; ++i ) { + if ( pB->i2eChannelMap[box] & 1<< i ) { + ++nports; + } + } + } + DevTableMem[boardnum] = pCh = + kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL ); + if ( !i2InitChannels( pB, nports, pCh ) ) { + printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError); + } + pB->i2eChannelPtr = &DevTable[portnum]; + pB->i2eChannelCnt = ABS_MOST_PORTS; + + for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) { + for( i = 0; i < ABS_BIGGEST_BOX; ++i ) { + if ( pB->i2eChannelMap[box] & (1 << i) ) { + DevTable[portnum + i] = pCh; + pCh->port_index = portnum + i; + pCh++; + } + } + } + printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit", + nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 ); + } + goto ex_exit; + break; + } + DevTableMem[boardnum] = pCh = + kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL ); + pB->i2eChannelPtr = pCh; + pB->i2eChannelCnt = nports; + i2InitChannels ( pB, pB->i2eChannelCnt, pCh ); + pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum]; + + for( i = 0; i < pB->i2eChannelCnt; ++i ) { + DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh; + pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i; + pCh++; + } +ex_exit: + printk ( KERN_INFO "\n" ); +} + +/******************************************************************************/ +/* Function: find_eisa_board ( int start_slot ) */ +/* Parameters: First slot to check */ +/* Returns: Address of EISA IntelliPort II controller */ +/* */ +/* Description: */ +/* This function searches for an EISA IntelliPort controller, starting */ +/* from the specified slot number. If the motherboard is not identified as an */ +/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */ +/* it returns the base address of the controller. */ +/******************************************************************************/ +__initfunc( static unsigned short +find_eisa_board( int start_slot )) +{ + int i, j; + unsigned int idm = 0; + unsigned int idp = 0; + unsigned int base = 0; + unsigned int value; + int setup_address; + int setup_irq; + int ismine = 0; + + /* + * First a check for an EISA motherboard, which we do by comparing the + * EISA ID registers for the system board and the first couple of slots. + * No slot ID should match the system board ID, but on an ISA or PCI + * machine the odds are that an empty bus will return similar values for + * each slot. + */ + i = 0x0c80; + value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3); + for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) { + j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3); + if ( value == j ) + return 0; + } + + /* + * OK, so we are inclined to believe that this is an EISA machine. Find + * an IntelliPort controller. + */ + for( i = start_slot; i < 16; i++ ) { + base = i << 12; + idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff); + idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff); + ismine = 0; + if ( idm == 0x0e8e ) { + if ( idp == 0x0281 || idp == 0x0218 ) { + ismine = 1; + } else if ( idp == 0x0282 || idp == 0x0283 ) { + ismine = 3; /* Can do edge-trigger */ + } + if ( ismine ) { + Eisa_slot = i; + break; + } + } + } + if ( !ismine ) + return 0; + + /* It's some sort of EISA card, but at what address is it configured? */ + + setup_address = base + 0xc88; + value = inb(base + 0xc86); + setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0; + + if ( (ismine & 2) && !(value & 0x10) ) { + ismine = 1; /* Could be edging, but not */ + } + + if ( Eisa_irq == 0 ) { + Eisa_irq = setup_irq; + } else if ( Eisa_irq != setup_irq ) { + printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" ); + } + +#ifdef IP2DEBUG_INIT +printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x", + base >> 12, idm, idp, setup_address); + if ( Eisa_irq ) { + printk(KERN_DEBUG ", Interrupt %d %s\n", + setup_irq, (ismine & 2) ? "(edge)" : "(level)"); + } else { + printk(KERN_DEBUG ", (polled)\n"); + } +#endif + return setup_address; +} + +/******************************************************************************/ +/* Function: set_irq() */ +/* Parameters: index to board in board table */ +/* IRQ to use */ +/* Returns: Success (0) */ +/* */ +/* Description: */ +/******************************************************************************/ +static void +set_irq( int boardnum, int boardIrq ) +{ + i2ChanStrPtr pCh; + unsigned char tempCommand[16]; + i2eBordStrPtr pB = i2BoardPtrTable[boardnum]; + unsigned long flags; + + /* + * Notify the boards they may generate interrupts. This is done by + * sending an in-line command to channel 0 on each board. This is why + * the channels have to be defined already. For each board, if the + * interrupt has never been defined, we must do so NOW, directly, since + * board will not send flow control or even give an interrupt until this + * is done. If polling we must send 0 as the interrupt parameter. + */ + + pCh = (i2ChanStrPtr) pB->i2eChannelPtr; + + // We will get an interrupt here at the end of this function + + iiDisableMailIrq(pB); + + /* We build up the entire packet header. */ + CHANNEL_OF(tempCommand) = 0; + PTYPE_OF(tempCommand) = PTYPE_INLINE; + CMD_COUNT_OF(tempCommand) = 2; + (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ; + (CMD_OF(tempCommand))[1] = boardIrq; + /* + * Write to FIFO; don't bother to adjust fifo capacity for this, since + * board will respond almost immediately after SendMail hit. + */ + WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + iiWriteBuf(pB, tempCommand, 4); + WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + pB->i2eUsingIrq = boardIrq; + pB->i2eOutMailWaiting |= MB_OUT_STUFFED; + + /* Need to update number of boards before you enable mailbox int */ + ++i2nBoards; + + CHANNEL_OF(tempCommand) = 0; + PTYPE_OF(tempCommand) = PTYPE_BYPASS; + CMD_COUNT_OF(tempCommand) = 6; + (CMD_OF(tempCommand))[0] = 88; // SILO + (CMD_OF(tempCommand))[1] = 64; // chars + (CMD_OF(tempCommand))[2] = 32; // ms + + (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK + (CMD_OF(tempCommand))[4] = 64; // chars + + (CMD_OF(tempCommand))[5] = 87; // HW_TEST + WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + iiWriteBuf(pB, tempCommand, 8); + WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + + CHANNEL_OF(tempCommand) = 0; + PTYPE_OF(tempCommand) = PTYPE_BYPASS; + CMD_COUNT_OF(tempCommand) = 1; + (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */ + iiWriteBuf(pB, tempCommand, 3); + +#ifdef XXX + // enable heartbeat for test porpoises + CHANNEL_OF(tempCommand) = 0; + PTYPE_OF(tempCommand) = PTYPE_BYPASS; + CMD_COUNT_OF(tempCommand) = 2; + (CMD_OF(tempCommand))[0] = 44; /* get ping */ + (CMD_OF(tempCommand))[1] = 200; /* 200 ms */ + WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + iiWriteBuf(pB, tempCommand, 4); + WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); +#endif + + iiEnableMailIrq(pB); + iiSendPendingMail(pB); +} + +/******************************************************************************/ +/* Interrupt Handler Section */ +/******************************************************************************/ + +static inline void +service_all_boards() +{ + int i; + i2eBordStrPtr pB; + + /* Service every board on the list */ + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + pB = i2BoardPtrTable[i]; + if ( pB ) { + i2ServiceBoard( pB ); + } + } +} + + +#ifdef USE_IQI +static struct tq_struct +senior_service = +{ // it's the death that worse than fate + NULL, + 0, + (void(*)(void*)) service_all_boards, + NULL, //later - board address XXX +}; +#endif + +/******************************************************************************/ +/* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */ +/* Parameters: irq - interrupt number */ +/* pointer to optional device ID structure */ +/* pointer to register structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int i; + i2eBordStrPtr pB; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq ); +#endif + +#ifdef USE_IQI + + queue_task(&senior_service, &tq_immediate); + mark_bh(IMMEDIATE_BH); + +#else + /* Service just the boards on the list using this irq */ + for( i = 0; i < i2nBoards; ++i ) { + pB = i2BoardPtrTable[i]; + if ( pB && (pB->i2eUsingIrq == irq) ) { + i2ServiceBoard( pB ); + } + } + +#endif /* USE_IQI */ + + ++irq_counter; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); +#endif +} + +/******************************************************************************/ +/* Function: ip2_poll(unsigned long arg) */ +/* Parameters: ? */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This function calls the library routine i2ServiceBoard for each board in */ +/* the board table. This is used instead of the interrupt routine when polled */ +/* mode is specified. */ +/******************************************************************************/ +static void +ip2_poll(unsigned long arg) +{ +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 ); +#endif + TimerOn = 0; // it's the truth but not checked in service + + bh_counter++; + +#ifdef USE_IQI + + queue_task(&senior_service, &tq_immediate); + mark_bh(IMMEDIATE_BH); + +#else + // Just polled boards, service_all might be better + ip2_interrupt(0, NULL, NULL); + +#endif /* USE_IQI */ + + PollTimer.expires = POLL_TIMEOUT; + add_timer( &PollTimer ); + TimerOn = 1; + +#ifdef IP2DEBUG_TRACE + ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); +#endif +} + +static inline void +do_input( i2ChanStrPtr pCh ) +{ + unsigned long flags; + +#ifdef IP2DEBUG_TRACE + ip2trace(PORTN, ITRC_INPUT, 21, 0 ); +#endif + // Data input + if ( pCh->pTTY != NULL ) { + READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags) + if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) { + READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + i2Input( pCh ); + } else + READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + } else { +#ifdef IP2DEBUG_TRACE + ip2trace(PORTN, ITRC_INPUT, 22, 0 ); +#endif + i2InputFlush( pCh ); + } +} + +// code duplicated from n_tty (ldisc) +static inline void +isig(int sig, struct tty_struct *tty, int flush) +{ + if (tty->pgrp > 0) + kill_pg(tty->pgrp, sig, 1); + if (flush || !L_NOFLSH(tty)) { + if ( tty->ldisc.flush_buffer ) + tty->ldisc.flush_buffer(tty); + i2InputFlush( tty->driver_data ); + } +} + +static inline void +do_status( i2ChanStrPtr pCh ) +{ + int status; + + status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_STATUS, 21, 1, status ); +#endif + + if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) { + if ( (status & I2_BRK) ) { + // code duplicated from n_tty (ldisc) + if (I_IGNBRK(pCh->pTTY)) + goto skip_this; + if (I_BRKINT(pCh->pTTY)) { + isig(SIGINT, pCh->pTTY, 1); + goto skip_this; + } + wake_up_interruptible(&pCh->pTTY->read_wait); + } +#ifdef NEVER_HAPPENS_AS_SETUP_XXX + // and can't work because we don't know the_char + // as the_char is reported on a seperate path + // The intelligent board does this stuff as setup + { + char brkf = TTY_NORMAL; + unsigned char brkc = '\0'; + unsigned char tmp; + if ( (status & I2_BRK) ) { + brkf = TTY_BREAK; + brkc = '\0'; + } + else if (status & I2_PAR) { + brkf = TTY_PARITY; + brkc = the_char; + } else if (status & I2_FRA) { + brkf = TTY_FRAME; + brkc = the_char; + } else if (status & I2_OVR) { + brkf = TTY_OVERRUN; + brkc = the_char; + } + tmp = pCh->pTTY->real_raw; + pCh->pTTY->real_raw = 0; + pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 ); + pCh->pTTY->real_raw = tmp; + } +#endif /* NEVER_HAPPENS_AS_SETUP_XXX */ + } +skip_this: + + if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) { + wake_up_interruptible(&pCh->delta_msr_wait); + + if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) { + if ( status & I2_DCD ) { + if ( pCh->wopen ) { + wake_up_interruptible ( &pCh->open_wait ); + } + } else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) { + if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) { + tty_hangup( pCh->pTTY ); + } + } + } + } + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_STATUS, 26, 0 ); +#endif +} + +/******************************************************************************/ +/* Device Open/Close/Ioctl Entry Point Section */ +/******************************************************************************/ + +/******************************************************************************/ +/* Function: open_sanity_check() */ +/* Parameters: Pointer to tty structure */ +/* Pointer to file structure */ +/* Returns: Success or failure */ +/* */ +/* Description: */ +/* Verifies the structure magic numbers and cross links. */ +/******************************************************************************/ +#ifdef IP2DEBUG_OPEN +static void +open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd ) +{ + if ( pBrd->i2eValid != I2E_MAGIC ) { + printk(KERN_ERR "IP2: invalid board structure\n" ); + } else if ( pBrd != pCh->pMyBord ) { + printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n", + pCh->pMyBord ); + } else if ( pBrd->i2eChannelCnt < pCh->port_index ) { + printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index ); + } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) { + } else { + printk(KERN_INFO "IP2: all pointers check out!\n" ); + } +} +#endif + + +/******************************************************************************/ +/* Function: ip2_open() */ +/* Parameters: Pointer to tty structure */ +/* Pointer to file structure */ +/* Returns: Success or failure */ +/* */ +/* Description: (MANDATORY) */ +/* A successful device open has to run a gauntlet of checks before it */ +/* completes. After some sanity checking and pointer setup, the function */ +/* blocks until all conditions are satisfied. It then initialises the port to */ +/* the default characteristics and returns. */ +/******************************************************************************/ +static int +ip2_open( PTTY tty, struct file *pFile ) +{ + int rc = 0; + int do_clocal = 0; + i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + +#ifdef IP2DEBUG_TRACE + ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 ); +#endif + + if ( pCh == NULL ) { + return -ENODEV; + } + /* Setup pointer links in device and tty structures */ + pCh->pTTY = tty; + tty->driver_data = pCh; + MOD_INC_USE_COUNT; + +#ifdef IP2DEBUG_OPEN + printk(KERN_DEBUG \ + "IP2:open(tty=%p,pFile=%p):dev=%x,maj=%d,min=%d,ch=%d,idx=%d\n", + tty, pFile, tty->device, MAJOR(tty->device), MINOR(tty->device), + pCh->infl.hd.i2sChannel, pCh->port_index); + open_sanity_check ( pCh, pCh->pMyBord ); +#endif + + i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); + pCh->dataSetOut |= (I2_DTR | I2_RTS); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, + CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP); + serviceOutgoingFifo( pCh->pMyBord ); + + /* Block here until the port is ready (per serial and istallion) */ + /* + * 1. If the port is in the middle of closing wait for the completion + * and then return the appropriate error. + */ + if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) { + if ( pCh->flags & ASYNC_CLOSING ) { + interruptible_sleep_on( &pCh->close_wait); + } + if ( tty_hung_up_p(pFile) ) { + return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS; + } + } + /* + * 2. If this is a callout device, make sure the normal port is not in + * use, and that someone else doesn't have the callout device locked. + * (These are the only tests the standard serial driver makes for + * callout devices.) + */ + if ( tty->driver.subtype == SERIAL_TYPE_CALLOUT ) { + if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) { + return -EBUSY; + } + if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) && + ( pCh->flags & ASYNC_SESSION_LOCKOUT ) && + ( pCh->session != current->session ) ) { + return -EBUSY; + } + if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) && + ( pCh->flags & ASYNC_PGRP_LOCKOUT ) && + ( pCh->pgrp != current->pgrp ) ) { + return -EBUSY; + } + pCh->flags |= ASYNC_CALLOUT_ACTIVE; + goto noblock; + } + /* + * 3. Handle a non-blocking open of a normal port. + */ + if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<flags & ASYNC_CALLOUT_ACTIVE ) { + return -EBUSY; + } + pCh->flags |= ASYNC_NORMAL_ACTIVE; + goto noblock; + } + /* + * 4. Now loop waiting for the port to be free and carrier present + * (if required). + */ + if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) { + if ( pCh->NormalTermios.c_cflag & CLOCAL ) { + do_clocal = 1; + } + } else { + if ( tty->termios->c_cflag & CLOCAL ) { + do_clocal = 1; + } + } + +#ifdef IP2DEBUG_OPEN + printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal); +#endif + + ++pCh->wopen; + for(;;) { + if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); + pCh->dataSetOut |= (I2_DTR | I2_RTS); + serviceOutgoingFifo( pCh->pMyBord ); + } + if ( tty_hung_up_p(pFile) ) { + return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS; + } + if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) && + !(pCh->flags & ASYNC_CLOSING) && + (do_clocal || (pCh->dataSetIn & I2_DCD) )) { + rc = 0; + break; + } + +#ifdef IP2DEBUG_OPEN + printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n", + (pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False"); + printk(KERN_DEBUG "ASYNC_CLOSING = %s\n", + (pCh->flags & ASYNC_CLOSING)?"True":"False"); + printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n"); +#endif +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE), + (pCh->flags & ASYNC_CLOSING) ); +#endif + /* check for signal */ + if (signal_pending(current)) { + rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS); + break; + } + interruptible_sleep_on(&pCh->open_wait); + } + --pCh->wopen; //why count? +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_OPEN, 4, 0 ); +#endif + if (rc != 0 ) { + return rc; + } + pCh->flags |= ASYNC_NORMAL_ACTIVE; + +noblock: + + /* first open - Assign termios structure to port */ + if ( tty->count == 1 ) { + i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB); + if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) { + if ( tty->driver.subtype == SERIAL_TYPE_NORMAL ) { + *tty->termios = pCh->NormalTermios; + } else { + *tty->termios = pCh->CalloutTermios; + } + } + /* Now we must send the termios settings to the loadware */ + set_params( pCh, NULL ); + } + + /* override previous and never reset ??? */ + pCh->session = current->session; + pCh->pgrp = current->pgrp; + + /* + * Now set any i2lib options. These may go away if the i2lib code ends + * up rolled into the mainline. + */ + pCh->channelOptions |= CO_NBLOCK_WRITE; + +#ifdef IP2DEBUG_OPEN + printk (KERN_DEBUG "IP2: open completed\n" ); +#endif + serviceOutgoingFifo( pCh->pMyBord ); + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_OPEN, ITRC_RETURN, 0 ); +#endif + return 0; +} + +/******************************************************************************/ +/* Function: ip2_close() */ +/* Parameters: Pointer to tty structure */ +/* Pointer to file structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_close( PTTY tty, struct file *pFile ) +{ + i2ChanStrPtr pCh = tty->driver_data; + + if ( !pCh ) { + return; + } + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_CLOSE, ITRC_ENTER, 0 ); +#endif + +#ifdef IP2DEBUG_OPEN + printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device)); +#endif + + if ( tty_hung_up_p ( pFile ) ) { + MOD_DEC_USE_COUNT; + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_CLOSE, 2, 1, 2 ); +#endif + return; + } + if ( tty->count > 1 ) { /* not the last close */ + MOD_DEC_USE_COUNT; +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_CLOSE, 2, 1, 3 ); +#endif + return; + } + pCh->flags |= ASYNC_CLOSING; // last close actually + + /* + * Save the termios structure, since this port may have separate termios + * for callout and dialin. + */ + if (pCh->flags & ASYNC_NORMAL_ACTIVE) + pCh->NormalTermios = *tty->termios; + if (pCh->flags & ASYNC_CALLOUT_ACTIVE) + pCh->CalloutTermios = *tty->termios; + + tty->closing = 1; + + if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) { + /* + * Before we drop DTR, make sure the transmitter has completely drained. + * This uses an timeout, after which the close + * completes. + */ + ip2_wait_until_sent(tty, pCh->ClosingWaitTime ); + } + /* + * At this point we stop accepting input. Here we flush the channel + * input buffer which will allow the board to send up more data. Any + * additional input is tossed at interrupt/poll time. + */ + i2InputFlush( pCh ); + + /* disable DSS reporting */ + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP); + if ( !tty || (tty->termios->c_cflag & HUPCL) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); + pCh->dataSetOut &= ~(I2_DTR | I2_RTS); + i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); + } + i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, + CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); + + serviceOutgoingFifo ( pCh->pMyBord ); + + if ( tty->driver.flush_buffer ) + tty->driver.flush_buffer(tty); + if ( tty->ldisc.flush_buffer ) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + + pCh->pTTY = NULL; + + if (pCh->wopen) { + if (pCh->ClosingDelay) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + schedule_timeout(pCh->ClosingDelay); + } + wake_up_interruptible(&pCh->open_wait); + } + + pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&pCh->close_wait); + +#ifdef IP2DEBUG_OPEN + DBG_CNT("ip2_close: after wakeups--"); +#endif + + MOD_DEC_USE_COUNT; + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_CLOSE, ITRC_RETURN, 1, 1 ); +#endif + return; +} + +/******************************************************************************/ +/* Function: ip2_hangup() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_hangup ( PTTY tty ) +{ + i2ChanStrPtr pCh = tty->driver_data; + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_HANGUP, ITRC_ENTER, 0 ); +#endif + + ip2_flush_buffer(tty); + + /* disable DSS reporting */ + + i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP); + i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB); + if ( !tty || (tty->termios->c_cflag & HUPCL) ) { + i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN); + pCh->dataSetOut &= ~(I2_DTR | I2_RTS); + i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); + } + i2QueueCommands(PTYPE_INLINE, pCh, 1, 3, + CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); + serviceOutgoingFifo ( pCh->pMyBord ); + + wake_up_interruptible ( &pCh->delta_msr_wait ); + + pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + pCh->pTTY = NULL; + wake_up_interruptible ( &pCh->open_wait ); + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_HANGUP, ITRC_RETURN, 0 ); +#endif +} + +/******************************************************************************/ +/******************************************************************************/ +/* Device Output Section */ +/******************************************************************************/ +/******************************************************************************/ + +/******************************************************************************/ +/* Function: ip2_write() */ +/* Parameters: Pointer to tty structure */ +/* Flag denoting data is in user (1) or kernel (0) space */ +/* Pointer to data */ +/* Number of bytes to write */ +/* Returns: Number of bytes actually written */ +/* */ +/* Description: (MANDATORY) */ +/* */ +/* */ +/******************************************************************************/ +static int +ip2_write( PTTY tty, int user, const unsigned char *pData, int count) +{ + i2ChanStrPtr pCh = tty->driver_data; + int bytesSent = 0; + unsigned long flags; + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 ); +#endif + + /* Flush out any buffered data left over from ip2_putchar() calls. */ + ip2_flush_chars( tty ); + + /* This is the actual move bit. Make sure it does what we need!!!!! */ + WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + bytesSent = i2Output( pCh, pData, count, user ); + WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); +#endif + return bytesSent > 0 ? bytesSent : 0; +} + +/******************************************************************************/ +/* Function: ip2_putchar() */ +/* Parameters: Pointer to tty structure */ +/* Character to write */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_putchar( PTTY tty, unsigned char ch ) +{ + i2ChanStrPtr pCh = tty->driver_data; + unsigned long flags; + +#ifdef IP2DEBUG_TRACE +// ip2trace (PORTN, ITRC_PUTC, ITRC_ENTER, 1, ch ); +#endif + + WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + pCh->Pbuf[pCh->Pbuf_stuff++] = ch; + if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) { + WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + ip2_flush_chars( tty ); + } else + WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + +#ifdef IP2DEBUG_TRACE +// ip2trace (PORTN, ITRC_PUTC, ITRC_RETURN, 1, ch ); +#endif +} + +/******************************************************************************/ +/* Function: ip2_flush_chars() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/******************************************************************************/ +static void +ip2_flush_chars( PTTY tty ) +{ + int strip; + i2ChanStrPtr pCh = tty->driver_data; + unsigned long flags; + + WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + if ( pCh->Pbuf_stuff ) { +#ifdef IP2DEBUG_TRACE +// ip2trace (PORTN, ITRC_PUTC, 10, 1, strip ); +#endif + // + // We may need to restart i2Output if it does not fullfill this request + // + strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 ); + if ( strip != pCh->Pbuf_stuff ) { + memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip ); + } + pCh->Pbuf_stuff -= strip; + } + WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); +} + +/******************************************************************************/ +/* Function: ip2_write_room() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Number of bytes that the driver can accept */ +/* */ +/* Description: */ +/* */ +/******************************************************************************/ +static int +ip2_write_room ( PTTY tty ) +{ + int bytesFree; + i2ChanStrPtr pCh = tty->driver_data; + unsigned long flags; + + READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff; + READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_WRITE, 11, 1, bytesFree ); +#endif + + return ((bytesFree > 0) ? bytesFree : 0); +} + +/******************************************************************************/ +/* Function: ip2_chars_in_buf() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Number of bytes queued for transmission */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static int +ip2_chars_in_buf ( PTTY tty ) +{ + i2ChanStrPtr pCh = tty->driver_data; + int rc; + unsigned long flags; +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff ); +#endif +#ifdef IP2DEBUG_WRITE + printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n", + pCh->Obuf_char_count + pCh->Pbuf_stuff, + pCh->Obuf_char_count, pCh->Pbuf_stuff ); +#endif + READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + rc = pCh->Obuf_char_count; + READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + rc += pCh->Pbuf_stuff; + READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + return rc; +} + +/******************************************************************************/ +/* Function: ip2_flush_buffer() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_flush_buffer( PTTY tty ) +{ + i2ChanStrPtr pCh = tty->driver_data; + unsigned long flags; + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_FLUSH, ITRC_ENTER, 0 ); +#endif +#ifdef IP2DEBUG_WRITE + printk (KERN_DEBUG "IP2: flush buffer\n" ); +#endif + WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + pCh->Pbuf_stuff = 0; + WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + i2FlushOutput( pCh ); + ip2_owake(tty); +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_FLUSH, ITRC_RETURN, 0 ); +#endif +} + +/******************************************************************************/ +/* Function: ip2_wait_until_sent() */ +/* Parameters: Pointer to tty structure */ +/* Timeout for wait. */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This function is used in place of the normal tty_wait_until_sent, which */ +/* only waits for the driver buffers to be empty (or rather, those buffers */ +/* reported by chars_in_buffer) which doesn't work for IP2 due to the */ +/* indeterminate number of bytes buffered on the board. */ +/******************************************************************************/ +static void +ip2_wait_until_sent ( PTTY tty, int timeout ) +{ + int i = jiffies; + i2ChanStrPtr pCh = tty->driver_data; + + tty_wait_until_sent(tty, timeout ); + if ( (i = timeout - (jiffies -i)) > 0) + i2DrainOutput( pCh, i ); +} + +/******************************************************************************/ +/******************************************************************************/ +/* Device Input Section */ +/******************************************************************************/ +/******************************************************************************/ + +/******************************************************************************/ +/* Function: ip2_throttle() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_throttle ( PTTY tty ) +{ + i2ChanStrPtr pCh = tty->driver_data; + +#ifdef IP2DEBUG_READ + printk (KERN_DEBUG "IP2: throttle\n" ); +#endif + /* + * Signal the poll/interrupt handlers not to forward incoming data to + * the line discipline. This will cause the buffers to fill up in the + * library and thus cause the library routines to send the flow control + * stuff. + */ + pCh->throttled = 1; +} + +/******************************************************************************/ +/* Function: ip2_unthrottle() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_unthrottle ( PTTY tty ) +{ + i2ChanStrPtr pCh = tty->driver_data; + unsigned long flags; + +#ifdef IP2DEBUG_READ + printk (KERN_DEBUG "IP2: unthrottle\n" ); +#endif + + /* Pass incoming data up to the line discipline again. */ + pCh->throttled = 0; + i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME); + serviceOutgoingFifo( pCh->pMyBord ); + READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags) + if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) { + READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) +#ifdef IP2DEBUG_READ + printk (KERN_DEBUG "i2Input called from unthrottle\n" ); +#endif + i2Input( pCh ); + } else + READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) +} + +static void +ip2_start ( PTTY tty ) +{ + i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + + i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME); + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND); + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME); +#ifdef IP2DEBUG_WRITE + printk (KERN_DEBUG "IP2: start tx\n" ); +#endif +} + +static void +ip2_stop ( PTTY tty ) +{ + i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND); +#ifdef IP2DEBUG_WRITE + printk (KERN_DEBUG "IP2: stop tx\n" ); +#endif +} + +/******************************************************************************/ +/* Device Ioctl Section */ +/******************************************************************************/ + +/******************************************************************************/ +/* Function: ip2_ioctl() */ +/* Parameters: Pointer to tty structure */ +/* Pointer to file structure */ +/* Command */ +/* Argument */ +/* Returns: Success or failure */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static int +ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) +{ + i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + int rc = 0; + + if ( pCh == NULL ) { + return -ENODEV; + } + +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg ); +#endif + +#ifdef IP2DEBUG_IOCTL + printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg ); +#endif + + switch(cmd) { + case TIOCGSERIAL: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 2, 1, rc ); +#endif + rc = get_serial_info(pCh, (struct serial_struct *) arg); + if (rc) + return rc; + break; + + case TIOCSSERIAL: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 3, 1, rc ); +#endif + rc = set_serial_info(pCh, (struct serial_struct *) arg); + if (rc) + return rc; + break; + + case TCXONC: + rc = tty_check_change(tty); + if (rc) + return rc; + switch (arg) { + case TCOOFF: + //return -ENOIOCTLCMD; + break; + case TCOON: + //return -ENOIOCTLCMD; + break; + case TCIOFF: + if (STOP_CHAR(tty) != __DISABLED_CHAR) { + i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1, + CMD_XMIT_NOW(STOP_CHAR(tty))); + } + break; + case TCION: + if (START_CHAR(tty) != __DISABLED_CHAR) { + i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1, + CMD_XMIT_NOW(START_CHAR(tty))); + } + break; + default: + return -EINVAL; + } + return 0; + + case TCSBRK: /* SVID version: non-zero arg --> no break */ + rc = tty_check_change(tty); +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 4, 1, rc ); +#endif + if (!rc) { + ip2_wait_until_sent(tty,0); + if (!arg) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250)); + serviceOutgoingFifo( pCh->pMyBord ); + } + } + break; + + case TCSBRKP: /* support for POSIX tcsendbreak() */ + rc = tty_check_change(tty); +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 5, 1, rc ); +#endif + if (!rc) { + ip2_wait_until_sent(tty,0); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, + CMD_SEND_BRK(arg ? arg*100 : 250)); + serviceOutgoingFifo ( pCh->pMyBord ); + } + break; + + case TIOCGSOFTCAR: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 6, 1, rc ); +#endif + rc=put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + if (rc) + return rc; + break; + + case TIOCSSOFTCAR: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 7, 1, rc ); +#endif + rc=get_user(arg,(unsigned long *) arg); + if (rc) + return rc; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) + | (arg ? CLOCAL : 0)); + + break; + + case TIOCMGET: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 8, 1, rc ); +#endif + rc = get_modem_info(pCh, (unsigned int *) arg); + if (rc) + return rc; + break; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 9, 0 ); +#endif + rc = set_modem_info(pCh, cmd, (unsigned int *) arg); + break; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask + * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS + * for masking). Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + cprev = pCh->icount; /* note the counters on entry */ + for(;;) { +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 10, 0 ); +#endif + interruptible_sleep_on(&pCh->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + cnow = pCh->icount; /* atomic copy */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; /* no change => rc */ + break; + } + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + rc = 0; + break; + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for RI where + * only 0->1 is counted. The controller is quite capable of counting + * both, but this done to preserve compatibility with the standard + * serial driver. + */ + case TIOCGICOUNT: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 11, 1, rc ); +#endif + cnow = pCh->icount; + p_cuser = (struct serial_icounter_struct *) arg; + put_user(cnow.cts, &p_cuser->cts); + put_user(cnow.dsr, &p_cuser->dsr); + put_user(cnow.rng, &p_cuser->rng); + put_user(cnow.dcd, &p_cuser->dcd); + break; + + /* + * The rest are not supported by this driver. By returning -ENOIOCTLCMD they + * will be passed to the line discipline for it to handle. + */ + case TIOCSERCONFIG: + case TIOCSERGWILD: + case TIOCSERGETLSR: + case TIOCSERSWILD: + case TIOCSERGSTRUCT: + case TIOCSERGETMULTI: + case TIOCSERSETMULTI: + + default: +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, 12, 0 ); +#endif + rc = -ENOIOCTLCMD; + break; + } +#ifdef IP2DEBUG_TRACE + ip2trace (PORTN, ITRC_IOCTL, ITRC_RETURN, 0 ); +#endif + return rc; +} +/******************************************************************************/ +/* Function: get_modem_info() */ +/* Parameters: Pointer to channel structure */ +/* Pointer to destination for data */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This returns the current settings of the dataset signal inputs to the user */ +/* program. */ +/******************************************************************************/ +static int +get_modem_info(i2ChanStrPtr pCh, unsigned int *value) +{ + unsigned short status; + unsigned int result; + int rc; + + status = pCh->dataSetIn; // snapshot settings + result = ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0) + | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0) + | ((status & I2_DCD) ? TIOCM_CAR : 0) + | ((status & I2_RI) ? TIOCM_RNG : 0) + | ((status & I2_DSR) ? TIOCM_DSR : 0) + | ((status & I2_CTS) ? TIOCM_CTS : 0); + rc=put_user(result,value); + return rc; +} + +/******************************************************************************/ +/* Function: set_modem_info() */ +/* Parameters: Pointer to channel structure */ +/* Specific ioctl command */ +/* Pointer to source for new settings */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This returns the current settings of the dataset signal inputs to the user */ +/* program. */ +/******************************************************************************/ +static int +set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value) +{ + int rc; + unsigned int arg; + + rc=get_user(arg,value); + if (rc) + return rc; + switch(cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP); + pCh->dataSetOut |= I2_RTS; + } + if (arg & TIOCM_DTR) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP); + pCh->dataSetOut |= I2_DTR; + } + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN); + pCh->dataSetOut &= ~I2_RTS; + } + if (arg & TIOCM_DTR) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN); + pCh->dataSetOut &= ~I2_DTR; + } + break; + case TIOCMSET: + if ( (arg & TIOCM_RTS) && !(pCh->dataSetOut & I2_RTS) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP); + pCh->dataSetOut |= I2_RTS; + } else if ( !(arg & TIOCM_RTS) && (pCh->dataSetOut & I2_RTS) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN); + pCh->dataSetOut &= ~I2_RTS; + } + if ( (arg & TIOCM_DTR) && !(pCh->dataSetOut & I2_DTR) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP); + pCh->dataSetOut |= I2_DTR; + } else if ( !(arg & TIOCM_DTR) && (pCh->dataSetOut & I2_DTR) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN); + pCh->dataSetOut &= ~I2_DTR; + } + break; + default: + return -EINVAL; + } + serviceOutgoingFifo( pCh->pMyBord ); + return 0; +} + +/******************************************************************************/ +/* Function: GetSerialInfo() */ +/* Parameters: Pointer to channel structure */ +/* Pointer to old termios structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This is to support the setserial command, and requires processing of the */ +/* standard Linux serial structure. */ +/******************************************************************************/ +static int +get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo ) +{ + struct serial_struct tmp; + int rc=0; + + if ( !retinfo ) { + return -EFAULT; + } + + memset ( &tmp, 0, sizeof(tmp) ); + tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16]; + if (BID_HAS_654(tmp.type)) { + tmp.type = PORT_16650; + } else { + tmp.type = PORT_CIRRUS; + } + tmp.line = pCh->port_index; + tmp.port = pCh->pMyBord->i2eBase; + tmp.irq = ip2config.irq[pCh->port_index/64]; + tmp.flags = pCh->flags; + tmp.baud_base = pCh->BaudBase; + tmp.close_delay = pCh->ClosingDelay; + tmp.closing_wait = pCh->ClosingWaitTime; + tmp.custom_divisor = pCh->BaudDivisor; + if(copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + rc= -EFAULT; + return rc; +} + +/******************************************************************************/ +/* Function: SetSerialInfo() */ +/* Parameters: Pointer to channel structure */ +/* Pointer to old termios structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This function provides support for setserial, which uses the TIOCSSERIAL */ +/* ioctl. Not all setserial parameters are relevant. If the user attempts to */ +/* change the IRQ, address or type of the port the ioctl fails. */ +/******************************************************************************/ +static int +set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info ) +{ + struct serial_struct ns; + int old_flags, old_baud_divisor; + int rc = 0; + + if ( !new_info ) { + return -EFAULT; + } + rc=copy_from_user(&ns, new_info, sizeof (ns) ); + if (rc) { + return rc; + } + /* + * We don't allow setserial to change IRQ, board address, type or baud + * base. Also line nunber as such is meaningless but we use it for our + * array index so it is fixed also. + */ + if ( ns.irq != ip2config.irq + || (int) ns.port != ((int) pCh->pMyBord->i2eBase) + || ns.baud_base != pCh->BaudBase + || ns.line != pCh->port_index ) { + return -EINVAL; + } + + old_flags = pCh->flags; + old_baud_divisor = pCh->BaudDivisor; + + if ( !suser() ) { + if ( ( ns.close_delay != pCh->ClosingDelay ) || + ( (ns.flags & ~ASYNC_USR_MASK) != + (pCh->flags & ~ASYNC_USR_MASK) ) ) { + return -EPERM; + } + + pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) | + (ns.flags & ASYNC_USR_MASK); + pCh->BaudDivisor = ns.custom_divisor; + } else { + pCh->flags = (pCh->flags & ~ASYNC_FLAGS) | + (ns.flags & ASYNC_FLAGS); + pCh->BaudDivisor = ns.custom_divisor; + pCh->ClosingDelay = ns.close_delay * HZ/100; + pCh->ClosingWaitTime = ns.closing_wait * HZ/100; + } + + if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) ) + || (old_baud_divisor != pCh->BaudDivisor) ) { + // Invalidate speed and reset parameters + set_params( pCh, NULL ); + } + + return rc; +} + +/******************************************************************************/ +/* Function: ip2_set_termios() */ +/* Parameters: Pointer to tty structure */ +/* Pointer to old termios structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_set_termios( PTTY tty, struct termios *old_termios ) +{ + i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data; + +#ifdef IP2DEBUG_IOCTL + printk (KERN_DEBUG "IP2: set termios %p\n", old_termios ); +#endif + + set_params( pCh, old_termios ); +} + +/******************************************************************************/ +/* Function: ip2_set_line_discipline() */ +/* Parameters: Pointer to tty structure */ +/* Returns: Nothing */ +/* */ +/* Description: Does nothing */ +/* */ +/* */ +/******************************************************************************/ +static void +ip2_set_line_discipline ( PTTY tty ) +{ +#ifdef IP2DEBUG_IOCTL + printk (KERN_DEBUG "IP2: set line discipline\n" ); +#endif +#ifdef IP2DEBUG_TRACE + ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 ); +#endif +} + +/******************************************************************************/ +/* Function: SetLine Characteristics() */ +/* Parameters: Pointer to channel structure */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* This routine is called to update the channel structure with the new line */ +/* characteristics, and send the appropriate commands to the board when they */ +/* change. */ +/******************************************************************************/ +static void +set_params( i2ChanStrPtr pCh, struct termios *o_tios ) +{ + tcflag_t cflag, iflag, lflag; + char stop_char, start_char; + struct termios dummy; + + lflag = pCh->pTTY->termios->c_lflag; + cflag = pCh->pTTY->termios->c_cflag; + iflag = pCh->pTTY->termios->c_iflag; + + if (o_tios == NULL) { + dummy.c_lflag = ~lflag; + dummy.c_cflag = ~cflag; + dummy.c_iflag = ~iflag; + o_tios = &dummy; + } + + { + switch ( cflag & CBAUD ) { + case B0: + i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); + pCh->dataSetOut &= ~(I2_DTR | I2_RTS); + i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); + pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag); + goto service_it; + break; + case B38400: + /* + * This is the speed that is overloaded with all the other high + * speeds, depending upon the flag settings. + */ + if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) { + pCh->speed = CBR_57600; + } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) { + pCh->speed = CBR_115200; + } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) { + pCh->speed = CBR_C1; + } else { + pCh->speed = CBR_38400; + } + break; + case B50: pCh->speed = CBR_50; break; + case B75: pCh->speed = CBR_75; break; + case B110: pCh->speed = CBR_110; break; + case B134: pCh->speed = CBR_134; break; + case B150: pCh->speed = CBR_150; break; + case B200: pCh->speed = CBR_200; break; + case B300: pCh->speed = CBR_300; break; + case B600: pCh->speed = CBR_600; break; + case B1200: pCh->speed = CBR_1200; break; + case B1800: pCh->speed = CBR_1800; break; + case B2400: pCh->speed = CBR_2400; break; + case B4800: pCh->speed = CBR_4800; break; + case B9600: pCh->speed = CBR_9600; break; + case B19200: pCh->speed = CBR_19200; break; + case B57600: pCh->speed = CBR_57600; break; + case B115200: pCh->speed = CBR_115200; break; + case B153600: pCh->speed = CBR_153600; break; + case B230400: pCh->speed = CBR_230400; break; + case B307200: pCh->speed = CBR_307200; break; + case B460800: pCh->speed = CBR_460800; break; + case B921600: pCh->speed = CBR_921600; break; + default: pCh->speed = CBR_9600; break; + } + if ( pCh->speed == CBR_C1 ) { + // Process the custom speed parameters. + int bps = pCh->BaudBase / pCh->BaudDivisor; + if ( bps == 921600 ) { + pCh->speed = CBR_921600; + } else { + bps = bps/10; + i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) ); + } + } + i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed)); + + i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); + pCh->dataSetOut |= (I2_DTR | I2_RTS); + } + if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag)) + { + i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, + CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1)); + } + if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag)) + { + i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, + CMD_SETPAR( + (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP) + ) + ); + } + /* byte size and parity */ + if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag)) + { + int datasize; + switch ( cflag & CSIZE ) { + case CS5: datasize = CSZ_5; break; + case CS6: datasize = CSZ_6; break; + case CS7: datasize = CSZ_7; break; + case CS8: datasize = CSZ_8; break; + default: datasize = CSZ_5; break; /* as per serial.c */ + } + i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) ); + } + /* Process CTS flow control flag setting */ + if ( (cflag & CRTSCTS) ) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, + 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB); + } else { + i2QueueCommands(PTYPE_INLINE, pCh, 100, + 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB); + } + // + // Process XON/XOFF flow control flags settings + // + stop_char = STOP_CHAR(pCh->pTTY); + start_char = START_CHAR(pCh->pTTY); + + //////////// can't be \000 + if (stop_char == __DISABLED_CHAR ) + { + stop_char = ~__DISABLED_CHAR; + } + if (start_char == __DISABLED_CHAR ) + { + start_char = ~__DISABLED_CHAR; + } + ///////////////////////////////// + + if ( o_tios->c_cc[VSTART] != start_char ) + { + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char)); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char)); + } + if ( o_tios->c_cc[VSTOP] != stop_char ) + { + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char)); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char)); + } + if (stop_char == __DISABLED_CHAR ) + { + stop_char = ~__DISABLED_CHAR; //TEST123 + goto no_xoff; + } + if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF))) + { + if ( iflag & IXOFF ) { // Enable XOFF output flow control + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON)); + } else { // Disable XOFF output flow control +no_xoff: + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE)); + } + } + if (start_char == __DISABLED_CHAR ) + { + goto no_xon; + } + if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY))) + { + if ( iflag & IXON ) { + if ( iflag & IXANY ) { // Enable XON/XANY output flow control + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY)); + } else { // Enable XON output flow control + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON)); + } + } else { // Disable XON output flow control +no_xon: + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE)); + } + } + if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) ) + { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, + CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0))); + } + if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) ) + { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, + CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB)); + } + + if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) + ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) ) + { + char brkrpt = 0; + char parrpt = 0; + + if ( iflag & IGNBRK ) { /* Ignore breaks altogether */ + /* Ignore breaks altogether */ + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP); + } else { + if ( iflag & BRKINT ) { + if ( iflag & PARMRK ) { + brkrpt = 0x0a; // exception an inline triple + } else { + brkrpt = 0x1a; // exception and NULL + } + brkrpt |= 0x04; // flush input + } else { + if ( iflag & PARMRK ) { + brkrpt = 0x0b; //POSIX triple \0377 \0 \0 + } else { + brkrpt = 0x01; // Null only + } + } + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt)); + } + + if (iflag & IGNPAR) { + parrpt = 0x20; + /* would be 2 for not cirrus bug */ + /* would be 0x20 cept for cirrus bug */ + } else { + if ( iflag & PARMRK ) { + /* + * Replace error characters with 3-byte sequence (\0377,\0,char) + */ + parrpt = 0x04 ; + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0)); + } else { + parrpt = 0x03; + } + } + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt)); + } + if (cflag & CLOCAL) { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP); + pCh->flags &= ~ASYNC_CHECK_CD; + } else { + i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP); + pCh->flags |= ASYNC_CHECK_CD; + } + +#ifdef XXX +do_flags_thing: // This is a test, we don't do the flags thing + + if ( (cflag & CRTSCTS) ) { + cflag |= 014000000000; + } + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, + CMD_UNIX_FLAGS(iflag,cflag,lflag)); +#endif + +service_it: + i2DrainOutput( pCh, 100 ); +} + +/******************************************************************************/ +/* IPL Device Section */ +/******************************************************************************/ + +/******************************************************************************/ +/* Function: ip2_ipl_read() */ +/* Parameters: Pointer to device inode */ +/* Pointer to file structure */ +/* Pointer to data */ +/* Number of bytes to read */ +/* Returns: Success or failure */ +/* */ +/* Description: Ugly */ +/* */ +/* */ +/******************************************************************************/ + +static +ssize_t +ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off ) +{ + unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev ); + int rc = 0; + +#ifdef IP2DEBUG_IPL + printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count ); +#endif + + switch( minor ) { + case 0: // IPL device + rc = -EINVAL; + break; + case 1: // Status dump + rc = -EINVAL; + break; + case 2: // Ping device + rc = -EINVAL; + break; + case 3: // Trace device + rc = DumpTraceBuffer ( pData, count ); + break; + case 4: // Trace device + rc = DumpFifoBuffer ( pData, count ); + break; + default: + rc = -ENODEV; + break; + } + return rc; +} + +static int +DumpFifoBuffer ( char *pData, int count ) +{ +#ifdef DEBUG_FIFO + int rc=0; + if(copy_to_user(pData, DBGBuf, count)) + rc=-EFAULT; + + printk(KERN_DEBUG "Last index %d\n", I ); + + return count; +#endif /* DEBUG_FIFO */ + return 0; +} + +static int +DumpTraceBuffer ( char *pData, int count ) +{ +#ifdef IP2DEBUG_TRACE + int rc; + int dumpcount; + int chunk; + int *pIndex = (int*)pData; + + if ( count < (sizeof(int) * 6) ) { + return -EIO; + } + put_user(tracewrap, pIndex ); + put_user(TRACEMAX, ++pIndex ); + put_user(tracestrip, ++pIndex ); + put_user(tracestuff, ++pIndex ); + pData += sizeof(int) * 6; + count -= sizeof(int) * 6; + + dumpcount = tracestuff - tracestrip; + if ( dumpcount < 0 ) { + dumpcount += TRACEMAX; + } + if ( dumpcount > count ) { + dumpcount = count; + } + chunk = TRACEMAX - tracestrip; + if ( dumpcount > chunk ) { + rc=copy_to_user(pData, &tracebuf[tracestrip], + chunk * sizeof(tracebuf[0]) )?-EFAULT:0; + pData += chunk * sizeof(tracebuf[0]); + tracestrip = 0; + chunk = dumpcount - chunk; + } else { + chunk = dumpcount; + } + rc=copy_to_user(pData, &tracebuf[tracestrip], + chunk * sizeof(tracebuf[0]) )?-EFAULT:0 + tracestrip += chunk; + tracewrap = 0; + + put_user(tracestrip, ++pIndex ); + put_user(tracestuff, ++pIndex ); + + return dumpcount; +#else + return 0; +#endif +} + +/******************************************************************************/ +/* Function: ip2_ipl_write() */ +/* Parameters: */ +/* Pointer to file structure */ +/* Pointer to data */ +/* Number of bytes to write */ +/* Returns: Success or failure */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static ssize_t +ip2_ipl_write(struct file *pFile, const char *pData, size_t count, loff_t *off) +{ +#ifdef IP2DEBUG_IPL + printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count ); +#endif + return 0; +} + +/******************************************************************************/ +/* Function: ip2_ipl_ioctl() */ +/* Parameters: Pointer to device inode */ +/* Pointer to file structure */ +/* Command */ +/* Argument */ +/* Returns: Success or failure */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static int +ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg ) +{ + unsigned int iplminor = MINOR(pInode->i_rdev); + int rc = 0; + ULONG *pIndex = (ULONG*)arg; + i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4]; + i2ChanStrPtr pCh; + +#ifdef IP2DEBUG_IPL + printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg ); +#endif + + switch ( iplminor ) { + case 0: // IPL device + rc = -EINVAL; + break; + case 1: // Status dump + case 5: + case 9: + case 13: + switch ( cmd ) { + case 64: /* Driver - ip2stat */ + put_user(ref_count, pIndex++ ); + put_user(irq_counter, pIndex++ ); + put_user(bh_counter, pIndex++ ); + break; + + case 65: /* Board - ip2stat */ + if ( pB ) { + if(copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) )) + rc=-EFAULT; + put_user(INB(pB->i2eStatus), + (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) ); + } else { + rc = -ENODEV; + } + break; + + default: + pCh = DevTable[cmd]; + if ( pCh ) + { + if(copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) )) + rc = -EFAULT; + } else { + rc = cmd < 64 ? -ENODEV : -EINVAL; + } + } + break; + + case 2: // Ping device + rc = -EINVAL; + break; + case 3: // Trace device + if ( cmd == 1 ) { + put_user(iiSendPendingMail, pIndex++ ); + put_user(i2InitChannels, pIndex++ ); + put_user(i2QueueNeeds, pIndex++ ); + put_user(i2QueueCommands, pIndex++ ); + put_user(i2GetStatus, pIndex++ ); + put_user(i2Input, pIndex++ ); + put_user(i2InputFlush, pIndex++ ); + put_user(i2Output, pIndex++ ); + put_user(i2FlushOutput, pIndex++ ); + put_user(i2DrainWakeup, pIndex++ ); + put_user(i2DrainOutput, pIndex++ ); + put_user(i2OutputFree, pIndex++ ); + put_user(i2StripFifo, pIndex++ ); + put_user(i2StuffFifoBypass, pIndex++ ); + put_user(i2StuffFifoFlow, pIndex++ ); + put_user(i2StuffFifoInline, pIndex++ ); + put_user(i2ServiceBoard, pIndex++ ); + put_user(serviceOutgoingFifo, pIndex++ ); + // put_user(ip2_init, pIndex++ ); + put_user(ip2_init_board, pIndex++ ); + put_user(find_eisa_board, pIndex++ ); + put_user(set_irq, pIndex++ ); + put_user(ip2_interrupt, pIndex++ ); + put_user(ip2_poll, pIndex++ ); + put_user(service_all_boards, pIndex++ ); + put_user(do_input, pIndex++ ); + put_user(do_status, pIndex++ ); +#ifndef IP2DEBUG_OPEN + put_user(0, pIndex++ ); +#else + put_user(open_sanity_check, pIndex++ ); +#endif + put_user(ip2_open, pIndex++ ); + put_user(ip2_close, pIndex++ ); + put_user(ip2_hangup, pIndex++ ); + put_user(ip2_write, pIndex++ ); + put_user(ip2_putchar, pIndex++ ); + put_user(ip2_flush_chars, pIndex++ ); + put_user(ip2_write_room, pIndex++ ); + put_user(ip2_chars_in_buf, pIndex++ ); + put_user(ip2_flush_buffer, pIndex++ ); + + //put_user(ip2_wait_until_sent, pIndex++ ); + put_user(0, pIndex++ ); + + put_user(ip2_throttle, pIndex++ ); + put_user(ip2_unthrottle, pIndex++ ); + put_user(ip2_ioctl, pIndex++ ); + put_user(get_modem_info, pIndex++ ); + put_user(set_modem_info, pIndex++ ); + put_user(get_serial_info, pIndex++ ); + put_user(set_serial_info, pIndex++ ); + put_user(ip2_set_termios, pIndex++ ); + put_user(ip2_set_line_discipline, pIndex++ ); + put_user(set_params, pIndex++ ); + } else { + rc = -EINVAL; + } + + break; + + default: + rc = -ENODEV; + break; + } + return rc; +} + +/******************************************************************************/ +/* Function: ip2_ipl_open() */ +/* Parameters: Pointer to device inode */ +/* Pointer to file structure */ +/* Returns: Success or failure */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +static int +ip2_ipl_open( struct inode *pInode, struct file *pFile ) +{ + unsigned int iplminor = MINOR(pInode->i_rdev); + i2eBordStrPtr pB; + i2ChanStrPtr pCh; + +#ifdef IP2DEBUG_IPL + printk (KERN_DEBUG "IP2IPL: open\n" ); +#endif + + //MOD_INC_USE_COUNT; // Needs close entry with decrement. + + switch(iplminor) { + // These are the IPL devices + case 0: + case 4: + case 8: + case 12: + break; + + // These are the status devices + case 1: + case 5: + case 9: + case 13: + break; + + // These are the debug devices + case 2: + case 6: + case 10: + case 14: + pB = i2BoardPtrTable[iplminor / 4]; + pCh = (i2ChanStrPtr) pB->i2eChannelPtr; + break; + + // This is the trace device + case 3: + break; + } + return 0; +} +/******************************************************************************/ +/* Function: ip2_read_procmem */ +/* Parameters: */ +/* */ +/* Returns: Length of output */ +/* */ +/* Description: */ +/* Supplies some driver operating parameters */ +/* Not real useful unless your debugging the fifo */ +/* */ +/******************************************************************************/ + +#define LIMIT (PAGE_SIZE - 120) + +int +ip2_read_procmem(char *buf, char **start, off_t offset, int len, int unused) +{ + i2eBordStrPtr pB; + i2ChanStrPtr pCh; + PTTY tty; + int i; + + len = 0; + +#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n" +#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n" +#define FMTLIN3 " 0x%04x 0x%04x rc flow\n" + + len += sprintf(buf+len,"\n"); + + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + pB = i2BoardPtrTable[i]; + if ( pB ) { + len += sprintf(buf+len,"board %d:\n",i); + len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n", + pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting); + } + } + + len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n"); + for (i=0; i < IP2_MAX_PORTS; i++) { + if (len > LIMIT) + break; + pCh = DevTable[i]; + if (pCh) { + tty = pCh->pTTY; + if (tty && tty->count) { + len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags, + tty->termios->c_cflag,tty->termios->c_iflag); + + len += sprintf(buf+len,FMTLIN2, + pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds); + len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room); + } + } + } + return len; +} + +/* + * This is the handler for /proc/tty/driver/ip2 + * + * This stretch of code has been largely plagerized from at least three + * different sources including ip2mkdev.c and a couple of other drivers. + * The bugs are all mine. :-) =mhw= + */ +int ip2_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i, j, box; + int len = 0; + int boxes = 0; + int ports = 0; + int tports = 0; + off_t begin = 0; + i2eBordStrPtr pB; + + len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion ); + len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n", + IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR, + IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX); + + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + /* This need to be reset for a board by board count... */ + boxes = 0; + pB = i2BoardPtrTable[i]; + if( pB ) { + switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) + { + case POR_ID_FIIEX: + len += sprintf( page+len, "Board %d: EX ports=", i ); + for( box = 0; box < ABS_MAX_BOXES; ++box ) + { + ports = 0; + + if( pB->i2eChannelMap[box] != 0 ) ++boxes; + for( j = 0; j < ABS_BIGGEST_BOX; ++j ) + { + if( pB->i2eChannelMap[box] & 1<< j ) { + ++ports; + } + } + len += sprintf( page+len, "%d,", ports ); + tports += ports; + } + + --len; /* Backup over that last comma */ + + len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 ); + break; + + case POR_ID_II_4: + len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i ); + tports = ports = 4; + break; + + case POR_ID_II_8: + len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i ); + tports = ports = 8; + break; + + case POR_ID_II_8R: + len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i ); + tports = ports = 8; + break; + + default: + len += sprintf(page+len, "Board %d: unknown", i ); + /* Don't try and probe for minor numbers */ + tports = ports = 0; + } + + } else { + /* Don't try and probe for minor numbers */ + len += sprintf(page+len, "Board %d: vacant", i ); + tports = ports = 0; + } + + if( tports ) { + len += sprintf(page+len, " minors=" ); + + for ( box = 0; box < ABS_MAX_BOXES; ++box ) + { + for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) + { + if ( pB->i2eChannelMap[box] & (1 << j) ) + { + len += sprintf (page+len,"%d,", + j + ABS_BIGGEST_BOX * + (box+i*ABS_MAX_BOXES)); + } + } + } + + page[ len - 1 ] = '\n'; /* Overwrite that last comma */ + } else { + len += sprintf (page+len,"\n" ); + } + + if (len+begin > off+count) + break; + if (len+begin < off) { + begin += len; + len = 0; + } + } + + if (i >= IP2_MAX_BOARDS) + *eof = 1; + if (off >= len+begin) + return 0; + + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); + } + +/******************************************************************************/ +/* Function: ip2trace() */ +/* Parameters: Value to add to trace buffer */ +/* Returns: Nothing */ +/* */ +/* Description: */ +/* */ +/* */ +/******************************************************************************/ +void +ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...) +{ +#ifdef IP2DEBUG_TRACE + long flags; + unsigned long *pCode = &codes; + union ip2breadcrumb bc; + i2ChanStrPtr pCh; + + + tracebuf[tracestuff++] = jiffies; + if ( tracestuff == TRACEMAX ) { + tracestuff = 0; + } + if ( tracestuff == tracestrip ) { + if ( ++tracestrip == TRACEMAX ) { + tracestrip = 0; + } + ++tracewrap; + } + + bc.hdr.port = 0xff & pn; + bc.hdr.cat = cat; + bc.hdr.codes = (unsigned char)( codes & 0xff ); + bc.hdr.label = label; + tracebuf[tracestuff++] = bc.value; + + for (;;) { + if ( tracestuff == TRACEMAX ) { + tracestuff = 0; + } + if ( tracestuff == tracestrip ) { + if ( ++tracestrip == TRACEMAX ) { + tracestrip = 0; + } + ++tracewrap; + } + + if ( !codes-- ) + break; + + tracebuf[tracestuff++] = *++pCode; + } +#endif +} + + diff -u --recursive --new-file v2.3.14/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.3.14/linux/drivers/char/isicom.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/char/isicom.c Mon Aug 23 10:10:29 1999 @@ -1808,6 +1808,7 @@ static int register_isr(void) { int count, done=0, card; + int flag; unsigned char request; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { @@ -1829,8 +1830,12 @@ isi_card[count].base = 0; break; } + flag=0; + if(isi_card[count].isa == NO) + flag |= SA_SHIRQ; + if (request == YES) { - if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { + if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) { printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", isi_card[count].irq, count+1); release_region(isi_card[count].base,16); diff -u --recursive --new-file v2.3.14/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.3.14/linux/drivers/char/pcwd.c Tue Jul 6 19:05:48 1999 +++ linux/drivers/char/pcwd.c Mon Aug 23 10:10:29 1999 @@ -246,7 +246,10 @@ return i ? -EFAULT : 0; case WDIOC_GETSTATUS: + if (revision == PCWD_REVISION_A) cdat = inb(current_readport); + else + cdat = inb(current_readport + 1 ); rv = 0; if (revision == PCWD_REVISION_A) diff -u --recursive --new-file v2.3.14/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.3.14/linux/drivers/char/random.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/random.c Mon Aug 23 10:10:29 1999 @@ -539,7 +539,7 @@ init_std_data(&random_state); } -__initfunc(void rand_initialize(void)) +void __init rand_initialize(void) { int i; @@ -1854,9 +1854,9 @@ return (((unsigned long long) high << 32) | low); } -__initfunc(static void +static void __init initialize_benchmark(struct random_benchmark *bench, - const char *descr, int unit)) + const char *descr, int unit) { bench->times = 0; bench->accum = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.14/linux/drivers/char/tty_io.c Thu Aug 5 14:47:44 1999 +++ linux/drivers/char/tty_io.c Mon Aug 23 10:23:23 1999 @@ -2152,6 +2152,9 @@ #ifdef CONFIG_SERIAL rs_init(); #endif +#ifdef CONFIG_COMPUTONE + ip2_init(); +#endif #ifdef CONFIG_MAC_SERIAL macserial_init(); #endif diff -u --recursive --new-file v2.3.14/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.14/linux/drivers/char/vt.c Fri Jul 9 15:05:41 1999 +++ linux/drivers/char/vt.c Mon Aug 23 11:15:53 1999 @@ -62,7 +62,7 @@ unsigned char keyboard_type = KB_101; #ifndef __alpha__ -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); +asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); #endif unsigned int video_font_height; diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.3.14/linux/drivers/isdn/Config.in Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/Config.in Wed Aug 25 15:18:07 1999 @@ -51,8 +51,8 @@ bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL + bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - bool 'HiSax Support for HFC PCI-Bus cards (EXPERIMENTAL)' CONFIG_HISAX_HFC_PCI # bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930 diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.3.14/linux/drivers/isdn/avmb1/b1.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/avmb1/b1.c Wed Aug 25 15:18:08 1999 @@ -1,11 +1,17 @@ /* - * $Id: b1.c,v 1.7 1999/08/04 10:10:09 calle Exp $ + * $Id: b1.c,v 1.8 1999/08/22 20:26:22 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.8 1999/08/22 20:26:22 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.7 1999/08/04 10:10:09 calle * Bugfix: corrected /proc functions, added structure for new AVM cards. * @@ -62,7 +68,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.8 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.3.14/linux/drivers/isdn/avmb1/b1isa.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/avmb1/b1isa.c Wed Aug 25 15:18:08 1999 @@ -1,11 +1,17 @@ /* - * $Id: b1isa.c,v 1.3 1999/07/09 15:05:40 keil Exp $ + * $Id: b1isa.c,v 1.4 1999/08/22 20:26:24 calle Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.4 1999/08/22 20:26:24 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/09 15:05:40 keil * compat.h is now isdn_compat.h * @@ -49,7 +55,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.3.14/linux/drivers/isdn/avmb1/b1pcmcia.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Wed Aug 25 15:18:08 1999 @@ -1,11 +1,17 @@ /* - * $Id: b1pcmcia.c,v 1.3 1999/07/09 15:05:41 keil Exp $ + * $Id: b1pcmcia.c,v 1.4 1999/08/22 20:26:26 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.4 1999/08/22 20:26:26 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/09 15:05:41 keil * compat.h is now isdn_compat.h * @@ -50,7 +56,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.3.14/linux/drivers/isdn/avmb1/t1isa.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/avmb1/t1isa.c Wed Aug 25 15:18:08 1999 @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.4 1999/07/09 15:05:50 keil Exp $ + * $Id: t1isa.c,v 1.5 1999/08/22 20:26:28 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.5 1999/08/22 20:26:28 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.4 1999/07/09 15:05:50 keil * compat.h is now isdn_compat.h * @@ -53,7 +59,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.4 $"; +static char *revision = "$Revision: 1.5 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c --- v2.3.14/linux/drivers/isdn/divert/divert_init.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/divert/divert_init.c Wed Aug 25 15:18:08 1999 @@ -1,5 +1,5 @@ /* - * $Id: divert_init.c,v 1.3 1999/07/05 20:21:39 werner Exp $ + * $Id: divert_init.c,v 1.4 1999/08/22 20:26:32 calle Exp $ * * Module init for DSS1 diversion services for i4l. * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_init.c,v $ + * Revision 1.4 1999/08/22 20:26:32 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/05 20:21:39 werner * changes to use diversion sources for all kernel versions. * removed static device, only proc filesystem used diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c --- v2.3.14/linux/drivers/isdn/divert/isdn_divert.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/divert/isdn_divert.c Wed Aug 25 15:18:08 1999 @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.c,v 1.2 1999/07/04 21:37:32 werner Exp $ + * $Id: isdn_divert.c,v 1.4 1999/08/25 20:02:21 werner Exp $ * * DSS1 main diversion supplementary handling for i4l. * @@ -20,6 +20,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_divert.c,v $ + * Revision 1.4 1999/08/25 20:02:21 werner + * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts + * with existing software definitions. (PtP incomplete called party number) + * + * Revision 1.3 1999/08/22 20:26:35 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/07/04 21:37:32 werner * Ported from kernel version 2.0 * @@ -508,14 +518,14 @@ strcpy(ic->parm.setup.phone,dv->rule.to_nr); cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - retval = 4; + retval = 5; } else retval = 1; /* alerting */ } else { cs->deflect_dest[0] = '\0'; - retval = 3; /* only proceed */ + retval = 4; /* only proceed */ } sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", cs->akt_state, diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/divert/isdn_divert.h linux/drivers/isdn/divert/isdn_divert.h --- v2.3.14/linux/drivers/isdn/divert/isdn_divert.h Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/divert/isdn_divert.h Wed Aug 25 15:18:08 1999 @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.h,v 1.2 1999/07/04 21:37:33 werner Exp $ + * $Id: isdn_divert.h,v 1.3 1999/08/22 20:26:37 calle Exp $ * * Header for the diversion supplementary ioctl interface. * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_divert.h,v $ + * Revision 1.3 1999/08/22 20:26:37 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/07/04 21:37:33 werner * Ported from kernel version 2.0 * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.3.14/linux/drivers/isdn/eicon/eicon.h Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.8 1999/07/25 15:12:01 armin Exp $ +/* $Id: eicon.h,v 1.10 1999/08/22 20:26:41 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon.h,v $ + * Revision 1.10 1999/08/22 20:26:41 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.9 1999/08/18 20:16:57 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.8 1999/07/25 15:12:01 armin * fix of some debug logs. * enabled ISA-cards option. @@ -73,6 +83,7 @@ #define EICON_IOCTL_LOADPCI 7 #define EICON_IOCTL_LOADISA 8 #define EICON_IOCTL_GETVER 9 +#define EICON_IOCTL_GETXLOG 10 #define EICON_IOCTL_MANIF 90 @@ -102,6 +113,7 @@ #define MAX_HEADER_LEN 10 + /* Struct for adding new cards */ typedef struct eicon_cdef { int membase; @@ -225,6 +237,92 @@ #endif /* KERNEL */ +#define DIVAS_SHARED_OFFSET (0x1000) + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +typedef struct { + __u8 Id __attribute__ ((packed)); + __u8 uX __attribute__ ((packed)); + __u8 listen __attribute__ ((packed)); + __u8 active __attribute__ ((packed)); + __u8 sin[3] __attribute__ ((packed)); + __u8 bc[6] __attribute__ ((packed)); + __u8 llc[6] __attribute__ ((packed)); + __u8 hlc[6] __attribute__ ((packed)); + __u8 oad[20] __attribute__ ((packed)); +}DSigStruc; + +typedef struct { + __u32 cx_b1 __attribute__ ((packed)); + __u32 cx_b2 __attribute__ ((packed)); + __u32 cr_b1 __attribute__ ((packed)); + __u32 cr_b2 __attribute__ ((packed)); + __u32 px_b1 __attribute__ ((packed)); + __u32 px_b2 __attribute__ ((packed)); + __u32 pr_b1 __attribute__ ((packed)); + __u32 pr_b2 __attribute__ ((packed)); + __u16 er_b1 __attribute__ ((packed)); + __u16 er_b2 __attribute__ ((packed)); +}BL1Struc; + +typedef struct { + __u32 XTotal __attribute__ ((packed)); + __u32 RTotal __attribute__ ((packed)); + __u16 XError __attribute__ ((packed)); + __u16 RError __attribute__ ((packed)); +}L2Struc; + +typedef struct { + __u16 free_n; +}OSStruc; + +typedef union +{ + DSigStruc DSigStats; + BL1Struc BL1Stats; + L2Struc L2Stats; + OSStruc OSStats; + __u8 b[MIPS_BUFFER_SZ]; + __u16 w[MIPS_BUFFER_SZ>>1]; + __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + __u32 d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + +typedef struct +{ + __u8 req __attribute__ ((packed)); + __u8 rc __attribute__ ((packed)); + __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ + __u8 *mem __attribute__ ((packed)); + __u16 length __attribute__ ((packed)); /* used to be short */ + __u16 port __attribute__ ((packed)); + __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ + MIPS_BUFFER data __attribute__ ((packed)); +} mi_pc_maint_t; + +typedef struct +{ + __u16 command; + mi_pc_maint_t pcm; +}xlogreq_t; + +typedef struct{ + __u16 code __attribute__ ((packed)); /* used to be short */ + __u16 timeh __attribute__ ((packed)); + __u16 timel __attribute__ ((packed)); + char buffer[MIPS_BUFFER_SZ - 6]; +}xlog_entry_t; + #define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 #define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 @@ -556,6 +654,7 @@ extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); +extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.3.14/linux/drivers/isdn/eicon/eicon_idi.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon_idi.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.11 1999/07/25 15:12:03 armin Exp $ +/* $Id: eicon_idi.c,v 1.13 1999/08/22 20:26:44 calle Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * IDI interface @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.13 1999/08/22 20:26:44 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.12 1999/08/18 20:16:59 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.11 1999/07/25 15:12:03 armin * fix of some debug logs. * enabled ISA-cards option. @@ -78,7 +88,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.11 $"; +char *eicon_idi_revision = "$Revision: 1.13 $"; eicon_manifbuf *manbuf; @@ -265,8 +275,8 @@ int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) { - struct sk_buff *skb = 0; - struct sk_buff *skb2 = 0; + struct sk_buff *skb; + struct sk_buff *skb2; eicon_REQ *reqbuf; eicon_chan_ptr *chan2; @@ -1081,7 +1091,8 @@ ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); #ifdef CONFIG_ISDN_TTY_FAX - chan->fax = 0; + if (!chan->e.B2Id) + chan->fax = 0; #endif break; case INDICATE_IND: @@ -1274,12 +1285,16 @@ chan->queued = 0; chan->waitq = 0; chan->waitpq = 0; + idi_do_req(ccard, chan, HANGUP, 0); if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); } +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif break; case IDI_N_DISC_ACK: if (DebugVar & 16) @@ -1328,7 +1343,7 @@ if (free_buff) dev_kfree_skb(skb); } -void +int idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) { isdn_ctrl cmd; @@ -1338,7 +1353,7 @@ if (DebugVar & 16) printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); - return; + return 1; } /* Management Interface */ @@ -1351,25 +1366,26 @@ /* Remove an Id */ if (chan->e.Req == REMOVE) { if (ack->Reference != chan->e.ref) { - if (DebugVar & 1) + if (DebugVar & 16) printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); + return 0; } ccard->IdTable[ack->RcId] = NULL; if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - return; + return 1; } /* Signal layer */ if (!chan->e.ReqCh) { if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); } else { /* Network layer */ @@ -1410,10 +1426,11 @@ break; default: if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); } } + return 1; } void @@ -1448,7 +1465,8 @@ printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh); break; } - idi_handle_ack_ok(ccard, chan, ack); + if (!idi_handle_ack_ok(ccard, chan, ack)) + chan = NULL; break; case ASSIGN_OK: @@ -1487,9 +1505,8 @@ case UNKNOWN_IE: case WRONG_IE: default: - chan->e.busy = 0; - if (DebugVar & 24) - printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", dCh, + if (DebugVar & 1) + printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh, ack->Rc, ack->RcId, ack->RcCh); if (dCh == ccard->nchannels) { /* Management */ chan->fsm_state = 2; @@ -1584,7 +1601,6 @@ dev_kfree_skb(skb); return len; } - int diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h --- v2.3.14/linux/drivers/isdn/eicon/eicon_idi.h Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon_idi.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.6 1999/07/25 15:12:04 armin Exp $ +/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $ * * ISDN lowlevel-module for the Eicon.Diehl active cards. * IDI-Interface @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.h,v $ + * Revision 1.7 1999/08/22 20:26:46 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/07/25 15:12:04 armin * fix of some debug logs. * enabled ISA-cards option. diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c --- v2.3.14/linux/drivers/isdn/eicon/eicon_io.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon_io.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.2 1999/07/25 15:12:05 armin Exp $ +/* $Id: eicon_io.c,v 1.4 1999/08/22 20:26:47 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Code for communicating with hardware. @@ -24,6 +24,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_io.c,v $ + * Revision 1.4 1999/08/22 20:26:47 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.3 1999/08/18 20:17:01 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.2 1999/07/25 15:12:05 armin * fix of some debug logs. * enabled ISA-cards option. @@ -61,7 +71,7 @@ /* doesn't matter if this happens */ break; default: - printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId); + printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId); printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } @@ -89,12 +99,18 @@ if (DebugVar & 1) printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n"); dev_kfree_skb(skb); - dev_kfree_skb(skb2); continue; } ind2 = (eicon_IND *)skb2->data; skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), GFP_ATOMIC); + if (!skb_new) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n"); + dev_kfree_skb(skb); + dev_kfree_skb(skb2); + continue; + } ind_new = (eicon_IND *)skb_put(skb_new, ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length)); ind_new->Ind = ind2->Ind; @@ -277,6 +293,92 @@ } /* + * XLOG + */ +int +eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +{ + int timeout, i; + int divas_shared_offset = 0; + int len = 0; + int stype = 0; + __u32 time = 0; + mi_pc_maint_t *pcm = &xlogreq->pcm; + eicon_pci_card *pci_card = &card->hwif.pci; + eicon_isa_card *isa_card = &card->hwif.isa; + eicon_pr_ram *prram = 0; + char *ram; + + switch(card->type) { + case EICON_CTYPE_MAESTRAP: + ram = (char *)pci_card->PCIram; + prram = (eicon_pr_ram *)ram; + divas_shared_offset = DIVAS_SHARED_OFFSET; + len = sizeof(mi_pc_maint_t); + break; + case EICON_CTYPE_MAESTRA: + prram = 0; + divas_shared_offset = 0; + len = sizeof(mi_pc_maint_t); + break; + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_S2M: + prram = (eicon_pr_ram *)isa_card->shmem; + divas_shared_offset = 0xfb80; + len = sizeof(mi_pc_maint_t) - 78; + stype = 1; + break; + default: + return -ENODEV; + } + + memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); + + xlogreq->pcm.rc = 0; + xlogreq->pcm.req = 1; /* DO_LOG */ + + ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; + + ram_outb(card, ram+1, pcm->rc); + ram_outb(card, ram+0, pcm->req); + + timeout = jiffies + 50; + while (timeout > jiffies) { + pcm->rc = ram_inb(card, ram+1); + pcm->req = ram_inb(card, ram+0); + if (!pcm->req) break; + SLEEP(10); + } + + if (pcm->req) { + return XLOG_ERR_TIMEOUT; + } + + if (pcm->rc != OK) { + return XLOG_ERR_DONE; + } + + ram_copyfromcard(card, pcm, ram, len); + + if (stype) { + for (i=0; i<8; i++) + ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; + time = (__u32)pcm->data.w[2] * 3600 * 1000 + + (__u32)pcm->data.w[1] * 1000 + + (__u32)pcm->data.b[1] * 20 + + (__u32)pcm->data.b[0] ; + pcm->data.w[1] = (__u16) (time >> 16); + pcm->data.w[2] = (__u16) (time & 0x0000ffff); + pcm->data.w[0] = 2; + } + + return XLOG_OK; +} + +/* * Transmit-Function */ void @@ -373,9 +475,13 @@ chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); - reqbuf = (eicon_REQ *)skb->data; + save_flags(flags); + cli(); + reqbuf = (eicon_REQ *)skb->data; + if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { + if (DebugVar & 16) + printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); + } else { if (scom) { ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); @@ -390,7 +496,7 @@ ram_outb(ccard, &ReqOut->Req, reqbuf->Req); } - if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */ + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ if (scom) @@ -439,14 +545,15 @@ ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); chan->e.busy = 1; - restore_flags(flags); if (DebugVar & 32) printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", reqbuf->Req, ram_inb(ccard, &ReqOut->ReqId), reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); - dev_kfree_skb(skb); + } + restore_flags(flags); + dev_kfree_skb(skb); } dev_kfree_skb(skb2); } @@ -636,16 +743,21 @@ } } else { skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); - ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); - ack->Rc = tmp; - ack->RcId = ram_inb(ccard, &com->RcId); - ack->RcCh = ram_inb(ccard, &com->RcCh); - ack->Reference = ccard->ref_in++; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", - tmp,ack->RcId,ack->RcCh,ack->Reference); - skb_queue_tail(&ccard->rackq, skb); - eicon_schedule_ack(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = tmp; + ack->RcId = ram_inb(ccard, &com->RcId); + ack->RcCh = ram_inb(ccard, &com->RcCh); + ack->Reference = ccard->ref_in++; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", + tmp,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } ram_outb(ccard, &com->Req, 0); ram_outb(ccard, &com->Rc, 0); } @@ -657,19 +769,24 @@ eicon_IND *ind; int len = ram_inw(ccard, &com->RBuffer.length); skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); - ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); - ind->Ind = tmp; - ind->IndId = ram_inb(ccard, &com->IndId); - ind->IndCh = ram_inb(ccard, &com->IndCh); - ind->MInd = ram_inb(ccard, &com->MInd); - ind->MLength = ram_inw(ccard, &com->MLength); - ind->RBuffer.length = len; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", - tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); - ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); - skb_queue_tail(&ccard->rcvq, skb); - eicon_schedule_rx(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = tmp; + ind->IndId = ram_inb(ccard, &com->IndId); + ind->IndCh = ram_inb(ccard, &com->IndCh); + ind->MInd = ram_inb(ccard, &com->MInd); + ind->MLength = ram_inw(ccard, &com->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", + tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + } ram_outb(ccard, &com->Ind, 0); } } @@ -686,17 +803,22 @@ if((Rc=ram_inb(ccard, &RcIn->Rc))) { skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); - ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); - ack->Rc = Rc; - ack->RcId = ram_inb(ccard, &RcIn->RcId); - ack->RcCh = ram_inb(ccard, &RcIn->RcCh); - ack->Reference = ram_inw(ccard, &RcIn->Reference); - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", - Rc,ack->RcId,ack->RcCh,ack->Reference); - ram_outb(ccard, &RcIn->Rc, 0); - skb_queue_tail(&ccard->rackq, skb); - eicon_schedule_ack(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = Rc; + ack->RcId = ram_inb(ccard, &RcIn->RcId); + ack->RcCh = ram_inb(ccard, &RcIn->RcCh); + ack->Reference = ram_inw(ccard, &RcIn->Reference); + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", + Rc,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } + ram_outb(ccard, &RcIn->Rc, 0); } /* get buffer address of next return code */ RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)]; @@ -716,19 +838,24 @@ if(Ind) { int len = ram_inw(ccard, &IndIn->RBuffer.length); skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); - ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); - ind->Ind = Ind; - ind->IndId = ram_inb(ccard, &IndIn->IndId); - ind->IndCh = ram_inb(ccard, &IndIn->IndCh); - ind->MInd = ram_inb(ccard, &IndIn->MInd); - ind->MLength = ram_inw(ccard, &IndIn->MLength); - ind->RBuffer.length = len; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", - Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); - ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); - skb_queue_tail(&ccard->rcvq, skb); - eicon_schedule_rx(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = Ind; + ind->IndId = ram_inb(ccard, &IndIn->IndId); + ind->IndCh = ram_inb(ccard, &IndIn->IndCh); + ind->MInd = ram_inb(ccard, &IndIn->MInd); + ind->MLength = ram_inw(ccard, &IndIn->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", + Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + } ram_outb(ccard, &IndIn->Ind, 0); } /* get buffer address of next indication */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.3.14/linux/drivers/isdn/eicon/eicon_isa.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon_isa.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.6 1999/07/25 15:12:06 armin Exp $ +/* $Id: eicon_isa.c,v 1.7 1999/08/22 20:26:48 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -22,6 +22,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.7 1999/08/22 20:26:48 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/07/25 15:12:06 armin * fix of some debug logs. * enabled ISA-cards option. @@ -58,7 +64,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.6 $"; +char *eicon_isa_revision = "$Revision: 1.7 $"; #ifdef CONFIG_ISDN_DRV_EICON_ISA diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.3.14/linux/drivers/isdn/eicon/eicon_mod.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/eicon/eicon_mod.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.8 1999/07/25 15:12:08 armin Exp $ +/* $Id: eicon_mod.c,v 1.9 1999/08/18 20:17:02 armin Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * @@ -26,6 +26,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.9 1999/08/18 20:17:02 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.8 1999/07/25 15:12:08 armin * fix of some debug logs. * enabled ISA-cards option. @@ -63,6 +67,8 @@ * */ +#define DRIVERPATCH "" + #include #include #include @@ -77,7 +83,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.8 $"; +static char *eicon_revision = "$Revision: 1.9 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -87,7 +93,7 @@ #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif -#define EICON_CTRL_VERSION 1 +#define EICON_CTRL_VERSION 2 ulong DebugVar; @@ -355,6 +361,32 @@ } } +static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) +{ + xlogreq_t *xlr; + int ret_val; + + if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n"); + return -ENOMEM; + } + if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { + kfree(xlr); + return -EFAULT; + } + + ret_val = eicon_get_xlog(card, xlr); + + if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { + kfree(xlr); + return -EFAULT; + } + kfree(xlr); + + return ret_val; +} + static int eicon_command(eicon_card * card, isdn_ctrl * c) { @@ -366,6 +398,10 @@ int ret = 0; unsigned long flags; + if (DebugVar & 16) + printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n", + c->command, c->arg, (ulong) *c->parm.num); + switch (c->command) { case ISDN_CMD_IOCTL: memcpy(&a, c->parm.num, sizeof(ulong)); @@ -507,6 +543,12 @@ card, (eicon_manifbuf *)a); return ret; + + case EICON_IOCTL_GETXLOG: + if (!card->flags & EICON_FLAGS_RUNNING) + return XLOG_ERR_CARD_STATE; + ret = eicon_xlog(card, (xlogreq_t *)a); + return ret; #if CONFIG_PCI case EICON_IOCTL_LOADPCI: if (card->flags & EICON_FLAGS_RUNNING) @@ -674,6 +716,10 @@ if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->l3prot = (c->arg >> 8); +#ifdef CONFIG_ISDN_TTY_FAX + if (chan->l3prot == ISDN_PROTO_L3_FAX) + chan->fax = c->parm.fax; +#endif return 0; case ISDN_CMD_GETL3: if (!card->flags & EICON_FLAGS_RUNNING) @@ -705,6 +751,17 @@ case ISDN_CMD_UNLOCK: MOD_DEC_USE_COUNT; return 0; +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_CMD_FAXCMD: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (!chan->fax) + break; + idi_fax_cmd(card, chan); + return 0; +#endif case ISDN_CMD_AUDIO: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; @@ -752,16 +809,19 @@ static int if_writecmd(const u_char * buf, int len, int user, int id, int channel) { +#if 0 + /* Not yet used */ eicon_card *card = eicon_findcard(id); if (card) { if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; + return (len); return (len); } printk(KERN_ERR "eicon: if_writecmd called with invalid driverId!\n"); - return -ENODEV; +#endif + return (len); } static int @@ -779,7 +839,7 @@ printk(KERN_ERR "eicon: if_readstatus called with invalid driverId!\n"); #endif - return -ENODEV; + return 0; } static int @@ -802,6 +862,13 @@ return -ENODEV; } if (chan->fsm_state == EICON_STATE_ACTIVE) { +#ifdef CONFIG_ISDN_TTY_FAX + if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((ret = idi_faxdata_send(card, chan, skb)) > 0) + ret = len; + } + else +#endif ret = idi_send_data(card, chan, ack, skb, 1); return (ret); } else { @@ -1231,8 +1298,8 @@ printk("%s\n", eicon_getrev(tmprev)); release += getrel(tmprev); sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev); + printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, + DRIVERRELEASE, tmprev, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.3.14/linux/drivers/isdn/eicon/eicon_pci.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/eicon/eicon_pci.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.9 1999/08/11 21:01:11 keil Exp $ +/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -26,6 +26,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_pci.c,v $ + * Revision 1.10 1999/08/22 20:26:49 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.9 1999/08/11 21:01:11 keil * new PCI codefix * @@ -71,7 +77,7 @@ #include "eicon_pci.h" -char *eicon_pci_revision = "$Revision: 1.9 $"; +char *eicon_pci_revision = "$Revision: 1.10 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c --- v2.3.14/linux/drivers/isdn/hisax/arcofi.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/arcofi.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: arcofi.c,v 1.7 1999/07/01 08:11:17 keil Exp $ +/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $ * arcofi.c Ansteuerung ARCOFI 2165 * @@ -7,6 +7,9 @@ * * * $Log: arcofi.c,v $ + * Revision 1.8 1999/08/25 16:50:51 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 1.7 1999/07/01 08:11:17 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -151,4 +154,8 @@ cs->dc.isac.arcofitimer.function = (void *) arcofi_timer; cs->dc.isac.arcofitimer.data = (long) cs; init_timer(&cs->dc.isac.arcofitimer); +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&cs->dc.isac.arcofi_wait); +#endif + test_and_set_bit(HW_ARCOFI, &cs->HW_Flags); } diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.3.14/linux/drivers/isdn/hisax/bkm_a4t.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/bkm_a4t.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.6 1999/08/11 21:01:22 keil Exp $ +/* $Id: bkm_a4t.c,v 1.7 1999/08/22 20:26:55 calle Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,12 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a4t.c,v $ + * Revision 1.7 1999/08/22 20:26:55 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/08/11 21:01:22 keil * new PCI codefix * @@ -42,7 +48,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.6 $"; +const char *bkm_a4t_revision = "$Revision: 1.7 $"; static inline u_char diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.3.14/linux/drivers/isdn/hisax/bkm_a8.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/bkm_a8.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.6 1999/08/11 21:01:24 keil Exp $ +/* $Id: bkm_a8.c,v 1.7 1999/08/22 20:26:58 calle Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,12 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a8.c,v $ + * Revision 1.7 1999/08/22 20:26:58 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/08/11 21:01:24 keil * new PCI codefix * @@ -43,7 +49,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.6 $"; +const char sct_quadro_revision[] = "$Revision: 1.7 $"; /* To survive the startup phase */ typedef struct { diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.3.14/linux/drivers/isdn/hisax/callc.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/callc.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.31 1999/08/05 20:43:10 keil Exp $ +/* $Id: callc.c,v 2.34 1999/08/25 20:02:34 werner Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,20 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.34 1999/08/25 20:02:34 werner + * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts + * with existing software definitions. (PtP incomplete called party number) + * + * Revision 2.33 1999/08/25 17:00:09 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * + * Revision 2.32 1999/08/22 20:27:01 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.31 1999/08/05 20:43:10 keil * ISAR analog modem support * @@ -140,7 +154,7 @@ #endif /* COMPAT_HAS_NEW_SYMTAB */ #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.31 $"; +const char *lli_revision = "$Revision: 2.34 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -498,12 +512,12 @@ FsmChangeState(fi, ST_IN_ALERT_SENT); chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); break; - case 4: /* direct redirect */ - case 3: /* Proceeding desired */ + case 5: /* direct redirect */ + case 4: /* Proceeding desired */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); - if (ret == 4) + if (ret == 5) { chanp->setup = ic.parm.setup; chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } @@ -971,6 +985,7 @@ case (ISDN_PROTO_L2_HDLC): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): + case (ISDN_PROTO_L2_FAX): releasestack_transl2(st); break; } @@ -1359,6 +1374,9 @@ case (ISDN_PROTO_L2_MODEM): st->l1.mode = L1_MODE_V32; break; + case (ISDN_PROTO_L2_FAX): + st->l1.mode = L1_MODE_FAX; + break; } chanp->bcs->conmsg = NULL; if (chanp->bcs->BC_SetStack(st, chanp->bcs)) @@ -1388,6 +1406,7 @@ case (ISDN_PROTO_L2_HDLC): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): + case (ISDN_PROTO_L2_FAX): st->l1.l1l2 = lltrans_handler; st->lli.userdata = chanp; st->lli.l1writewakeup = ll_writewakeup; @@ -1395,8 +1414,7 @@ setstack_l3bc(st, chanp); break; } - test_and_set_bit(FLG_START_B, &chanp->Flags); - + test_and_set_bit(FLG_START_B, &chanp->Flags); return (0); } @@ -1547,28 +1565,28 @@ /***************************************************************/ static int set_channel_limit(struct IsdnCardState *cs, int chanmax) -{ isdn_ctrl ic; - int i, ii; - - if ((chanmax < 0) || (chanmax > 2)) - return(-EINVAL); - cs->chanlimit = 0; - for (ii = 0; ii < 2; ii++) { - ic.driver = cs->myid; - ic.command = ISDN_STAT_DISCH; - ic.arg = ii; - if (ii >= chanmax) - ic.parm.num[0] = 0; /* disabled */ - else - ic.parm.num[0] = 1; /* enabled */ - i = cs->iif.statcallb(&ic); - if (i) return(-EINVAL); - if (ii < chanmax) - cs->chanlimit++; - } - return(0); -} /* set_channel_limit */ +{ + isdn_ctrl ic; + int i, ii; + if ((chanmax < 0) || (chanmax > 2)) + return(-EINVAL); + cs->chanlimit = 0; + for (ii = 0; ii < 2; ii++) { + ic.driver = cs->myid; + ic.command = ISDN_STAT_DISCH; + ic.arg = ii; + if (ii >= chanmax) + ic.parm.num[0] = 0; /* disabled */ + else + ic.parm.num[0] = 1; /* enabled */ + i = cs->iif.statcallb(&ic); + if (i) return(-EINVAL); + if (ii < chanmax) + cs->chanlimit++; + } + return(0); +} /* set_channel_limit */ int HiSax_command(isdn_ctrl * ic) @@ -1578,7 +1596,6 @@ struct Channel *chanp; int i; u_int num; - u_long adr; if (!csta) { printk(KERN_ERR @@ -1586,12 +1603,10 @@ ic->command, ic->driver); return -ENODEV; } - switch (ic->command) { case (ISDN_CMD_SETEAZ): chanp = csta->channel + ic->arg; break; - case (ISDN_CMD_SETL2): chanp = csta->channel + (ic->arg & 0xff); if (chanp->debug & 1) @@ -1767,11 +1782,6 @@ chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); break; - case (9): /* load firmware */ - memcpy(&adr, ic->parm.num, sizeof(ulong)); - csta->cardmsg(csta, CARD_LOAD_FIRM, - (void *) adr); - break; #ifdef MODULE case (55): MOD_USE_COUNT = 0; @@ -1797,23 +1807,12 @@ printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", csta->cardnr + 1, *(unsigned int *) ic->parm.num); break; - case (10): - i = *(unsigned int *) ic->parm.num; - if ((i < 0) || (i > 2)) - return(-EINVAL); /* invalid number */ + case (10): + i = *(unsigned int *) ic->parm.num; return(set_channel_limit(csta, i)); - break; - case (12): - i = *(unsigned int *) ic->parm.num; -#ifdef CONFIG_HISAX_HFC_PCI - if (csta->typ != ISDN_CTYPE_HFC_PCI) - return(-EINVAL); - return(hfcpci_set_echo(csta,i)); -#else - return(-EINVAL); -#endif - break; default: + if (csta->auxcmd) + return(csta->auxcmd(csta, ic)); printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", (int) ic->arg); return (-EINVAL); @@ -1850,9 +1849,10 @@ return(-EINVAL); break; default: - break; + if (csta->auxcmd) + return(csta->auxcmd(csta, ic)); + return(-EINVAL); } - return (0); } diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.3.14/linux/drivers/isdn/hisax/config.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/config.c Wed Aug 25 15:18:08 1999 @@ -1,10 +1,13 @@ -/* $Id: config.c,v 2.30 1999/08/05 20:43:14 keil Exp $ +/* $Id: config.c,v 2.31 1999/08/25 16:47:43 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.31 1999/08/25 16:47:43 keil + * Support new __setup; allow to add FEATURES after register_isdn + * * Revision 2.30 1999/08/05 20:43:14 keil * ISAR analog modem support * @@ -117,6 +120,10 @@ #include #include #include +#include +#ifdef COMPAT_HAS_NEW_SETUP +#include +#endif #include "hisax.h" #include #include @@ -546,12 +553,24 @@ #ifdef MODULE #define HiSax_init init_module #else +#ifdef COMPAT_HAS_NEW_SETUP +#define MAX_ARG (HISAX_MAX_CARDS*5) +__initfunc(int +HiSax_setup(char *line)) +{ + int i, j, argc; + int ints[MAX_ARG + 1]; + char *str; + + str = get_options(line, MAX_ARG, ints); +#else __initfunc(void HiSax_setup(char *str, int *ints)) { int i, j, argc; - +#endif argc = ints[0]; + printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str); i = 0; j = 1; while (argc && (i < HISAX_MAX_CARDS)) { @@ -589,8 +608,15 @@ strcpy(HiSaxID, "HiSax"); HiSax_id = HiSaxID; } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); } -#endif + +__setup("hisax=", HiSax_setup); +#else +} +#endif /* COMPAT_HAS_NEW_SETUP */ +#endif /* MODULES */ #if CARD_TELES0 extern int setup_teles0(struct IsdnCard *card); @@ -875,7 +901,7 @@ } int -ll_run(struct IsdnCardState *cs) +ll_run(struct IsdnCardState *cs, int addfeatures) { long flags; isdn_ctrl ic; @@ -884,6 +910,7 @@ cli(); ic.driver = cs->myid; ic.command = ISDN_STAT_RUN; + cs->iif.features |= addfeatures; cs->iif.statcallb(&ic); restore_flags(flags); return 0; @@ -1053,7 +1080,6 @@ cs->iif.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_MODEM | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | #ifdef CONFIG_HISAX_1TR6 @@ -1269,7 +1295,7 @@ CallcNewChan(cs); /* ISAR needs firmware download first */ if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs); + ll_run(cs, 0); restore_flags(flags); return (1); } diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.3.14/linux/drivers/isdn/hisax/elsa.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/elsa.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 2.17 1999/08/11 20:57:40 keil Exp $ +/* $Id: elsa.c,v 2.18 1999/08/25 16:50:54 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * @@ -14,6 +14,9 @@ * for ELSA PCMCIA support * * $Log: elsa.c,v $ + * Revision 2.18 1999/08/25 16:50:54 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 2.17 1999/08/11 20:57:40 keil * bugfix IPAC version 1.1 * new PCI codefix @@ -96,7 +99,7 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.17 $"; +const char *Elsa_revision = "$Revision: 2.18 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", @@ -180,6 +183,7 @@ #define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ #define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ +#if ARCOFI_USE static struct arcofi_msg ARCOFI_XOP_F = {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ static struct arcofi_msg ARCOFI_XOP_1 = @@ -203,9 +207,8 @@ static void set_arcofi(struct IsdnCardState *cs, int bc); -#if ARCOFI_USE #include "elsa_ser.c" -#endif +#endif /* ARCOFI_USE */ static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -432,6 +435,7 @@ cs->hw.elsa.counter++; } } +#if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_MCR); val ^= 0x8; @@ -440,6 +444,7 @@ val ^= 0x8; serial_outp(cs, UART_MCR, val); } +#endif if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); @@ -514,7 +519,9 @@ int bytecnt = 8; del_timer(&cs->hw.elsa.tl); +#if ARCOFI_USE clear_arcofi(cs); +#endif if (cs->hw.elsa.ctrl) byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ if (cs->subtyp == ELSA_QS1000PCI) { @@ -536,7 +543,9 @@ (cs->subtyp == ELSA_PCF) || (cs->subtyp == ELSA_QS3000PCI)) { bytecnt = 16; +#if ARCOFI_USE release_modem(cs); +#endif } if (cs->hw.elsa.base) release_region(cs->hw.elsa.base, bytecnt); @@ -592,6 +601,8 @@ } } +#if ARCOFI_USE + static void set_arcofi(struct IsdnCardState *cs, int bc) { cs->dc.isac.arcofi_bc = bc; @@ -602,7 +613,6 @@ static int check_arcofi(struct IsdnCardState *cs) { -#if ARCOFI_USE int arcofi_present = 0; char tmp[40]; char *t; @@ -690,9 +700,9 @@ interruptible_sleep_on(&cs->dc.isac.arcofi_wait); return(1); } -#endif return(0); } +#endif /* ARCOFI_USE */ static void elsa_led_handler(struct IsdnCardState *cs) @@ -738,8 +748,7 @@ static int Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int len, ret = 0; - u_char *msg; + int ret = 0; long flags; switch (mt) { @@ -828,8 +837,12 @@ cs->hw.elsa.status &= ~0x0100; } break; +#if ARCOFI_USE case CARD_AUX_IND: if (cs->hw.elsa.MFlag) { + int len; + u_char *msg; + if (!arg) return(0); msg = arg; @@ -838,6 +851,7 @@ modem_write_cmd(cs, msg, len); } break; +#endif } if (cs->typ == ISDN_CTYPE_ELSA) { int pwr = bytein(cs->hw.elsa.ale); @@ -1199,7 +1213,9 @@ request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci"); } } +#if ARCOFI_USE init_arcofi(cs); +#endif cs->hw.elsa.tl.function = (void *) elsa_led_handler; cs->hw.elsa.tl.data = (long) cs; init_timer(&cs->hw.elsa.tl); diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.3.14/linux/drivers/isdn/hisax/gazel.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/gazel.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: gazel.c,v 2.5 1999/08/11 21:01:26 keil Exp $ +/* $Id: gazel.c,v 2.6 1999/08/22 20:27:03 calle Exp $ * gazel.c low level stuff for Gazel isdn cards * @@ -6,6 +6,12 @@ * based on source code from Karsten Keil * * $Log: gazel.c,v $ + * Revision 2.6 1999/08/22 20:27:03 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.5 1999/08/11 21:01:26 keil * new PCI codefix * @@ -36,7 +42,7 @@ #endif extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.5 $"; +const char *gazel_revision = "$Revision: 2.6 $"; #define R647 1 #define R685 2 diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.3.14/linux/drivers/isdn/hisax/hfc_pci.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/hfc_pci.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.13 1999/08/11 21:01:28 keil Exp $ +/* $Id: hfc_pci.c,v 1.16 1999/08/25 17:01:27 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.16 1999/08/25 17:01:27 keil + * Use new LL->HL auxcmd call + * + * Revision 1.15 1999/08/22 20:27:05 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.14 1999/08/12 18:59:45 werner + * Added further manufacturer and device ids to PCI list + * * Revision 1.13 1999/08/11 21:01:28 keil * new PCI codefix * @@ -80,20 +92,33 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.13 $"; - -static const int CCD_VENDOR_IDS[] = { - 0x1043, /* Asuscom */ - 0x1051, /* Motorola MC145575 */ - 0x1397, /* CCD and Billion */ - 0, -}; +static const char *hfcpci_revision = "$Revision: 1.16 $"; -static const int CCD_DEVICE_IDS[] = { - 0x675, /* Asuscom */ - 0x100, /* Motorola MC145575 */ - 0x2BD0, /* CCD and Billion */ - 0, +/* table entry in the PCI devices list */ +typedef struct { + int vendor_id; + int device_id; + char *vendor_name; + char *card_name; + } PCI_ENTRY; + +static const PCI_ENTRY id_list[] = { + {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"}, + {0x1397,0xB000,"Billion","B000"}, + {0x1397,0xB006,"Billion","B006"}, + {0x1397,0xB007,"Billion","B007"}, + {0x1397,0xB008,"Billion","B008"}, + {0x1397,0xB009,"Billion","B009"}, + {0x1397,0xB00A,"Billion","B00A"}, + {0x1397,0xB00B,"Billion","B00B"}, + {0x1397,0xB00C,"Billion","B00C"}, + {0x1043,0x0675,"Asuscom/Askey","675"}, + {0x0871,0xFFA2,"German telekom","T-Concept"}, + {0x0871,0xFFA1,"German telekom","A1T"}, + {0x1051,0x0100,"Motorola MC145575","MC145575"}, + {0x1397,0xB100,"Seyeon","B100"}, + {0x15B0,0x2BD0,"Zoltrix","2BD0"}, + {0,0,NULL,NULL}, }; @@ -618,9 +643,12 @@ /***********************/ /* set/reset echo mode */ /***********************/ -int hfcpci_set_echo(struct IsdnCardState *cs, int i) -{ int flags; - +static int +hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) +{ + int flags; + int i = *(unsigned int *) ic->parm.num; + if (cs->chanlimit > 1) return(-EINVAL); @@ -651,7 +679,7 @@ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); restore_flags(flags); return(0); -} /* hfcpci_set_echo */ +} /* hfcpci_auxcmd */ /*****************************/ /* E-channel receive routine */ @@ -1476,9 +1504,9 @@ return (0); } i = 0; - while (CCD_VENDOR_IDS[i]) { - tmp_hfcpci = pci_find_device(CCD_VENDOR_IDS[i], - CCD_DEVICE_IDS[i], + while (id_list[i].vendor_id) { + tmp_hfcpci = pci_find_device(id_list[i].vendor_id, + id_list[i].device_id, dev_hfcpci); if (tmp_hfcpci) break; i++; @@ -1494,6 +1522,7 @@ return (0); } cs->hw.hfcpci.pci_io = (char *) get_pcibase(dev_hfcpci, 1); + printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name); } else { printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); return (0); @@ -1503,14 +1532,14 @@ unsigned char irq; i = 0; - while (CCD_VENDOR_IDS[i]) { - if (pcibios_find_device(CCD_VENDOR_IDS[i], - CCD_DEVICE_IDS[i], pci_index, + while (id_list[i].vendor_id) { + if (pcibios_find_device(id_list[i].vendor_id, + id_list[i].device_id, pci_index, &cs->hw.hfcpci.pci_bus, &cs->hw.hfcpci.pci_device_fn) == 0) break; i++; } - if (!CCD_VENDOR_IDS[i]) + if (!id_list[i].vendor_id) continue; pcibios_read_config_byte(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, @@ -1520,6 +1549,7 @@ pcibios_read_config_dword(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_BASE_ADDRESS_1, (void *) &cs->hw.hfcpci.pci_io); + printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name); break; } if (pci_index == 255) { @@ -1577,6 +1607,7 @@ reset_hfcpci(cs); cs->cardmsg = &hfcpci_card_msg; + cs->auxcmd = &hfcpci_auxcmd; return (1); #else printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n"); diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.3.14/linux/drivers/isdn/hisax/hisax.h Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/hisax.h Wed Aug 25 15:18:08 1999 @@ -1,8 +1,12 @@ -/* $Id: hisax.h,v 2.33 1999/08/05 20:43:16 keil Exp $ +/* $Id: hisax.h,v 2.34 1999/08/25 17:00:04 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.34 1999/08/25 17:00:04 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 2.33 1999/08/05 20:43:16 keil * ISAR analog modem support * @@ -154,7 +158,6 @@ #define CARD_RELEASE 0x00F3 #define CARD_TEST 0x00F4 #define CARD_AUX_IND 0x00F5 -#define CARD_LOAD_FIRM 0x00F6 #define PH_ACTIVATE 0x0100 #define PH_DEACTIVATE 0x0110 @@ -458,6 +461,12 @@ int rcvidx; int txcnt; int mml; + u_char state; + u_char cmd; + u_char mod; + u_char newcmd; + u_char newmod; + struct timer_list ftimer; u_char *rcvbuf; /* B-Channel receive Buffer */ u_char conmsg[16]; struct isar_reg *reg; @@ -528,6 +537,14 @@ #define BC_FLG_HALF 5 #define BC_FLG_EMPTY 6 #define BC_FLG_ORIG 7 +#define BC_FLG_DLEETX 8 +#define BC_FLG_LASTDLE 9 +#define BC_FLG_FIRST 10 +#define BC_FLG_LASTDATA 11 +#define BC_FLG_NMD_DATA 12 +#define BC_FLG_FTI_RUN 13 +#define BC_FLG_LL_OK 14 +#define BC_FLG_LL_CONN 15 #define L1_MODE_NULL 0 #define L1_MODE_TRANS 1 @@ -852,6 +869,7 @@ #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 +#define HW_ARCOFI 3 #define FLG_TWO_DCHAN 4 #define FLG_L1_DBUSY 5 #define FLG_DBUSY_TIMER 6 @@ -910,6 +928,7 @@ void (*setstack_d) (struct PStack *, struct IsdnCardState *); void (*DC_Close) (struct IsdnCardState *); void (*irq_func) (int, void *, struct pt_regs *); + int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); struct Channel channel[2+MAX_WAITING_CALLS]; struct BCState bcs[2+MAX_WAITING_CALLS]; struct PStack *stlist; @@ -1138,7 +1157,6 @@ #ifdef CONFIG_HISAX_HFC_PCI #define CARD_HFC_PCI 1 -extern int hfcpci_set_echo(struct IsdnCardState *, int); #else #define CARD_HFC_PCI 0 #endif @@ -1327,7 +1345,7 @@ #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} -int ll_run(struct IsdnCardState *cs); +int ll_run(struct IsdnCardState *cs, int addfeatures); void ll_stop(struct IsdnCardState *cs); void CallcNew(void); void CallcFree(void); diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c --- v2.3.14/linux/drivers/isdn/hisax/isac.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/isac.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.22 1999/08/09 19:04:40 keil Exp $ +/* $Id: isac.c,v 1.23 1999/08/25 16:50:52 keil Exp $ * isac.c ISAC specific routines * @@ -9,6 +9,9 @@ * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.23 1999/08/25 16:50:52 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 1.22 1999/08/09 19:04:40 keil * Fix race condition - Thanks to Christer Weinigel * @@ -168,10 +171,14 @@ DChannel_proc_rcv(cs); if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; if (test_and_clear_bit(D_RX_MON1, &cs->event)) arcofi_fsm(cs, ARCOFI_RX_END, NULL); if (test_and_clear_bit(D_TX_MON1, &cs->event)) arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif } void diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.3.14/linux/drivers/isdn/hisax/isar.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/isar.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.4 1999/08/05 20:43:18 keil Exp $ +/* $Id: isar.c,v 1.5 1999/08/25 16:59:55 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,10 @@ * * * $Log: isar.c,v $ + * Revision 1.5 1999/08/25 16:59:55 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.4 1999/08/05 20:43:18 keil * ISAR analog modem support * @@ -309,6 +313,10 @@ printk(KERN_DEBUG"isar firmware block %5d words loaded\n", blk_head.len); } + /* 10ms delay */ + cnt = 10; + while (cnt--) + udelay(1000); msg[0] = 0xff; msg[1] = 0xfe; ireg->bstat = 0; @@ -343,20 +351,26 @@ printk(KERN_DEBUG"isar general status event %x\n", ireg->bstat); } + /* 10ms delay */ + cnt = 10; + while (cnt--) + udelay(1000); ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { printk(KERN_ERR"isar sendmsg self tst failed\n"); ret = 1;goto reterrflg; } - cnt = 1000; /* max 10 ms */ + cnt = 10000; /* max 100 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } + udelay(1000); if (!cnt) { printk(KERN_ERR"isar no self tst response\n"); ret = 1;goto reterrflg; - } else if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) + } + if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) && (ireg->par[0] == 0)) { printk(KERN_DEBUG"isar selftest OK\n"); } else { @@ -369,11 +383,12 @@ printk(KERN_ERR"isar RQST SVN failed\n"); ret = 1;goto reterror; } - cnt = 10000; /* max 100 ms */ + cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } + udelay(1000); if (!cnt) { printk(KERN_ERR"isar no SVN response\n"); ret = 1;goto reterrflg; @@ -402,7 +417,18 @@ return(ret); } -void +extern void BChannel_bh(struct BCState *); +#define B_LL_NOCARRIER 8 +#define B_LL_CONNECT 9 +#define B_LL_OK 10 + +static void +isar_bh(struct BCState *bcs) +{ + BChannel_bh(bcs); +} + +static void isar_sched_event(struct BCState *bcs, int event) { bcs->event |= 1 << event; @@ -464,9 +490,9 @@ if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) + } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); - else { + } else { SET_SKB_FREE(skb); memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2); @@ -709,7 +735,6 @@ case PSEV_DSR_ON: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev DSR ON"); -// sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, 0xCF, 0, NULL); break; case PSEV_DSR_OFF: if (cs->debug & L1_DEB_HSCX) @@ -734,7 +759,7 @@ } } -static char debbuf[64]; +static char debbuf[128]; void isar_int_main(struct IsdnCardState *cs) @@ -806,6 +831,12 @@ debugl1(cs, debbuf); } break; + case ISAR_IIS_INVMSG: + rcv_mbox(cs, ireg, debbuf); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "invalid msg his:%x", + ireg->cmsb); + break; default: rcv_mbox(cs, ireg, debbuf); if (cs->debug & L1_DEB_WARN) @@ -816,7 +847,7 @@ restore_flags(flags); } -void +static void setup_pump(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -840,15 +871,12 @@ } else { param[5] = PV32P6_ATN; } - param[0] = 11; /* 11 db */ -// param[1] = PV32P2_V22A | PV32P2_V22B | PV32P2_V21; - param[1] = PV32P2_V22A; -// param[2] = PV32P3_AMOD | PV32P3_V32B; - param[2] = PV32P3_AMOD; - param[3] = PV32P4_48; - param[4] = PV32P5_48; -// param[3] = PV32P4_UT144; -// param[4] = PV32P5_UT144; + param[0] = 6; /* 6 db */ + param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | + PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; + param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; + param[3] = PV32P4_UT144; + param[4] = PV32P5_UT144; if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) { if (cs->debug) debugl1(cs, "isar pump datamodem cfg dp%d failed", @@ -863,7 +891,7 @@ } else { param[1] = PFAXP2_ATN; } - param[0] = 8; /* 8 db */ + param[0] = 6; /* 6 db */ if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) { if (cs->debug) debugl1(cs, "isar pump faxmodem cfg dp%d failed", @@ -878,7 +906,7 @@ } } -void +static void setup_sart(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -900,7 +928,9 @@ } break; case L1_MODE_HDLC: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, "\0")) { + case L1_MODE_FAX: + param[0] = 0; + if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) { if (cs->debug) debugl1(cs, "isar sart hdlc dp%d failed", bcs->hw.isar.dpath); @@ -924,7 +954,7 @@ } } -void +static void setup_iom2(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -967,6 +997,9 @@ bcs->channel = bc; switch (mode) { case L1_MODE_NULL: /* init */ + if (!bcs->hw.isar.dpath) + /* no init for dpath 0 */ + return(0); break; case L1_MODE_TRANS: case L1_MODE_HDLC: @@ -983,6 +1016,7 @@ } break; case L1_MODE_V32: + case L1_MODE_FAX: /* only datapath 1 */ if (!test_and_set_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags)) @@ -1032,6 +1066,7 @@ cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; modeisar(&cs->bcs[i], 0, 0); + cs->bcs[i].tqueue.routine = (void *) (void *) isar_bh; } } @@ -1167,6 +1202,36 @@ bcs->st = st; setstack_l1_B(st); return (0); +} + +int +isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { + u_long adr; + int features; + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg); + switch (ic->command) { + case (ISDN_CMD_IOCTL): + switch (ic->arg) { + case (9): /* load firmware */ + features = ISDN_FEATURE_L2_MODEM; + memcpy(&adr, ic->parm.num, sizeof(ulong)); + if (isar_load_firmware(cs, (u_char *)adr)) + return(1); + else + ll_run(cs, features); + break; + default: + printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", + (int) ic->arg); + return(-EINVAL); + } + break; + default: + return(-EINVAL); + } + return(0); } HISAX_INITFUNC(void diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h --- v2.3.14/linux/drivers/isdn/hisax/isar.h Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/isar.h Wed Aug 25 15:18:08 1999 @@ -1,10 +1,14 @@ -/* $Id: isar.h,v 1.4 1999/08/05 20:43:20 keil Exp $ +/* $Id: isar.h,v 1.5 1999/08/25 16:59:59 keil Exp $ * isar.h ISAR (Siemens PSB 7110) specific defines * * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: isar.h,v $ + * Revision 1.5 1999/08/25 16:59:59 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.4 1999/08/05 20:43:20 keil * ISAR analog modem support * @@ -33,40 +37,41 @@ #define ISAR_WADR 0x4a #define ISAR_RADR 0x48 -#define ISAR_HIS_VNR 0x14 -#define ISAR_HIS_DKEY 0x02 -#define ISAR_HIS_FIRM 0x1e -#define ISAR_HIS_STDSP 0x08 -#define ISAR_HIS_DIAG 0x05 -#define ISAR_HIS_P0CFG 0x3c -#define ISAR_HIS_P12CFG 0x24 +#define ISAR_HIS_VNR 0x14 +#define ISAR_HIS_DKEY 0x02 +#define ISAR_HIS_FIRM 0x1e +#define ISAR_HIS_STDSP 0x08 +#define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_P0CFG 0x3c +#define ISAR_HIS_P12CFG 0x24 #define ISAR_HIS_SARTCFG 0x25 #define ISAR_HIS_PUMPCFG 0x26 #define ISAR_HIS_PUMPCTRL 0x2a #define ISAR_HIS_IOM2CFG 0x27 #define ISAR_HIS_IOM2REQ 0x07 #define ISAR_HIS_IOM2CTRL 0x2b -#define ISAR_HIS_BSTREQ 0x0c -#define ISAR_HIS_PSTREQ 0x0e -#define ISAR_HIS_SDATA 0x20 -#define ISAR_HIS_DPS1 0x40 -#define ISAR_HIS_DPS2 0x80 -#define SET_DPS(x) ((x<<6) & 0xc0) - -#define ISAR_IIS_MSCMSD 0x3f -#define ISAR_IIS_VNR 0x15 -#define ISAR_IIS_DKEY 0x03 -#define ISAR_IIS_FIRM 0x1f -#define ISAR_IIS_STDSP 0x09 -#define ISAR_IIS_DIAG 0x25 -#define ISAR_IIS_GSTEV 0x0 -#define ISAR_IIS_BSTEV 0x28 -#define ISAR_IIS_BSTRSP 0x2c -#define ISAR_IIS_PSTRSP 0x2e -#define ISAR_IIS_PSTEV 0x2a +#define ISAR_HIS_BSTREQ 0x0c +#define ISAR_HIS_PSTREQ 0x0e +#define ISAR_HIS_SDATA 0x20 +#define ISAR_HIS_DPS1 0x40 +#define ISAR_HIS_DPS2 0x80 +#define SET_DPS(x) ((x<<6) & 0xc0) + +#define ISAR_IIS_MSCMSD 0x3f +#define ISAR_IIS_VNR 0x15 +#define ISAR_IIS_DKEY 0x03 +#define ISAR_IIS_FIRM 0x1f +#define ISAR_IIS_STDSP 0x09 +#define ISAR_IIS_DIAG 0x25 +#define ISAR_IIS_GSTEV 0x00 +#define ISAR_IIS_BSTEV 0x28 +#define ISAR_IIS_BSTRSP 0x2c +#define ISAR_IIS_PSTRSP 0x2e +#define ISAR_IIS_PSTEV 0x2a #define ISAR_IIS_IOM2RSP 0x27 +#define ISAR_IIS_RDATA 0x20 +#define ISAR_IIS_INVMSG 0x3f -#define ISAR_IIS_RDATA 0x20 #define ISAR_CTRL_SWVER 0x10 #define ISAR_CTRL_STST 0x40 @@ -93,30 +98,33 @@ #define PV32P2_V21 0x02 #define PV32P2_BEL 0x01 +// LSB MSB in ISAR doc wrong !!! Arghhh #define PV32P3_AMOD 0x80 #define PV32P3_V32B 0x02 -#define PV32P4_48 0x05 -#define PV32P5_48 0x11 -#define PV32P4_UT48 0x0d -#define PV32P5_UT48 0x11 -#define PV32P4_96 0x03 -#define PV32P5_96 0x11 -#define PV32P4_UT96 0x0f -#define PV32P5_UT96 0x11 -#define PV32P4_B96 0x0b -#define PV32P5_B96 0x91 -#define PV32P4_UTB96 0x0f -#define PV32P5_UTB96 0xd1 -#define PV32P4_120 0x09 -#define PV32P5_120 0xb1 -#define PV32P4_UT120 0x0f -#define PV32P5_UT120 0xf1 -#define PV32P4_144 0x09 -#define PV32P5_144 0x99 -#define PV32P4_UT144 0x0f -#define PV32P5_UT144 0xf9 +#define PV32P3_V23B 0x01 +#define PV32P4_48 0x11 +#define PV32P5_48 0x05 +#define PV32P4_UT48 0x11 +#define PV32P5_UT48 0x0d +#define PV32P4_96 0x11 +#define PV32P5_96 0x03 +#define PV32P4_UT96 0x11 +#define PV32P5_UT96 0x0f +#define PV32P4_B96 0x91 +#define PV32P5_B96 0x0b +#define PV32P4_UTB96 0xd1 +#define PV32P5_UTB96 0x0f +#define PV32P4_120 0xb1 +#define PV32P5_120 0x09 +#define PV32P4_UT120 0xf1 +#define PV32P5_UT120 0x0f +#define PV32P4_144 0x99 +#define PV32P5_144 0x09 +#define PV32P4_UT144 0xf9 +#define PV32P5_UT144 0x0f #define PV32P6_CTN 0x01 #define PV32P6_ATN 0x02 + #define PFAXP2_CTN 0x01 #define PFAXP2_ATN 0x04 @@ -156,7 +164,7 @@ #define S_P1_CHS_6 0x01 #define S_P1_CHS_5 0x00 -#define S_P2_BFT_DEF 30 +#define S_P2_BFT_DEF 0x10 #define IOM_CTRL_ENA 0x80 #define IOM_CTRL_NOPCM 0x00 @@ -170,15 +178,15 @@ #define HDLC_FSD 0x20 #define HDLC_FST 0x20 #define HDLC_ERROR 0x1c +#define SART_NMD 0x01 #define BSTAT_RDM0 0x1 #define BSTAT_RDM1 0x2 #define BSTAT_RDM2 0x4 #define BSTAT_RDM3 0x8 - extern int ISARVersion(struct IsdnCardState *cs, char *s); -extern int isar_load_firmware(struct IsdnCardState *cs, u_char *buf); extern void isar_int_main(struct IsdnCardState *cs); extern void initisar(struct IsdnCardState *cs); extern void isar_fill_fifo(struct BCState *bcs); +extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic); diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.3.14/linux/drivers/isdn/hisax/isdnl1.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/isdnl1.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdnl1.c,v 2.34 1999/07/09 13:50:15 keil Exp $ +/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden @@ -15,6 +15,15 @@ * * * $Log: isdnl1.c,v $ + * Revision 2.36 1999/08/25 16:50:57 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * + * Revision 2.35 1999/08/22 20:27:07 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.34 1999/07/09 13:50:15 keil * remove unused variable * @@ -129,7 +138,7 @@ * */ -const char *l1_revision = "$Revision: 2.34 $"; +const char *l1_revision = "$Revision: 2.36 $"; #define __NO_VERSION__ #include "hisax.h" @@ -390,7 +399,7 @@ } } -static void +void BChannel_bh(struct BCState *bcs) { if (!bcs) diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.3.14/linux/drivers/isdn/hisax/isdnl2.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/isdnl2.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.19 1999/08/05 20:40:26 keil Exp $ +/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,9 @@ * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 2.20 1999/08/25 16:52:04 keil + * Make gcc on AXP happy + * * Revision 2.19 1999/08/05 20:40:26 keil * Fix interlayer communication * @@ -80,7 +83,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.19 $"; +const char *l2_revision = "$Revision: 2.20 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); @@ -1747,7 +1750,7 @@ } if(c) { FreeSkb(skb); - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) c); + FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c); ret = 0; } if (ret) diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c --- v2.3.14/linux/drivers/isdn/hisax/isurf.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/hisax/isurf.c Wed Aug 25 15:18:08 1999 @@ -1,10 +1,20 @@ -/* $Id: isurf.c,v 1.3 1999/07/12 21:05:18 keil Exp $ +/* $Id: isurf.c,v 1.5 1999/08/25 17:00:02 keil Exp $ * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * * $Log: isurf.c,v $ + * Revision 1.5 1999/08/25 17:00:02 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * + * Revision 1.4 1999/08/22 20:27:09 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/12 21:05:18 keil * fix race in IRQ handling * added watchdog for lost IRQs @@ -24,7 +34,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.3 $"; +static const char *ISurf_revision = "$Revision: 1.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -174,18 +184,26 @@ return(0); case CARD_TEST: return(0); - case CARD_LOAD_FIRM: - if (isar_load_firmware(cs, arg)) - return(1); - ll_run(cs); + } + return(0); +} + +static int +isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { + int ret; + + if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { + ret = isar_auxcmd(cs, ic); + if (!ret) { reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET); initisac(cs); cs->writeisac(cs, ISAC_MASK, 0); cs->writeisac(cs, ISAC_CMDR, 0x41); - return(0); + } + return(ret); } - return(0); + return(isar_auxcmd(cs, ic)); } __initfunc(int @@ -228,6 +246,7 @@ cs->cardmsg = &ISurf_card_msg; cs->irq_func = &isurf_interrupt; + cs->auxcmd = &isurf_auxcmd; cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.3.14/linux/drivers/isdn/hisax/l3dss1.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/l3dss1.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.18 1999/08/11 20:54:39 keil Exp $ +/* $Id: l3dss1.c,v 2.19 1999/08/25 16:55:23 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.19 1999/08/25 16:55:23 keil + * Fix for test case TC10011 + * * Revision 2.18 1999/08/11 20:54:39 keil * High layer compatibility is valid in SETUP * @@ -87,7 +90,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.18 $"; +const char *dss1_revision = "$Revision: 2.19 $"; #define EXT_BEARER_CAPS 1 @@ -764,11 +767,6 @@ int ret = 1; while (*checklist != -1) { -#if 0 - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "ie_in_set ie(%x) cl(%x)", - ie, *checklist); -#endif if ((*checklist & 0xff) == ie) { if (ie & 0x80) return(-ret); @@ -1737,15 +1735,12 @@ return; } /* Now we are on none mandatory IEs */ -#if 1 -/* !!!!!! this check seems to be a problem ? info bugfix to Karsten */ err = check_infoelements(pc, skb, ie_SETUP); if (ERR_IE_COMPREHENSION == err) { pc->para.cause = 96; l3dss1_msg_without_setup(pc, pr, NULL); return; } -#endif p = skb->data; if ((p = findie(p, skb->len, 0x70, 0))) iecpy(pc->para.setup.eazmsn, p, 1); @@ -1787,29 +1782,10 @@ } else if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "wrong calling subaddress"); } - -#if 0 - if (bcfound) { - if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) { - l3_debug(pc->st, "non-digital call: %s -> %s", - pc->para.setup.phone, pc->para.setup.eazmsn); - } - if ((pc->para.setup.si1 != 7) && - test_bit(FLG_PTP, &pc->st->l2.flag)) { - pc->para.cause = 88; /* incompatible destination */ - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - newl3state(pc, 6); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); - } else - dss1_release_l3_process(pc); -#else newl3state(pc, 6); if (err) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, err); pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -#endif } static void @@ -2106,8 +2082,6 @@ ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); l3dss1_std_ie_err(pc, ret); -// KKe 19.7.99 test eicon -// idev_kfree_skb(skb, FREE_READ); pc->para.cause = 30; /* response to STATUS_ENQUIRY */ l3dss1_status_send(pc, pr, NULL); } @@ -2862,7 +2836,8 @@ MT_STATUS, l3dss1_status}, {SBIT(0), MT_SETUP, l3dss1_setup}, - {SBIT(6) | SBIT(7), + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), MT_SETUP, l3dss1_dummy}, {SBIT(1) | SBIT(2), MT_CALL_PROCEEDING, l3dss1_call_proc}, @@ -2885,8 +2860,6 @@ {SBIT(19), MT_RELEASE, l3dss1_release_ind}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), MT_DISCONNECT, l3dss1_disconnect}, -// {SBIT(11), -// MT_DISCONNECT, l3dss1_release_req}, {SBIT(19), MT_DISCONNECT, l3dss1_dummy}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.3.14/linux/drivers/isdn/hisax/md5sums.asc Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/md5sums.asc Wed Aug 25 15:18:08 1999 @@ -6,16 +6,16 @@ # Eicon Technology Diva 2.01 PCI cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -d93f31e02c1b153ec04d16f69e5688b3 isac.c -e2a78c07f32c8ca7c88fc9f92a87dfab isdnl1.c -54490c4f46a998ff4ef34287bc262185 isdnl2.c +0cc164fadd4ec0e2983ec9735e209cbd isac.c +5fe8cb5526c78c91f61b0a94a423ea5d isdnl1.c +3b9522e8bf9e1c3e7848d729fc3dc05d isdnl2.c f4184a50e35e5b568608e6cb7a693319 isdnl3.c ef70f4269fdc2ca15100f9b776afaa0d tei.c -cf3923304983e9d64cf35bc5a3533f6c callc.c +65be616dd9d0e06c788d4fdd0fe5fe0a callc.c bf9605b36429898f7be6630034e83230 cert.c -309261e4c36d950db6978440e8bc8342 l3dss1.c +97c5e31c2739665b9c2976a30ce0b357 l3dss1.c b674eee9314a7cc413971c84003cf1d2 l3_1tr6.c -8f86d92f43ecc42f6457773168cfc114 elsa.c +51b2ef1efb221bb09fd08ab28bd2c565 elsa.c 24cda374da44b57f6a1bb215424267b5 diva.c # end of md5sums @@ -23,9 +23,9 @@ Version: 2.6.3i Charset: noconv -iQCVAwUBN7HnvDpxHvX/mS9tAQFANgP+LGuG98lvCv97vN2dc6T/6hZTxFW+WirJ -XMhU5NHoZ+8MISMOVKB7ugsGO9cJI0lUA0sOe8jtPCo5070nF1ZkNsxV/x7WK2dS -RwXfHy6+TAH7qIiBnkP9odB2lib+VFl/nnkkTwsXfVwRCD8bLaagMPv+nAveDoNE -uff0xxXEnJw= -=Wu2M +iQCVAwUBN8RgFjpxHvX/mS9tAQFzFQP/dOgnppDIm5ug1hnlWjQ/0BVurKEEJ64r +DYDHwkcog+0gVE/EB1A7WUDqpFEnj52OZeoVinCfdVuVjP8IkrAJ8dCONsnXjBXz +pzM+FunP1LFxuv2TVM0f642j98JxS8rObGWH8ZwY36P2QfNp47zorO2F9WvdCkuz +sxJUtMUOlQ8= +=8uEP -----END PGP SIGNATURE----- diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.3.14/linux/drivers/isdn/hisax/sedlbauer.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/sedlbauer.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.14 1999/08/11 20:59:22 keil Exp $ +/* $Id: sedlbauer.c,v 1.15 1999/08/25 17:00:00 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -17,6 +17,10 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.15 1999/08/25 17:00:00 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.14 1999/08/11 20:59:22 keil * new PCI codefix * fix IRQ problem while unload @@ -99,7 +103,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.14 $"; +const char *Sedlbauer_revision = "$Revision: 1.15 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -530,19 +534,10 @@ return(0); case CARD_TEST: return(0); - case CARD_LOAD_FIRM: - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - if (isar_load_firmware(cs, arg)) - return(1); - else - ll_run(cs); - } - return(0); } return(0); } - #ifdef SEDLBAUER_PCI #ifdef COMPAT_HAS_NEW_PCI static struct pci_dev *dev_sedl __initdata = NULL; @@ -743,7 +738,7 @@ cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; test_and_set_bit(HW_ISAR, &cs->HW_Flags); cs->irq_func = &sedlbauer_interrupt_isar; - + cs->auxcmd = &isar_auxcmd; ISACVersion(cs, "Sedlbauer:"); cs->BC_Read_Reg = &ReadISAR; diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.3.14/linux/drivers/isdn/icn/icn.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/icn/icn.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.57 1999/07/06 16:15:30 detabc Exp $ +/* $Id: icn.c,v 1.58 1999/08/25 16:44:17 keil Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.58 1999/08/25 16:44:17 keil + * Support for new __setup function + * * Revision 1.57 1999/07/06 16:15:30 detabc * remove unused messages * @@ -232,7 +235,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.57 $"; +*revision = "$Revision: 1.58 $"; static int icn_addcard(int, char *, char *); @@ -1846,13 +1849,25 @@ #ifdef MODULE #define icn_init init_module #else +#ifdef COMPAT_HAS_NEW_SETUP +#include +int +icn_setup(char *line) +{ + char *p, *str; + int ints[3]; + static char sid[20]; + static char sid2[20]; + + str = get_options(line, 2, ints); +#else void icn_setup(char *str, int *ints) { char *p; static char sid[20]; static char sid2[20]; - +#endif if (ints[0]) portbase = ints[1]; if (ints[0] > 1) @@ -1866,8 +1881,14 @@ icn_id2 = sid2; } } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); +} +__setup("icn=", icn_setup); +#else } #endif +#endif /* MODULES */ int icn_init(void) diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.3.14/linux/drivers/isdn/isdn_audio.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/isdn_audio.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_audio.c,v 1.16 1999/08/06 12:47:35 calle Exp $ +/* $Id: isdn_audio.c,v 1.17 1999/08/17 11:10:52 paul Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.17 1999/08/17 11:10:52 paul + * don't try to use x86 assembler on non-x86! + * * Revision 1.16 1999/08/06 12:47:35 calle * Using __GNUC__ == 2 && __GNUC_MINOR__ < 95 how to define * ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT @@ -92,7 +95,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.16 $"; +char *isdn_audio_revision = "$Revision: 1.17 $"; /* * Misc. lookup-tables. @@ -294,7 +297,7 @@ * egcs 2.95 complain about invalid asm statement: * "fixed or forbidden register 2 (cx) was spilled for class CREG." */ -#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) || defined(__GNUC__) +#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__) #if __GNUC__ == 2 && __GNUC_MINOR__ < 95 #define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT #endif diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c --- v2.3.14/linux/drivers/isdn/isdn_concap.c Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_concap.c Wed Aug 25 15:18:08 1999 @@ -1,10 +1,16 @@ -/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $ +/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. * * $Log: isdn_concap.c,v $ + * Revision 1.6 1999/08/22 20:26:01 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.5 1998/10/30 18:44:48 he * pass return value from isdn_net_dial_req for dialmode change * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.3.14/linux/drivers/isdn/isdn_net.c Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_net.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.88 1999/07/07 10:13:31 detabc Exp $ +/* $Id: isdn_net.c,v 1.89 1999/08/22 20:26:03 calle Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.89 1999/08/22 20:26:03 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.88 1999/07/07 10:13:31 detabc * remove unused messages * @@ -360,7 +366,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.88 $"; +char *isdn_net_revision = "$Revision: 1.89 $"; /* * Code for raw-networking over ISDN diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.3.14/linux/drivers/isdn/isdn_net.h Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_net.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $ +/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.10 1999/08/22 20:26:06 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.9 1999/04/12 12:33:27 fritz * Changes from 2.0 tree. * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.3.14/linux/drivers/isdn/isdn_ppp.c Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_ppp.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.49 1999/07/06 07:47:11 calle Exp $ +/* $Id: isdn_ppp.c,v 1.52 1999/08/22 20:26:07 calle Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.52 1999/08/22 20:26:07 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.51 1999/08/18 16:19:17 hipp + * applied MPPP-resize-headroom patch + * + * Revision 1.50 1999/08/16 07:11:41 hipp + * Additional VJ decomp-buffer-size increased from 40 to 128 + * * Revision 1.49 1999/07/06 07:47:11 calle * bugfix: dev_alloc_skb only reserve 16 bytes. We need to look at the * hdrlen the driver want. So I changed dev_alloc_skb calls @@ -269,7 +281,7 @@ static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.49 $"; +char *isdn_ppp_revision = "$Revision: 1.52 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; static struct isdn_ppp_compressor *ipc_head = NULL; @@ -1352,7 +1364,7 @@ { struct sk_buff *skb_old = skb; int pkt_len; - skb = dev_alloc_skb(skb_old->len + 40); + skb = dev_alloc_skb(skb_old->len + 128); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); @@ -1361,7 +1373,7 @@ return; } skb->dev = dev; - skb_put(skb, skb_old->len + 40); + skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, @@ -1415,9 +1427,17 @@ struct sk_buff *skb = *skb_p; if(skb_headroom(skb) < len) { - printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); + struct sk_buff *nskb = skb_realloc_headroom(skb, len); + + if (!nskb) { + printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); + dev_kfree_skb(skb); + return NULL; + } + printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); dev_kfree_skb(skb); - return NULL; + *skb_p = nskb; + return skb_push(nskb, len); } return skb_push(skb,len); } diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v2.3.14/linux/drivers/isdn/isdn_ppp.h Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_ppp.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $ +/* $Id: isdn_ppp.h,v 1.14 1999/08/22 20:26:10 calle 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.14 1999/08/22 20:26:10 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.13 1998/03/22 18:50:50 hipp * Added BSD Compression for syncPPP .. UNTESTED at the moment * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.3.14/linux/drivers/isdn/isdn_tty.h Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/isdn_tty.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.15 1999/07/31 12:59:48 armin Exp $ +/* $Id: isdn_tty.h,v 1.16 1999/08/22 20:26:10 calle Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.16 1999/08/22 20:26:10 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.15 1999/07/31 12:59:48 armin * Added tty fax capabilities. * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_ttyfax.c linux/drivers/isdn/isdn_ttyfax.c --- v2.3.14/linux/drivers/isdn/isdn_ttyfax.c Sun Aug 15 11:49:08 1999 +++ linux/drivers/isdn/isdn_ttyfax.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_ttyfax.c,v 1.2 1999/08/05 10:36:10 armin Exp $ +/* $Id: isdn_ttyfax.c,v 1.3 1999/08/22 20:26:12 calle Exp $ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ttyfax.c,v $ + * Revision 1.3 1999/08/22 20:26:12 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/08/05 10:36:10 armin * Bugfix: kernel oops on getting revision. * @@ -40,7 +46,7 @@ #include "isdn_ttyfax.h" -static char *isdn_tty_fax_revision = "$Revision: 1.2 $"; +static char *isdn_tty_fax_revision = "$Revision: 1.3 $"; #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/isdn_x25iface.c linux/drivers/isdn/isdn_x25iface.c --- v2.3.14/linux/drivers/isdn/isdn_x25iface.c Wed Aug 18 11:38:57 1999 +++ linux/drivers/isdn/isdn_x25iface.c Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $ +/* $Id: isdn_x25iface.c,v 1.7 1999/08/22 20:26:13 calle Exp $ * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -10,6 +10,12 @@ * goes to another -- device related -- concap_proto support source file. * * $Log: isdn_x25iface.c,v $ + * Revision 1.7 1999/08/22 20:26:13 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/01/27 22:53:19 he * minor updates (spellings, jiffies wrap around in isdn_tty) * diff -u --recursive --new-file v2.3.14/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.3.14/linux/drivers/isdn/pcbit/module.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/pcbit/module.c Wed Aug 25 15:18:08 1999 @@ -102,10 +102,21 @@ } #else -void pcbit_setup(char *str, int *ints) +#ifdef COMPAT_HAS_NEW_SETUP +#define MAX_PARA (MAX_PCBIT_CARDS * 2) +#include +int pcbit_setup(char *line) { int i, j, argc; + char *str; + int ints[MAX_PARA+1]; + str = get_options(line, MAX_PARA, ints); +#else +void pcbit_setup(char *str, int *ints) +{ + int i, j, argc; +#endif argc = ints[0]; i = 0; j = 1; @@ -124,7 +135,13 @@ i++; } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); +} +__setup("pcbit=", pcbit_setup); +#else } +#endif #endif diff -u --recursive --new-file v2.3.14/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.14/linux/drivers/net/Config.in Fri Aug 6 10:44:11 1999 +++ linux/drivers/net/Config.in Mon Aug 23 10:10:29 1999 @@ -24,6 +24,9 @@ tristate 'Ethertap network tap' CONFIG_ETHERTAP fi fi + +tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 + # # Ethernet # @@ -90,6 +93,7 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN fi bool 'Other ISA cards' CONFIG_NET_ISA @@ -229,6 +233,11 @@ endmenu +bool 'Fibre Channel driver support' CONFIG_NET_FC +if [ "$CONFIG_NET_FC" = "y" ]; then + tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526 +fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER @@ -285,6 +294,7 @@ fi endmenu + # # X.25 network drivers diff -u --recursive --new-file v2.3.14/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.14/linux/drivers/net/Makefile Thu Aug 12 09:46:13 1999 +++ linux/drivers/net/Makefile Mon Aug 23 10:10:29 1999 @@ -5,7 +5,7 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda +ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc L_TARGET := net.a L_OBJS := auto_irq.o @@ -91,6 +91,14 @@ endif endif +ifeq ($(CONFIG_NET_SB1000),y) +L_OBJS += sb1000.o +else + ifeq ($(CONFIG_NET_SB1000),m) + M_OBJS += sb1000.o + endif +endif + ifeq ($(CONFIG_DAYNAPORT), y) L_OBJS += daynaport.o CONFIG_8390_BUILTIN = y @@ -580,6 +588,14 @@ endif endif +ifeq ($(CONFIG_SIS900),y) +L_OBJS += sis900.o +else + ifeq ($(CONFIG_SIS900),m) + M_OBJS += sis900.o + endif +endif + ifeq ($(CONFIG_YELLOWFIN),y) L_OBJS += yellowfin.o else @@ -1171,6 +1187,15 @@ else ifeq ($(CONFIG_IRDA),m) MOD_IN_SUB_DIRS += irda + endif +endif + +ifeq ($(CONFIG_NET_FC),y) +SUB_DIRS += fc +MOD_IN_SUB_DIRS += fc +else + ifeq ($(CONFIG_NET_FC),m) + MOD_IN_SUB_DIRS += fc endif endif diff -u --recursive --new-file v2.3.14/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.14/linux/drivers/net/Space.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/Space.c Mon Aug 23 10:10:29 1999 @@ -111,6 +111,7 @@ extern int am79c961_probe(struct net_device *dev); extern int epic100_probe(struct net_device *dev); extern int rtl8139_probe(struct net_device *dev); +extern int sis900_probe(struct net_device *dev); extern int hplance_probe(struct net_device *dev); extern int bagetlance_probe(struct net_device *); extern int dec_lance_probe(struct net_device *); @@ -137,6 +138,9 @@ /* HIPPI boards */ extern int rr_hippi_probe(struct net_device *); +/* Fibre Channel adapters */ +extern int iph5526_probe(struct net_device *dev); + struct devprobe { int (*probe)(struct net_device *dev); @@ -207,6 +211,9 @@ #ifdef CONFIG_RTL8139 {rtl8139_probe, 0}, #endif +#ifdef CONFIG_SIS900 + {sis900_probe, 0}, +#endif #ifdef CONFIG_YELLOWFIN {yellowfin_probe, 0}, #endif @@ -578,15 +585,41 @@ } #endif +/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */ +#define __PAD6 "\0\0\0\0\0\0\0\0\0" +#define __PAD5 __PAD6 "\0" +#define __PAD4 __PAD5 "\0" +#define __PAD3 __PAD4 "\0" +#define __PAD2 __PAD3 "\0" + + +#ifdef CONFIG_NET_FC +static int fcif_probe(struct net_device *dev) +{ + if (dev->base_addr == -1) + return 1; + + if (1 +#ifdef CONFIG_IPHASE5526 + && iph5526_probe(dev) +#endif + && 1 ) { + return 1; /* -ENODEV or -EAGAIN would be more accurate. */ + } + return 0; +} +#endif /* CONFIG_NET_FC */ + + #ifdef CONFIG_ETHERTAP - static struct net_device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, }; + static struct net_device tap0_dev = { "tap0" __PAD4, 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, }; # undef NEXT_DEV # define NEXT_DEV (&tap0_dev) #endif #ifdef CONFIG_SDLA extern int sdla_init(struct net_device *); - static struct net_device sdla0_dev = { "sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, }; + static struct net_device sdla0_dev = { "sdla0" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, }; # undef NEXT_DEV # define NEXT_DEV (&sdla0_dev) @@ -595,7 +628,7 @@ #if defined(CONFIG_LTPC) extern int ltpc_probe(struct net_device *); static struct net_device dev_ltpc = { - "lt0\0 ", + "lt0" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, ltpc_probe }; @@ -605,9 +638,9 @@ #if defined(CONFIG_COPS) extern int cops_probe(struct net_device *); - static struct net_device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe }; - static struct net_device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe }; - static struct net_device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe }; + static struct net_device cops2_dev = { "lt2" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe }; + static struct net_device cops1_dev = { "lt1" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe }; + static struct net_device cops0_dev = { "lt0" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe }; # undef NEXT_DEV # define NEXT_DEV (&cops0_dev) #endif /* COPS */ @@ -615,7 +648,7 @@ #if defined(CONFIG_IPDDP) extern int ipddp_init(struct net_device *dev); static struct net_device dev_ipddp = { - "ipddp0\0 ", + "ipddp0" __PAD6, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, ipddp_init }; @@ -638,22 +671,22 @@ #define ETH_NOPROBE_ADDR 0xffe0 static struct net_device eth7_dev = { - "eth7", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; + "eth7" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; static struct net_device eth6_dev = { - "eth6", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð7_dev, ethif_probe }; + "eth6" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð7_dev, ethif_probe }; static struct net_device eth5_dev = { - "eth5", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð6_dev, ethif_probe }; + "eth5" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð6_dev, ethif_probe }; static struct net_device eth4_dev = { - "eth4", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð5_dev, ethif_probe }; + "eth4" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð5_dev, ethif_probe }; static struct net_device eth3_dev = { - "eth3", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð4_dev, ethif_probe }; + "eth3" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð4_dev, ethif_probe }; static struct net_device eth2_dev = { - "eth2", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe }; + "eth2" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe }; static struct net_device eth1_dev = { - "eth1", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe }; + "eth1" __PAD4, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe }; static struct net_device eth0_dev = { - "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_probe }; + "eth0" __PAD4, 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_probe }; # undef NEXT_DEV # define NEXT_DEV (ð0_dev) @@ -715,7 +748,7 @@ #ifdef CONFIG_DUMMY extern int dummy_init(struct net_device *dev); static struct net_device dummy_dev = { - "dummy", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, }; + "dummy" __PAD5, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, }; # undef NEXT_DEV # define NEXT_DEV (&dummy_dev) #endif @@ -723,7 +756,7 @@ #ifdef CONFIG_EQUALIZER extern int eql_init(struct net_device *dev); struct net_device eql_dev = { - "eql", /* Master device for IP traffic load + "eql" __PAD3, /* Master device for IP traffic load balancing */ 0x0, 0x0, 0x0, 0x0, /* recv end/start; mem end/start */ 0, /* base I/O address */ @@ -763,21 +796,21 @@ return 0; } static struct net_device tr7_dev = { - "tr7",0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe }; + "tr7" __PAD3,0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe }; static struct net_device tr6_dev = { - "tr6",0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe }; + "tr6" __PAD3,0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe }; static struct net_device tr5_dev = { - "tr5",0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe }; + "tr5" __PAD3,0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe }; static struct net_device tr4_dev = { - "tr4",0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe }; + "tr4" __PAD3,0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe }; static struct net_device tr3_dev = { - "tr3",0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe }; + "tr3" __PAD3,0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe }; static struct net_device tr2_dev = { - "tr2",0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe }; + "tr2" __PAD3,0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe }; static struct net_device tr1_dev = { - "tr1",0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe }; + "tr1" __PAD3,0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe }; static struct net_device tr0_dev = { - "tr0",0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe }; + "tr0" __PAD3,0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe }; # undef NEXT_DEV # define NEXT_DEV (&tr0_dev) @@ -785,34 +818,34 @@ #ifdef CONFIG_FDDI static struct net_device fddi7_dev = - {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe}; + {"fddi7" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe}; static struct net_device fddi6_dev = - {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe}; + {"fddi6" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe}; static struct net_device fddi5_dev = - {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe}; + {"fddi5" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe}; static struct net_device fddi4_dev = - {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe}; + {"fddi4" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe}; static struct net_device fddi3_dev = - {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe}; + {"fddi3" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe}; static struct net_device fddi2_dev = - {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe}; + {"fddi2" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe}; static struct net_device fddi1_dev = - {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe}; + {"fddi1" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe}; static struct net_device fddi0_dev = - {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe}; + {"fddi0" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe}; #undef NEXT_DEV #define NEXT_DEV (&fddi0_dev) #endif #ifdef CONFIG_HIPPI static struct net_device hip3_dev = - {"hip3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, hippi_probe}; + {"hip3" __PAD4, 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, hippi_probe}; static struct net_device hip2_dev = - {"hip2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip3_dev, hippi_probe}; + {"hip2" __PAD4, 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip3_dev, hippi_probe}; static struct net_device hip1_dev = - {"hip1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip2_dev, hippi_probe}; + {"hip1" __PAD4, 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip2_dev, hippi_probe}; static struct net_device hip0_dev = - {"hip0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip1_dev, hippi_probe}; + {"hip0" __PAD4, 0, 0, 0, 0, 0, 0, 0, 0, 0, &hip1_dev, hippi_probe}; #undef NEXT_DEV #define NEXT_DEV (&hip0_dev) @@ -821,14 +854,33 @@ #ifdef CONFIG_APBIF extern int bif_init(struct net_device *dev); static struct net_device bif_dev = { - "bif", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init }; + "bif" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init }; # undef NEXT_DEV # define NEXT_DEV (&bif_dev) #endif + + +#ifdef CONFIG_NET_FC + static struct net_device fc1_dev = { + "fc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fcif_probe}; + static struct net_device fc0_dev = { + "fc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fc1_dev, fcif_probe}; +# undef NEXT_DEV +# define NEXT_DEV (&fc0_dev) +#endif + + +#ifdef CONFIG_NET_SB1000 + extern int sb1000_probe(struct net_device *dev); + static struct net_device sb1000_dev = { + "cm0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, sb1000_probe }; +# undef NEXT_DEV +# define NEXT_DEV (&sb1000_dev) +#endif extern int loopback_init(struct net_device *dev); struct net_device loopback_dev = { - "lo", /* Software Loopback interface */ + "lo" __PAD2, /* Software Loopback interface */ 0x0, /* recv memory end */ 0x0, /* recv memory start */ 0x0, /* memory end */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.3.14/linux/drivers/net/a2065.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/a2065.c Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ /* * Amiga Linux/68k A2065 Ethernet Driver * - * (C) Copyright 1995 by Geert Uytterhoeven - * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * (C) Copyright 1995 by Geert Uytterhoeven * * Fixes and tips by: * - Janos Farkas (CHEXUM@sparta.banki.hu) diff -u --recursive --new-file v2.3.14/linux/drivers/net/a2065.h linux/drivers/net/a2065.h --- v2.3.14/linux/drivers/net/a2065.h Fri Dec 20 01:20:00 1996 +++ linux/drivers/net/a2065.h Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ /* * Amiga Linux/68k A2065 Ethernet Driver * - * (C) Copyright 1995 by Geert Uytterhoeven - * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * (C) Copyright 1995 by Geert Uytterhoeven * * --------------------------------------------------------------------------- * diff -u --recursive --new-file v2.3.14/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.14/linux/drivers/net/acenic.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/acenic.c Mon Aug 23 10:12:37 1999 @@ -2,7 +2,7 @@ * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * - * Copyright 1998 by Jes Sorensen, . + * Copyright 1998, 1999 by Jes Sorensen, . * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -67,6 +67,15 @@ #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a #endif +/* + * They used the DEC vendor ID by mistake + */ +#ifndef PCI_DEVICE_ID_FARALLON_PN9000SX +#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a +#endif +#ifndef PCI_VENDOR_ID_SGI_ACENIC +#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 +#endif /* * This driver currently supports Tigon I and Tigon II based cards @@ -156,10 +165,10 @@ * Default values for tuning parameters */ #define DEF_TX_RATIO 31 -#define DEF_TX_COAL TICKS_PER_SEC / 500 -#define DEF_TX_MAX_DESC 7 -#define DEF_RX_COAL TICKS_PER_SEC / 10000 -#define DEF_RX_MAX_DESC 2 +#define DEF_TX_COAL 1000 +#define DEF_TX_MAX_DESC 40 +#define DEF_RX_COAL 1000 +#define DEF_RX_MAX_DESC 20 #define DEF_TRACE 0 #define DEF_STAT 2 * TICKS_PER_SEC @@ -171,7 +180,7 @@ static int max_rx_desc[8] = {0, }; static int tx_ratio[8] = {0, }; -static const char __initdata *version = "acenic.c: v0.32 03/15/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static const char __initdata *version = "acenic.c: v0.33a 08/16/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct net_device *root_dev = NULL; @@ -208,7 +217,15 @@ !((pdev->vendor == PCI_VENDOR_ID_3COM) && (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620))) + (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)) && + /* + * Farallon used the DEC vendor ID on their cards by + * mistake for a while + */ + !((pdev->vendor == PCI_VENDOR_ID_DEC) && + (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && + !((pdev->vendor == PCI_VENDOR_ID_SGI) && + (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) continue; dev = init_etherdev(dev, sizeof(struct ace_private)); @@ -282,6 +299,18 @@ sprintf(ap->name, "NetGear GA620 Gigabit Ethernet"); printk(KERN_INFO "%s: NetGear GA620 ", dev->name); break; + case PCI_VENDOR_ID_DEC: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { + sprintf(ap->name, "Farallon PN9000-SX " + "Gigabit Ethernet"); + printk(KERN_INFO "%s: Farallon PN9000-SX ", + dev->name); + break; + } + case PCI_VENDOR_ID_SGI: + sprintf(ap->name, "SGI AceNIC Gigabit Ethernet"); + printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + break; default: sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet"); printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); @@ -569,7 +598,7 @@ * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ - if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL | GFP_DMA))){ + if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))){ free_irq(dev->irq, dev); return -EAGAIN; } @@ -1162,6 +1191,12 @@ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); +#if 0 + /* + * This was never actually enabled in the RX descriptors + * anyway - it requires a bit more testing before enabling + * it again. + */ /* * If the checksum is correct and this is not a * fragment, tell the stack that the data is correct. @@ -1172,7 +1207,7 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; - +#endif netif_rx(skb); /* send it up */ ap->stats.rx_packets++; diff -u --recursive --new-file v2.3.14/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.3.14/linux/drivers/net/acenic_firmware.h Mon Mar 22 08:08:12 1999 +++ linux/drivers/net/acenic_firmware.h Mon Aug 23 10:12:38 1999 @@ -1,31 +1,31 @@ /* Generated by genfw.c */ int tigonFwReleaseMajor = 0xc; int tigonFwReleaseMinor = 0x3; -int tigonFwReleaseFix = 0x5; +int tigonFwReleaseFix = 0xa; u32 tigonFwStartAddr = 0x00004000; u32 tigonFwTextAddr = 0x00004000; -int tigonFwTextLen = 0x10910; -u32 tigonFwRodataAddr = 0x00014910; +int tigonFwTextLen = 0x10920; +u32 tigonFwRodataAddr = 0x00014920; int tigonFwRodataLen = 0xaa0; -u32 tigonFwDataAddr = 0x000153d0; +u32 tigonFwDataAddr = 0x000153e0; int tigonFwDataLen = 0x150; -u32 tigonFwSbssAddr = 0x00015520; +u32 tigonFwSbssAddr = 0x00015530; int tigonFwSbssLen = 0x2c; -u32 tigonFwBssAddr = 0x00015550; +u32 tigonFwBssAddr = 0x00015560; int tigonFwBssLen = 0x2080; u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, -0x8fbd5404, 0x3a0f021, 0x3c100000, 0x26104000, +0x8fbd5414, 0x3a0f021, 0x3c100000, 0x26104000, 0xc00100c, 0x0, 0xd, 0x27bdffd8, 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, 0xafbf0024, 0xc00248c, 0xafb00020, 0xc0023ec, -0x0, 0x3c040001, 0x24844970, 0x24050001, -0x2e03021, 0x3821, 0x3c100001, 0x261075d0, +0x0, 0x3c040001, 0x24844984, 0x24050001, +0x2e03021, 0x3821, 0x3c100001, 0x261075e0, 0xafb00010, 0xc002407, 0xafbb0014, 0x3c02000f, 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, -0x24050003, 0x3c040001, 0x2484497c, 0x2003021, +0x24050003, 0x3c040001, 0x24844990, 0x2003021, 0x3603821, 0x3c020010, 0xafa20010, 0xc002407, 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 0x370821, 0xa02083b0, 0x3c010001, 0x370821, @@ -63,7 +63,7 @@ 0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc, 0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, 0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, -0x24844988, 0x3c050001, 0xafa00010, 0xafa00014, +0x2484499c, 0x3c050001, 0xafa00010, 0xafa00014, 0x8ee704fc, 0x34a5f000, 0xc002407, 0x603021, 0x26e40030, 0xc00248c, 0x24050400, 0x27440080, 0xc00248c, 0x24050080, 0x26e4777c, 0xc00248c, @@ -73,7 +73,7 @@ 0x3442ca00, 0x2021, 0x24030002, 0xaee30074, 0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, -0x641821, 0x906353d0, 0x2e41021, 0x24840001, +0x641821, 0x906353e0, 0x2e41021, 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 0x24420030, 0xa062009c, 0x2e41021, 0xa040009c, @@ -119,7 +119,7 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, -0xaee90608, 0x3c040001, 0x24844994, 0xafa00010, +0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x8001223, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, @@ -145,21 +145,21 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, -0x3c040001, 0x2484499c, 0xafa00010, 0xafa00014, +0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, -0x8001223, 0x8ee201b0, 0x3c040001, 0x248449a8, +0x8001223, 0x8ee201b0, 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, -0x248449b4, 0x3405f001, 0x24420001, 0xaee20160, +0x248449c8, 0x3405f001, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x8001238, 0x0, 0x3c020001, 0x2442f5b8, 0x21100, 0x21182, 0x431025, 0x3c010001, 0xac221278, 0x96e2045a, 0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, 0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, -0x3c040001, 0x248449c0, 0x24020001, 0xa2e204ec, +0x3c040001, 0x248449d4, 0x24020001, 0xa2e204ec, 0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, 0x2442a3a0, 0x451024, 0x21082, 0xaee304c8, 0x3c030800, 0x431025, 0x3c010001, 0xac221220, @@ -202,7 +202,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x800136d, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, @@ -227,17 +227,17 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, -0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, -0x8ee20160, 0x3c040001, 0x248449b4, 0x3405f002, +0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f002, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, -0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449cc, +0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449e0, 0x24050012, 0xafa00010, 0xc002407, 0xafa00014, 0xc004500, 0x0, 0xc002318, 0x0, 0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, @@ -280,7 +280,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x80014a5, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, @@ -305,11 +305,11 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, -0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, @@ -331,7 +331,7 @@ 0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821, 0xac2083bc, 0x3c010001, 0x370821, 0x3e00008, 0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020, -0x8f820054, 0x3c030001, 0x8c635488, 0x24420067, +0x8f820054, 0x3c030001, 0x8c635498, 0x24420067, 0x1060000d, 0xaf820058, 0x3c020001, 0x571021, 0x904283b8, 0x10400005, 0x3c030200, 0x3c010001, 0x370821, 0x8001503, 0xa02083b8, 0x8ee20000, @@ -349,7 +349,7 @@ 0x0, 0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, 0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, -0x24844a40, 0xafa00014, 0xafa20010, 0x8f8600b0, +0x24844a50, 0xafa00014, 0xafa20010, 0x8f8600b0, 0x3c050005, 0xc002407, 0x34a50900, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, @@ -377,10 +377,10 @@ 0xac820000, 0x24020001, 0xac820004, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4, 0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001, -0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a4c, +0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a5c, 0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, -0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a54, +0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a64, 0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, 0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002407, 0x34a50900, 0x80015cc, 0x0, 0x8f820104, @@ -413,7 +413,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, -0x8ee204e4, 0x3c040001, 0x24844a5c, 0xafa00014, +0x8ee204e4, 0x3c040001, 0x24844a6c, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f006, 0x16000003, 0x24020001, 0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, @@ -443,7 +443,7 @@ 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, -0x24844a68, 0xafa00014, 0xafa20010, 0x8ee6724c, +0x24844a78, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, 0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, @@ -554,11 +554,11 @@ 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x14620003, 0x3c050009, 0x800197c, 0x24100001, 0x3c040001, -0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, -0x24844a80, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a90, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x34a5f010, 0xc002407, 0x8021, -0x800197c, 0x0, 0x3c040001, 0x24844a8c, +0x800197c, 0x0, 0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, @@ -589,7 +589,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x5600000c, 0xaee90608, -0x3c040001, 0x24844a98, 0xafa00010, 0xafa00014, +0x3c040001, 0x24844aa8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x800197c, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, @@ -615,10 +615,10 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600001d, 0x24100001, 0x3c040001, -0x24844aa0, 0xafa00010, 0xafa00014, 0x8ee60608, +0x24844ab0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, -0x8ee201b0, 0x3c040001, 0x24844aac, 0xafa00014, +0x8ee201b0, 0x3c040001, 0x24844abc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, 0xc002407, 0x0, 0x8ee201ac, 0x8021, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, @@ -626,7 +626,7 @@ 0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, 0x8ee30158, 0x800198c, 0xaee27278, 0x24020001, 0x3c010001, 0x370821, 0xa02283b0, 0x3c020001, -0x8c425488, 0x10400187, 0x0, 0x8ee27b84, +0x8c425498, 0x10400187, 0x0, 0x8ee27b84, 0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84, 0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84, 0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002, @@ -690,12 +690,12 @@ 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, -0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, -0x8001aad, 0x0, 0x3c040001, 0x24844a80, +0x8001aad, 0x0, 0x3c040001, 0x24844a90, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x8001aad, 0x0, -0x3c040001, 0x24844a8c, 0xafa00014, 0x8ee60608, +0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, @@ -742,18 +742,18 @@ 0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001, 0x10400004, 0x24020001, 0xaf820064, 0x80022f4, 0x0, 0x32c20002, 0x1440000c, 0x3c050003, -0x3c040001, 0x24844b24, 0x34a50001, 0x2c03021, +0x3c040001, 0x24844b34, 0x34a50001, 0x2c03021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 0x21080, 0x5a1021, 0x8c420300, 0xafa20020, 0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, -0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b30, +0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b40, 0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, 0xc002407, 0x34a5f01f, 0x3821, 0x14e00003, 0x0, 0x80022ed, 0xaf960064, 0x93a20020, 0x2443ffff, 0x2c620011, 0x10400658, 0x31080, -0x3c010001, 0x220821, 0x8c224be8, 0x400008, +0x3c010001, 0x220821, 0x8c224bf8, 0x400008, 0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c, 0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118, 0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118, @@ -769,7 +769,7 @@ 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x8001bd0, 0xaee20078, -0x3c040001, 0x24844b3c, 0xafa00014, 0x8fa60020, +0x3c040001, 0x24844b4c, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a50004, 0x8ee20110, 0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, @@ -785,7 +785,7 @@ 0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010, 0x618c0, 0x610c0, 0x571821, 0x8c63737c, 0x571021, 0xafa30010, 0x8c427380, 0x3c040001, -0x24844b48, 0xafa20014, 0x8f470214, 0x3c050003, +0x24844b58, 0xafa20014, 0x8f470214, 0x3c050003, 0xc002407, 0x34a50013, 0x8001c90, 0x3c020800, 0x97440212, 0x771021, 0xa444737e, 0x8f440214, 0x771021, 0x2e31821, 0xac447380, 0x34028000, @@ -803,7 +803,7 @@ 0x24840001, 0x2c820080, 0x1440fff8, 0x410c0, 0x4c10023, 0x618c0, 0x910c0, 0x571821, 0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, -0x3c040001, 0x24844b54, 0xafa20014, 0x8f470214, +0x3c040001, 0x24844b64, 0xafa20014, 0x8f470214, 0x3c050003, 0xc002407, 0x34a5f017, 0x8001c90, 0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, 0x8f430214, 0xb71021, 0xac437780, 0x3c020001, @@ -878,13 +878,13 @@ 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24844b60, +0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x8001da0, -0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x8001da0, 0x0, 0x3c040001, -0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, 0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, @@ -899,7 +899,7 @@ 0x1221004, 0x21027, 0x621824, 0xaf830228, 0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e, 0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, -0x571021, 0x8c42727c, 0x3c040001, 0x24844b84, +0x571021, 0x8c42727c, 0x3c040001, 0x24844b94, 0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, 0xc002407, 0x1203021, 0x8001e83, 0x3c020800, 0xb71021, 0x9443727e, 0x97420212, 0x14620019, @@ -927,7 +927,7 @@ 0x910c0, 0x2e41821, 0x3402c000, 0x15000015, 0xa462737c, 0x910c0, 0x2e21821, 0x34028000, 0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, -0x3c040001, 0x24844b90, 0x3c050003, 0xafa20010, +0x3c040001, 0x24844ba0, 0x3c050003, 0xafa20010, 0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, 0x1203021, 0xc002407, 0xafa20014, 0x8001e83, 0x3c020800, 0x2021, 0x428c0, 0xb71021, @@ -1003,12 +1003,12 @@ 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, -0x0, 0x3c040001, 0x24844b60, 0xafa00010, +0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x8001f93, 0x0, -0x3c040001, 0x24844b6c, 0xafa00014, 0x8f860120, +0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, -0x8001f93, 0x0, 0x3c040001, 0x24844b78, +0x8001f93, 0x0, 0x3c040001, 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, @@ -1020,7 +1020,7 @@ 0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228, 0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, 0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, -0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844b98, +0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844ba8, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, 0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, @@ -1031,7 +1031,7 @@ 0x370821, 0xa02283b2, 0x8001fea, 0xaee40108, 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, -0x8001fea, 0xaee40108, 0x3c040001, 0x24844ba4, +0x8001fea, 0xaee40108, 0x3c040001, 0x24844bb4, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, @@ -1043,13 +1043,13 @@ 0x571021, 0x904283b2, 0x3c010001, 0x370821, 0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0x8002018, 0xaf820220, -0x3c040001, 0x24844bb0, 0xafa00014, 0x8fa60020, +0x3c040001, 0x24844bc0, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00b, 0x8ee20114, 0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, 0x27840208, 0x27450200, 0xc00249e, 0x24060008, 0x26e40094, 0x27450200, 0xc00249e, 0x24060008, 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, -0x8ee20134, 0x8f460248, 0x2021, 0xc004fa4, +0x8ee20134, 0x8f460248, 0x2021, 0xc004fa8, 0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, 0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, 0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, @@ -1063,7 +1063,7 @@ 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaee30108, 0x8002061, 0x2021, 0xaee40108, 0x2021, -0x3c030001, 0x641821, 0x906353e0, 0x2e41021, +0x3c030001, 0x641821, 0x906353f0, 0x2e41021, 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 0x24420030, 0xa062009c, 0x2e41021, @@ -1143,13 +1143,13 @@ 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24844b60, +0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x80021c4, -0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x80021c4, 0x0, 0x3c040001, -0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, @@ -1159,7 +1159,7 @@ 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, 0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, -0x24844bbc, 0xafa00010, 0xafa00014, 0x8fa60020, +0x24844bcc, 0xafa00010, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00f, 0x93a20020, 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, @@ -1190,7 +1190,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bc4, +0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bd4, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x80022e0, 0x0, 0x8f830120, 0x27623800, 0x24660020, @@ -1216,11 +1216,11 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, -0x0, 0x3c040001, 0x24844bcc, 0xafa00010, +0x0, 0x3c040001, 0x24844bdc, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, -0x24844bd8, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844be8, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, 0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, @@ -1247,7 +1247,7 @@ 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, -0x8f87011c, 0x3c040001, 0x24844c8c, 0xc002407, +0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002407, 0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, 0x3c020400, 0x1062002b, 0x43102b, 0x14400008, 0x3c022000, 0x3c020100, 0x10620026, 0x3c020200, @@ -1264,7 +1264,7 @@ 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, 0xafa20014, 0x8f8600a0, -0x8f87011c, 0x3c040001, 0x24844c98, 0xc002407, +0x8f87011c, 0x3c040001, 0x24844cac, 0xc002407, 0x34a5f000, 0x8f8300a0, 0x3c027f00, 0x621824, 0x3c020400, 0x10620055, 0x8021, 0x43102b, 0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, @@ -1290,43 +1290,43 @@ 0xaee2019c, 0x80023e7, 0x8ee2019c, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x0, 0x3c020001, -0x8c425408, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26105550, 0x2002021, +0x8c425418, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26105560, 0x2002021, 0xc00248c, 0x24052000, 0x26021fe0, 0x3c010001, -0xac225524, 0x3c010001, 0xac225520, 0xaf420250, +0xac225534, 0x3c010001, 0xac225530, 0xaf420250, 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, -0x3c010001, 0xac225408, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635524, +0x3c010001, 0xac225418, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635534, 0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, -0x3c020001, 0x8c425524, 0x8c830004, 0xac430004, +0x3c020001, 0x8c425534, 0x8c830004, 0xac430004, 0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010, 0xac470014, 0xac480018, 0xac49001c, 0x3c010001, -0xac235524, 0xac44000c, 0x3c020001, 0x24425550, +0xac235534, 0xac44000c, 0x3c020001, 0x24425560, 0x62182b, 0x10600005, 0x0, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, -0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x3c020001, 0x8c425400, 0xac620000, +0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400, 0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0x27bdffd0, +0x8c635534, 0x3c020001, 0x8c425400, 0x27bdffd0, 0xafb40020, 0x8fb40040, 0xafb00010, 0x808021, 0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, 0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, -0xac620000, 0x3c050001, 0x8ca55524, 0x3c020001, -0x8c4253f0, 0xc09021, 0xe09821, 0x10800006, +0xac620000, 0x3c050001, 0x8ca55534, 0x3c020001, +0x8c425400, 0xc09021, 0xe09821, 0x10800006, 0xaca20004, 0x24a50008, 0xc002494, 0x24060018, 0x8002452, 0x0, 0x24a40008, 0xc00248c, -0x24050018, 0x3c020001, 0x8c425524, 0x3c050001, -0x24a55550, 0x2442ffe0, 0x3c010001, 0xac225524, +0x24050018, 0x3c020001, 0x8c425534, 0x3c050001, +0x24a55560, 0x2442ffe0, 0x3c010001, 0xac225534, 0x45102b, 0x10400005, 0x0, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x8e020000, 0xac620000, 0x3c030001, -0x8c635524, 0x8e020004, 0xac620004, 0xac710008, -0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225524, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x8e020000, 0xac620000, 0x3c030001, +0x8c635534, 0x8e020004, 0xac620004, 0xac710008, +0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225534, 0x45102b, 0xac720010, 0xac730014, 0xac740018, 0xac75001c, 0x10400005, 0xac64000c, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, -0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x3c020001, 0x8c425400, 0xac620000, +0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400, 0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005, @@ -1372,7 +1372,7 @@ 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f114, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, 0x24480010, 0x3641021, @@ -1401,7 +1401,7 @@ 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f125, 0x34028100, 0xa5020000, 0x9582000e, 0x8002621, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, @@ -1428,7 +1428,7 @@ 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, -0x3c040001, 0x24844f00, 0x3c050004, 0xafa20014, +0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, 0x8ee37264, 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 0x8002685, 0x24e70004, 0x8f840100, 0x27623000, @@ -1454,7 +1454,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x15200009, 0x3c050004, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f004, 0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, 0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, @@ -1474,7 +1474,7 @@ 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, 0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, -0x3c040001, 0x24844f0c, 0xafa20014, 0x8fa60018, +0x3c040001, 0x24844f1c, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050004, 0xc002407, 0x34a5f005, 0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, 0x80028d7, 0xaee0725c, 0x30430003, 0x24020002, @@ -1516,7 +1516,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f014, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, @@ -1545,7 +1545,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, 0x34028100, 0xa5020000, 0x9582000e, 0x8002863, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, @@ -1572,7 +1572,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 0x80028c6, 0x24e70004, @@ -1598,7 +1598,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, -0x24844f18, 0xafab0010, 0xafa00014, 0x8ee604e4, +0x24844f28, 0xafab0010, 0xafa00014, 0x8ee604e4, 0x34a5f017, 0xc002407, 0x30e7ffff, 0x80028e5, 0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, 0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, @@ -1664,7 +1664,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000a, 0x24020001, -0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a53, 0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, 0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, @@ -1698,7 +1698,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, -0x24844f18, 0x3c050004, 0xafa90010, 0xafa00014, +0x24844f28, 0x3c050004, 0xafa90010, 0xafa00014, 0x8ee604e4, 0x34a5f237, 0xc002407, 0x30e7ffff, 0x8002a76, 0x0, 0x8ee27264, 0x451021, 0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, @@ -1722,7 +1722,7 @@ 0x8f830108, 0x21140, 0x621821, 0xaf830108, 0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013, 0x104000c1, 0x31080, 0x3c010001, 0x220821, -0x8c224f40, 0x400008, 0x0, 0x8ee204f0, +0x8c224f50, 0x400008, 0x0, 0x8ee204f0, 0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c, 0x43102b, 0x144000be, 0x0, 0x8ee304e4, 0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120, @@ -1749,7 +1749,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f006, 0x16000003, 0x24020001, 0x8002b75, 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, @@ -1770,7 +1770,7 @@ 0x8002b75, 0xaee20000, 0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, 0x8002b75, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, -0x3c040001, 0x24844f30, 0xafa60014, 0xafa20010, +0x3c040001, 0x24844f40, 0xafa60014, 0xafa20010, 0x8cc60018, 0x3c050008, 0xc002407, 0x34a50910, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, @@ -1779,7 +1779,7 @@ 0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001, 0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018, 0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf, -0x31080, 0x3c010001, 0x220821, 0x8c224f90, +0x31080, 0x3c010001, 0x220821, 0x8c224fa0, 0x400008, 0x0, 0x9663000e, 0x8ee2725c, 0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c, 0x96e20458, 0x24840001, 0xaee404f0, 0x24630001, @@ -1808,7 +1808,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, 0x1200030a, 0x240c0001, 0x8002f1d, 0x0, 0x966c001c, @@ -2002,7 +2002,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, -0x8ee204e4, 0x3c040001, 0x24844f24, 0xafa00014, +0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, 0x16000003, 0x240c0001, 0x8002f60, 0xa2ec04f4, @@ -2057,7 +2057,7 @@ 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, -0x3c040001, 0x24845040, 0xafa20014, 0x8f8600e0, +0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, 0x80034d0, 0x0, 0x8fa3001c, 0x8fb20018, 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, @@ -2155,11 +2155,11 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f003, 0x80034d0, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 0x431024, 0x8003474, 0xaee20000, @@ -2211,7 +2211,7 @@ 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, -0x3c050006, 0x8e020018, 0x3c040001, 0x24845060, +0x3c050006, 0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 0xc002407, 0xafa30014, 0x93a20037, 0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, @@ -2244,7 +2244,7 @@ 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 0x8ee6724c, 0x800343f, 0x34a5f00b, 0x3c010001, 0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, 0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, @@ -2276,7 +2276,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, -0x8ee2724c, 0x3c040001, 0x24845078, 0xafa00014, +0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, 0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, @@ -2303,7 +2303,7 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, -0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, 0x8ee20174, 0x24420001, 0xaee20174, 0x8ee20174, 0x8003472, @@ -2333,7 +2333,7 @@ 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620001d, 0x0, 0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 0x8ee6724c, 0x34a5f00d, 0xc002407, 0x2003821, 0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, @@ -2395,7 +2395,7 @@ 0x10430007, 0x4821, 0x8f8200e4, 0x24090001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24845040, 0xafa20014, +0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, 0x8003854, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, @@ -2493,15 +2493,15 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f003, 0x8003854, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 0x431024, 0x80037fc, 0xaee20000, 0x8ee25240, -0xafa20010, 0x8ee25244, 0x3c040001, 0x24845054, +0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x80037fc, 0x8ee201c0, 0x96e20468, @@ -2560,7 +2560,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x15200018, 0x3c050006, -0x8e020018, 0x3c040001, 0x24845060, 0xafa20010, +0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 0xc002407, 0xafa30014, 0x32c200ff, 0x1040002b, 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, @@ -2620,7 +2620,7 @@ 0x10430007, 0x3821, 0x8f8200e4, 0x24070001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24845084, 0xafa20014, +0x8f8200c8, 0x3c040001, 0x24845094, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f200, 0x8003c5f, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, @@ -2718,11 +2718,11 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845090, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x248450a0, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f203, 0x8003c5f, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x2484509c, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x248450ac, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f202, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8003c06, 0x8ee201c0, 0x96e20468, 0x53102b, 0x54400001, 0x3c168000, @@ -2818,7 +2818,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x14e00019, 0x3c050006, 0x3c040001, 0x24845060, +0x14e00019, 0x3c050006, 0x3c040001, 0x24845070, 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, 0x8e230004, 0x2203021, 0x1603821, 0xc002407, 0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, @@ -2882,7 +2882,7 @@ 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, 0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, -0x248450a4, 0xc002407, 0x34a5f001, 0x8003ce1, +0x248450b4, 0xc002407, 0x34a5f001, 0x8003ce1, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 0x571021, 0xac490508, @@ -2914,7 +2914,7 @@ 0x24020003, 0xac620000, 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, 0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, -0x8ee75240, 0x3c040001, 0x248450b0, 0xc002407, +0x8ee75240, 0x3c040001, 0x248450c0, 0xc002407, 0x34a5f010, 0x8003d63, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, @@ -2934,7 +2934,7 @@ 0x8f830128, 0x21140, 0x621821, 0xaf830128, 0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012, 0x10400008, 0x31080, 0x3c010001, 0x220821, -0x8c2250c0, 0x400008, 0x0, 0x24020001, +0x8c2250d0, 0x400008, 0x0, 0x24020001, 0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128, @@ -2943,7 +2943,7 @@ 0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020, 0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe, 0x2c620012, 0x1040029c, 0x31080, 0x3c010001, -0x220821, 0x8c225118, 0x400008, 0x0, +0x220821, 0x8c225128, 0x400008, 0x0, 0x8f420218, 0x30420100, 0x10400007, 0x0, 0x95830016, 0x95820018, 0x621823, 0x31402, 0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, @@ -3044,7 +3044,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x1600000d, 0x0, -0x8f820120, 0x3c040001, 0x24845108, 0xafa00014, +0x8f820120, 0x3c040001, 0x24845118, 0xafa00014, 0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, 0xc002407, 0x34a50001, 0x800405b, 0x0, 0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, @@ -3079,7 +3079,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, -0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, 0x24420001, 0xaee20188, 0x8004054, 0x8ee20188, @@ -3105,7 +3105,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x1600000b, -0x0, 0x8ee2724c, 0x3c040001, 0x24845078, +0x0, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x8ee20174, 0x24420001, 0xaee20174, 0x800405b, 0x8ee20174, @@ -3117,16 +3117,16 @@ 0xc00249e, 0xafb00010, 0x2021, 0x24100001, 0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, -0x3c010001, 0xac235474, 0x3c010001, 0xac235478, -0x3c010001, 0xac20552c, 0x3c010001, 0xac225470, -0x3c010001, 0xac235478, 0xc004fa4, 0x24050004, +0x3c010001, 0xac235484, 0x3c010001, 0xac235488, +0x3c010001, 0xac20553c, 0x3c010001, 0xac225480, +0x3c010001, 0xac235488, 0xc004fa8, 0x24050004, 0xc004784, 0x0, 0x8ee20000, 0x3c03feff, 0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, 0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, -0x248451c0, 0xc002407, 0x3821, 0x8ee20280, +0x248451d0, 0xc002407, 0x3821, 0x8ee20280, 0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, @@ -3138,16 +3138,16 @@ 0xaee20218, 0x8ee20218, 0x80040ca, 0x3c03fdff, 0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, -0x8ee20000, 0x3c040001, 0x248451cc, 0x3c050008, +0x8ee20000, 0x3c040001, 0x248451dc, 0x3c050008, 0x2003021, 0x431024, 0xaee20000, 0x8f820220, 0x3821, 0x3c030300, 0x481024, 0x431025, 0xaf820220, 0xafa00010, 0xc002407, 0xafa00014, 0x800429a, 0x0, 0x2111024, 0x1040001f, 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, -0x3c03fdff, 0x3c040001, 0x248451d8, 0x3c050008, +0x3c03fdff, 0x3c040001, 0x248451e8, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, 0xc002407, 0x3821, 0x3c03fdff, 0x8ee20000, -0x3463ffff, 0x2002021, 0x431024, 0xc004cf0, +0x3463ffff, 0x2002021, 0x431024, 0xc004cf4, 0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, 0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x8004299, 0x511025, 0x2021024, @@ -3218,7 +3218,7 @@ 0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, 0x10c4002a, 0x0, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0, -0x3c020001, 0x8c4275b0, 0x3c030008, 0x8f8600e0, +0x3c020001, 0x8c4275c0, 0x3c030008, 0x8f8600e0, 0x431024, 0x1040001d, 0x0, 0x10c4001b, 0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080, 0x24850008, 0x27622800, 0x50a20001, 0x27651800, @@ -3254,12 +3254,12 @@ 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425488, +0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425498, 0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001, -0x248451e4, 0x3c050008, 0x24020001, 0x3c010001, +0x248451f4, 0x3c050008, 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50498, 0x3c010001, 0xac205488, -0x3c010001, 0xac22547c, 0xc002407, 0x3821, +0x8f860220, 0x34a50498, 0x3c010001, 0xac205498, +0x3c010001, 0xac22548c, 0xc002407, 0x3821, 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, 0x431024, 0x30840002, 0x1080011e, 0xaee204d0, @@ -3325,24 +3325,24 @@ 0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x54620003, 0xafa00010, 0x80043da, -0x0, 0x3c040001, 0x248451f0, 0xafa00014, +0x0, 0x3c040001, 0x24845200, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x80043da, 0x0, 0x3c040001, -0x248451fc, 0xafa00014, 0x8f860120, 0x8f870124, +0x2484520c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x80043da, -0x0, 0x3c040001, 0x24845208, 0xafa00014, +0x0, 0x3c040001, 0x24845218, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, -0x3c020001, 0x8c425488, 0x27bdffe0, 0x1440000d, -0xafbf0018, 0x3c040001, 0x24845214, 0x3c050008, +0x3c020001, 0x8c425498, 0x27bdffe0, 0x1440000d, +0xafbf0018, 0x3c040001, 0x24845224, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, -0x24020001, 0x3c010001, 0xac225488, 0xc002407, +0x24020001, 0x3c010001, 0xac225498, 0xc002407, 0x3821, 0x8ee204d0, 0x3c030001, 0x771821, 0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420008, 0xaf820220, 0x2021, 0xc0050af, +0x34420008, 0xaf820220, 0x2021, 0xc0050b3, 0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -3359,7 +3359,7 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c120001, -0x26521200, 0x3c140001, 0x8e945400, 0x3c100001, +0x26521200, 0x3c140001, 0x8e945410, 0x3c100001, 0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, 0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, 0x0, 0xd, 0x0, 0x0, @@ -3420,100 +3420,100 @@ 0x1062000c, 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x8004539, 0x0, 0x10620004, 0x24020800, 0x8004539, -0x0, 0x24020700, 0x3c010001, 0xac22548c, +0x0, 0x24020700, 0x3c010001, 0xac22549c, 0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028, -0x3c010001, 0xc004ccd, 0xac205474, 0x24040001, -0x2821, 0x27a60020, 0x34028000, 0xc0048ea, +0x3c010001, 0xc004cd1, 0xac205484, 0x24040001, +0x2821, 0x27a60020, 0x34028000, 0xc0048ee, 0xa7a20020, 0x8f830054, 0x8f820054, 0x800454b, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004557, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004563, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050002, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050002, 0xc0048ac, 0x27a60018, 0x8f830054, 0x8f820054, 0x800456f, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050003, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050003, 0xc0048ac, 0x27a6001a, 0x97a20020, 0x10400027, 0x24030001, -0x3c020001, 0x8c425474, 0x97a30018, 0x34420001, -0x3c010001, 0xac225474, 0x24020015, 0x1462000d, +0x3c020001, 0x8c425484, 0x97a30018, 0x34420001, +0x3c010001, 0xac225484, 0x24020015, 0x1462000d, 0x0, 0x97a2001a, 0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, 0x621825, 0x10600005, -0x24020003, 0x3c010001, 0xac225540, 0x80045a7, +0x24020003, 0x3c010001, 0xac225550, 0x80045a7, 0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, 0x24020002, 0x97a3001a, 0x24020001, 0x14620006, -0x24020002, 0x24020004, 0x3c010001, 0xac225540, -0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225540, -0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425474, -0x3c010001, 0xac235540, 0x34420004, 0x3c010001, -0xac225474, 0x3c08fff0, 0x3508bdc0, 0x8f830054, -0x97a60018, 0x3c070001, 0x8ce75540, 0x3c040001, -0x24845280, 0x24020001, 0x3c010001, 0xac22547c, -0xafa60010, 0x3c060001, 0x8cc65474, 0x97a2001a, -0x3c05000d, 0x34a50100, 0x3c010001, 0xac205478, -0x681821, 0x3c010001, 0xac235538, 0xc002407, +0x24020002, 0x24020004, 0x3c010001, 0xac225550, +0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225550, +0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425484, +0x3c010001, 0xac235550, 0x34420004, 0x3c010001, +0xac225484, 0x3c08fff0, 0x3508bdc0, 0x8f830054, +0x97a60018, 0x3c070001, 0x8ce75550, 0x3c040001, +0x24845290, 0x24020001, 0x3c010001, 0xac22548c, +0xafa60010, 0x3c060001, 0x8cc65484, 0x97a2001a, +0x3c05000d, 0x34a50100, 0x3c010001, 0xac205488, +0x681821, 0x3c010001, 0xac235548, 0xc002407, 0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, -0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845478, +0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845488, 0x3021, 0x24020001, 0x1482000a, 0xafbf0010, -0x3c020001, 0x8c4275bc, 0x3c050004, 0x30428000, +0x3c020001, 0x8c4275cc, 0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, 0x80045da, -0x34a54240, 0x3c020001, 0x8c4275bc, 0x3c05000f, +0x34a54240, 0x3c020001, 0x8c4275cc, 0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, -0x34a58480, 0x3c020001, 0x8c425538, 0x8f830054, +0x34a58480, 0x3c020001, 0x8c425548, 0x8f830054, 0x451021, 0x431023, 0x45102b, 0x1440002e, -0x0, 0x3c020001, 0x8c425480, 0x1440002a, +0x0, 0x3c020001, 0x8c425490, 0x1440002a, 0x2cc20001, 0x7182b, 0x431024, 0x1040001d, -0x0, 0x3c090001, 0x8d295474, 0x240b0001, -0x3c054000, 0x3c080001, 0x250875bc, 0x250afffc, +0x0, 0x3c090001, 0x8d295484, 0x240b0001, +0x3c054000, 0x3c080001, 0x250875cc, 0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 0x80045ff, 0x451024, 0x8d420000, 0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, -0x42042, 0x3c010001, 0x10c00024, 0xac245478, -0x8f830054, 0x24020001, 0x3c010001, 0xac22547c, -0x3c010001, 0xac235538, 0x3c020001, 0x8c42547c, -0x10400006, 0x24020001, 0x3c010001, 0xac20547c, +0x42042, 0x3c010001, 0x10c00024, 0xac245488, +0x8f830054, 0x24020001, 0x3c010001, 0xac22548c, +0x3c010001, 0xac235548, 0x3c020001, 0x8c42548c, +0x10400006, 0x24020001, 0x3c010001, 0xac20548c, 0x3c010001, 0x370821, 0xac2283ac, 0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, 0x10620005, 0x24020001, 0xc00462f, 0x0, 0x800462c, -0x0, 0x3c030001, 0x8c635478, 0x10620007, -0x2402000e, 0x3c030001, 0x8c637550, 0x10620003, -0x0, 0xc004cf0, 0x8f840220, 0x8fbf0010, +0x0, 0x3c030001, 0x8c635488, 0x10620007, +0x2402000e, 0x3c030001, 0x8c637560, 0x10620003, +0x0, 0xc004cf4, 0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, -0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55478, -0x3c040001, 0x8c845498, 0x3442ffff, 0x621824, +0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55488, +0x3c040001, 0x8c8454a8, 0x3442ffff, 0x621824, 0x14a40008, 0xaee30000, 0x3c030001, 0x771821, -0x8c6383ac, 0x3c020001, 0x8c42549c, 0x10620008, +0x8c6383ac, 0x3c020001, 0x8c4254ac, 0x10620008, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, -0x3c010001, 0xac255498, 0x3c010001, 0xac22549c, -0x3c030001, 0x8c635478, 0x24020002, 0x10620131, +0x3c010001, 0xac2554a8, 0x3c010001, 0xac2254ac, +0x3c030001, 0x8c635488, 0x24020002, 0x10620131, 0x2c620003, 0x10400005, 0x24020001, 0x10620008, 0x0, 0x800477e, 0x0, 0x24020004, 0x10620079, 0x24020001, 0x800477f, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, 0x10400122, 0x31080, 0x3c010001, -0x220821, 0x8c225298, 0x400008, 0x0, -0xc004784, 0x0, 0x3c020001, 0x8c425484, -0x3c010001, 0xac205410, 0x104000bd, 0x24020002, +0x220821, 0x8c2252a8, 0x400008, 0x0, +0xc004784, 0x0, 0x3c020001, 0x8c425494, +0x3c010001, 0xac205420, 0x104000bd, 0x24020002, 0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, -0x8004781, 0xac205484, 0xc00492b, 0x0, -0x3c030001, 0x8c6354a0, 0x80046f0, 0x24020011, -0x3c050001, 0x8ca55478, 0x3c060001, 0x8cc675bc, -0xc004fa4, 0x2021, 0x24020005, 0x3c010001, -0xac205484, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c040001, 0x2484528c, 0x3c05000f, +0x8004781, 0xac205494, 0xc00492f, 0x0, +0x3c030001, 0x8c6354b0, 0x80046f0, 0x24020011, +0x3c050001, 0x8ca55488, 0x3c060001, 0x8cc675cc, +0xc004fa8, 0x2021, 0x24020005, 0x3c010001, +0xac205494, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x3c040001, 0x2484529c, 0x3c05000f, 0x34a50100, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x8004781, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0x8004719, 0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 0x14400090, 0x24020007, 0x8f830054, 0x3c020001, -0x8c425530, 0x2463d8f0, 0x431023, 0x2c422710, +0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000df, 0x24020001, 0x800477f, 0x0, -0x3c050001, 0x8ca55478, 0xc0050af, 0x2021, -0xc00517a, 0x2021, 0x3c030001, 0x8c6375b4, +0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, +0xc00517e, 0x2021, 0x3c030001, 0x8c6375c4, 0x46100d1, 0x24020001, 0x3c020008, 0x621024, 0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 0x431024, 0x80046bc, 0x3442251f, 0x8f820214, @@ -3524,69 +3524,69 @@ 0x3c010001, 0x370821, 0xc0043e1, 0xac2283ac, 0x8004781, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, 0x104000ac, -0x31080, 0x3c010001, 0x220821, 0x8c2252b8, +0x31080, 0x3c010001, 0x220821, 0x8c2252c8, 0x400008, 0x0, 0xc00429f, 0x0, -0x3c010001, 0xac20547c, 0xaf800204, 0x3c010001, -0xc004784, 0xac2075a0, 0x24020001, 0x3c010001, -0xac225490, 0x24020002, 0x3c010001, 0x370821, +0x3c010001, 0xac20548c, 0xaf800204, 0x3c010001, +0xc004784, 0xac2075b0, 0x24020001, 0x3c010001, +0xac2254a0, 0x24020002, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0xc004801, 0x0, -0x3c030001, 0x8c635490, 0x24020009, 0x14620090, +0x3c030001, 0x8c6354a0, 0x24020009, 0x14620090, 0x24020003, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c020001, 0x8c4275b8, 0x30424000, +0xac2283ac, 0x3c020001, 0x8c4275c8, 0x30424000, 0x10400005, 0x0, 0x8f820044, 0x3c03ffff, 0x8004701, 0x34637fff, 0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044, 0x8f830054, 0x800471b, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425530, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400074, 0x24020005, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac2075a0, +0xaf820220, 0xaf800204, 0x3c010001, 0xac2075b0, 0x8f830054, 0x24020006, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0x8004781, 0xac235530, -0x8f830054, 0x3c020001, 0x8c425530, 0x2463fff6, +0xac2283ac, 0x3c010001, 0x8004781, 0xac235540, +0x8f830054, 0x3c020001, 0x8c425540, 0x2463fff6, 0x431023, 0x2c42000a, 0x14400059, 0x0, 0x24020007, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0x8f820220, 0x3c04f700, 0x441025, 0xaf820220, 0x8f820220, 0x3c030300, 0x431024, 0x14400005, 0x1821, 0x8f820220, 0x24030001, 0x441025, 0xaf820220, 0x10600043, 0x24020001, -0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845528, +0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845538, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x3c010001, 0x370821, 0x1080000b, 0xac2283ac, -0x3c020001, 0x8c425504, 0x14400007, 0x24020001, -0x3c010001, 0xac227550, 0xc004cf0, 0x8f840220, +0x3c020001, 0x8c425514, 0x14400007, 0x24020001, +0x3c010001, 0xac227560, 0xc004cf4, 0x8f840220, 0x800476e, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x14400017, 0x2402000e, 0x3c010001, -0xac227550, 0x8ee20000, 0x2021, 0x3c030200, -0x431025, 0xc00517a, 0xaee20000, 0x8f820220, +0xac227560, 0x8ee20000, 0x2021, 0x3c030200, +0x431025, 0xc00517e, 0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xc0043e1, 0xaf820220, 0x3c050001, -0x8ca55478, 0xc0050af, 0x2021, 0x8004781, -0x0, 0x3c020001, 0x8c425504, 0x10400010, -0x0, 0x3c020001, 0x8c425500, 0x2442ffff, -0x3c010001, 0xac225500, 0x14400009, 0x24020002, -0x3c010001, 0xac205504, 0x3c010001, 0x8004781, -0xac225500, 0x24020001, 0x3c010001, 0xac22547c, +0x8ca55488, 0xc0050b3, 0x2021, 0x8004781, +0x0, 0x3c020001, 0x8c425514, 0x10400010, +0x0, 0x3c020001, 0x8c425510, 0x2442ffff, +0x3c010001, 0xac225510, 0x14400009, 0x24020002, +0x3c010001, 0xac205514, 0x3c010001, 0x8004781, +0xac225510, 0x24020001, 0x3c010001, 0xac22548c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c060001, 0x8cc65478, 0x34420004, +0x8f820200, 0x3c060001, 0x8cc65488, 0x34420004, 0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001, 0x10c20008, 0x0, 0x80047ca, 0x0, 0x24020004, 0x10c20013, 0x24020001, 0x80047ca, 0x0, 0x3c030001, -0x8c635468, 0x3c020001, 0x8c425470, 0x3c040001, -0x8c84548c, 0x3c050001, 0x8ca5546c, 0xaf860200, +0x8c635478, 0x3c020001, 0x8c425480, 0x3c040001, +0x8c84549c, 0x3c050001, 0x8ca5547c, 0xaf860200, 0xaf860220, 0x34630022, 0x441025, 0x451025, 0x34420002, 0x80047c9, 0xaf830200, 0x3c030001, -0x8c635528, 0xaf820200, 0x10600009, 0xaf820220, -0x3c020001, 0x8c425504, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c425460, 0x80047bd, 0x346300e0, -0x3c020001, 0x8c425460, 0x3c033f00, 0x346300e2, -0x431025, 0xaf820200, 0x3c030001, 0x8c635464, -0x3c04f700, 0x3c020001, 0x8c425470, 0x3c050001, -0x8ca5548c, 0x641825, 0x431025, 0x451025, +0x8c635538, 0xaf820200, 0x10600009, 0xaf820220, +0x3c020001, 0x8c425514, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c425470, 0x80047bd, 0x346300e0, +0x3c020001, 0x8c425470, 0x3c033f00, 0x346300e2, +0x431025, 0xaf820200, 0x3c030001, 0x8c635474, +0x3c04f700, 0x3c020001, 0x8c425480, 0x3c050001, +0x8ca5549c, 0x641825, 0x431025, 0x451025, 0xaf820220, 0x3e00008, 0x0, 0x8f820220, -0x3c030001, 0x8c635478, 0x34420004, 0xaf820220, +0x3c030001, 0x8c635488, 0x34420004, 0xaf820220, 0x24020001, 0x1062000f, 0x0, 0x8f830054, 0x8f820054, 0x24630002, 0x621023, 0x2c420003, 0x10400011, 0x0, 0x8f820054, 0x621023, @@ -3599,19 +3599,19 @@ 0x2c420033, 0x10400004, 0x0, 0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, 0x431024, 0xaf820220, 0x3e00008, 0x0, -0x3c030001, 0x8c635490, 0x3c020001, 0x8c425494, -0x50620004, 0x2463ffff, 0x3c010001, 0xac235494, -0x2463ffff, 0x2c620009, 0x10400099, 0x31080, -0x3c010001, 0x220821, 0x8c2252d8, 0x400008, +0x3c030001, 0x8c6354a0, 0x3c020001, 0x8c4254a4, +0x50620004, 0x2463ffff, 0x3c010001, 0xac2354a4, +0x2463ffff, 0x2c620009, 0x1040009d, 0x31080, +0x3c010001, 0x220821, 0x8c2252e8, 0x400008, 0x0, 0x8f820044, 0x34428080, 0xaf820044, -0x8f830054, 0x8004896, 0x24020002, 0x8f830054, -0x3c020001, 0x8c425534, 0x2463d8f0, 0x431023, -0x2c422710, 0x14400086, 0x24020003, 0x80048a3, +0x8f830054, 0x800489a, 0x24020002, 0x8f830054, +0x3c020001, 0x8c425544, 0x2463d8f0, 0x431023, +0x2c422710, 0x1440008a, 0x24020003, 0x80048a7, 0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, -0x431024, 0xaf820044, 0x8f830054, 0x8004896, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425534, -0x2463fff6, 0x431023, 0x2c42000a, 0x14400074, -0x24020005, 0x80048a3, 0x0, 0x8f820220, +0x431024, 0xaf820044, 0x8f830054, 0x800489a, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425544, +0x2463fff6, 0x431023, 0x2c42000a, 0x14400078, +0x24020005, 0x80048a7, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, @@ -3629,529 +3629,530 @@ 0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008, 0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, -0x24425420, 0xac820000, 0xac830004, 0xaf8500f0, -0x8f830054, 0x8004896, 0x24020006, 0x8f830054, -0x3c020001, 0x8c425534, 0x2463fff6, 0x431023, -0x2c42000a, 0x1440001e, 0x24020007, 0x80048a3, +0x24425430, 0xac820000, 0xac830004, 0xaf8500f0, +0x8f830054, 0x800489a, 0x24020006, 0x8f830054, +0x3c020001, 0x8c425544, 0x2463fff6, 0x431023, +0x2c42000a, 0x14400022, 0x24020007, 0x80048a7, 0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820220, 0x2403fff7, 0x431024, 0xaf820220, 0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, -0x24020008, 0x3c010001, 0xac225490, 0x3c010001, -0x80048a5, 0xac235534, 0x8f830054, 0x3c020001, -0x8c425534, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020009, 0x3c010001, 0xac225490, +0x24020008, 0x3c010001, 0xac2254a0, 0x3c010001, +0x80048a9, 0xac235544, 0x8f830054, 0x3c020001, +0x8c425544, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020009, 0x3c010001, 0xac2254a0, 0x3e00008, 0x0, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc004ca7, 0x24040001, +0xafbf0020, 0xa6200000, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004ca7, 0x2021, 0xc004ca7, 0x24040001, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x2021, 0xc004cab, 0x24040001, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fffa, +0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fffa, 0x2701024, 0xc004ccd, 0x34108000, -0xc004ccd, 0x0, 0xc004c87, 0x0, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fffa, 0x2701024, 0xc004cd1, 0x34108000, +0xc004cd1, 0x0, 0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004ccd, 0x0, 0x8fbf0020, 0x8fb3001c, +0xc004cd1, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc004ca7, +0xafb00010, 0x8021, 0xafbf0020, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x2501024, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x2501024, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8fbf0020, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354a0, -0x3c020001, 0x8c4254e4, 0x27bdffd8, 0xafbf0020, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354b0, +0x3c020001, 0x8c4254f4, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac2354e4, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c225300, -0x400008, 0x0, 0xc004ccd, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc004ca7, +0xac2354f4, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c225310, +0x400008, 0x0, 0xc004cd1, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc004ca7, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc004cab, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8004c80, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc004ca7, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004ca7, -0x2021, 0xc004ca7, 0x24040001, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x24100010, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8004c84, 0x24020002, 0x27b10010, 0xa7a00010, +0x8021, 0xc004cab, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc004cab, +0x2021, 0xc004cab, 0x24040001, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004ca7, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc004ccd, 0x34108000, -0xc004ccd, 0x0, 0xc004c87, 0x0, +0xc004cab, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc004cab, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc004cd1, 0x34108000, +0xc004cd1, 0x0, 0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004ccd, 0x0, 0x97a20010, 0x30428000, -0x144002dc, 0x24020003, 0x8004c80, 0x0, +0xc004cd1, 0x0, 0x97a20010, 0x30428000, +0x144002dc, 0x24020003, 0x8004c84, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc004ca7, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc004ca7, 0x24040001, 0xc004ca7, +0xc004cab, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fff8, 0x0, 0xc004ccd, -0x0, 0x8f830054, 0x8004c72, 0x24020004, -0x8f830054, 0x3c020001, 0x8c42553c, 0x2463ff9c, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fff8, 0x0, 0xc004cd1, +0x0, 0x8f830054, 0x8004c76, 0x24020004, +0x8f830054, 0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c635540, 0x10620297, 0x2c620003, +0x3c030001, 0x8c635550, 0x10620297, 0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, -0x24020004, 0x10620291, 0x2402000f, 0x8004c80, -0x24020011, 0x8004c80, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x24020004, 0x10620291, 0x2402000f, 0x8004c84, +0x24020011, 0x8004c84, 0x24020005, 0x24020014, +0xa7a20010, 0x27b10010, 0x8021, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x32020012, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x32020012, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8f830054, -0x8004c72, 0x24020006, 0x8f830054, 0x3c020001, -0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400250, 0x24020007, 0x8004c80, 0x0, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8f830054, +0x8004c76, 0x24020006, 0x8f830054, 0x3c020001, +0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400250, 0x24020007, 0x8004c84, 0x0, 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020013, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020013, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x24020008, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440020f, 0x24020009, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x24020008, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440020f, 0x24020009, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440019b, 0x2402000b, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000a, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440019b, 0x2402000b, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020017, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020017, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400127, 0x24020012, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000c, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x14400127, 0x24020012, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020014, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020014, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x24020013, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x144000b3, 0x2402000d, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x24020013, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x144000b3, 0x2402000d, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000e, 0x24020840, +0xa7a20010, 0x27b10010, 0x8021, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x32020013, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x32020013, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac2254a0, 0x3c010001, -0x8004c82, 0xac23553c, 0x8f830054, 0x3c020001, -0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac2254b0, 0x3c010001, +0x8004c86, 0xac23554c, 0x8f830054, 0x3c020001, +0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac2254a0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0xac2254b0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, -0x8f840054, 0x8f820054, 0xa32824, 0x8004c93, +0x8f840054, 0x8f820054, 0xa32824, 0x8004c97, 0x24840001, 0x8f820054, 0x821023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004ca1, 0x24630001, 0x8f820054, +0x8f820054, 0x8004ca5, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, 0x3c020002, 0x822025, 0x641825, 0xaf830044, 0x8f820044, 0x3c030001, 0x431025, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004cb9, 0x24630001, 0x8f820054, +0x8f820054, 0x8004cbd, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004cc7, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004ccb, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, 0xaf820044, 0x8f820044, 0x3c030001, 0x431025, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdb, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdf, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004ce9, 0x24630001, 0x8f820054, +0x8f820054, 0x8004ced, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, 0x1462022c, 0x803021, 0x3c020001, -0x8c425528, 0x14400033, 0x0, 0x8f850224, +0x8c425538, 0x14400033, 0x0, 0x8f850224, 0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001, 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 0x38a20400, 0x2c420001, 0x621825, 0x14600007, 0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, 0x621825, 0x10600005, 0x0, 0xc00429f, -0x0, 0x8004d29, 0x2402000e, 0xc0043e1, -0x0, 0x3c050001, 0x8ca55478, 0xc0050af, -0x2021, 0x3c030001, 0x8c635478, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c425474, -0x8004d25, 0x2403fff7, 0x3c020001, 0x8c425474, -0x431024, 0x3c010001, 0xac225474, 0x2402000e, -0x3c010001, 0xc00429f, 0xac227550, 0x8004f23, +0x0, 0x8004d2d, 0x2402000e, 0xc0043e1, +0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, +0x2021, 0x3c030001, 0x8c635488, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484, +0x8004d29, 0x2403fff7, 0x3c020001, 0x8c425484, +0x431024, 0x3c010001, 0xac225484, 0x2402000e, +0x3c010001, 0xc00429f, 0xac227560, 0x8004f27, 0x0, 0x8f820220, 0x3c030400, 0x431024, 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, -0x8c42755c, 0xa32024, 0x431024, 0x1482000c, -0x0, 0x3c020001, 0x8c427560, 0x24420001, -0x3c010001, 0xac227560, 0x2c420002, 0x14400008, -0x24020001, 0x3c010001, 0x8004d49, 0xac227580, -0x3c010001, 0xac207560, 0x3c010001, 0xac207580, -0x3c020001, 0x8c427580, 0x10400006, 0x30a20040, -0x10400004, 0x24020001, 0x3c010001, 0x8004d54, -0xac227584, 0x3c010001, 0xac207584, 0x3c010001, -0xac25755c, 0x3c010001, 0x8004d64, 0xac207590, -0x24020001, 0x3c010001, 0xac227590, 0x3c010001, -0xac207580, 0x3c010001, 0xac207560, 0x3c010001, -0xac207584, 0x3c010001, 0xac20755c, 0x3c030001, -0x8c637550, 0x3c020001, 0x8c427554, 0x10620003, -0x3c020200, 0x3c010001, 0xac237554, 0xc21024, +0x8c42756c, 0xa32024, 0x431024, 0x1482000c, +0x0, 0x3c020001, 0x8c427570, 0x24420001, +0x3c010001, 0xac227570, 0x2c420002, 0x14400008, +0x24020001, 0x3c010001, 0x8004d4d, 0xac227590, +0x3c010001, 0xac207570, 0x3c010001, 0xac207590, +0x3c020001, 0x8c427590, 0x10400006, 0x30a20040, +0x10400004, 0x24020001, 0x3c010001, 0x8004d58, +0xac227594, 0x3c010001, 0xac207594, 0x3c010001, +0xac25756c, 0x3c010001, 0x8004d68, 0xac2075a0, +0x24020001, 0x3c010001, 0xac2275a0, 0x3c010001, +0xac207590, 0x3c010001, 0xac207570, 0x3c010001, +0xac207594, 0x3c010001, 0xac20756c, 0x3c030001, +0x8c637560, 0x3c020001, 0x8c427564, 0x10620003, +0x3c020200, 0x3c010001, 0xac237564, 0xc21024, 0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, -0x3c010001, 0xac23547c, 0x8004f21, 0x3c03f700, +0x3c010001, 0xac23548c, 0x8004f25, 0x3c03f700, 0x2c62000e, 0x104001a8, 0x31080, 0x3c010001, -0x220821, 0x8c225350, 0x400008, 0x0, -0x3c010001, 0xac207580, 0x3c010001, 0xac207560, -0x3c010001, 0xac20755c, 0x3c010001, 0xac207584, -0x3c010001, 0xac207578, 0x3c010001, 0xac207570, +0x220821, 0x8c225360, 0x400008, 0x0, +0x3c010001, 0xac207590, 0x3c010001, 0xac207570, +0x3c010001, 0xac20756c, 0x3c010001, 0xac207594, +0x3c010001, 0xac207588, 0x3c010001, 0xac207580, 0xc0047cc, 0xaf800224, 0x24020002, 0x3c010001, -0xac227550, 0x3c020001, 0x8c427590, 0x14400056, +0xac227560, 0x3c020001, 0x8c4275a0, 0x14400056, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 0xc00429f, 0xaee20000, 0xaf800204, 0x8f820200, 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, -0xac2075a0, 0x8f830054, 0x3c020001, 0x8c427578, -0x24040001, 0x3c010001, 0xac24758c, 0x24420001, -0x3c010001, 0xac227578, 0x2c420004, 0x3c010001, -0xac237574, 0x14400006, 0x24020003, 0x3c010001, -0xac24547c, 0x3c010001, 0x8004f1f, 0xac207578, -0x3c010001, 0x8004f1f, 0xac227550, 0x8f830054, -0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0xac2075b0, 0x8f830054, 0x3c020001, 0x8c427588, +0x24040001, 0x3c010001, 0xac24759c, 0x24420001, +0x3c010001, 0xac227588, 0x2c420004, 0x3c010001, +0xac237584, 0x14400006, 0x24020003, 0x3c010001, +0xac24548c, 0x3c010001, 0x8004f23, 0xac207588, +0x3c010001, 0x8004f23, 0xac227560, 0x8f830054, +0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, 0x24020004, 0x3c010001, -0xac227550, 0x3c020001, 0x8c427590, 0x14400026, +0xac227560, 0x3c020001, 0x8c4275a0, 0x14400026, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, -0x8004f1f, 0xaee20000, 0x3c040001, 0x8c84552c, -0x3c010001, 0xc004f26, 0xac207568, 0x3c020001, -0x8c42759c, 0xaf820204, 0x3c020001, 0x8c427590, +0x8004f23, 0xaee20000, 0x3c040001, 0x8c84553c, +0x3c010001, 0xc004f2a, 0xac207578, 0x3c020001, +0x8c4275ac, 0xaf820204, 0x3c020001, 0x8c4275a0, 0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 0xaee20000, 0x8f820204, 0x30420030, -0x1440013c, 0x24020002, 0x3c030001, 0x8c63759c, -0x24020005, 0x3c010001, 0xac227550, 0x3c010001, -0x8004f1f, 0xac2375a0, 0x3c020001, 0x8c427590, -0x10400010, 0x3c03fdff, 0x3c020001, 0x8c4254fc, -0x24420001, 0x3c010001, 0xac2254fc, 0x2c420002, -0x14400131, 0x24020001, 0x3c010001, 0xac225504, -0x3c010001, 0xac2054fc, 0x3c010001, 0x8004f1f, -0xac22547c, 0x8ee20000, 0x3463ffff, 0x431024, -0xaee20000, 0x3c020001, 0x8c427580, 0x10400122, -0x0, 0x3c020001, 0x8c42755c, 0x1040011e, -0x0, 0x3c010001, 0xac227588, 0x24020003, -0x3c010001, 0xac227560, 0x8004ec0, 0x24020006, -0x3c010001, 0xac207568, 0x8f820204, 0x34420040, -0xaf820204, 0x3c020001, 0x8c4275a0, 0x24030007, -0x3c010001, 0xac237550, 0x34420040, 0x3c010001, -0xac2275a0, 0x3c020001, 0x8c427580, 0x10400005, -0x0, 0x3c020001, 0x8c42755c, 0x104000f9, -0x24020002, 0x3c050001, 0x24a57560, 0x8ca20000, +0x1440013c, 0x24020002, 0x3c030001, 0x8c6375ac, +0x24020005, 0x3c010001, 0xac227560, 0x3c010001, +0x8004f23, 0xac2375b0, 0x3c020001, 0x8c4275a0, +0x10400010, 0x3c03fdff, 0x3c020001, 0x8c42550c, +0x24420001, 0x3c010001, 0xac22550c, 0x2c420002, +0x14400131, 0x24020001, 0x3c010001, 0xac225514, +0x3c010001, 0xac20550c, 0x3c010001, 0x8004f23, +0xac22548c, 0x8ee20000, 0x3463ffff, 0x431024, +0xaee20000, 0x3c020001, 0x8c427590, 0x10400122, +0x0, 0x3c020001, 0x8c42756c, 0x1040011e, +0x0, 0x3c010001, 0xac227598, 0x24020003, +0x3c010001, 0xac227570, 0x8004ec4, 0x24020006, +0x3c010001, 0xac207578, 0x8f820204, 0x34420040, +0xaf820204, 0x3c020001, 0x8c4275b0, 0x24030007, +0x3c010001, 0xac237560, 0x34420040, 0x3c010001, +0xac2275b0, 0x3c020001, 0x8c427590, 0x10400005, +0x0, 0x3c020001, 0x8c42756c, 0x104000f9, +0x24020002, 0x3c050001, 0x24a57570, 0x8ca20000, 0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001, -0x8c427584, 0x104000f8, 0x2404ffbf, 0x3c020001, -0x8c42755c, 0x3c030001, 0x8c637588, 0x441024, +0x8c427594, 0x104000f8, 0x2404ffbf, 0x3c020001, +0x8c42756c, 0x3c030001, 0x8c637598, 0x441024, 0x641824, 0x10430004, 0x24020001, 0x3c010001, -0x8004f1f, 0xac227550, 0x24020003, 0xaca20000, -0x24020008, 0x3c010001, 0xac227550, 0x3c020001, -0x8c42758c, 0x1040000c, 0x24020001, 0x3c040001, -0xc004f33, 0x8c84755c, 0x3c020001, 0x8c4275a8, -0x14400005, 0x24020001, 0x3c020001, 0x8c4275a4, -0x10400006, 0x24020001, 0x3c010001, 0xac22547c, -0x3c010001, 0x8004f1f, 0xac207578, 0x3c020001, -0x8c427570, 0x3c030001, 0x8c63755c, 0x2c420001, -0x210c0, 0x30630008, 0x3c010001, 0xac227570, -0x3c010001, 0xac23756c, 0x8f830054, 0x24020009, -0x3c010001, 0xac227550, 0x3c010001, 0x8004f1f, -0xac237574, 0x8f830054, 0x3c020001, 0x8c427574, +0x8004f23, 0xac227560, 0x24020003, 0xaca20000, +0x24020008, 0x3c010001, 0xac227560, 0x3c020001, +0x8c42759c, 0x1040000c, 0x24020001, 0x3c040001, +0xc004f37, 0x8c84756c, 0x3c020001, 0x8c4275b8, +0x14400005, 0x24020001, 0x3c020001, 0x8c4275b4, +0x10400006, 0x24020001, 0x3c010001, 0xac22548c, +0x3c010001, 0x8004f23, 0xac207588, 0x3c020001, +0x8c427580, 0x3c030001, 0x8c63756c, 0x2c420001, +0x210c0, 0x30630008, 0x3c010001, 0xac227580, +0x3c010001, 0xac23757c, 0x8f830054, 0x24020009, +0x3c010001, 0xac227560, 0x3c010001, 0x8004f23, +0xac237584, 0x8f830054, 0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8, -0x0, 0x3c020001, 0x8c427580, 0x10400005, -0x0, 0x3c020001, 0x8c42755c, 0x104000a9, -0x24020002, 0x3c030001, 0x24637560, 0x8c620000, +0x0, 0x3c020001, 0x8c427590, 0x10400005, +0x0, 0x3c020001, 0x8c42756c, 0x104000a9, +0x24020002, 0x3c030001, 0x24637570, 0x8c620000, 0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001, -0x8c42758c, 0x1040000e, 0x0, 0x3c020001, -0x8c42755c, 0x3c010001, 0xac20758c, 0x30420080, +0x8c42759c, 0x1040000e, 0x0, 0x3c020001, +0x8c42756c, 0x3c010001, 0xac20759c, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, -0x1440000c, 0x24020003, 0x8004ead, 0x2402000c, -0x3c020001, 0x8c42755c, 0x30420080, 0x14400005, +0x1440000c, 0x24020003, 0x8004eb1, 0x2402000c, +0x3c020001, 0x8c42756c, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, 0xac620000, 0x2402000a, 0x3c010001, -0xac227550, 0x3c040001, 0x24847598, 0x8c820000, -0x3c030001, 0x8c637570, 0x431025, 0xaf820204, -0x8c830000, 0x3c040001, 0x8c847570, 0x2402000b, -0x3c010001, 0xac227550, 0x641825, 0x3c010001, -0xac2375a0, 0x3c050001, 0x24a57560, 0x8ca20000, +0xac227560, 0x3c040001, 0x248475a8, 0x8c820000, +0x3c030001, 0x8c637580, 0x431025, 0xaf820204, +0x8c830000, 0x3c040001, 0x8c847580, 0x2402000b, +0x3c010001, 0xac227560, 0x641825, 0x3c010001, +0xac2375b0, 0x3c050001, 0x24a57570, 0x8ca20000, 0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001, -0x8c427590, 0x10400005, 0x0, 0x2402000c, -0x3c010001, 0x8004f1f, 0xac227550, 0x3c020001, -0x8c427580, 0x1040006c, 0x0, 0x3c040001, -0x8c84755c, 0x1080005e, 0x30820008, 0x3c030001, -0x8c63756c, 0x10620064, 0x24020003, 0x3c010001, -0xac247588, 0xaca20000, 0x24020006, 0x3c010001, -0x8004f1f, 0xac227550, 0x8f820200, 0x34420002, +0x8c4275a0, 0x10400005, 0x0, 0x2402000c, +0x3c010001, 0x8004f23, 0xac227560, 0x3c020001, +0x8c427590, 0x1040006c, 0x0, 0x3c040001, +0x8c84756c, 0x1080005e, 0x30820008, 0x3c030001, +0x8c63757c, 0x10620064, 0x24020003, 0x3c010001, +0xac247598, 0xaca20000, 0x24020006, 0x3c010001, +0x8004f23, 0xac227560, 0x8f820200, 0x34420002, 0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, -0xac227550, 0x3c010001, 0xac237574, 0x8f830054, -0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0xac227560, 0x3c010001, 0xac237584, 0x8f830054, +0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440003a, 0x0, 0x3c020001, -0x8c427590, 0x10400029, 0x2402000e, 0x3c030001, -0x8c6375a4, 0x3c010001, 0x14600015, 0xac227550, -0xc0043e1, 0x0, 0x3c050001, 0x8ca55478, -0xc0050af, 0x2021, 0x3c030001, 0x8c635478, +0x8c4275a0, 0x10400029, 0x2402000e, 0x3c030001, +0x8c6375b4, 0x3c010001, 0x14600015, 0xac227560, +0xc0043e1, 0x0, 0x3c050001, 0x8ca55488, +0xc0050b3, 0x2021, 0x3c030001, 0x8c635488, 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, -0x8c425474, 0x8004eee, 0x2403fff7, 0x3c020001, -0x8c425474, 0x431024, 0x3c010001, 0xac225474, +0x8c425484, 0x8004ef2, 0x2403fff7, 0x3c020001, +0x8c425484, 0x431024, 0x3c010001, 0xac225484, 0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, -0x8f820224, 0x3c010001, 0xac2275ac, 0x8f820220, +0x8f820224, 0x3c010001, 0xac2275bc, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0x8004f1f, 0xaf820220, 0x3c020001, -0x8c427580, 0x10400005, 0x0, 0x3c020001, -0x8c42755c, 0x1040000f, 0x24020002, 0x3c020001, -0x8c427560, 0x2c424e21, 0x1040000a, 0x24020002, -0x3c020001, 0x8c427580, 0x1040000f, 0x0, -0x3c020001, 0x8c42755c, 0x1440000b, 0x0, -0x24020002, 0x3c010001, 0x8004f1f, 0xac227550, -0x3c020001, 0x8c427580, 0x10400003, 0x0, +0x34420002, 0x8004f23, 0xaf820220, 0x3c020001, +0x8c427590, 0x10400005, 0x0, 0x3c020001, +0x8c42756c, 0x1040000f, 0x24020002, 0x3c020001, +0x8c427570, 0x2c424e21, 0x1040000a, 0x24020002, +0x3c020001, 0x8c427590, 0x1040000f, 0x0, +0x3c020001, 0x8c42756c, 0x1440000b, 0x0, +0x24020002, 0x3c010001, 0x8004f23, 0xac227560, +0x3c020001, 0x8c427590, 0x10400003, 0x0, 0xc00429f, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x3c030001, 0x246375a8, 0x8c620000, -0x10400005, 0x34422000, 0x3c010001, 0xac22759c, -0x8004f31, 0xac600000, 0x3c010001, 0xac24759c, +0x27bd0018, 0x3c030001, 0x246375b8, 0x8c620000, +0x10400005, 0x34422000, 0x3c010001, 0xac2275ac, +0x8004f35, 0xac600000, 0x3c010001, 0xac2475ac, 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, -0xafbf0018, 0x3c010001, 0xac2275a4, 0x14400067, +0xafbf0018, 0x3c010001, 0xac2275b4, 0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 0x21200, 0x3c040001, -0x8c84552c, 0x621825, 0x331c2, 0x3c030001, -0x24635508, 0x30828000, 0x21202, 0x30840001, +0x8c84553c, 0x621825, 0x331c2, 0x3c030001, +0x24635518, 0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, 0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, 0x0, 0x10600007, 0x24020002, 0x10620013, 0x24020003, 0x1062002c, 0x3c05000f, -0x8004f95, 0x0, 0x8f820200, 0x2403feff, +0x8004f99, 0x0, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 0x3c010001, -0xac2075c4, 0x3c010001, 0x8004fa0, 0xac2075cc, +0xac2075d4, 0x3c010001, 0x8004fa4, 0xac2075dc, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x24020100, 0x3c010001, 0xac2275c4, 0x3c010001, -0x8004fa0, 0xac2075cc, 0x8f820200, 0x2403feff, +0x24020100, 0x3c010001, 0xac2275d4, 0x3c010001, +0x8004fa4, 0xac2075dc, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, -0x431025, 0xaf820220, 0x3c010001, 0xac2075c4, -0x3c010001, 0x8004fa0, 0xac2375cc, 0x8f820200, +0x431025, 0xaf820220, 0x3c010001, 0xac2075d4, +0x3c010001, 0x8004fa4, 0xac2375dc, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 0x24020100, 0x3c010001, -0xac2275c4, 0x3c010001, 0x8004fa0, 0xac2375cc, -0x34a5ffff, 0x3c040001, 0x24845388, 0xafa30010, -0xc002407, 0xafa00014, 0x8004fa0, 0x0, -0x24020030, 0x3c010001, 0xac2275a8, 0x8fbf0018, +0xac2275d4, 0x3c010001, 0x8004fa4, 0xac2375dc, +0x34a5ffff, 0x3c040001, 0x24845398, 0xafa30010, +0xc002407, 0xafa00014, 0x8004fa4, 0x0, +0x24020030, 0x3c010001, 0xac2275b8, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x248453a0, -0x3c050009, 0x3c020001, 0x8c425478, 0x34a59001, +0xafb00020, 0xc08021, 0x3c040001, 0x248453b0, +0x3c050009, 0x3c020001, 0x8c425488, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, 0xa7a0001a, 0xafb00014, 0xc002407, 0xafa20010, 0x24020002, 0x126200ed, 0x2e620003, 0x10400005, -0x24020001, 0x1262000a, 0x3c02fffb, 0x80050a8, +0x24020001, 0x1262000a, 0x3c02fffb, 0x80050ac, 0x0, 0x24020004, 0x1262006d, 0x24020008, -0x1262006c, 0x3c02ffec, 0x80050a8, 0x0, +0x1262006c, 0x3c02ffec, 0x80050ac, 0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, -0x320821, 0xac3075bc, 0x3c024000, 0x2021024, +0x320821, 0xac3075cc, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, 0x101382, -0x3042000c, 0x3c030001, 0x246354a4, 0x431021, +0x3042000c, 0x3c030001, 0x246354b4, 0x431021, 0x823821, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010001, 0x320821, 0xac2275c0, -0x8004fe7, 0x3c020080, 0x3c010001, 0x320821, -0xac2075c0, 0x3c020080, 0x2021024, 0x10400006, +0x24020100, 0x3c010001, 0x320821, 0xac2275d0, +0x8004feb, 0x3c020080, 0x3c010001, 0x320821, +0xac2075d0, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x8004ff3, 0xac2275c8, 0x111140, 0x3c010001, -0x220821, 0xac2075c8, 0x94e30000, 0x32024000, +0x8004ff7, 0xac2275d8, 0x111140, 0x3c010001, +0x220821, 0xac2075d8, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, -0x34420001, 0xc0048ea, 0xa4e20002, 0x24040001, -0x2821, 0xc0048ea, 0x27a60018, 0x3c020001, -0x8c425478, 0x24110001, 0x3c010001, 0xac315484, +0x34420001, 0xc0048ee, 0xa4e20002, 0x24040001, +0x2821, 0xc0048ee, 0x27a60018, 0x3c020001, +0x8c425488, 0x24110001, 0x3c010001, 0xac315494, 0x14530004, 0x32028000, 0xc00429f, 0x0, 0x32028000, 0x10400099, 0x0, 0xc00429f, -0x0, 0x24020002, 0x3c010001, 0xac31547c, -0x3c010001, 0x80050a8, 0xac225478, 0x24040001, -0x24050004, 0x27b0001a, 0xc0048ea, 0x2003021, -0x24040001, 0x2821, 0xc0048ea, 0x2003021, -0x3c020001, 0x521021, 0x8c4275b4, 0x3c040001, -0x8c845478, 0x3c03bfff, 0x3463ffff, 0x3c010001, -0xac335484, 0x431024, 0x3c010001, 0x320821, -0x10930078, 0xac2275b4, 0x80050a8, 0x0, +0x0, 0x24020002, 0x3c010001, 0xac31548c, +0x3c010001, 0x80050ac, 0xac225488, 0x24040001, +0x24050004, 0x27b0001a, 0xc0048ee, 0x2003021, +0x24040001, 0x2821, 0xc0048ee, 0x2003021, +0x3c020001, 0x521021, 0x8c4275c4, 0x3c040001, +0x8c845488, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac335494, 0x431024, 0x3c010001, 0x320821, +0x10930078, 0xac2275c4, 0x80050ac, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, -0xac3075b8, 0x3c022000, 0x2021024, 0x10400009, -0x0, 0x3c020001, 0x8c425504, 0x14400005, -0x24020001, 0x3c010001, 0xac225528, 0x8005049, -0x3c024000, 0x3c010001, 0xac205528, 0x3c024000, +0xac3075c8, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c425514, 0x14400005, +0x24020001, 0x3c010001, 0xac225538, 0x800504d, +0x3c024000, 0x3c010001, 0xac205538, 0x3c024000, 0x2021024, 0x1440001c, 0x0, 0x3c020001, -0x8c425528, 0x10400007, 0x24022020, 0x3c010001, -0xac22552c, 0x24020001, 0x3c010001, 0x370821, +0x8c425538, 0x10400007, 0x24022020, 0x3c010001, +0xac22553c, 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 0x3c04bfff, 0x111940, 0x3c020001, -0x431021, 0x8c4275b0, 0x3c050001, 0x8ca55478, +0x431021, 0x8c4275c0, 0x3c050001, 0x8ca55488, 0x3484ffff, 0x441024, 0x3c010001, 0x230821, -0xac2275b0, 0x24020001, 0x10a20044, 0x0, -0x80050a6, 0x0, 0x3c020001, 0x8c425528, -0x1040001c, 0x24022000, 0x3c010001, 0xac22552c, +0xac2275c0, 0x24020001, 0x10a20044, 0x0, +0x80050aa, 0x0, 0x3c020001, 0x8c425538, +0x1040001c, 0x24022000, 0x3c010001, 0xac22553c, 0x3c0300a0, 0x2031024, 0x14430005, 0x111140, -0x3402a000, 0x3c010001, 0x80050a1, 0xac22552c, -0x3c030001, 0x621821, 0x8c6375b8, 0x3c020020, +0x3402a000, 0x3c010001, 0x80050a5, 0xac22553c, +0x3c030001, 0x621821, 0x8c6375c8, 0x3c020020, 0x621024, 0x10400004, 0x24022001, 0x3c010001, -0x80050a1, 0xac22552c, 0x3c020080, 0x621024, -0x1040001f, 0x3402a001, 0x3c010001, 0x80050a1, -0xac22552c, 0x3c020020, 0x2021024, 0x10400007, +0x80050a5, 0xac22553c, 0x3c020080, 0x621024, +0x1040001f, 0x3402a001, 0x3c010001, 0x80050a5, +0xac22553c, 0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, 0x3c010001, 0x230821, -0xac2275c4, 0x8005095, 0x3c020080, 0x111140, -0x3c010001, 0x220821, 0xac2075c4, 0x3c020080, +0xac2275d4, 0x8005099, 0x3c020080, 0x111140, +0x3c010001, 0x220821, 0xac2075d4, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, -0x3c010001, 0x230821, 0x80050a1, 0xac2275cc, -0x111140, 0x3c010001, 0x220821, 0xac2075cc, -0x3c030001, 0x8c635478, 0x24020001, 0x10620003, +0x3c010001, 0x230821, 0x80050a5, 0xac2275dc, +0x111140, 0x3c010001, 0x220821, 0xac2075dc, +0x3c030001, 0x8c635488, 0x24020001, 0x10620003, 0x0, 0xc00429f, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028, @@ -4159,124 +4160,124 @@ 0x9821, 0xafb1001c, 0x8821, 0x24020002, 0xafbf002c, 0xafb00018, 0xa7a00012, 0x10a20068, 0xa7a00010, 0x2ca20003, 0x10400005, 0x24020001, -0x10a2000a, 0x148140, 0x8005172, 0x2201021, +0x10a2000a, 0x148140, 0x8005176, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, -0x142940, 0x8005172, 0x2201021, 0x3c030001, -0x701821, 0x8c6375bc, 0x3c024000, 0x621024, +0x142940, 0x8005176, 0x2201021, 0x3c030001, +0x701821, 0x8c6375cc, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, -0x628824, 0x3c010001, 0x300821, 0xac3175b4, -0x8005172, 0x2201021, 0x24050001, 0xc0048a8, -0x27a60010, 0x24040001, 0x24050001, 0xc0048a8, +0x628824, 0x3c010001, 0x300821, 0xac3175c4, +0x8005176, 0x2201021, 0x24050001, 0xc0048ac, +0x27a60010, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, -0x3c114000, 0x3c030001, 0x8c635540, 0x24020003, +0x3c114000, 0x3c030001, 0x8c635550, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, -0x24020004, 0x10620014, 0x24040001, 0x8005115, +0x24020004, 0x10620014, 0x24040001, 0x8005119, 0x3c028000, 0x24040001, 0x24050011, 0x27b00012, -0xc0048a8, 0x2003021, 0x24040001, 0x24050011, -0xc0048a8, 0x2003021, 0x97a30012, 0x30624000, +0xc0048ac, 0x2003021, 0x24040001, 0x24050011, +0xc0048ac, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, -0x8005112, 0x30628000, 0x24050014, 0x27b00012, -0xc0048a8, 0x2003021, 0x24040001, 0x24050014, -0xc0048a8, 0x2003021, 0x97a30012, 0x30621000, +0x8005116, 0x30628000, 0x24050014, 0x27b00012, +0xc0048ac, 0x2003021, 0x24040001, 0x24050014, +0xc0048ac, 0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, -0x2221025, 0x2531825, 0x800511f, 0x438825, -0x3c110001, 0x2308821, 0x8e3175bc, 0x3c027fff, +0x2221025, 0x2531825, 0x8005123, 0x438825, +0x3c110001, 0x2308821, 0x8e3175cc, 0x3c027fff, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, -0x220821, 0xac3175b4, 0x8005172, 0x2201021, -0x142940, 0x3c030001, 0x651821, 0x8c6375b8, +0x220821, 0xac3175c4, 0x8005176, 0x2201021, +0x142940, 0x3c030001, 0x651821, 0x8c6375c8, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, 0x250821, -0xac3175b0, 0x8005172, 0x2201021, 0x3c020001, -0x8c425488, 0x10400033, 0x3c11c00c, 0x3c020001, -0x8c425504, 0x3c04c00c, 0x34842000, 0x3c030001, -0x8c635528, 0x2102b, 0x21023, 0x441024, +0xac3175c0, 0x8005176, 0x2201021, 0x3c020001, +0x8c425498, 0x10400033, 0x3c11c00c, 0x3c020001, +0x8c425514, 0x3c04c00c, 0x34842000, 0x3c030001, +0x8c635538, 0x2102b, 0x21023, 0x441024, 0x10600003, 0x518825, 0x3c022000, 0x2228825, -0x3c020001, 0x451021, 0x8c4275c4, 0x10400003, -0x3c020020, 0x800514f, 0x2228825, 0x3c02ffdf, +0x3c020001, 0x451021, 0x8c4275d4, 0x10400003, +0x3c020020, 0x8005153, 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, -0x220821, 0x8c2275cc, 0x10400003, 0x3c020080, -0x800515a, 0x2228825, 0x3c02ff7f, 0x3442ffff, -0x2228824, 0x3c020001, 0x8c4254f0, 0x10400002, -0x3c020800, 0x2228825, 0x3c020001, 0x8c4254f4, +0x220821, 0x8c2275dc, 0x10400003, 0x3c020080, +0x800515e, 0x2228825, 0x3c02ff7f, 0x3442ffff, +0x2228824, 0x3c020001, 0x8c425500, 0x10400002, +0x3c020800, 0x2228825, 0x3c020001, 0x8c425504, 0x10400002, 0x3c020400, 0x2228825, 0x3c020001, -0x8c4254f8, 0x10400006, 0x3c020100, 0x800516d, +0x8c425508, 0x10400006, 0x3c020100, 0x8005171, 0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, -0x141140, 0x3c010001, 0x220821, 0xac3175b0, +0x141140, 0x3c010001, 0x220821, 0xac3175c0, 0x2201021, 0x8fbf002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffd8, 0xafb40020, 0x80a021, 0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, -0xafb00010, 0x8f900200, 0x3c030001, 0x8c635478, +0xafb00010, 0x8f900200, 0x3c030001, 0x8c635488, 0x8f930220, 0x24020002, 0x106200b4, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x141940, -0x800523c, 0x0, 0x24020004, 0x1062005a, -0x24020008, 0x10620059, 0x149140, 0x800523c, -0x0, 0x3c040001, 0x832021, 0x8c8475bc, -0x3c110001, 0x2238821, 0x8e3175b4, 0x3c024000, +0x8005240, 0x0, 0x24020004, 0x1062005a, +0x24020008, 0x10620059, 0x149140, 0x8005240, +0x0, 0x3c040001, 0x832021, 0x8c8475cc, +0x3c110001, 0x2238821, 0x8e3175c4, 0x3c024000, 0x821024, 0x1040003e, 0x3c020008, 0x2221024, 0x10400020, 0x36100002, 0x3c020001, 0x431021, -0x8c4275c0, 0x10400005, 0x36100020, 0x36100100, -0x3c020020, 0x80051b1, 0x2228825, 0x2402feff, +0x8c4275d0, 0x10400005, 0x36100020, 0x36100100, +0x3c020020, 0x80051b5, 0x2228825, 0x2402feff, 0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x141140, 0x3c010001, 0x220821, 0x8c2275c8, +0x141140, 0x3c010001, 0x220821, 0x8c2275d8, 0x10400005, 0x3c020001, 0x2629825, 0x3c020080, -0x80051d0, 0x2228825, 0x3c02fffe, 0x3442ffff, -0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d0, +0x80051d4, 0x2228825, 0x3c02fffe, 0x3442ffff, +0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d4, 0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, -0x2228824, 0x3c010001, 0x230821, 0xac2075c0, -0x3c010001, 0x230821, 0xac2075c8, 0xc0047cc, +0x2228824, 0x3c010001, 0x230821, 0xac2075d0, +0x3c010001, 0x230821, 0xac2075d8, 0xc0047cc, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xaf820220, 0x80051e7, 0x141140, +0x34420002, 0xaf820220, 0x80051eb, 0x141140, 0x8f820200, 0x2403fffd, 0x431024, 0xc0047cc, 0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, 0x2228824, 0x141140, 0x3c010001, 0x220821, -0x800523c, 0xac3175b4, 0x149140, 0x3c040001, -0x922021, 0x8c8475b8, 0x3c110001, 0x2328821, -0x8e3175b0, 0x3c024000, 0x821024, 0x14400011, -0x0, 0x3c020001, 0x8c425528, 0x14400006, +0x8005240, 0xac3175c4, 0x149140, 0x3c040001, +0x922021, 0x8c8475c8, 0x3c110001, 0x2328821, +0x8e3175c0, 0x3c024000, 0x821024, 0x14400011, +0x0, 0x3c020001, 0x8c425538, 0x14400006, 0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cc, 0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, -0x2228824, 0x3c010001, 0x320821, 0x800523c, -0xac3175b0, 0x3c020001, 0x8c425528, 0x10400005, -0x3c020020, 0x3c020001, 0x8c425504, 0x1040002b, +0x2228824, 0x3c010001, 0x320821, 0x8005240, +0xac3175c0, 0x3c020001, 0x8c425538, 0x10400005, +0x3c020020, 0x3c020001, 0x8c425514, 0x1040002b, 0x3c020020, 0x821024, 0x10400007, 0x36100020, -0x24020100, 0x3c010001, 0x320821, 0xac2275c4, -0x800521c, 0x36100100, 0x3c010001, 0x320821, -0xac2075c4, 0x2402feff, 0x2028024, 0x3c020080, +0x24020100, 0x3c010001, 0x320821, 0xac2275d4, +0x8005220, 0x36100100, 0x3c010001, 0x320821, +0xac2075d4, 0x2402feff, 0x2028024, 0x3c020080, 0x821024, 0x10400007, 0x141940, 0x3c020001, -0x3c010001, 0x230821, 0xac2275cc, 0x800522d, +0x3c010001, 0x230821, 0xac2275dc, 0x8005231, 0x2629825, 0x141140, 0x3c010001, 0x220821, -0xac2075cc, 0x3c02fffe, 0x3442ffff, 0x2629824, +0xac2075dc, 0x3c02fffe, 0x3442ffff, 0x2629824, 0xc0047cc, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x141140, -0x3c010001, 0x220821, 0xac3175b0, 0x8fbf0024, +0x3c010001, 0x220821, 0xac3175c0, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f66, -0x776d6169, 0x6e2e632c, 0x7620312e, 0x312e322e, -0x31312031, 0x3939382f, 0x30342f32, 0x37203232, -0x3a31333a, 0x34322073, 0x6875616e, 0x67204578, -0x70202400, 0x7468655f, 0x4441574e, 0x0, -0x53544143, 0x4b5f3120, 0x0, 0x42616453, -0x6e64526e, 0x67000000, 0x3f456e71, 0x45767400, -0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, -0x6746756c, 0x6c000000, 0x496c6c43, 0x6f6e6652, -0x78000000, 0x53656e64, 0x436b5375, 0x6d000000, -0x52656376, 0x566c616e, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e, +0x322e3131, 0x20313939, 0x382f3034, 0x2f323720, +0x32323a31, 0x333a3432, 0x20736875, 0x616e6720, +0x45787020, 0x24000000, 0x7468655f, 0x4441574e, +0x0, 0x53544143, 0x4b5f3120, 0x0, +0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71, +0x45767400, 0x3f6e6f51, 0x64457650, 0x0, +0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43, +0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375, +0x6d000000, 0x52656376, 0x566c616e, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, -0x696d6572, 0x2e632c76, 0x20312e31, 0x2e322e38, -0x20313939, 0x382f3037, 0x2f333120, 0x31373a35, -0x383a3435, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x542d446d, 0x61526431, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32, +0x2e382031, 0x3939382f, 0x30372f33, 0x31203137, +0x3a35383a, 0x34352073, 0x6875616e, 0x67204578, +0x70202400, 0x542d446d, 0x61526431, 0x0, 0x542d446d, 0x61424200, 0x542d446d, 0x61320000, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, 0x64527845, 0x0, 0x656e714d, 0x45765046, @@ -4286,11 +4287,11 @@ 0x6576526e, 0x6746756c, 0x6c000000, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, -0x6f6d6d61, 0x6e642e63, 0x2c762031, 0x2e312e32, -0x2e313020, 0x31393938, 0x2f31312f, 0x31382031, -0x373a3131, 0x3a313820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x3f4d626f, 0x78457674, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31, +0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138, +0x2031373a, 0x31313a31, 0x38207368, 0x75616e67, +0x20457870, 0x20240000, 0x3f4d626f, 0x78457674, 0x0, 0x4e4f636f, 0x6d616e64, 0x0, 0x68737465, 0x5f455252, 0x0, 0x412d4572, 0x72427563, 0x0, 0x4552524f, 0x522d4164, @@ -4309,29 +4310,29 @@ 0x7e70, 0x80cc, 0x6e64, 0x81cc, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, -0x6d612e63, 0x2c762031, 0x2e312e32, 0x2e332031, -0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, -0x34312073, 0x6875616e, 0x67204578, 0x70202400, -0x646d6172, 0x6441544e, 0x0, 0x646d6177, -0x7241544e, 0x0, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3431, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x646d6172, 0x6441544e, 0x0, +0x646d6177, 0x7241544e, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, -0x72616365, 0x2e632c76, 0x20312e31, 0x2e322e32, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3530, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x24486561, 0x6465723a, 0x202f7072, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32, +0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, +0x3a31333a, 0x35302073, 0x6875616e, 0x67204578, +0x70202400, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, -0x6174612e, 0x632c7620, 0x312e312e, 0x322e3220, -0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, -0x3a343020, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x2331204d, 0x6f6e2046, 0x65622031, 0x2031363a, -0x35393a30, 0x31205053, 0x54203139, 0x39390000, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e, +0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, +0x31333a34, 0x30207368, 0x75616e67, 0x20457870, +0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, +0x23312054, 0x75652041, 0x70722032, 0x30203137, +0x3a32313a, 0x30382050, 0x44542031, 0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031363a, 0x35393a30, 0x31000000, 0x46575f43, +0x2031373a, 0x32313a30, 0x38000000, 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, @@ -4342,17 +4343,17 @@ 0x2e320000, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, -0x656d2e63, 0x2c762031, 0x2e312e32, 0x2e322031, -0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, -0x34342073, 0x6875616e, 0x67204578, 0x70202400, -0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3434, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f73, -0x656e642e, 0x632c7620, 0x312e312e, 0x322e3131, -0x20313939, 0x382f3132, 0x2f323220, 0x31373a31, -0x373a3535, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x736e6464, 0x654e6f51, 0x20000000, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e, +0x31312031, 0x3939382f, 0x31322f32, 0x32203137, +0x3a31373a, 0x35352073, 0x6875616e, 0x67204578, +0x70202400, 0x736e6464, 0x654e6f51, 0x20000000, 0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, 0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, 0x0, 0x756e6b72, 0x64747970, 0x65000000, @@ -4368,11 +4369,11 @@ 0xbd80, 0xbd80, 0xbd80, 0xbd64, 0xb050, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f72, -0x6563762e, 0x632c7620, 0x312e312e, 0x322e3139, -0x20313939, 0x382f3037, 0x2f323420, 0x32313a33, -0x303a3035, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x706b5278, 0x45525200, 0x66726d32, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e, +0x31392031, 0x3939382f, 0x30372f32, 0x34203231, +0x3a33303a, 0x30352073, 0x6875616e, 0x67204578, +0x70202400, 0x706b5278, 0x45525200, 0x66726d32, 0x4c617267, 0x65000000, 0x72784e6f, 0x52784264, 0x0, 0x72785144, 0x6d614446, 0x0, 0x72785144, 0x6d614246, 0x0, 0x3f6e6f51, @@ -4392,11 +4393,11 @@ 0x1016c, 0x1016c, 0x10164, 0x10164, 0x10164, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, -0x61632e63, 0x2c762031, 0x2e312e32, 0x2e313220, -0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, -0x3a343220, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x6d616374, 0x7841544e, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31, +0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, +0x31333a34, 0x32207368, 0x75616e67, 0x20457870, +0x20240000, 0x6d616374, 0x7841544e, 0x0, 0x4e745379, 0x6e264c6b, 0x0, 0x72656d61, 0x73737274, 0x0, 0x6c696e6b, 0x444f574e, 0x0, 0x656e714d, 0x45765046, 0x61696c00, @@ -4404,27 +4405,27 @@ 0x456e454d, 0x0, 0x6c696e6b, 0x55500000, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, -0x6b73756d, 0x2e632c76, 0x20312e31, 0x2e322e32, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3339, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x50726f62, 0x65506879, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32, +0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, +0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, +0x70202400, 0x50726f62, 0x65506879, 0x0, 0x6c6e6b41, 0x53535254, 0x0, 0x11994, 0x119cc, 0x119e4, 0x11a18, 0x11a44, 0x11a58, 0x11a94, 0x11e04, 0x11b6c, 0x11bac, 0x11bd8, 0x11c18, 0x11c48, 0x11c84, 0x11cb8, 0x11e04, 0x12048, 0x12060, 0x12088, 0x120a8, 0x120d0, -0x12200, 0x12228, 0x1226c, 0x12294, -0x0, 0x124fc, 0x125cc, 0x126a4, -0x12774, 0x127d0, 0x128ac, 0x128d4, -0x129b0, 0x129d8, 0x12b80, 0x12ba8, -0x12d50, 0x12f48, 0x131dc, 0x130f0, -0x131dc, 0x13208, 0x12d78, 0x12f20, -0x0, 0x135f4, 0x13638, 0x136d0, -0x1371c, 0x1378c, 0x13824, 0x13858, -0x138e0, 0x13978, 0x13a48, 0x13a88, -0x13b0c, 0x13b30, 0x13c64, 0x646f4261, +0x12200, 0x12228, 0x1227c, 0x122a4, +0x0, 0x1250c, 0x125dc, 0x126b4, +0x12784, 0x127e0, 0x128bc, 0x128e4, +0x129c0, 0x129e8, 0x12b90, 0x12bb8, +0x12d60, 0x12f58, 0x131ec, 0x13100, +0x131ec, 0x13218, 0x12d88, 0x12f30, +0x0, 0x13604, 0x13648, 0x136e0, +0x1372c, 0x1379c, 0x13834, 0x13868, +0x138f0, 0x13988, 0x13a58, 0x13a98, +0x13b1c, 0x13b40, 0x13c74, 0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, 0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; @@ -4454,24 +4455,24 @@ /* Generated by genfw.c */ int tigon2FwReleaseMajor = 0xc; int tigon2FwReleaseMinor = 0x3; -int tigon2FwReleaseFix = 0x5; +int tigon2FwReleaseFix = 0xa; u32 tigon2FwStartAddr = 0x00004000; u32 tigon2FwTextAddr = 0x00004000; -int tigon2FwTextLen = 0xec80; -u32 tigon2FwRodataAddr = 0x00012c80; -int tigon2FwRodataLen = 0xfb0; -u32 tigon2FwDataAddr = 0x00013c50; +int tigon2FwTextLen = 0xed40; +u32 tigon2FwRodataAddr = 0x00012d40; +int tigon2FwRodataLen = 0xff0; +u32 tigon2FwDataAddr = 0x00013d60; int tigon2FwDataLen = 0x170; -u32 tigon2FwSbssAddr = 0x00013dc0; +u32 tigon2FwSbssAddr = 0x00013ed0; int tigon2FwSbssLen = 0xbc; -u32 tigon2FwBssAddr = 0x00013e80; +u32 tigon2FwBssAddr = 0x00013f90; int tigon2FwBssLen = 0x20c0; u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, -0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, 0x3c100000, +0x3c1d0001, 0x8fbd3db0, 0x3a0f021, 0x3c100000, 0x26104000, 0xc0010c0, 0x0, 0xd, -0x3c1d0001, 0x8fbd3ca4, 0x3a0f021, 0x3c100000, +0x3c1d0001, 0x8fbd3db4, 0x3a0f021, 0x3c100000, 0x26104000, 0xc00178d, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -4485,19 +4486,19 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000008, 0x0, 0x80016de, 0x3c0a0001, 0x80016de, -0x3c0a0002, 0x80016de, 0x0, 0x8002acd, -0x0, 0x8002a70, 0x0, 0x80016de, -0x3c0a0004, 0x8003095, 0x0, 0x8001a0e, -0x0, 0x800373f, 0x0, 0x80036e6, -0x0, 0x80016de, 0x3c0a0006, 0x80037ad, +0x3c0a0002, 0x80016de, 0x0, 0x8002afd, +0x0, 0x8002aa0, 0x0, 0x80016de, +0x3c0a0004, 0x80030d1, 0x0, 0x8001a0e, +0x0, 0x8003779, 0x0, 0x8003720, +0x0, 0x80016de, 0x3c0a0006, 0x80037e7, 0x3c0a0007, 0x80016de, 0x3c0a0008, 0x80016de, -0x3c0a0009, 0x8003805, 0x0, 0x8002cc0, +0x3c0a0009, 0x800383f, 0x0, 0x8002cf7, 0x0, 0x80016de, 0x3c0a000b, 0x80016de, -0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027ac, +0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027c5, 0x0, 0x800275a, 0x0, 0x80016de, 0x3c0a000e, 0x8001f28, 0x0, 0x8001920, -0x0, 0x80019c0, 0x0, 0x8003a70, -0x0, 0x8003a5e, 0x0, 0x80016de, +0x0, 0x80019c0, 0x0, 0x8003aa8, +0x0, 0x8003a96, 0x0, 0x80016de, 0x0, 0x80018c6, 0x0, 0x80016de, 0x0, 0x80016de, 0x3c0a0013, 0x80016de, 0x3c0a0014, 0x0, 0x0, 0x0, @@ -4517,79 +4518,79 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27bdffe0, 0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, -0x24030003, 0xaf8300ec, 0x34420004, 0xc0029b8, +0x24030003, 0xaf8300ec, 0x34420004, 0xc0029e8, 0xaf820140, 0x3c0100c0, 0xc001712, 0xac203ffc, -0x403021, 0x3c020008, 0x3c010001, 0xac263dd8, +0x403021, 0x3c020008, 0x3c010001, 0xac263ee8, 0x50c2000d, 0x3c020003, 0x3c100010, 0x10d00009, -0x24050100, 0x3c040001, 0x24842d34, 0x3821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x3c010001, -0xac303dd8, 0x3c020003, 0x34422000, 0x3c010001, -0xac223de8, 0x24020008, 0x3c010001, 0xac223df0, -0x2402001f, 0x3c010001, 0xac223e00, 0x24020016, -0x3c010001, 0xac223dd4, 0x3c05fffe, 0x34a56f08, -0x3c020001, 0x8c423dd8, 0x3c030001, 0x24635f40, -0x3c040001, 0x8c843c54, 0x431023, 0x14800002, +0x24050100, 0x3c040001, 0x24842df4, 0x3821, +0xafa00010, 0xc002a03, 0xafa00014, 0x3c010001, +0xac303ee8, 0x3c020003, 0x34422000, 0x3c010001, +0xac223ef8, 0x24020008, 0x3c010001, 0xac223f00, +0x2402001f, 0x3c010001, 0xac223f10, 0x24020016, +0x3c010001, 0xac223ee4, 0x3c05fffe, 0x34a56f08, +0x3c020001, 0x8c423ee8, 0x3c030001, 0x24636050, +0x3c040001, 0x8c843d64, 0x431023, 0x14800002, 0x458021, 0x2610fa48, 0x2402f000, 0x2028024, 0xc001734, 0x2002021, 0x2022823, 0x3c040020, 0x821823, 0x651823, 0x247bb000, 0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, -0x3c070001, 0x8ce73c50, 0x3c0300bf, 0x3463e000, -0x852023, 0x3c010001, 0xac243de4, 0x822023, -0x3c010001, 0xac223dc0, 0x27620ffc, 0x3c010001, -0xac223ca0, 0x27621ffc, 0xdb3023, 0x7b1823, -0x3c010001, 0xac253dcc, 0x3c010001, 0xac243dc4, -0x3c010001, 0xac223ca4, 0xaf860150, 0x10e00011, -0xaf830250, 0x3c1d0001, 0x8fbd3c5c, 0x3a0f021, -0xc0016f8, 0x0, 0x3c020001, 0x8c423c60, -0x3c030001, 0x8c633c64, 0x2442fe00, 0x24630200, -0x3c010001, 0xac223c60, 0x3c010001, 0x10000004, -0xac233c64, 0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, -0x3c020001, 0x8c423c54, 0x1040000d, 0x26fafa48, -0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, -0x3c1a0001, 0x8f5a3c64, 0x2442fa48, 0x246305b8, -0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, -0x3c020001, 0x8c423c58, 0x14400003, 0x0, -0x3c010001, 0xac203c60, 0xc00114d, 0x0, +0x3c070001, 0x8ce73d60, 0x3c0300bf, 0x3463e000, +0x852023, 0x3c010001, 0xac243ef4, 0x822023, +0x3c010001, 0xac223ed0, 0x27620ffc, 0x3c010001, +0xac223db0, 0x27621ffc, 0xdb3023, 0x7b1823, +0x3c010001, 0xac253edc, 0x3c010001, 0xac243ed4, +0x3c010001, 0xac223db4, 0xaf860150, 0x10e00011, +0xaf830250, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, +0xc0016f8, 0x0, 0x3c020001, 0x8c423d70, +0x3c030001, 0x8c633d74, 0x2442fe00, 0x24630200, +0x3c010001, 0xac223d70, 0x3c010001, 0x10000004, +0xac233d74, 0x3c1d0001, 0x8fbd3db0, 0x3a0f021, +0x3c020001, 0x8c423d64, 0x1040000d, 0x26fafa48, +0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, +0x3c1a0001, 0x8f5a3d74, 0x2442fa48, 0x246305b8, +0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, +0x3c020001, 0x8c423d68, 0x14400003, 0x0, +0x3c010001, 0xac203d70, 0xc00114d, 0x0, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, -0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1036f4, -0x3c040001, 0x24842d40, 0xafbf0058, 0xafbe0054, +0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, +0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1037d8, +0x3c040001, 0x24842e00, 0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050200, 0xc0029d3, 0x2003821, +0x8f860040, 0x24050200, 0xc002a03, 0x2003821, 0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, 0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, -0x24842d48, 0xa3ae003f, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050300, 0xc0029d3, 0x2003821, +0x24842e08, 0xa3ae003f, 0xafa00010, 0xafa00014, +0x8f860040, 0x24050300, 0xc002a03, 0x2003821, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 0xaf800048, 0x8f820048, 0x14400005, 0x0, 0xaf800048, 0x8f820048, 0x10400004, 0x0, 0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, -0x2e02021, 0x3c050001, 0xc002a40, 0x34a540f8, -0x3402021, 0xc002a40, 0x240505b8, 0x3c020001, -0x8c423de4, 0x3c0d0001, 0x8dad3dc4, 0x3c030001, -0x8c633dc0, 0x3c080001, 0x8d083dcc, 0x3c090001, -0x8d293de8, 0x3c0a0001, 0x8d4a3df0, 0x3c0b0001, -0x8d6b3e00, 0x3c0c0001, 0x8d8c3dd4, 0x3c040001, -0x24842d54, 0x24050400, 0xaf420130, 0x8f420130, +0x2e02021, 0x3c050001, 0xc002a70, 0x34a540f8, +0x3402021, 0xc002a70, 0x240505b8, 0x3c020001, +0x8c423ef4, 0x3c0d0001, 0x8dad3ed4, 0x3c030001, +0x8c633ed0, 0x3c080001, 0x8d083edc, 0x3c090001, +0x8d293ef8, 0x3c0a0001, 0x8d4a3f00, 0x3c0b0001, +0x8d6b3f10, 0x3c0c0001, 0x8d8c3ee4, 0x3c040001, +0x24842e14, 0x24050400, 0xaf420130, 0x8f420130, 0x24060001, 0x24070001, 0xaf400000, 0xaf4d012c, 0xaf430138, 0xaf48013c, 0xaf490140, 0xaf4a0144, 0xaf4b0148, 0xaf4c014c, 0x2442ff80, 0xaf420134, -0x24020001, 0xafa20010, 0xc0029d3, 0xafa00014, +0x24020001, 0xafa20010, 0xc002a03, 0xafa00014, 0x8f42012c, 0xafa20010, 0x8f420130, 0xafa20014, -0x8f460138, 0x8f47013c, 0x3c040001, 0x24842d60, -0xc0029d3, 0x24050500, 0xafb70010, 0xafba0014, -0x8f460140, 0x8f470144, 0x3c040001, 0x24842d6c, -0xc0029d3, 0x24050600, 0x3c020001, 0x8c423dd8, -0x3603821, 0x3c060001, 0x24c65f40, 0x2448ffff, +0x8f460138, 0x8f47013c, 0x3c040001, 0x24842e20, +0xc002a03, 0x24050500, 0xafb70010, 0xafba0014, +0x8f460140, 0x8f470144, 0x3c040001, 0x24842e2c, +0xc002a03, 0x24050600, 0x3c020001, 0x8c423ee8, +0x3603821, 0x3c060001, 0x24c66050, 0x2448ffff, 0x1061824, 0xe81024, 0x43102b, 0x10400006, -0x24050900, 0x3c040001, 0x24842d78, 0xafa80010, -0xc0029d3, 0xafa00014, 0x8f82000c, 0xafa20010, +0x24050900, 0x3c040001, 0x24842e38, 0xafa80010, +0xc002a03, 0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, -0x3c040001, 0x24842d84, 0xc0029d3, 0x24051000, +0x3c040001, 0x24842e44, 0xc002a03, 0x24051000, 0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, -0x3c040001, 0x24842d8c, 0x24051100, 0xafa20010, -0xc0029d3, 0xafa30014, 0xaf800054, 0xaf80011c, +0x3c040001, 0x24842e4c, 0x24051100, 0xafa20010, +0xc002a03, 0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218, 0x30420002, 0x10400009, 0x0, 0x8c020220, 0x3c030002, 0x34630004, 0x431025, 0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, @@ -4611,7 +4612,7 @@ 0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, 0x24051200, 0x96e20472, 0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001, -0x24842d94, 0xc0029d3, 0xafa20014, 0x96f00452, +0x24842e54, 0xc002a03, 0xafa20014, 0x96f00452, 0x32020001, 0x10400002, 0xb021, 0x24160001, 0x32020002, 0x54400001, 0x36d60002, 0x32020008, 0x54400001, 0x36d60004, 0x32020010, 0x54400001, @@ -4624,8 +4625,8 @@ 0x14400004, 0x3207009b, 0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000, 0x1440000d, 0x32020001, 0x3062009b, 0x10e20009, 0x240e0001, 0x3c040001, -0x24842da0, 0x24051300, 0x2003821, 0xa3ae003f, -0xafa30010, 0xc0029d3, 0xafa00014, 0x32020001, +0x24842e60, 0x24051300, 0x2003821, 0xa3ae003f, +0xafa30010, 0xc002a03, 0xafa00014, 0x32020001, 0x54400001, 0x36d60080, 0x32020002, 0x54400001, 0x36d60100, 0x32020008, 0x54400001, 0x36d60200, 0x32020010, 0x54400001, 0x36d60400, 0x32020080, @@ -4649,191 +4650,191 @@ 0xaf420180, 0xaf430184, 0x8ee20478, 0x8ee3047c, 0xaf420188, 0xaf43018c, 0x8ee20488, 0x8ee3048c, 0xaf420190, 0xaf430194, 0x8ee204b0, 0x8ee304b4, -0x24040080, 0xaf420198, 0xaf43019c, 0xc002a40, +0x24040080, 0xaf420198, 0xaf43019c, 0xc002a70, 0x24050080, 0x8c02025c, 0x27440214, 0xaf4201e0, -0x8c020260, 0x24050200, 0x24060008, 0xc002a57, +0x8c020260, 0x24050200, 0x24060008, 0xc002a87, 0xaf4201e8, 0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006, 0x24030002, 0xaf4201e4, 0x240203e8, 0xaf4301f4, 0xaf4301f0, 0xaf4401ec, 0xaf420284, 0x24020001, 0xaf430280, 0xaf42028c, 0x3c030001, -0x671821, 0x90633c68, 0x3471021, 0x24e70001, +0x671821, 0x90633d78, 0x3471021, 0x24e70001, 0xa043021c, 0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040, -0x3c040001, 0x24842dac, 0x24051400, 0x21702, +0x3c040001, 0x24842e6c, 0x24051400, 0x21702, 0x24420030, 0xa062021c, 0x3471021, 0xa040021c, 0x8c070218, 0x2c03021, 0x240205b8, 0xafa20010, -0xc0029d3, 0xafa80014, 0x3c040001, 0x24842db8, +0xc002a03, 0xafa80014, 0x3c040001, 0x24842e78, 0x3c050000, 0x24a55b3c, 0x24060010, 0x27b10030, 0x2203821, 0x27b30034, 0xc001750, 0xafb30010, -0x3c030001, 0x8c633c58, 0x1060000a, 0x408021, +0x3c030001, 0x8c633d68, 0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, 0x831823, 0x431023, 0xafa20034, -0xafa40030, 0xafb30010, 0x3c040001, 0x24842dc4, +0xafa40030, 0xafb30010, 0x3c040001, 0x24842e84, 0x3c050000, 0x24a54100, 0x24060108, 0xc001750, 0x2203821, 0x409021, 0x32c20003, 0x50400045, 0x2203821, 0x8f820050, 0x3c030010, 0x431024, 0x10400016, 0x0, 0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, -0x240e0001, 0x3c040001, 0x24842dd0, 0xa3ae003f, +0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, -0xc0029d3, 0x2c03021, 0x10000004, 0x0, +0xc002a03, 0x2c03021, 0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, -0x24842ddc, 0x3c050001, 0x24a59ce8, 0x3c060001, +0x24842e9c, 0x3c050001, 0x24a59ce8, 0x3c060001, 0x24c69d60, 0xc53023, 0x8f420010, 0x27b30030, 0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, -0xc001750, 0xafb10010, 0x3c040001, 0x24842df0, -0x3c050001, 0x24a5af7c, 0x3c060001, 0x24c6b2f8, +0xc001750, 0xafb10010, 0x3c040001, 0x24842eb0, +0x3c050001, 0x24a5b058, 0x3c060001, 0x24c6b3d4, 0xc53023, 0x2603821, 0xaf420108, 0xc001750, -0xafb10010, 0x3c040001, 0x24842e0c, 0x3c050001, -0x24a5b714, 0x3c060001, 0x24c6c1d4, 0xc53023, -0x2603821, 0x3c010001, 0xac223e30, 0xc001750, -0xafb10010, 0x3c040001, 0x24842e24, 0x10000024, -0x24051600, 0x3c040001, 0x24842e2c, 0x3c050001, +0xafb10010, 0x3c040001, 0x24842ecc, 0x3c050001, +0x24a5b7e4, 0x3c060001, 0x24c6c2c8, 0xc53023, +0x2603821, 0x3c010001, 0xac223f40, 0xc001750, +0xafb10010, 0x3c040001, 0x24842ee4, 0x10000024, +0x24051600, 0x3c040001, 0x24842eec, 0x3c050001, 0x24a59bb4, 0x3c060001, 0x24c69ce0, 0xc53023, -0xc001750, 0xafb30010, 0x3c040001, 0x24842e3c, -0x3c050001, 0x24a5ab34, 0x3c060001, 0x24c6af74, +0xc001750, 0xafb30010, 0x3c040001, 0x24842efc, +0x3c050001, 0x24a5abf4, 0x3c060001, 0x24c6b050, 0xc53023, 0x2203821, 0xaf420108, 0xc001750, -0xafb30010, 0x3c040001, 0x24842e50, 0x3c050001, -0x24a5b300, 0x3c060001, 0x24c6b70c, 0xc53023, -0x2203821, 0x3c010001, 0xac223e30, 0xc001750, -0xafb30010, 0x3c040001, 0x24842e64, 0x24051650, -0x2c03021, 0x3821, 0x3c010001, 0xac223e34, -0xafa00010, 0xc0029d3, 0xafa00014, 0x32c20020, -0x10400021, 0x27a70030, 0x3c040001, 0x24842e70, -0x3c050001, 0x24a5a9c0, 0x3c060001, 0x24c6ab2c, +0xafb30010, 0x3c040001, 0x24842f10, 0x3c050001, +0x24a5b3dc, 0x3c060001, 0x24c6b7dc, 0xc53023, +0x2203821, 0x3c010001, 0xac223f40, 0xc001750, +0xafb30010, 0x3c040001, 0x24842f24, 0x24051650, +0x2c03021, 0x3821, 0x3c010001, 0xac223f44, +0xafa00010, 0xc002a03, 0xafa00014, 0x32c20020, +0x10400021, 0x27a70030, 0x3c040001, 0x24842f30, +0x3c050001, 0x24a5aa80, 0x3c060001, 0x24c6abec, 0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, 0xc001750, 0xafa20010, 0x21900, 0x31982, 0x3c040800, 0x641825, 0xae430028, 0x24030010, 0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, -0x3c040001, 0x24842e84, 0xafa00014, 0xafa30010, -0x8f47001c, 0x24051660, 0x3c010001, 0xac223e2c, +0x3c040001, 0x24842f44, 0xafa00014, 0xafa30010, +0x8f47001c, 0x24051660, 0x3c010001, 0xac223f3c, 0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, -0x1440000a, 0x240e0001, 0x3c040001, 0x24842e90, +0x1440000a, 0x240e0001, 0x3c040001, 0x24842f50, 0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, -0x24051700, 0xc0029d3, 0x3821, 0x3c020000, +0x24051700, 0xc002a03, 0x3821, 0x3c020000, 0x24425b78, 0x21100, 0x21182, 0x3c030800, 0x431025, 0xae420028, 0x24020008, 0xaf42003c, 0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, -0x24842e9c, 0xafa00014, 0xafa20010, 0x8f47001c, -0x24051800, 0x32c60020, 0xc0029d3, 0x0, -0x3c030001, 0x8c633e30, 0x3c050fff, 0x34a5ffff, -0x3c020001, 0x8c423e34, 0x3c040800, 0x651824, +0x24842f5c, 0xafa00014, 0xafa20010, 0x8f47001c, +0x24051800, 0x32c60020, 0xc002a03, 0x0, +0x3c030001, 0x8c633f40, 0x3c050fff, 0x34a5ffff, +0x3c020001, 0x8c423f44, 0x3c040800, 0x651824, 0x31882, 0x641825, 0x451024, 0x21082, 0x441025, 0xae420080, 0x32c20180, 0x10400056, 0xae430020, 0x8f82005c, 0x3c030080, 0x431024, 0x1040000d, 0x0, 0x8f820050, 0xafa20010, -0x8f82005c, 0x240e0001, 0x3c040001, 0x24842ea8, +0x8f82005c, 0x240e0001, 0x3c040001, 0x24842f68, 0xa3ae003f, 0xafa20014, 0x8f870040, 0x24051900, -0xc0029d3, 0x2c03021, 0x8f820050, 0x3c030010, +0xc002a03, 0x2c03021, 0x8f820050, 0x3c030010, 0x431024, 0x10400016, 0x0, 0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 0x8f820050, -0x8c030218, 0x240e0001, 0x3c040001, 0x24842dd0, +0x8c030218, 0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, -0x24052000, 0xc0029d3, 0x2c03021, 0x10000004, +0x24052000, 0xc002a03, 0x2c03021, 0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02240f4, -0x3c040001, 0x24842eb4, 0x3c050001, 0x24a59b2c, +0x3c040001, 0x24842f74, 0x3c050001, 0x24a59b2c, 0x3c060001, 0x24c69bac, 0xc53023, 0x8f420008, 0x27b30030, 0x2603821, 0x27b10034, 0x34420e00, 0xaf420008, 0xc001750, 0xafb10010, 0x3c040001, -0x24842ecc, 0x3c050001, 0x24a5d090, 0x3c060001, -0x24c6db90, 0xc53023, 0x2603821, 0xaf42010c, -0xc001750, 0xafb10010, 0x3c040001, 0x24842ee4, -0x3c050001, 0x24a5e174, 0x3c060001, 0x24c6e860, -0xc53023, 0x2603821, 0x3c010001, 0xac223e40, -0xc001750, 0xafb10010, 0x3c040001, 0x24842efc, -0x10000027, 0x24052100, 0x3c040001, 0x24842f04, +0x24842f8c, 0x3c050001, 0x24a5d180, 0x3c060001, +0x24c6dc78, 0xc53023, 0x2603821, 0xaf42010c, +0xc001750, 0xafb10010, 0x3c040001, 0x24842fa4, +0x3c050001, 0x24a5e25c, 0x3c060001, 0x24c6e948, +0xc53023, 0x2603821, 0x3c010001, 0xac223f50, +0xc001750, 0xafb10010, 0x3c040001, 0x24842fbc, +0x10000027, 0x24052100, 0x3c040001, 0x24842fc4, 0x3c050001, 0x24a599e8, 0x3c060001, 0x24c69b24, 0xc53023, 0x27b10030, 0x2203821, 0x27b30034, -0xc001750, 0xafb30010, 0x3c040001, 0x24842f14, -0x3c050001, 0x24a5c300, 0x3c060001, 0x24c6d088, +0xc001750, 0xafb30010, 0x3c040001, 0x24842fd4, +0x3c050001, 0x24a5c3f0, 0x3c060001, 0x24c6d178, 0xc53023, 0x2203821, 0xaf42010c, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f24, 0x3c050001, -0x24a5e014, 0x3c060001, 0x24c6e16c, 0xc53023, -0x2203821, 0x3c010001, 0xac223e40, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f38, 0x24052150, -0x2c03021, 0x3821, 0x3c010001, 0xac223e4c, -0xafa00010, 0xc0029d3, 0xafa00014, 0x3c030001, -0x8c633e40, 0x3c110fff, 0x3631ffff, 0x3c020001, -0x8c423e4c, 0x3c1e0800, 0x711824, 0x31882, +0xafb30010, 0x3c040001, 0x24842fe4, 0x3c050001, +0x24a5e0fc, 0x3c060001, 0x24c6e254, 0xc53023, +0x2203821, 0x3c010001, 0xac223f50, 0xc001750, +0xafb30010, 0x3c040001, 0x24842ff8, 0x24052150, +0x2c03021, 0x3821, 0x3c010001, 0xac223f5c, +0xafa00010, 0xc002a03, 0xafa00014, 0x3c030001, +0x8c633f50, 0x3c110fff, 0x3631ffff, 0x3c020001, +0x8c423f5c, 0x3c1e0800, 0x711824, 0x31882, 0x7e1825, 0x511024, 0x21082, 0x5e1025, 0xae430038, 0xae420078, 0x8c020218, 0x30420040, 0x14400004, 0x24020001, 0x3c010001, 0x370821, -0xa02240f4, 0x3c040001, 0x24842f44, 0x3c050001, -0x24a5db98, 0x3c060001, 0x24c6dcf4, 0xc53023, +0xa02240f4, 0x3c040001, 0x24843004, 0x3c050001, +0x24a5dc80, 0x3c060001, 0x24c6dddc, 0xc53023, 0x27b50030, 0x2a03821, 0x27b30034, 0xc001750, -0xafb30010, 0x3c010001, 0xac223e38, 0x511024, +0xafb30010, 0x3c010001, 0xac223f48, 0x511024, 0x21082, 0x5e1025, 0xae420050, 0x32c22000, 0x10400005, 0x2a03821, 0x3c020000, 0x24425b78, -0x1000000d, 0x511024, 0x3c040001, 0x24842f58, -0x3c050001, 0x24a5dcfc, 0x3c060001, 0x24c6deac, +0x1000000d, 0x511024, 0x3c040001, 0x24843018, +0x3c050001, 0x24a5dde4, 0x3c060001, 0x24c6df94, 0xc53023, 0xc001750, 0xafb30010, 0x3c010001, -0xac223e50, 0x511024, 0x21082, 0x5e1025, +0xac223f60, 0x511024, 0x21082, 0x5e1025, 0xae420048, 0x32c24000, 0x10400005, 0x27a70030, 0x3c020000, 0x24425b78, 0x1000000e, 0x21100, -0x3c040001, 0x24842f70, 0x3c050001, 0x24a5deb4, -0x3c060001, 0x24c6e00c, 0xc53023, 0x27a20034, -0xc001750, 0xafa20010, 0x3c010001, 0xac223e44, +0x3c040001, 0x24843030, 0x3c050001, 0x24a5df9c, +0x3c060001, 0x24c6e0f4, 0xc53023, 0x27a20034, +0xc001750, 0xafa20010, 0x3c010001, 0xac223f54, 0x21100, 0x21182, 0x3c030800, 0x431025, -0xae420060, 0x3c040001, 0x24842f88, 0x3c050000, +0xae420060, 0x3c040001, 0x24843048, 0x3c050000, 0x24a57ca0, 0x3c060001, 0x24c680c4, 0xc53023, 0x27b10030, 0x2203821, 0x27b30034, 0xc001750, 0xafb30010, 0x3c1e0fff, 0x37deffff, 0x3c040001, -0x24842f94, 0x3c050000, 0x24a56318, 0x3c060000, +0x24843054, 0x3c050000, 0x24a56318, 0x3c060000, 0x24c66478, 0xc53023, 0x2203821, 0x3c010001, -0xac223e18, 0x5e1024, 0x21082, 0x3c150800, +0xac223f28, 0x5e1024, 0x21082, 0x3c150800, 0x551025, 0xae4200b8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fa0, 0x3c050000, 0x24a56480, +0x3c040001, 0x24843060, 0x3c050000, 0x24a56480, 0x3c060000, 0x24c666f8, 0xc53023, 0x2203821, -0x3c010001, 0xac223e0c, 0x5e1024, 0x21082, +0x3c010001, 0xac223f1c, 0x5e1024, 0x21082, 0x551025, 0xae4200e8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fb8, 0x3c050000, 0x24a56700, +0x3c040001, 0x24843078, 0x3c050000, 0x24a56700, 0x3c060000, 0x24c66830, 0xc53023, 0x2203821, -0x3c010001, 0xac223e04, 0x5e1024, 0x21082, +0x3c010001, 0xac223f14, 0x5e1024, 0x21082, 0x551025, 0xae4200c0, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fd0, 0x3c050001, 0x24a5f240, -0x3c060001, 0x24c6f318, 0xc53023, 0x2203821, -0x3c010001, 0xac223e10, 0x5e1024, 0x21082, +0x3c040001, 0x24843090, 0x3c050001, 0x24a5f300, +0x3c060001, 0x24c6f3d8, 0xc53023, 0x2203821, +0x3c010001, 0xac223f20, 0x5e1024, 0x21082, 0x551025, 0xae4200c8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fdc, 0x3c050001, 0x24a5c1e0, -0x3c060001, 0x24c6c21c, 0xc53023, 0x2203821, +0x3c040001, 0x2484309c, 0x3c050001, 0x24a5c2d0, +0x3c060001, 0x24c6c30c, 0xc53023, 0x2203821, 0xaf420110, 0xc001750, 0xafb30010, 0x3c040001, -0x24842fec, 0x3c050001, 0x24a5c224, 0x3c060001, -0x24c6c24c, 0xc53023, 0x2203821, 0xaf420114, -0xc001750, 0xafb30010, 0x3c040001, 0x24842ff8, -0x3c050001, 0x24a5e9c0, 0x3c060001, 0x24c6eeac, +0x248430ac, 0x3c050001, 0x24a5c314, 0x3c060001, +0x24c6c33c, 0xc53023, 0x2203821, 0xaf420114, +0xc001750, 0xafb30010, 0x3c040001, 0x248430b8, +0x3c050001, 0x24a5eaa0, 0x3c060001, 0x24c6ef78, 0xc53023, 0x2203821, 0xaf420118, 0xc001750, -0xafb30010, 0x3c010001, 0xac223e54, 0x5e1024, -0x21082, 0x551025, 0xc003d9f, 0xae4200d0, -0xc003a1c, 0x0, 0xc002630, 0x0, +0xafb30010, 0x3c010001, 0xac223f64, 0x5e1024, +0x21082, 0x551025, 0xc003dcf, 0xae4200d0, +0xc003a54, 0x0, 0xc002630, 0x0, 0xac000228, 0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038, 0x96e20460, 0xaf420080, 0x32c24000, 0x14400003, 0x0, 0x96e20480, 0xaf420084, 0x96e70490, 0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088, 0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000, 0x10400003, 0x24020400, 0x10e2000b, -0x0, 0x240e0001, 0x3c040001, 0x24843008, +0x0, 0x240e0001, 0x3c040001, 0x248430c8, 0xa3ae003f, 0x96e60490, 0x24052170, 0x2c03821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8f43012c, +0xafa00010, 0xc002a03, 0xafa00014, 0x8f43012c, 0x8f44012c, 0x24020001, 0xa34205b3, 0xaf430094, 0xaf440098, 0xafa00010, 0xafa00014, 0x8f460080, -0x8f470084, 0x3c040001, 0x24843014, 0xc0029d3, +0x8f470084, 0x3c040001, 0x248430d4, 0xc002a03, 0x24052200, 0xc00232c, 0x3c110800, 0x3c1433d8, 0x3694cb58, 0x3c020800, 0x34420080, 0x3c040001, -0x24843020, 0x3c050000, 0x24a55bbc, 0x3c060000, +0x248430e0, 0x3c050000, 0x24a55bbc, 0x3c060000, 0x24c65bd8, 0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, 0xaf820064, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223df4, 0x21100, +0xafa20010, 0x3c010001, 0xac223f04, 0x21100, 0x21182, 0x511025, 0xc0018a8, 0xae420000, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 0x3c020000, 0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, 0x511024, 0x14400005, 0x3c030800, 0x8f820060, 0x431024, 0x1040fffd, 0x0, -0xc003a29, 0x8821, 0x3c020100, 0xafa20020, +0xc003a61, 0x8821, 0x3c020100, 0xafa20020, 0x8f530018, 0x240200ff, 0x56620001, 0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24842ce4, 0x3c050009, 0xafa00014, +0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, @@ -4842,21 +4843,21 @@ 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842cec, 0x3c050009, 0xafa20014, +0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842cf4, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc0029d3, 0x2603821, +0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc002a03, 0x2603821, 0x8f4202d4, 0x24420001, 0xaf4202d4, 0x8f4202d4, 0x93a2003f, 0x10400069, 0x3c020700, 0x34423000, 0xafa20028, 0x8f530018, 0x240200ff, 0x12620002, 0x8821, 0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x24842ce4, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, 0xac4304c0, 0xac4404c4, 0xc01821, @@ -4865,19 +4866,19 @@ 0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842cec, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842cf4, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, 0x8fa60028, 0x34a50300, -0xc0029d3, 0x2603821, 0x8f4202e0, 0x24420001, -0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x24843030, +0xc002a03, 0x2603821, 0x8f4202e0, 0x24420001, +0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x248430f0, 0xafa00010, 0xafa00014, 0x8fa60028, 0x24052300, -0xc0029d3, 0x3821, 0x10000004, 0x0, +0xc002a03, 0x3821, 0x10000004, 0x0, 0x8c020264, 0x10400005, 0x0, 0x8f8200a0, 0x30420004, 0x1440fffa, 0x0, 0x8f820044, 0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, @@ -4887,29 +4888,29 @@ 0x8f430138, 0x431021, 0xaf420090, 0x24020001, 0xaf42008c, 0x32c20008, 0x10400006, 0x0, 0x8f820214, 0x3c038100, 0x3042ffff, 0x431025, -0xaf820214, 0x3c020001, 0x8c423d14, 0x30420001, -0x10400009, 0x0, 0x3c040001, 0x2484303c, +0xaf820214, 0x3c020001, 0x8c423e24, 0x30420001, +0x10400009, 0x0, 0x3c040001, 0x248430fc, 0x3c050000, 0x24a56c40, 0x3c060000, 0x24c670e8, -0x10000008, 0xc53023, 0x3c040001, 0x2484304c, +0x10000008, 0xc53023, 0x3c040001, 0x2484310c, 0x3c050000, 0x24a56838, 0x3c060000, 0x24c66c38, 0xc53023, 0x27a70030, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223e08, 0x3c020001, -0x8c423e08, 0x3c030800, 0x21100, 0x21182, +0xafa20010, 0x3c010001, 0xac223f18, 0x3c020001, +0x8c423f18, 0x3c030800, 0x21100, 0x21182, 0x431025, 0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c, 0x8f87011c, -0x3c040001, 0x2484305c, 0x3c010001, 0xac363de0, -0x3c010001, 0xac203dd0, 0x3c010001, 0xac3c3dc8, -0x3c010001, 0xac3b3df8, 0x3c010001, 0xac373dfc, -0x3c010001, 0xac3a3ddc, 0xc0029d3, 0x24052400, +0x3c040001, 0x2484311c, 0x3c010001, 0xac363ef0, +0x3c010001, 0xac203ee0, 0x3c010001, 0xac3c3ed8, +0x3c010001, 0xac3b3f08, 0x3c010001, 0xac373f0c, +0x3c010001, 0xac3a3eec, 0xc002a03, 0x24052400, 0x8f820200, 0xafa20010, 0x8f820220, 0xafa20014, -0x8f860044, 0x8f870050, 0x3c040001, 0x24843068, -0xc0029d3, 0x24052500, 0x8f830060, 0x74100b, +0x8f860044, 0x8f870050, 0x3c040001, 0x24843128, +0xc002a03, 0x24052500, 0x8f830060, 0x74100b, 0x242000a, 0x200f821, 0x0, 0xd, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, -0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843074, +0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843134, 0x24052600, 0x3021, 0x3821, 0xafbf0018, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8fbf0018, +0xafa00010, 0xc002a03, 0xafa00014, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e00008, @@ -4918,16 +4919,16 @@ 0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018, 0xa22823, 0xa32824, 0x8ca20000, 0x1044000a, 0x0, 0xafa50010, 0x8ca20000, 0xafa20014, -0x8f860150, 0x8f870250, 0x3c040001, 0x2484307c, -0xc0029d3, 0x24052700, 0x8fbf0218, 0x3e00008, +0x8f860150, 0x8f870250, 0x3c040001, 0x2484313c, +0xc002a03, 0x24052700, 0x8fbf0218, 0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f, 0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000, 0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000, 0xaca30000, 0x10460005, 0xae040000, 0xa08021, 0xf0102b, -0x1040fff5, 0x102840, 0x3c040001, 0x24843088, +0x1040fff5, 0x102840, 0x3c040001, 0x24843148, 0x24052800, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x2001021, 0x8fbf001c, +0xc002a03, 0xafa00014, 0x2001021, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x8c020224, 0x3047003f, 0x10e00010, 0x803021, 0x2821, 0x24030020, 0xe31024, 0x10400002, 0x63042, @@ -4941,84 +4942,84 @@ 0xafb00018, 0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b, 0x1440001b, 0xe08821, 0x8e330000, 0xafb00010, 0x8ea20000, 0xafa20014, 0x8e270000, -0x24053000, 0xc0029d3, 0x2403021, 0x8e230000, +0x24053000, 0xc002a03, 0x2403021, 0x8e230000, 0x702021, 0x64102b, 0x10400007, 0x2402821, 0x8ca20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24a50004, 0x8ea20000, 0x501023, 0xaea20000, 0x8e220000, 0x501021, 0x1000000b, 0xae220000, 0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000, 0x2409821, 0xafa20014, 0x8e270000, -0x24053100, 0xc0029d3, 0x2603021, 0x2601021, +0x24053100, 0xc002a03, 0x2603021, 0x2601021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 0x3c030001, -0x8c633dc0, 0x3c040001, 0x8c843dcc, 0x34a5bf08, -0x24021ffc, 0x3c010001, 0xac223c60, 0x3c0200c0, -0x3c010001, 0xac223c64, 0x3c020020, 0xafbf0010, +0x8c633ed0, 0x3c040001, 0x8c843edc, 0x34a5bf08, +0x24021ffc, 0x3c010001, 0xac223d70, 0x3c0200c0, +0x3c010001, 0xac223d74, 0x3c020020, 0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, -0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3c5c, +0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, 0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0, 0x346307b8, 0x24021dfc, 0x3c010001, -0xac223c60, 0x24021844, 0x3c010001, 0xac243c64, -0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, +0xac223d70, 0x24021844, 0x3c010001, 0xac243d74, +0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, 0xc0017ba, 0x375a0200, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843094, -0x24053200, 0x3c020001, 0x8c423c60, 0x3c030001, -0x8c633c64, 0x3021, 0x3603821, 0xafbf0030, +0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843154, +0x24053200, 0x3c020001, 0x8c423d70, 0x3c030001, +0x8c633d74, 0x3021, 0x3603821, 0xafbf0030, 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, -0xafa2001c, 0xafa30018, 0xafb70010, 0xc0029d3, +0xafa2001c, 0xafa30018, 0xafb70010, 0xc002a03, 0xafba0014, 0xc0018c2, 0x0, 0x8f820240, 0x34420004, 0xaf820240, 0x24020001, 0xaf420000, 0x3c020001, 0x571021, 0x904240f4, 0x10400092, -0x2403fffc, 0x3c100001, 0x2610a6d3, 0x3c120001, -0x2652a2ac, 0x2121023, 0x438024, 0x8fa3001c, -0x3c040001, 0x248430a0, 0x70102b, 0x1440001a, +0x2403fffc, 0x3c100001, 0x2610a79b, 0x3c120001, +0x2652a374, 0x2121023, 0x438024, 0x8fa3001c, +0x3c040001, 0x24843160, 0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, -0xafb00010, 0xafa30014, 0xc0029d3, 0x2203821, +0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, 0xae620000, 0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, -0x8fa3001c, 0x3c040001, 0x248430bc, 0x24120020, -0x3c010001, 0xac313dec, 0x2c620020, 0x1440001d, +0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, +0x8fa3001c, 0x3c040001, 0x2484317c, 0x24120020, +0x3c010001, 0xac313efc, 0x2c620020, 0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63e80, 0xafa70010, 0xafa30014, 0xc0029d3, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843e80, +0x24c63f90, 0xafa70010, 0xafa30014, 0xc002a03, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843f90, 0x24650020, 0x65102b, 0x10400007, 0x0, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103e80, 0x24053100, +0xae220000, 0x3c100001, 0x26103f90, 0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, -0x3c040001, 0x248430d0, 0x8fa3001c, 0x24120020, -0x3c010001, 0xac303e20, 0x2c620020, 0x1440001d, +0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, +0x3c040001, 0x24843190, 0x8fa3001c, 0x24120020, +0x3c010001, 0xac303f30, 0x2c620020, 0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63ea0, 0xafa70010, 0xafa30014, 0xc0029d3, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843ea0, +0x24c63fb0, 0xafa70010, 0xafa30014, 0xc002a03, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843fb0, 0x24650020, 0x65102b, 0x10400007, 0x0, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103ea0, 0x24053100, +0xae220000, 0x3c100001, 0x26103fb0, 0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x3c010001, -0x10000031, 0xac303e1c, 0x3c100000, 0x26107c8f, +0x2402002d, 0xc002a03, 0xa0820000, 0x3c010001, +0x10000031, 0xac303f2c, 0x3c100000, 0x26107c8f, 0x3c120000, 0x26527b0c, 0x2121023, 0x438024, -0x8fa3001c, 0x3c040001, 0x248430e4, 0x70102b, +0x8fa3001c, 0x3c040001, 0x248431a4, 0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, -0x2403021, 0xafb00010, 0xafa30014, 0xc0029d3, +0x2403021, 0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, 0xae620000, 0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, -0x2203021, 0x2402002d, 0xc0029d3, 0xa0820000, -0x3c010001, 0xac313dec, 0x3c030001, 0x8c633dec, +0x2203021, 0x2402002d, 0xc002a03, 0xa0820000, +0x3c010001, 0xac313efc, 0x3c030001, 0x8c633efc, 0x24020400, 0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x0, 0x8f820040, @@ -5032,17 +5033,17 @@ 0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, 0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, -0x36940040, 0x3c020001, 0x8c423d28, 0x10400027, -0x0, 0x3c020001, 0x8c423d14, 0x30420001, -0x14400010, 0x0, 0x3c020001, 0x8c423e58, -0x1040000c, 0x0, 0x3c020001, 0x8c423da4, +0x36940040, 0x3c020001, 0x8c423e38, 0x10400027, +0x0, 0x3c020001, 0x8c423e24, 0x30420001, +0x14400010, 0x0, 0x3c020001, 0x8c423f68, +0x1040000c, 0x0, 0x3c020001, 0x8c423eb4, 0x14400008, 0x0, 0x8f830224, 0x3c020001, -0x8c425f1c, 0x10620003, 0x0, 0xc003bad, +0x8c42602c, 0x10620003, 0x0, 0xc003be0, 0x0, 0x934205b1, 0x10400012, 0x24020001, 0x934305b1, 0x14620004, 0x3c0208ff, 0x24020002, 0x1000000c, 0xa34205b1, 0x3442fffb, 0xa34005b1, 0x8f830220, 0x3c040200, 0x284a025, 0x621824, -0xaf830220, 0x10000004, 0x3c020200, 0xc003f27, +0xaf830220, 0x10000004, 0x3c020200, 0xc003f57, 0x0, 0x3c020200, 0x2c21024, 0x10400003, 0x0, 0xc001de7, 0x0, 0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, @@ -5059,8 +5060,8 @@ 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24843184, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x8f820128, 0x3c040001, 0x24843248, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 0x1000005c, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0x10000027, 0xaf420038, 0x8f440160, @@ -5069,8 +5070,8 @@ 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x24843190, 0xafa20014, 0x8f46002c, 0x8f870120, -0x3c050009, 0xc0029d3, 0x34a51100, 0x10000036, +0x24843254, 0xafa20014, 0x8f46002c, 0x8f870120, +0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, @@ -5098,8 +5099,8 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x24843198, 0xafa20014, 0x8f460044, -0x8f870120, 0x3c050009, 0xc0029d3, 0x34a51300, +0x3c040001, 0x2484325c, 0xafa20014, 0x8f460044, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, 0x1000000f, 0x0, 0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 0x10000004, @@ -5111,20 +5112,20 @@ 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x3c020001, 0x8c423d28, 0x27bdffa8, +0x0, 0x3c020001, 0x8c423e38, 0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, 0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, -0x8c633d18, 0x34420002, 0xaf420004, 0x24020001, +0x8c633e28, 0x34420002, 0xaf420004, 0x24020001, 0x14620003, 0x3c020600, 0x10000002, 0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, 0x11420002, 0x1821, 0x25430001, 0x8c020228, 0x609821, 0x1662000e, 0x3c050009, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x8fa70034, 0x3c040001, 0x24843168, 0xafa00014, +0x8fa70034, 0x3c040001, 0x2484322c, 0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, @@ -5139,7 +5140,7 @@ 0x32a200ff, 0x54400018, 0xaf530018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843174, 0xafa20014, 0x8d460000, +0x3c040001, 0x24843238, 0xafa20014, 0x8d460000, 0x3c050009, 0x10000035, 0x34a50600, 0x8f4202f8, 0x24150001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, @@ -5152,8 +5153,8 @@ 0x1440ffee, 0x0, 0x32a200ff, 0x14400011, 0x3c050009, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, -0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, +0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 0x0, 0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 0x50400029, 0x36100040, 0x3c020400, 0x2c21024, 0x10400013, @@ -5176,10 +5177,10 @@ 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008, 0x0, 0x3c020001, -0x8c423d28, 0x27bdffb0, 0xafbf0048, 0xafbe0044, +0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, -0x8c843d18, 0x24430001, 0x2842000b, 0xaf4400e8, +0x8c843e28, 0x24430001, 0x2842000b, 0xaf4400e8, 0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, 0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, 0xaf420004, 0x24020001, 0x14820003, 0x3c020600, @@ -5188,7 +5189,7 @@ 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24843168, 0x3c050009, 0xafa00014, +0x3c040001, 0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, @@ -5202,7 +5203,7 @@ 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843174, 0x3c050009, +0x8f820124, 0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, 0x8f830054, @@ -5215,9 +5216,9 @@ 0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc0029d3, 0x3c03821, 0x8f4202dc, 0x24420001, +0xc002a03, 0x3c03821, 0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 0x10400033, 0x3c020400, 0x2c21024, 0x10400017, 0x0, 0x934205b0, 0x8f440240, 0x8f450244, @@ -5247,7 +5248,7 @@ 0x8f4300e8, 0x3042007f, 0xa34205b0, 0x24020001, 0x14620005, 0x0, 0x934405b0, 0x42102, 0x10000003, 0x348400f0, 0x934405b0, 0x3484000f, -0xc004b04, 0x0, 0x2402ff7f, 0x282a024, +0xc004b34, 0x0, 0x2402ff7f, 0x282a024, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, @@ -5300,7 +5301,7 @@ 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x24843168, 0x3c050009, 0xafa00014, 0xafa20010, +0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, @@ -5314,7 +5315,7 @@ 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843174, 0x3c050009, 0xafa20014, +0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, @@ -5327,13 +5328,13 @@ 0x326200ff, 0x54400012, 0x24020001, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x2484317c, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc0029d3, 0x3c03821, 0x1021, +0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, +0x34a50700, 0xc002a03, 0x3c03821, 0x1021, 0x1440005b, 0x24020001, 0x10000065, 0x0, 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x24843150, 0x3c050009, +0x8c020228, 0x3c040001, 0x24843214, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, @@ -5342,15 +5343,15 @@ 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843158, 0x3c050009, +0x8f820124, 0x3c040001, 0x2484321c, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x54400011, 0x24020001, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843160, 0x3c050009, -0xafa20014, 0x8fa60020, 0x34a50300, 0xc0029d3, +0x8f820124, 0x3c040001, 0x24843224, 0x3c050009, +0xafa20014, 0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, 0x1021, 0x1040000d, 0x24020001, 0x8f4202d8, 0xa34005b7, 0xaf4001a0, 0x24420001, 0xaf4202d8, 0x8f4202d8, 0x8ee20150, 0x24420001, @@ -5370,11 +5371,11 @@ 0x14620005, 0x0, 0x8f430124, 0x8f8200b4, 0x10620010, 0x0, 0x8f820104, 0xaf42011c, 0x8f8200b4, 0x8f43011c, 0xaf420124, 0xafa30010, -0x8f420124, 0x3c040001, 0x248431a0, 0xafa20014, +0x8f420124, 0x3c040001, 0x24843264, 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, 0x34a50900, 0x8f42011c, 0xafa20010, 0x8f420124, -0x3c040001, 0x248431ac, 0xafa20014, 0x8f86011c, -0x8f8700b0, 0x3c050005, 0xc0029d3, 0x34a51000, +0x3c040001, 0x24843270, 0xafa20014, 0x8f86011c, +0x8f8700b0, 0x3c050005, 0xc002a03, 0x34a51000, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, 0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, @@ -5382,9 +5383,9 @@ 0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42011c, -0xafa20010, 0x8f420124, 0x3c040001, 0x248431b8, +0xafa20010, 0x8f420124, 0x3c040001, 0x2484327c, 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, -0x34a51100, 0xc0029d3, 0x0, 0x8f8200a0, +0x34a51100, 0xc002a03, 0x0, 0x8f8200a0, 0x30420004, 0x10400069, 0x0, 0x8f430120, 0x8f820124, 0x14620005, 0x0, 0x8f430128, 0x8f8200a4, 0x10620006, 0x0, 0x8f820124, @@ -5397,21 +5398,21 @@ 0x0, 0x8f430128, 0x8f8200a4, 0x10620010, 0x0, 0x8f820124, 0xaf420120, 0x8f8200a4, 0x8f430120, 0xaf420128, 0xafa30010, 0x8f420128, -0x3c040001, 0x248431c4, 0xafa20014, 0x8f86011c, +0x3c040001, 0x24843288, 0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, 0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001, -0x248431d0, 0xafa20014, 0x8f86011c, 0x8f8700a0, -0x3c050005, 0xc0029d3, 0x34a51300, 0x8f82011c, +0x24843294, 0xafa20014, 0x8f86011c, 0x8f8700a0, +0x3c050005, 0xc002a03, 0x34a51300, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, 0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, 0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, -0x24c63e14, 0x40f809, 0x24070004, 0x8f82011c, +0x24c63f24, 0x40f809, 0x24070004, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, -0xafa20010, 0x8f420128, 0x3c040001, 0x248431dc, +0xafa20010, 0x8f420128, 0x3c040001, 0x248432a0, 0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, -0x34a51400, 0xc0029d3, 0x0, 0x8fbf0020, +0x34a51400, 0xc002a03, 0x0, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, 0x3c060080, 0x3c050100, 0x8f820070, 0x481024, 0x1040fffd, 0x0, 0x8f820054, 0x24420005, @@ -5479,8 +5480,8 @@ 0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048, 0x30c20001, 0x10400004, 0x24020001, 0xaf820064, 0x10000063, 0x0, 0x30c20002, 0x1440000b, -0x3c050003, 0x3c040001, 0x248432a4, 0x34a50500, -0x3821, 0xafa00010, 0xc0029d3, 0xafa00014, +0x3c050003, 0x3c040001, 0x24843364, 0x34a50500, +0x3821, 0xafa00010, 0xc002a03, 0xafa00014, 0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c, 0x8c02010c, 0x12020047, 0x101080, 0x8c450300, 0x26020001, 0x3050003f, 0x24020003, 0xac10022c, @@ -5508,29 +5509,29 @@ 0x808021, 0x101602, 0x2442ffff, 0x304300ff, 0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c, -0x31080, 0x3c010001, 0x220821, 0x8c2232e8, +0x31080, 0x3c010001, 0x220821, 0x8c2233a8, 0x400008, 0x0, 0x101302, 0x30440fff, 0x24020001, 0x10820005, 0x24020002, 0x1082000a, 0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, -0x3c020001, 0x8c423e40, 0xaf4401f0, 0xaf4401f4, +0x3c020001, 0x8c423f50, 0xaf4401f0, 0xaf4401f4, 0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0, -0xaf4401f4, 0x621824, 0x3c020001, 0x2442c254, +0xaf4401f4, 0x621824, 0x3c020001, 0x2442c344, 0x21100, 0x21182, 0xaf430004, 0x3c030800, 0x431025, 0x3c010000, 0xac224138, 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x10000009, 0xaf4201f8, 0x3c040001, -0x248432b0, 0x34a51000, 0x2003021, 0x3821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8f420290, +0x24843370, 0x34a51000, 0x2003021, 0x3821, +0xafa00010, 0xc002a03, 0xafa00014, 0x8f420290, 0x24420001, 0xaf420290, 0x10000215, 0x8f420290, -0x27b00028, 0x2002021, 0x24050210, 0xc002a57, +0x27b00028, 0x2002021, 0x24050210, 0xc002a87, 0x24060008, 0xc0023a0, 0x2002021, 0x1000020c, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c, 0xafa50028, 0xc0023a0, 0xafa3002c, 0x100001fc, 0x0, 0x27b00028, 0x2002021, 0x24050210, -0xc002a57, 0x24060008, 0xc0024df, 0x2002021, +0xc002a87, 0x24060008, 0xc0024df, 0x2002021, 0x100001f3, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, @@ -5550,8 +5551,8 @@ 0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009, -0x2c2b024, 0x3c040001, 0x248432bc, 0x34a51100, -0x2003021, 0x3821, 0xafa00010, 0xc0029d3, +0x2c2b024, 0x3c040001, 0x2484337c, 0x34a51100, +0x2003021, 0x3821, 0xafa00010, 0xc002a03, 0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc, 0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff, 0x24020001, 0x10a20005, 0x24020002, 0x10a2000d, @@ -5560,24 +5561,24 @@ 0x621824, 0x34630008, 0xaf830220, 0x10000012, 0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220, -0x10000009, 0xaf450288, 0x3c040001, 0x248432c8, +0x10000009, 0xaf450288, 0x3c040001, 0x24843388, 0x34a51200, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x8f4202ac, 0x24420001, +0xc002a03, 0xafa00014, 0x8f4202ac, 0x24420001, 0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208, -0x24050200, 0xc002a57, 0x24060008, 0x27440214, -0x24050200, 0xc002a57, 0x24060008, 0x8f4202b4, +0x24050200, 0xc002a87, 0x24060008, 0x27440214, +0x24050200, 0xc002a87, 0x24060008, 0x8f4202b4, 0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4, 0x101302, 0x30430fff, 0x24020001, 0x10620011, 0x28620002, 0x50400005, 0x24020002, 0x10600007, 0x0, 0x10000017, 0x0, 0x1062000f, 0x0, 0x10000013, 0x0, 0x8c060248, -0x2021, 0xc004878, 0x24050004, 0x10000007, -0x0, 0x8c060248, 0x2021, 0xc004878, +0x2021, 0xc0048a8, 0x24050004, 0x10000007, +0x0, 0x8c060248, 0x2021, 0xc0048a8, 0x24050004, 0x10000010, 0x0, 0x8c06024c, -0x2021, 0xc004878, 0x24050001, 0x1000000a, -0x0, 0x3c040001, 0x248432d4, 0x3c050003, +0x2021, 0xc0048a8, 0x24050001, 0x1000000a, +0x0, 0x3c040001, 0x24843394, 0x3c050003, 0x34a51300, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x8f4202b0, 0x24420001, +0xc002a03, 0xafa00014, 0x8f4202b0, 0x24420001, 0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022b4, 0x0, 0x10000132, 0x0, 0x24020001, 0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c, @@ -5590,7 +5591,7 @@ 0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x2484326c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x2484332c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, @@ -5605,7 +5606,7 @@ 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843278, 0x3c050009, 0xafa20014, 0x8d460000, +0x24843338, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, @@ -5617,26 +5618,26 @@ 0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843280, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843340, 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc0029d3, 0x3c03821, 0x8f4202a0, 0x24420001, +0xc002a03, 0x3c03821, 0x8f4202a0, 0x24420001, 0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001, 0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, -0x24060008, 0xc002a57, 0xaf4201e8, 0x8f820220, +0x24060008, 0xc002a87, 0xaf4201e8, 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c, 0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff, 0x2021824, 0x32c20180, 0x14400006, 0x3402fffb, 0x43102b, 0x14400003, 0x0, 0x1000006c, -0xaf4300bc, 0x3c040001, 0x248432e0, 0x3c050003, +0xaf4300bc, 0x3c040001, 0x248433a0, 0x3c050003, 0x34a51500, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x3c020700, 0x34421000, +0xc002a03, 0xafa00014, 0x3c020700, 0x34421000, 0x101e02, 0x621825, 0xafa30020, 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24843254, 0x3c050009, 0xafa00014, +0x3c040001, 0x24843314, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, @@ -5645,15 +5646,15 @@ 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x2484325c, 0x3c050009, 0xafa20014, +0x3c040001, 0x2484331c, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843264, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc0029d3, 0x2203821, +0x3c040001, 0x24843324, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, 0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0, 0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, @@ -5673,21 +5674,21 @@ 0x431024, 0x34420004, 0xaf820200, 0x8f53034c, 0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014, 0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0, -0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a40, +0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a70, 0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354, 0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4, 0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8, -0x24020006, 0xc002a57, 0xaf4201e4, 0x3c023b9a, +0x24020006, 0xc002a87, 0xaf4201e4, 0x3c023b9a, 0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002, 0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaf430288, 0x10000003, 0x3021, 0xaf440288, -0x3021, 0x3c030001, 0x661821, 0x90633c80, +0x3021, 0x3c030001, 0x661821, 0x90633d90, 0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f, 0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040, 0x24040080, 0x24050080, 0x21702, 0x24420030, -0xa062021c, 0x3461021, 0xc002a40, 0xa040021c, +0xa062021c, 0x3461021, 0xc002a70, 0xa040021c, 0x8fa7001c, 0x30e20004, 0x14400006, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006, @@ -5739,15 +5740,15 @@ 0x10c00014, 0x610c0, 0x571821, 0x3c010001, 0x230821, 0x8c2334d0, 0x571021, 0xafa30010, 0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, -0x248433f0, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc0029d3, 0x34a50400, 0x10000063, +0x248434b4, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc002a03, 0x34a50400, 0x10000063, 0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, 0x2e21021, 0x3c010001, 0x220821, 0x942234d0, 0xaf420100, 0xa03021, 0x14c00011, 0x628c0, 0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, -0x220821, 0x942230d0, 0x3c040001, 0x248433fc, +0x220821, 0x942230d0, 0x3c040001, 0x248434c0, 0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, -0xc0029d3, 0x34a50500, 0x10000048, 0x3c020800, +0xc002a03, 0x34a50500, 0x10000048, 0x3c020800, 0xb71821, 0x3c020001, 0x96040000, 0x344234d2, 0x621821, 0xa4640000, 0x8e020002, 0x720c0, 0xac620002, 0x2e41021, 0x3c030001, 0x621821, @@ -5770,7 +5771,7 @@ 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x248433b8, 0x3c050009, +0x8c020228, 0x3c040001, 0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, @@ -5784,7 +5785,7 @@ 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x248433c4, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, @@ -5797,8 +5798,8 @@ 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x248433cc, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0x8f820124, 0x3c040001, 0x24843490, 0x3c050009, +0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4, 0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, @@ -5818,8 +5819,8 @@ 0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, 0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, 0x3c010001, 0x220821, 0x942230d0, 0x3c040001, -0x24843408, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc0029d3, 0x34a50900, 0x10000075, +0x248434cc, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc002a03, 0x34a50900, 0x10000075, 0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, 0x3c030001, 0x621821, 0x946334d0, 0x710c0, 0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, @@ -5854,7 +5855,7 @@ 0xafab0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x248433b8, 0x3c050009, 0xafa00014, 0xafa20010, +0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, @@ -5868,7 +5869,7 @@ 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, -0x3c040001, 0x248433c4, 0x3c050009, 0xafa20014, +0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, 0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, @@ -5881,14 +5882,14 @@ 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x248433cc, 0x3c050009, 0xafa20014, 0x8d660000, -0x34a50700, 0xc0029d3, 0x3c03821, 0x8f4202a8, +0x24843490, 0x3c050009, 0xafa20014, 0x8d660000, +0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a8, 0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 0x0, 0x0, 0x0, 0x27bdffe0, -0x27644000, 0xafbf0018, 0xc002a40, 0x24051000, +0x27644000, 0xafbf0018, 0xc002a70, 0x24051000, 0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, 0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, @@ -5897,15 +5898,15 @@ 0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, 0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, 0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, -0x3c040001, 0x248434d0, 0x3c050001, 0x34420001, +0x3c040001, 0x24843590, 0x3c050001, 0x34420001, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x34a50100, 0xc0029d3, 0x3821, 0x8c020218, +0x34a50100, 0xc002a03, 0x3821, 0x8c020218, 0x30420040, 0x10400014, 0x0, 0x8f82011c, -0x3c040001, 0x248434dc, 0x3c050001, 0x34420004, +0x3c040001, 0x2484359c, 0x3c050001, 0x34420004, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x10000007, 0x34a50200, 0x3c040001, 0x248434e4, +0x10000007, 0x34a50200, 0x3c040001, 0x248435a4, 0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, -0xc0029d3, 0x3821, 0x8fbf0018, 0x3e00008, +0xc002a03, 0x3821, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, 0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, 0x24680020, 0x27684800, 0x8f820128, 0x11020004, @@ -5962,189 +5963,201 @@ 0xad0b0010, 0xaf890100, 0x10000006, 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0xaf430328, 0x8f430328, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x27bdffd8, 0x3c040001, 0x248434ec, +0x0, 0x27bdffd8, 0x3c040001, 0x248435ac, 0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, 0x2403021, 0x2203821, -0xafa20010, 0xc0029d3, 0xafb00014, 0x8e020008, -0xafa20010, 0x8e02000c, 0x3c040001, 0x248434f8, +0xafa20010, 0xc002a03, 0xafb00014, 0x8e020008, +0xafa20010, 0x8e02000c, 0x3c040001, 0x248435b8, 0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001, -0xc0029d3, 0x34a52510, 0x8e020018, 0xafa20010, -0x8e02001c, 0x3c040001, 0x24843504, 0xafa20014, -0x8e060010, 0x8e070014, 0x3c050001, 0xc0029d3, -0x34a52520, 0x3c030200, 0x2c31024, 0x1040000d, +0xc002a03, 0x34a52510, 0x8e020018, 0xafa20010, +0x8e02001c, 0x3c040001, 0x248435c4, 0xafa20014, +0x8e060010, 0x8e070014, 0x3c050001, 0xc002a03, +0x34a52520, 0x3c027f00, 0x2221024, 0x3c030800, +0x54430016, 0x3c030200, 0x8f82009c, 0x3042ffff, +0x14400012, 0x3c030200, 0x3c040001, 0x248435d0, +0x3c050002, 0x34a5f030, 0x3021, 0x3821, +0x36420002, 0xaf82011c, 0x36220001, 0xaf8200b0, +0xaf900104, 0xaf92011c, 0xafa00010, 0xc002a03, +0xafa00014, 0x10000024, 0x0, 0x2c31024, +0x1040000d, 0x2231024, 0x1040000b, 0x36420002, +0xaf82011c, 0x36220001, 0xaf8200b0, 0xaf900104, +0xaf92011c, 0x8f420320, 0x24420001, 0xaf420320, +0x10000015, 0x8f420320, 0x3c040001, 0x248435d8, +0x240202a2, 0xafa20010, 0xafa00014, 0x8f860144, +0x3c070001, 0x24e735e0, 0xc002a03, 0x3405dead, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, +0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, +0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, +0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, +0x27bdffd8, 0x3c040001, 0x24843608, 0x3c050001, +0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, +0x8f900124, 0x8f9100a0, 0x8f92011c, 0x34a52600, +0x8f820120, 0x2403021, 0x2203821, 0xafa20010, +0xc002a03, 0xafb00014, 0x8e020008, 0xafa20010, +0x8e02000c, 0x3c040001, 0x24843614, 0xafa20014, +0x8e060000, 0x8e070004, 0x3c050001, 0xc002a03, +0x34a52610, 0x8e020018, 0xafa20010, 0x8e02001c, +0x3c040001, 0x24843620, 0xafa20014, 0x8e060010, +0x8e070014, 0x3c050001, 0xc002a03, 0x34a52620, +0x3c027f00, 0x2221024, 0x3c030800, 0x54430016, +0x3c030200, 0x8f8200ac, 0x3042ffff, 0x14400012, +0x3c030200, 0x3c040001, 0x2484362c, 0x3c050001, +0x34a5f030, 0x3021, 0x3821, 0x36420002, +0xaf82011c, 0x36220001, 0xaf8200a0, 0xaf900124, +0xaf92011c, 0xafa00010, 0xc002a03, 0xafa00014, +0x10000024, 0x0, 0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, 0x36420002, 0xaf82011c, -0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, -0x8f420320, 0x24420001, 0xaf420320, 0x10000015, -0x8f420320, 0x3c040001, 0x24843510, 0x24020290, +0x36220001, 0xaf8200a0, 0xaf900124, 0xaf92011c, +0x8f42031c, 0x24420001, 0xaf42031c, 0x10000015, +0x8f42031c, 0x3c040001, 0x248435d8, 0x240202db, 0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001, -0x24e73518, 0xc0029d3, 0x3405dead, 0x8f82011c, +0x24e735e0, 0xc002a03, 0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0028, 0x27bdffd8, -0x3c040001, 0x24843540, 0x3c050001, 0xafbf0024, -0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900124, -0x8f9100a0, 0x8f92011c, 0x34a52600, 0x8f820120, -0x2403021, 0x2203821, 0xafa20010, 0xc0029d3, -0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, -0x3c040001, 0x2484354c, 0xafa20014, 0x8e060000, -0x8e070004, 0x3c050001, 0xc0029d3, 0x34a52610, -0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, -0x24843558, 0xafa20014, 0x8e060010, 0x8e070014, -0x3c050001, 0xc0029d3, 0x34a52620, 0x3c030200, -0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, -0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, -0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001, -0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001, -0x24843510, 0x240202bc, 0xafa20010, 0xafa00014, -0x8f860144, 0x3c070001, 0x24e73518, 0xc0029d3, -0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, -0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, -0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, -0x27bd0028, 0x6021, 0x5021, 0x3021, -0x2821, 0x6821, 0x4821, 0x7821, -0x7021, 0x8f880124, 0x8f870104, 0x1580002e, -0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, -0x10460029, 0x0, 0x3c040001, 0x8c843e20, -0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, -0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, -0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c843e20, 0x8d020000, 0x8d030004, -0xac820000, 0xac830004, 0x8d020008, 0xac820008, -0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, -0xac820014, 0x27624fe0, 0x43102b, 0x54400001, -0x27634800, 0x603021, 0x1540002f, 0x31620100, -0x11200014, 0x31628000, 0x8f820100, 0x1045002a, -0x31620100, 0x3c040001, 0x8c843e1c, 0x8ca20000, -0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, -0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, -0x24a50020, 0x10400018, 0x31620100, 0x3c040001, -0x8c843e1c, 0x8ce20000, 0x8ce30004, 0xac820000, -0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, -0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, -0x276247e0, 0x43102b, 0x54400001, 0x27634000, -0x602821, 0x31620100, 0x5440001d, 0x31621000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, -0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, -0x8f880124, 0x6821, 0x11800011, 0x31621000, -0x3c040001, 0x8c843e20, 0x8c820000, 0x8c830004, -0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, -0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, -0x1440ff82, 0x0, 0x1120000f, 0x31220800, -0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1221024, 0x10400004, 0x24e20020, -0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, -0x8f870104, 0x4821, 0x1140ff70, 0x0, -0x3c040001, 0x8c843e1c, 0x8c820000, 0x8c830004, -0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, -0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, -0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, -0x3e00008, 0x0, 0x6021, 0x5821, -0x3021, 0x2821, 0x6821, 0x5021, -0x7821, 0x7021, 0x8f880124, 0x8f870104, -0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, -0x31220800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c843e20, 0x8cc20000, 0x8cc30004, +0x8fb00018, 0x3e00008, 0x27bd0028, 0x6021, +0x5021, 0x3021, 0x2821, 0x6821, +0x4821, 0x7821, 0x7021, 0x8f880124, +0x8f870104, 0x1580002e, 0x8f8b011c, 0x11a00014, +0x31620800, 0x8f820120, 0x10460029, 0x0, +0x3c040001, 0x8c843f30, 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, -0x10400017, 0x0, 0x3c040001, 0x8c843e20, +0x10400017, 0x0, 0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, 0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, 0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, 0x43102b, 0x54400001, 0x27634800, 0x603021, -0x1560002f, 0x31220100, 0x11400014, 0x31228000, -0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, -0x8c843e1c, 0x8ca20000, 0x8ca30004, 0xac820000, +0x1540002f, 0x31620100, 0x11200014, 0x31628000, +0x8f820100, 0x1045002a, 0x31620100, 0x3c040001, +0x8c843f2c, 0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, -0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, +0xa482000e, 0x8ca20010, 0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, -0x31220100, 0x3c040001, 0x8c843e1c, 0x8ce20000, +0x31620100, 0x3c040001, 0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, -0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, +0x24e50020, 0xac820010, 0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31220100, -0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, +0x54400001, 0x27634000, 0x602821, 0x31620100, +0x5440001d, 0x31621000, 0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 0x8f880124, 0x6821, -0x11800011, 0x31221000, 0x3c040001, 0x8c843e20, +0x11800011, 0x31621000, 0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, -0x8c8f0014, 0x31221000, 0x14400022, 0x0, -0x1140000f, 0x31420800, 0x10400004, 0x3c020002, -0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, +0x8c8f0014, 0x31621000, 0x1440ff82, 0x0, +0x1120000f, 0x31220800, 0x10400004, 0x3c020002, +0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1221024, 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x5021, -0x11600010, 0x0, 0x3c040001, 0x8c843e1c, +0x24e20020, 0xaf820104, 0x8f870104, 0x4821, +0x1140ff70, 0x0, 0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, -0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, -0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, -0x1040ff5c, 0x0, 0x8f820054, 0x24420005, -0xaf820078, 0x8c040234, 0x10800016, 0x1821, -0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, -0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, -0x571021, 0x8c4240e8, 0x44102b, 0x14400009, -0x24020001, 0x3c030080, 0x3c010001, 0x370821, -0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, -0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, -0x14400006, 0x3c020080, 0x3c020001, 0x571021, -0x904240f1, 0x10400002, 0x3c020080, 0x621825, -0x8c040230, 0x10800013, 0x0, 0x3c020001, -0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, -0x370821, 0xac2240ec, 0x3c020001, 0x571021, -0x8c4240ec, 0x44102b, 0x14400006, 0x0, -0x3c010001, 0x370821, 0xac2040ec, 0x10000006, -0x781825, 0x3c020001, 0x571021, 0x904240f2, -0x54400001, 0x781825, 0x1060ff1a, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x431025, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x1000ff05, -0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, -0x0, 0x0, 0x0, 0x3c020001, -0x8c423ca8, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26103ec0, 0x2002021, -0xc002a40, 0x24052000, 0x26021fe0, 0x3c010001, -0xac223e28, 0x3c010001, 0xac223e24, 0xac020250, +0x8c820010, 0x5021, 0xaf8200b0, 0x8c890010, +0x1000ff60, 0x8c8e0014, 0x3e00008, 0x0, +0x6021, 0x5821, 0x3021, 0x2821, +0x6821, 0x5021, 0x7821, 0x7021, +0x8f880124, 0x8f870104, 0x3c180100, 0x1580002e, +0x8f89011c, 0x11a00014, 0x31220800, 0x8f820120, +0x10460029, 0x0, 0x3c040001, 0x8c843f30, +0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, +0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, +0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, +0x10000012, 0x24c60020, 0x10400017, 0x0, +0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, +0xac820000, 0xac830004, 0x8d020008, 0xac820008, +0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, +0xac820010, 0x8d020014, 0x240c0001, 0xc01821, +0xac820014, 0x27624fe0, 0x43102b, 0x54400001, +0x27634800, 0x603021, 0x1560002f, 0x31220100, +0x11400014, 0x31228000, 0x8f820100, 0x1045002a, +0x31220100, 0x3c040001, 0x8c843f2c, 0x8ca20000, +0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, +0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, +0x240b0001, 0xac820010, 0x8ca20014, 0x10000012, +0x24a50020, 0x10400018, 0x31220100, 0x3c040001, +0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, +0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, +0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, +0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, +0x276247e0, 0x43102b, 0x54400001, 0x27634000, +0x602821, 0x31220100, 0x5440001d, 0x31221000, +0x11a00009, 0x31a20800, 0x10400004, 0x25020020, +0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, +0x8f880124, 0x6821, 0x11800011, 0x31221000, +0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, +0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, +0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, +0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31221000, +0x14400022, 0x0, 0x1140000f, 0x31420800, +0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, +0x3c020002, 0x1421024, 0x10400004, 0x24e20020, +0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, +0x8f870104, 0x5021, 0x11600010, 0x0, +0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, +0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, +0x9482000e, 0xaf82009c, 0x8c820010, 0x5821, +0xaf8200b0, 0x8c8a0010, 0x8c8e0014, 0x8f820070, +0x3c031000, 0x431024, 0x1040ff5c, 0x0, +0x8f820054, 0x24420005, 0xaf820078, 0x8c040234, +0x10800016, 0x1821, 0x3c020001, 0x571021, +0x8c4240e8, 0x24420005, 0x3c010001, 0x370821, +0xac2240e8, 0x3c020001, 0x571021, 0x8c4240e8, +0x44102b, 0x14400009, 0x24020001, 0x3c030080, +0x3c010001, 0x370821, 0xac2040e8, 0x3c010001, +0x370821, 0x1000000c, 0xa02240f0, 0x3c020001, +0x571021, 0x904240f0, 0x14400006, 0x3c020080, +0x3c020001, 0x571021, 0x904240f1, 0x10400002, +0x3c020080, 0x621825, 0x8c040230, 0x10800013, +0x0, 0x3c020001, 0x571021, 0x8c4240ec, +0x24420005, 0x3c010001, 0x370821, 0xac2240ec, +0x3c020001, 0x571021, 0x8c4240ec, 0x44102b, +0x14400006, 0x0, 0x3c010001, 0x370821, +0xac2040ec, 0x10000006, 0x781825, 0x3c020001, +0x571021, 0x904240f2, 0x54400001, 0x781825, +0x1060ff1a, 0x0, 0x8f420000, 0x10400007, +0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, +0x0, 0x10000005, 0x0, 0xaf800048, +0x8f820048, 0x1040fffd, 0x0, 0x8f820060, +0x431025, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x1000ff05, 0xaf80004c, 0x1000ff03, +0xaf800048, 0x3e00008, 0x0, 0x3c020001, +0x8c423db8, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26103fd0, 0x2002021, +0xc002a70, 0x24052000, 0x26021fe0, 0x3c010001, +0xac223f38, 0x3c010001, 0xac223f34, 0xac020250, 0x24022000, 0xac100254, 0xac020258, 0x24020001, -0x3c010001, 0xac223ca8, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e28, +0x3c010001, 0xac223db8, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293f38, 0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, 0x8c820004, 0xad250008, 0xad220004, 0x8f820054, 0xad260010, 0xad270014, 0xad230018, 0xad28001c, -0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423ec0, +0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423fd0, 0x122102b, 0x10400003, 0x0, 0x3c090001, -0x8d293e24, 0x3c020001, 0x8c423c90, 0xad220000, -0x3c020001, 0x8c423c90, 0x3c010001, 0xac293e28, +0x8d293f34, 0x3c020001, 0x8c423da0, 0xad220000, +0x3c020001, 0x8c423da0, 0x3c010001, 0xac293f38, 0xad220004, 0xac090250, 0x3e00008, 0x0, -0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e28, -0x3c020001, 0x8c423c90, 0xafb10014, 0x808821, +0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103f38, +0x3c020001, 0x8c423da0, 0xafb10014, 0x808821, 0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, 0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, -0xae020000, 0x3c020001, 0x8c423c90, 0xc09821, +0xae020000, 0x3c020001, 0x8c423da0, 0xc09821, 0xe0a821, 0x10800006, 0xae020004, 0x26050008, -0xc002a4b, 0x24060018, 0x10000005, 0x2610ffe0, -0x26040008, 0xc002a40, 0x24050018, 0x2610ffe0, -0x3c030001, 0x24633ec0, 0x203102b, 0x10400003, -0x0, 0x3c100001, 0x8e103e24, 0x8e220000, +0xc002a7b, 0x24060018, 0x10000005, 0x2610ffe0, +0x26040008, 0xc002a70, 0x24050018, 0x2610ffe0, +0x3c030001, 0x24633fd0, 0x203102b, 0x10400003, +0x0, 0x3c100001, 0x8e103f34, 0x8e220000, 0xae020000, 0x8e220004, 0xae120008, 0xae020004, 0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, 0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, 0x203102b, 0x10400003, 0x0, 0x3c100001, -0x8e103e24, 0x3c020001, 0x8c423c90, 0xae020000, -0x3c020001, 0x8c423c90, 0x3c010001, 0xac303e28, +0x8e103f34, 0x3c020001, 0x8c423da0, 0xae020000, +0x3c020001, 0x8c423da0, 0x3c010001, 0xac303f38, 0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, 0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, @@ -6186,7 +6199,7 @@ 0x27bdffc0, 0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030, 0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028, 0x10000002, 0x0, 0x8f530020, -0x8f420030, 0x105300e4, 0x21100, 0x8f43001c, +0x8f420030, 0x105300eb, 0x21100, 0x8f43001c, 0x628021, 0x8e040000, 0x8e050004, 0x96120008, 0x8f420090, 0x9611000a, 0x3246ffff, 0x46102a, 0x10400017, 0x0, 0x8f8200d8, 0x8f430098, @@ -6194,9 +6207,9 @@ 0x2842fff9, 0x10400005, 0x0, 0x8f420090, 0x8f430138, 0x431021, 0xaf420090, 0x8f420090, 0x46102a, 0x10400006, 0x0, 0x8f420338, -0x24420001, 0xaf420338, 0x100000da, 0x8f420338, +0x24420001, 0xaf420338, 0x100000e1, 0x8f420338, 0x8f8200fc, 0x14400006, 0x32c20008, 0x8f420334, -0x24420001, 0xaf420334, 0x100000d2, 0x8f420334, +0x24420001, 0xaf420334, 0x100000d9, 0x8f420334, 0x5040000c, 0xaf4000ac, 0x934205b3, 0x10400008, 0x32220200, 0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, 0x21400, 0x10000002, 0xaf4200b0, @@ -6205,7 +6218,7 @@ 0x24020004, 0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, 0x3c030002, 0x431025, 0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, 0x0, -0x104000b0, 0x0, 0x8f42009c, 0x8f430094, +0x104000b7, 0x0, 0x8f42009c, 0x8f430094, 0x2421021, 0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008, 0x3c034000, 0x8f420094, 0x431025, 0xafa20020, 0x8f42009c, 0x8f4300b0, 0x10000004, @@ -6232,123 +6245,124 @@ 0x8f420090, 0x8f430094, 0x862024, 0x441023, 0x65182b, 0x14600005, 0xaf420090, 0x8f420094, 0x8f430138, 0x431023, 0xaf420094, 0x8f420094, -0x10000023, 0xaf40009c, 0x3247ffff, 0x10e00021, -0x0, 0x14400002, 0x24020010, 0x24020002, +0x10000023, 0xaf40009c, 0x3247ffff, 0x50e00022, +0x32c20020, 0x14400002, 0x24020010, 0x24020002, 0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, -0x0, 0x10400033, 0x3245ffff, 0x8f420098, +0x0, 0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090, 0x8f460130, 0x451021, 0xaf420098, 0x8f42009c, 0x8f440098, 0xa34005b3, 0x651823, 0xaf430090, 0x451021, 0x86202b, 0x14800005, 0xaf42009c, 0x8f420098, 0x8f430138, 0x431023, -0xaf420098, 0x8f420030, 0x8f430040, 0x24420001, -0x2463ffff, 0x431024, 0xaf420030, 0x8f420030, -0x14530018, 0x0, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x2403fff7, 0x431024, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x8fbf0038, 0x8fb30034, 0x8fb20030, -0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0040, -0x3e00008, 0x0, 0x27bdffd0, 0x32c20020, -0xafbf002c, 0xafb20028, 0xafb10024, 0x10400004, -0xafb00020, 0x8f520028, 0x10000002, 0x0, -0x8f520020, 0x8f420030, 0x105200b5, 0x21100, -0x8f43001c, 0x628021, 0x8e040000, 0x8e050004, -0x96110008, 0x8f420090, 0x9607000a, 0x3226ffff, -0x46102a, 0x10400017, 0x0, 0x8f8200d8, -0x8f430098, 0x431023, 0x2442ff80, 0xaf420090, -0x8f420090, 0x2842ff81, 0x10400005, 0x0, -0x8f420090, 0x8f430138, 0x431021, 0xaf420090, -0x8f420090, 0x46102a, 0x10400006, 0x0, -0x8f420338, 0x24420001, 0xaf420338, 0x100000ab, -0x8f420338, 0x8f8600fc, 0x10c0000c, 0x0, -0x8f8200f4, 0x2403fff8, 0x431024, 0x461023, -0x218c3, 0x50600001, 0x24030100, 0x8f42008c, -0x43102b, 0x14400006, 0x712c2, 0x8f420334, -0x24420001, 0xaf420334, 0x10000098, 0x8f420334, -0x934305b3, 0x1060000f, 0x30460001, 0x8f420010, -0x34480400, 0x32c20008, 0x10400008, 0x30e20200, -0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, -0x21400, 0x10000004, 0xaf4200b0, 0x10000002, -0xaf4000ac, 0x8f480010, 0x30e20004, 0x10400045, -0x3227ffff, 0x8f4900ac, 0x11200005, 0x30c200ff, -0x14400006, 0x24020040, 0x10000004, 0x24020008, -0x14400002, 0x24020020, 0x24020004, 0xafa20010, -0x8f430030, 0x11200004, 0xafa30014, 0x8f4200b0, -0x621025, 0xafa20014, 0x3c020002, 0x1021025, -0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, -0x0, 0x10400069, 0x3224ffff, 0x8f42008c, -0x8f430094, 0x24420001, 0xaf42008c, 0x24020001, -0xae03000c, 0xa34205b3, 0x8f420098, 0x2406fff8, -0x8f450130, 0x441021, 0x24420007, 0x461024, -0x24840007, 0xaf420094, 0x8f420090, 0x8f430094, -0x862024, 0x441023, 0x65182b, 0x14600005, -0xaf420090, 0x8f420094, 0x8f430138, 0x431023, -0xaf420094, 0x8f430094, 0x8f420134, 0x43102b, -0x10400009, 0x0, 0x8f430130, 0x8f440094, -0x8f420090, 0x8f45012c, 0x641823, 0x431023, -0xaf420090, 0xaf450094, 0x8f420094, 0x1000001f, -0xaf420098, 0x10e0001d, 0x30c200ff, 0x14400002, -0x24020010, 0x24020002, 0xafa20010, 0x8f420030, -0xafa80018, 0xafa20014, 0x8f460098, 0x8f420108, -0x40f809, 0x0, 0x10400030, 0x3225ffff, -0x8f420098, 0x8f440130, 0x451021, 0xaf420098, -0x8f420090, 0x8f430098, 0xa34005b3, 0x451023, -0x64182b, 0x14600005, 0xaf420090, 0x8f420098, -0x8f430138, 0x431023, 0xaf420098, 0x8f420030, -0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf420030, 0x8f420030, 0x14520018, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x2403fff7, 0x431024, -0xaf820060, 0x8f420000, 0x10400003, 0x0, -0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, -0x27bd0030, 0x3e00008, 0x0, 0x27bdffd8, -0x3c020001, 0x34422ec0, 0xafbf0020, 0x8f4300f0, -0x8f840108, 0x2e21021, 0x54620004, 0x24620008, -0x3c020001, 0x34422cc0, 0x2e21021, 0x401821, -0xaf4300f0, 0xac600000, 0x8f4200ec, 0x8c660004, -0x14620004, 0x3c020001, 0x24820020, 0x1000000f, -0xaf820108, 0x8f4300f0, 0x34422ec0, 0x2e21021, -0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, -0x2e21021, 0x401821, 0x8c620004, 0x21140, -0x821021, 0xaf820108, 0xac600000, 0x8c850018, -0x30a20036, 0x1040006c, 0x30a20001, 0x8c82001c, -0x8f430040, 0x8f440034, 0x24420001, 0x2463ffff, -0x431024, 0x862021, 0xaf42002c, 0x30a20030, -0x14400006, 0xaf440034, 0x8f420034, 0x8c03023c, -0x43102b, 0x144000c9, 0x0, 0x32c20010, -0x10400028, 0x24070008, 0x8f440160, 0x8f450164, -0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020080, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x24020001, -0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x24843800, -0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51100, 0x10000036, 0x0, -0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, -0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, -0xaf430038, 0x8f440160, 0x8f450164, 0x8f43002c, -0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, +0xaf420098, 0x32c20020, 0x10400005, 0x0, +0x8f420348, 0x2442ffff, 0xaf420348, 0x8f420348, +0x8f420030, 0x8f430040, 0x24420001, 0x2463ffff, +0x431024, 0xaf420030, 0x8f420030, 0x14530018, +0x0, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x2403fff7, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, +0x8fb00028, 0x3e00008, 0x27bd0040, 0x3e00008, +0x0, 0x27bdffd0, 0x32c20020, 0xafbf002c, +0xafb20028, 0xafb10024, 0x10400004, 0xafb00020, +0x8f520028, 0x10000002, 0x0, 0x8f520020, +0x8f420030, 0x105200b5, 0x21100, 0x8f43001c, +0x628021, 0x8e040000, 0x8e050004, 0x96110008, +0x8f420090, 0x9607000a, 0x3226ffff, 0x46102a, +0x10400017, 0x0, 0x8f8200d8, 0x8f430098, +0x431023, 0x2442ff80, 0xaf420090, 0x8f420090, +0x2842ff81, 0x10400005, 0x0, 0x8f420090, +0x8f430138, 0x431021, 0xaf420090, 0x8f420090, +0x46102a, 0x10400006, 0x0, 0x8f420338, +0x24420001, 0xaf420338, 0x100000ab, 0x8f420338, +0x8f8600fc, 0x10c0000c, 0x0, 0x8f8200f4, +0x2403fff8, 0x431024, 0x461023, 0x218c3, +0x50600001, 0x24030100, 0x8f42008c, 0x43102b, +0x14400006, 0x712c2, 0x8f420334, 0x24420001, +0xaf420334, 0x10000098, 0x8f420334, 0x934305b3, +0x1060000f, 0x30460001, 0x8f420010, 0x34480400, +0x32c20008, 0x10400008, 0x30e20200, 0x10400006, +0x3c034000, 0x9602000e, 0xaf4300ac, 0x21400, +0x10000004, 0xaf4200b0, 0x10000002, 0xaf4000ac, +0x8f480010, 0x30e20004, 0x10400045, 0x3227ffff, +0x8f4900ac, 0x11200005, 0x30c200ff, 0x14400006, +0x24020040, 0x10000004, 0x24020008, 0x14400002, +0x24020020, 0x24020004, 0xafa20010, 0x8f430030, +0x11200004, 0xafa30014, 0x8f4200b0, 0x621025, +0xafa20014, 0x3c020002, 0x1021025, 0xafa20018, +0x8f460098, 0x8f420108, 0x40f809, 0x0, +0x10400069, 0x3224ffff, 0x8f42008c, 0x8f430094, +0x24420001, 0xaf42008c, 0x24020001, 0xae03000c, +0xa34205b3, 0x8f420098, 0x2406fff8, 0x8f450130, +0x441021, 0x24420007, 0x461024, 0x24840007, +0xaf420094, 0x8f420090, 0x8f430094, 0x862024, +0x441023, 0x65182b, 0x14600005, 0xaf420090, +0x8f420094, 0x8f430138, 0x431023, 0xaf420094, +0x8f430094, 0x8f420134, 0x43102b, 0x10400009, +0x0, 0x8f430130, 0x8f440094, 0x8f420090, +0x8f45012c, 0x641823, 0x431023, 0xaf420090, +0xaf450094, 0x8f420094, 0x1000001f, 0xaf420098, +0x10e0001d, 0x30c200ff, 0x14400002, 0x24020010, +0x24020002, 0xafa20010, 0x8f420030, 0xafa80018, +0xafa20014, 0x8f460098, 0x8f420108, 0x40f809, +0x0, 0x10400030, 0x3225ffff, 0x8f420098, +0x8f440130, 0x451021, 0xaf420098, 0x8f420090, +0x8f430098, 0xa34005b3, 0x451023, 0x64182b, +0x14600005, 0xaf420090, 0x8f420098, 0x8f430138, +0x431023, 0xaf420098, 0x8f420030, 0x8f430040, +0x24420001, 0x2463ffff, 0x431024, 0xaf420030, +0x8f420030, 0x14520018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403fff7, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf002c, 0x8fb20028, +0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030, +0x3e00008, 0x0, 0x27bdffd8, 0x3c020001, +0x34422ec0, 0xafbf0020, 0x8f4300f0, 0x8f840108, +0x2e21021, 0x54620004, 0x24620008, 0x3c020001, +0x34422cc0, 0x2e21021, 0x401821, 0xaf4300f0, +0xac600000, 0x8f4200ec, 0x8c660004, 0x14620004, +0x3c020001, 0x24820020, 0x1000000f, 0xaf820108, +0x8f4300f0, 0x34422ec0, 0x2e21021, 0x54620004, +0x24620008, 0x3c020001, 0x34422cc0, 0x2e21021, +0x401821, 0x8c620004, 0x21140, 0x821021, +0xaf820108, 0xac600000, 0x8c850018, 0x30a20036, +0x1040006c, 0x30a20001, 0x8c82001c, 0x8f430040, +0x8f440034, 0x24420001, 0x2463ffff, 0x431024, +0x862021, 0xaf42002c, 0x30a20030, 0x14400006, +0xaf440034, 0x8f420034, 0x8c03023c, 0x43102b, +0x144000c6, 0x0, 0x32c20010, 0x10400028, +0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, +0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, -0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x248437f4, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, -0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, -0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, -0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, -0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, -0xaf400034, 0x8f420304, 0x24420001, 0xaf420304, -0x1000006e, 0x8f420304, 0x10400025, 0x30a27000, -0x8c85001c, 0x8f420028, 0xa22023, 0x4810003, -0x0, 0x8f420040, 0x822021, 0x8f420348, -0x8f430000, 0x441021, 0xaf420348, 0x8f42035c, -0xaf450028, 0x441021, 0x10600007, 0xaf42035c, +0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, +0x34a51100, 0x10000036, 0x0, 0x8f4202f0, +0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, +0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, +0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, +0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, +0x1000000f, 0x0, 0x8f4202f0, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, +0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, +0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, +0x8f420304, 0x24420001, 0xaf420304, 0x1000006b, +0x8f420304, 0x10400022, 0x30a27000, 0x8c85001c, +0x8f420028, 0xa22023, 0x4810003, 0x0, +0x8f420040, 0x822021, 0x8f420348, 0x8f430000, +0xaf450028, 0x441021, 0x10600007, 0xaf420348, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x34420008, @@ -6367,7 +6381,7 @@ 0x441021, 0xaf420358, 0x3c020800, 0x2c21024, 0x5040001a, 0x36940040, 0x10000018, 0x0, 0x30a20100, 0x10400015, 0x0, 0x3c020001, -0x8c423c54, 0x1040000c, 0x0, 0x274301b0, +0x8c423d64, 0x1040000c, 0x0, 0x274301b0, 0x24650400, 0x65102b, 0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, @@ -6376,7 +6390,7 @@ 0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, 0x8f910108, 0x26220020, 0xaf820108, 0x8e320018, -0xa821, 0x32420024, 0x104001b1, 0xf021, +0xa821, 0x32420024, 0x104001b7, 0xf021, 0x8e26001c, 0x8f42001c, 0x61900, 0x431021, 0x8c50000c, 0x9603000c, 0x962d0016, 0x9453000a, 0x2c6205dd, 0x10400015, 0x2821, 0x32c20040, @@ -6400,8 +6414,8 @@ 0x431021, 0x904c0009, 0x318900ff, 0x39230006, 0x3182b, 0x39220011, 0x2102b, 0x621824, 0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, -0x24843810, 0xafa20010, 0x8f4200a0, 0x34a54600, -0x1203821, 0xc0029d3, 0xafa20014, 0x1000004e, +0x248438f4, 0xafa20010, 0x8f4200a0, 0x34a54600, +0x1203821, 0xc002a03, 0xafa20014, 0x1000004e, 0x0, 0x32c20004, 0x14400013, 0x2821, 0x316200ff, 0x14400004, 0x0, 0x95020002, 0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, @@ -6429,7 +6443,7 @@ 0x8f4200b4, 0x24430001, 0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, 0x220821, -0xac2438ec, 0x100000a5, 0xaf40009c, 0x10400064, +0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064, 0x0, 0x8f4200b4, 0x24430001, 0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, @@ -6463,41 +6477,44 @@ 0xaf450264, 0x92020000, 0x30420001, 0x1440000c, 0x2402ffff, 0x8f420268, 0x8f43026c, 0x24630001, 0x2c640001, 0x441021, 0xaf420268, 0xaf43026c, -0x8f420268, 0x8f43026c, 0x1000001c, 0xaf40009c, +0x8f420268, 0x8f43026c, 0x1000001c, 0x32c20020, 0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004, 0x1462000c, 0x0, 0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, 0x8f420278, 0x8f43027c, 0x1000000b, -0xaf40009c, 0x8f420270, 0x8f430274, 0x24630001, +0x32c20020, 0x8f420270, 0x8f430274, 0x24630001, 0x2c640001, 0x441021, 0xaf420270, 0xaf430274, -0x8f420270, 0x8f430274, 0xaf40009c, 0x8e22001c, +0x8f420270, 0x8f430274, 0x32c20020, 0x10400005, +0xaf40009c, 0x8f420348, 0x2442ffff, 0xaf420348, +0x8f420348, 0x8e22001c, 0x8f430040, 0x24420001, +0x2463ffff, 0x431024, 0xaf42002c, 0x32420060, +0x14400008, 0x32c20010, 0x8f420034, 0x24420001, +0xaf420034, 0x8c03023c, 0x43102b, 0x14400114, +0x32c20010, 0x10400018, 0x24070008, 0x8f440160, +0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, +0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, +0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047, +0x24020001, 0x8f4202f0, 0x8f43002c, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, +0x1000007c, 0xaf430038, 0x8f440160, 0x8f450164, +0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x10400057, 0x24020001, +0x10000065, 0x0, 0x32420012, 0x10400075, +0x32420001, 0x9622000e, 0x8f43009c, 0x621821, +0x32c20020, 0x10400005, 0xaf43009c, 0x8f420348, +0x2442ffff, 0xaf420348, 0x8f420348, 0x8e22001c, 0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf42002c, 0x32420060, 0x14400008, 0x32c20010, +0xaf42002c, 0x32420010, 0x14400008, 0x32c20010, 0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c, -0x43102b, 0x14400111, 0x32c20010, 0x10400018, -0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, -0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, -0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x10400041, 0x24020001, 0x8f4202f0, -0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, -0x24020001, 0xa34205b2, 0x10000076, 0xaf430038, -0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, -0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x10400051, 0x24020001, 0x1000005f, 0x0, -0x32420012, 0x1040006f, 0x32420001, 0x9623000e, -0x8f42009c, 0x431021, 0xaf42009c, 0x8e23001c, -0x8f420040, 0x24630001, 0x2442ffff, 0x621824, -0x32420010, 0x14400008, 0xaf43002c, 0x8f420034, -0x24420001, 0xaf420034, 0x8c03023c, 0x43102b, -0x144000d2, 0x0, 0x32c20010, 0x10400028, +0x43102b, 0x144000ce, 0x32c20010, 0x10400028, 0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24843800, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, @@ -6506,46 +6523,45 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248437f4, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc0029d3, 0x34a50900, +0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, -0x8f420304, 0x24420001, 0xaf420304, 0x10000077, -0x8f420304, 0x10400025, 0x32427000, 0x8e25001c, +0x8f420304, 0x24420001, 0xaf420304, 0x10000074, +0x8f420304, 0x10400022, 0x32427000, 0x8e25001c, 0x8f420028, 0xa22023, 0x4810003, 0x0, 0x8f420040, 0x822021, 0x8f420348, 0x8f430000, -0x441021, 0xaf420348, 0x8f42035c, 0xaf450028, -0x441021, 0x10600007, 0xaf42035c, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420008, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000053, -0xaf80004c, 0x10000051, 0xaf800048, 0x1040002f, -0x32421000, 0x1040000c, 0x32424000, 0x8e23001c, -0x8f420050, 0x622023, 0x4820001, 0x24840200, -0x8f42034c, 0x441021, 0xaf42034c, 0x8f420358, -0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000, -0x8e23001c, 0x8f420070, 0x622023, 0x4820001, -0x24840400, 0x8f420354, 0x441021, 0xaf420354, -0x8f420358, 0x1000000d, 0xaf430070, 0x1040000e, -0x3c020800, 0x8e23001c, 0x8f420060, 0x622023, -0x4820001, 0x24840100, 0x8f420350, 0x441021, -0xaf420350, 0x8f420358, 0xaf430060, 0x441021, -0xaf420358, 0x3c020800, 0x2c21024, 0x50400023, -0x36940040, 0x10000021, 0x0, 0x32420048, -0x10400007, 0x24150001, 0x8e22001c, 0x3c03ffff, -0x43f024, 0x3042ffff, 0x1000fd81, 0xae22001c, -0x32420100, 0x10400015, 0x0, 0x3c020001, -0x8c423c54, 0x1040000c, 0x0, 0x274301b0, -0x24650400, 0x65102b, 0x10400007, 0x26e40028, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, -0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0050, -0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, -0x8fb1003c, 0x8fb00038, 0x3e00008, 0x27bd0058, -0x3e00008, 0x0, 0x0, 0x8f8600e4, +0xaf450028, 0x441021, 0x10600007, 0xaf420348, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x34420008, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x10000053, 0xaf80004c, 0x10000051, 0xaf800048, +0x1040002f, 0x32421000, 0x1040000c, 0x32424000, +0x8e23001c, 0x8f420050, 0x622023, 0x4820001, +0x24840200, 0x8f42034c, 0x441021, 0xaf42034c, +0x8f420358, 0x1000001a, 0xaf430050, 0x1040000c, +0x32c28000, 0x8e23001c, 0x8f420070, 0x622023, +0x4820001, 0x24840400, 0x8f420354, 0x441021, +0xaf420354, 0x8f420358, 0x1000000d, 0xaf430070, +0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060, +0x622023, 0x4820001, 0x24840100, 0x8f420350, +0x441021, 0xaf420350, 0x8f420358, 0xaf430060, +0x441021, 0xaf420358, 0x3c020800, 0x2c21024, +0x50400023, 0x36940040, 0x10000021, 0x0, +0x32420048, 0x10400007, 0x24150001, 0x8e22001c, +0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd78, +0xae22001c, 0x32420100, 0x10400015, 0x0, +0x3c020001, 0x8c423d64, 0x1040000c, 0x0, +0x274301b0, 0x24650400, 0x65102b, 0x10400007, +0x26e40028, 0x8c820000, 0xac620000, 0x24630004, +0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, +0xa34005b6, 0x24420001, 0xaf4202cc, 0x8f4202cc, +0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, +0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, +0x27bd0058, 0x3e00008, 0x0, 0x8f8600e4, 0x8f8200e0, 0x2403fff8, 0x431024, 0x10c20007, 0x803821, 0x8cc20000, 0x8cc30004, 0xace20000, 0xace30004, 0x10000002, 0x24020001, 0x1021, @@ -6601,8 +6617,8 @@ 0x10400014, 0x307000ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 0x8f4201d8, 0x8faa007c, 0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 0x34a50800, 0x12000010, 0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c, 0x3c020080, 0x34420100, 0x1621024, 0x10400005, 0x0, @@ -6624,22 +6640,22 @@ 0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, 0x1000023f, 0x8f420340, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 0x34a52250, 0x1000022f, 0x0, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x24020002, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x248439e4, 0x24020002, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 0x34a52450, 0x1000021f, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, -0xafbe0014, 0x8ea70018, 0x34a52800, 0xc0029d3, +0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, +0xafbe0014, 0x8ea70018, 0x34a52800, 0xc002a03, 0x603021, 0x10000213, 0x0, 0xa6b1000a, -0x8f820124, 0x3c040001, 0x24843920, 0xafbe0014, +0x8f820124, 0x3c040001, 0x24843a04, 0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007, -0xc0029d3, 0x34a53000, 0x10000206, 0x0, +0xc002a03, 0x34a53000, 0x10000206, 0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124, 0x3c040001, -0x2484392c, 0xafbe0014, 0xafa20010, 0x8f460044, -0x8f870120, 0x3c050007, 0xc0029d3, 0x34a53200, +0x24843a10, 0xafbe0014, 0xafa20010, 0x8f460044, +0x8f870120, 0x3c050007, 0xc002a03, 0x34a53200, 0x100001f8, 0x0, 0x8f420084, 0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001, 0x2c21024, 0x10400004, 0x0, 0x240b0002, 0xafab005c, @@ -6650,17 +6666,17 @@ 0x3403ecc0, 0xafab004c, 0x27c20001, 0x304201ff, 0xafa20054, 0x1e1140, 0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001, -0x248438dc, 0xafaa0014, 0xafa20010, 0x8f460054, -0x8f470050, 0x3c050007, 0xc0029d3, 0x34a51300, +0x248439c0, 0xafaa0014, 0xafa20010, 0x8f460054, +0x8f470050, 0x3c050007, 0xc002a03, 0x34a51300, 0x8f430340, 0x2402ffbf, 0x282a024, 0x24630001, 0xaf430340, 0x100001c3, 0x8f420340, 0x1562001d, 0x0, 0x8f430074, 0x8f420070, 0x1062000a, 0x274a0074, 0x8f5e0074, 0xafaa004c, 0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140, 0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, 0x8fab006c, -0x3c040001, 0x248438e8, 0x3c050007, 0xafab0014, +0x3c040001, 0x248439cc, 0x3c050007, 0xafab0014, 0xafa20010, 0x8f460074, 0x8f470070, 0x34a51500, -0x240a0001, 0xc0029d3, 0xafaa005c, 0x1000ffc3, +0x240a0001, 0xc002a03, 0xafaa005c, 0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, 0x1062001a, 0x274b0064, 0x8f5e0064, 0x8faa005c, 0xafab004c, 0x27c20001, 0x304200ff, 0xafa20054, 0x24020004, @@ -6669,8 +6685,8 @@ 0x8faa006c, 0x4a102b, 0x10400024, 0x25750020, 0x240b0001, 0x10000021, 0xa3ab0097, 0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, -0x3c040001, 0x248438f4, 0xafaa0014, 0xafa20010, -0x8f460064, 0x8f470060, 0x3c050007, 0xc0029d3, +0x3c040001, 0x248439d8, 0xafaa0014, 0xafa20010, +0x8f460064, 0x8f470060, 0x3c050007, 0xc002a03, 0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff34, 0x0, 0x8f420360, 0x240b0001, 0xafab005c, 0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, @@ -6691,9 +6707,9 @@ 0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011, 0x24030001, 0x10000015, 0x306200ff, 0x8faa0064, 0x96070018, -0xafaa0010, 0x8e220008, 0x3c040001, 0x2484390c, +0xafaa0010, 0x8e220008, 0x3c040001, 0x248439f0, 0x8c430004, 0x8c420000, 0x34a52400, 0x2403021, -0xc0029d3, 0xafa30014, 0x1000002b, 0x0, +0xc002a03, 0xafa30014, 0x1000002b, 0x0, 0x8f420324, 0x1821, 0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, 0x5040fedc, 0x3c020800, 0x12600021, 0x9021, 0x8fb100a4, 0x2208021, @@ -6745,9 +6761,9 @@ 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, +0xafa20010, 0x8f820128, 0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51300, 0x1000000b, 0x0, +0xc002a03, 0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, @@ -6787,14 +6803,14 @@ 0xa7a00076, 0x10400007, 0xa7a0007e, 0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4, 0x10000129, 0xafab006c, 0x8f420114, 0x40f809, 0x27a40020, -0x304200ff, 0x1040029c, 0x0, 0x8fac0024, +0x304200ff, 0x1040029a, 0x0, 0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc, 0xafa20064, 0x3c020006, 0x2c21024, 0x14400015, 0xafac006c, 0x93c20000, 0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b, 0x0, 0xc002343, 0x3c02021, 0x304200ff, 0x14400006, 0x0, 0x8f420118, -0x40f809, 0x0, 0x1000027f, 0x0, +0x40f809, 0x0, 0x1000027d, 0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, 0x10000040, 0x8021, 0x3c020080, 0x621024, @@ -6817,13 +6833,13 @@ 0x10400015, 0x320200ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 0x8f4201d8, 0x8fac006c, 0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 0x34a53600, 0x320200ff, 0x10400010, 0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, 0x8fab006c, 0x3c020080, 0x34420100, 0x1621024, 0x10400005, 0x0, 0x8f4201fc, 0x24420001, 0xaf4201fc, -0x8f4201fc, 0x10000201, 0x8fa30064, 0x32c20400, +0x8f4201fc, 0x100001ff, 0x8fa30064, 0x32c20400, 0x10400012, 0x34028100, 0x97c3000c, 0x1462000f, 0x0, 0x240c0200, 0xa7ac0076, 0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064, 0x8fc50000, @@ -6843,56 +6859,56 @@ 0x2c420001, 0x621825, 0x10600004, 0x3c020100, 0x94820002, 0x453821, 0x3c020100, 0x2c21024, 0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, -0x3c050007, 0x3c040001, 0x24843938, 0x8fa60064, -0x34a54000, 0xafa00010, 0xc0029d3, 0xafa00014, +0x3c050007, 0x3c040001, 0x24843a1c, 0x8fa60064, +0x34a54000, 0xafa00010, 0xc002a03, 0xafa00014, 0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, 0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, 0x10400034, 0x240b0003, 0x32c21000, 0x10400031, 0xafab005c, 0x1000002e, 0x240c0004, 0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, -0x10000175, 0x8f420340, 0x3c020800, 0x2c2b025, +0x10000173, 0x8f420340, 0x3c020800, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, -0x34a55300, 0x10000164, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, -0xafb20014, 0x8ea70018, 0x34a55900, 0xc0029d3, -0x603021, 0x10000158, 0x0, 0x8f420084, +0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, +0x34a55300, 0x10000162, 0x0, 0x8ea20000, +0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, +0xafb10014, 0x8ea70018, 0x34a55900, 0xc002a03, +0x603021, 0x10000156, 0x0, 0x8f420084, 0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, 0x2c21024, 0x10400004, 0x0, 0x240c0002, -0xafac005c, 0x8fab0064, 0x11600168, 0x27ac0020, +0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020, 0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, 0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, -0x274b0054, 0x8f520054, 0x3403ecc0, 0xafab004c, -0x26420001, 0x304201ff, 0xafa20054, 0x121140, +0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, +0x26220001, 0x304201ff, 0xafa20054, 0x111140, 0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, -0x8fac0064, 0x3c040001, 0x248438dc, 0xafac0014, +0x8fac0064, 0x3c040001, 0x248439c0, 0xafac0014, 0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, -0xc0029d3, 0x34a54300, 0x8f430340, 0x2402ffbf, -0x282a024, 0x24630001, 0xaf430340, 0x10000126, +0xc002a03, 0x34a54300, 0x8f430340, 0x2402ffbf, +0x282a024, 0x24630001, 0xaf430340, 0x10000124, 0x8f420340, 0x156c001d, 0x0, 0x8f430074, -0x8f420070, 0x1062000a, 0x274b0074, 0x8f520074, -0xafab004c, 0x26420001, 0x304203ff, 0xafa20054, -0x121140, 0x24426cc0, 0x1000004a, 0x2e2a821, -0x8f420044, 0x8fac0064, 0x3c040001, 0x248438e8, +0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, +0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, +0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, +0x8f420044, 0x8fac0064, 0x3c040001, 0x248439cc, 0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, -0x8f470070, 0x34a54500, 0x240b0001, 0xc0029d3, +0x8f470070, 0x34a54500, 0x240b0001, 0xc002a03, 0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, -0x8f420060, 0x1062001a, 0x274c0064, 0x8f520064, -0x8fab005c, 0xafac004c, 0x26420001, 0x304200ff, -0xafa20054, 0x24020004, 0x1562000e, 0x121140, -0x121180, 0x24420cc0, 0x2e21021, 0xafa20044, +0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, +0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, +0xafa20054, 0x24020004, 0x1562000e, 0x111140, +0x111180, 0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, 0x10400024, 0x25950020, 0x240c0001, 0x10000021, 0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, -0x8f420044, 0x8fab0064, 0x3c040001, 0x248438f4, +0x8f420044, 0x8fab0064, 0x3c040001, 0x248439d8, 0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, -0x3c050007, 0xc0029d3, 0x34a54800, 0x3c020008, +0x3c050007, 0xc002a03, 0x34a54800, 0x3c020008, 0x2c21024, 0x1440ff61, 0x0, 0x8f420360, 0x240c0001, 0xafac005c, 0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, 0x27a30036, 0x131040, 0x621821, 0x94620000, 0x441021, 0x1000001f, -0xa4620000, 0xaebe0018, 0x93a20087, 0x10400086, +0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084, 0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, 0x25620020, 0xafa20028, 0x25620008, 0xafa20030, 0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, @@ -6906,289 +6922,288 @@ 0x431023, 0x21943, 0x58600001, 0x24630040, 0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, -0x1000001a, 0x306200ff, 0x8fac008c, 0x111040, -0x4c1021, 0x94470018, 0x111080, 0x4c1021, -0xafbe0010, 0x8c420008, 0x3c040001, 0x2484390c, +0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, +0x4c1021, 0x94470018, 0x101080, 0x4c1021, +0xafbe0010, 0x8c420008, 0x3c040001, 0x248439f0, 0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, -0x2203021, 0xc0029d3, 0xafa30014, 0x1000003b, +0x2003021, 0xc002a03, 0xafa30014, 0x10000039, 0x0, 0x8f420324, 0x1821, 0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, 0x1040ff06, -0x8821, 0x8f430008, 0x2402fbff, 0x621824, -0x605021, 0x1260002d, 0xaf430008, 0x2669ffff, -0x8fb0008c, 0x3c0b4000, 0x24b4025, 0x2009021, -0x8e420008, 0x96070018, 0x8c440000, 0x8c450004, -0x56290004, 0x240b0001, 0x240c0002, 0x10000002, -0xafac0010, 0xafab0010, 0x16200004, 0xafa80014, -0x8f420008, 0x10000002, 0xafa20018, 0xafaa0018, -0x8f42010c, 0x3c03021, 0xafa80098, 0xafa9009c, -0x40f809, 0xafaa00a0, 0x8fa80098, 0x8fa9009c, -0x8faa00a0, 0x1040ffc0, 0x3c02001f, 0x96030018, -0x3442ffff, 0x3c3f021, 0x5e102b, 0x10400003, -0x26100002, 0x8f42013c, 0x3c2f023, 0x26310001, -0x233102b, 0x1440ffda, 0x26520004, 0x8fb00064, -0x1000001a, 0x0, 0x96a3000a, 0x8fb00064, -0x70102b, 0x54400001, 0x608021, 0x8ea40000, -0x8ea50004, 0x8fab005c, 0x240c0002, 0xafac0010, -0x934305b5, 0xb1700, 0x10600003, 0x2423025, -0x3c020800, 0xc23025, 0xafa60014, 0x8f420008, -0xafa20018, 0x8f42010c, 0x3c03021, 0x40f809, -0x2003821, 0x1040fec9, 0x3c050007, 0x97ac0076, -0x11800007, 0x96a3000e, 0x934205b5, 0x14400004, -0x0, 0x97ab007e, 0x6c1825, 0xa6ab0016, -0x8fac006c, 0x3c02ffff, 0x1821024, 0x10400003, -0xc1402, 0x34630400, 0xa6a20014, 0xa6b0000a, -0x8fab0064, 0x560b0006, 0x3d0f021, 0x34620004, -0xafa00064, 0xa6a2000e, 0x1000000d, 0xa34005b5, -0x8fac0064, 0x3c02001f, 0x3442ffff, 0x5e102b, -0x1906023, 0xafac0064, 0xa6a3000e, 0x240b0001, -0x10400003, 0xa34b05b5, 0x8f42013c, 0x3c2f023, -0x8fab0054, 0x8fac004c, 0xad8b0000, 0x8fac0064, -0x1580feb8, 0x0, 0x8fab0064, 0x1160001b, -0x0, 0x934205b5, 0x10400006, 0x0, -0xaf5e00c4, 0xaf4b00c0, 0x8fac006c, 0x1000000e, -0xaf4c00c8, 0x97ab0076, 0x1160000b, 0x34038100, -0x8fa20020, 0x8c46000c, 0xa443000c, 0x97ac007e, -0x8c440004, 0x8c450008, 0xa44c000e, 0xac440000, -0xac450004, 0xac460008, 0x8f42033c, 0x24420001, -0xaf42033c, 0x10000010, 0x8f42033c, 0x8fab006c, -0x3164ffff, 0x2484fffc, 0x801821, 0x8f440240, -0x8f450244, 0x8f460118, 0x1021, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0xaf440240, -0xc0f809, 0xaf450244, 0x8fbf00c0, 0x8fbe00bc, -0x8fb500b8, 0x8fb300b4, 0x8fb200b0, 0x8fb100ac, -0x8fb000a8, 0x3e00008, 0x27bd00c8, 0x3e00008, -0x0, 0x27bdffd8, 0xafbf0024, 0xafb00020, -0x8f43004c, 0x8f420048, 0x10620034, 0x0, -0x8f430048, 0x8f42004c, 0x622023, 0x4820001, -0x24840200, 0x8f430054, 0x8f42004c, 0x43102b, -0x14400004, 0x24020200, 0x8f43004c, 0x10000005, -0x431023, 0x8f420054, 0x8f43004c, 0x431023, -0x2442ffff, 0x405021, 0x8a102a, 0x54400001, -0x805021, 0x8f49004c, 0x8f48004c, 0x8f440178, -0x8f45017c, 0x8f46004c, 0x24071000, 0xafa70010, -0x84140, 0x1001821, 0x12a4821, 0x313001ff, -0xafb00014, 0x8f470014, 0x1021, 0x63140, -0xafa70018, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0x3402ecc0, 0xc23021, 0x8f420108, -0x2e63021, 0x40f809, 0xa3940, 0x54400001, -0xaf50004c, 0x8f43004c, 0x8f420048, 0x14620018, +0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, +0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c, +0x2669ffff, 0x2209021, 0x8e420008, 0x96270018, +0x8c440000, 0x8c450004, 0x56090004, 0x240b0001, +0x240c0002, 0x10000002, 0xafac0010, 0xafab0010, +0x16000004, 0xafa80014, 0x8f420008, 0x10000002, +0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021, +0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0, +0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2, +0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021, +0x5e102b, 0x10400003, 0x26310002, 0x8f42013c, +0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda, +0x26520004, 0x8fb00064, 0x1000001a, 0x0, +0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001, +0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c, +0x240c0002, 0xafac0010, 0x934305b5, 0xb1700, +0x10600003, 0x2223025, 0x3c020800, 0xc23025, +0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c, +0x3c03021, 0x40f809, 0x2003821, 0x1040fecb, +0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e, +0x934205b5, 0x14400004, 0x0, 0x97ab007e, +0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff, +0x1821024, 0x10400003, 0xc1402, 0x34630400, +0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006, +0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e, +0x1000000d, 0xa34005b5, 0x8fac0064, 0x3c02001f, +0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064, +0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05b5, +0x8f42013c, 0x3c2f023, 0x8fab0054, 0x8fac004c, +0xad8b0000, 0x8fac0064, 0x1580feba, 0x0, +0x8fab0064, 0x1160001b, 0x0, 0x934205b5, +0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0, +0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076, +0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, +0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008, +0xa44c000e, 0xac440000, 0xac450004, 0xac460008, +0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, +0x8f42033c, 0x8fab006c, 0x3164ffff, 0x2484fffc, +0x801821, 0x8f440240, 0x8f450244, 0x8f460118, +0x1021, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0xaf440240, 0xc0f809, 0xaf450244, +0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, +0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008, +0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8, +0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048, +0x10620034, 0x0, 0x8f430048, 0x8f42004c, +0x622023, 0x4820001, 0x24840200, 0x8f430054, +0x8f42004c, 0x43102b, 0x14400004, 0x24020200, +0x8f43004c, 0x10000005, 0x431023, 0x8f420054, +0x8f43004c, 0x431023, 0x2442ffff, 0x405021, +0x8a102a, 0x54400001, 0x805021, 0x8f49004c, +0x8f48004c, 0x8f440178, 0x8f45017c, 0x8f46004c, +0x24071000, 0xafa70010, 0x84140, 0x1001821, +0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014, +0x1021, 0x63140, 0xafa70018, 0xa32821, +0xa3382b, 0x822021, 0x872021, 0x3402ecc0, +0xc23021, 0x8f420108, 0x2e63021, 0x40f809, +0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c, +0x8f420048, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c, +0x8f420058, 0x10620049, 0x0, 0x8f430058, +0x8f42005c, 0x622023, 0x4820001, 0x24840100, +0x8f430064, 0x8f42005c, 0x43102b, 0x14400004, +0x24020100, 0x8f43005c, 0x10000005, 0x431023, +0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff, +0x403821, 0x87102a, 0x54400001, 0x803821, +0x8f42005c, 0x471021, 0x305000ff, 0x32c21000, +0x10400015, 0x24082000, 0x8f49005c, 0x8f440180, +0x8f450184, 0x8f46005c, 0x73980, 0xafa80010, +0xafb00014, 0x8f480014, 0x94980, 0x1201821, +0x1021, 0xa32821, 0xa3482b, 0x822021, +0x892021, 0x63180, 0xafa80018, 0x8f420108, +0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440180, +0x8f450184, 0x8f46005c, 0x73940, 0xafa80010, +0xafb00014, 0x8f480014, 0x94940, 0x1201821, +0x1021, 0xa32821, 0xa3482b, 0x822021, +0x892021, 0x63140, 0xafa80018, 0x8f420108, +0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001, +0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018, 0x0, 0x8f420000, 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403fdff, +0x1040fffd, 0x0, 0x8f820060, 0x2403feff, 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049, -0x0, 0x8f430058, 0x8f42005c, 0x622023, -0x4820001, 0x24840100, 0x8f430064, 0x8f42005c, -0x43102b, 0x14400004, 0x24020100, 0x8f43005c, -0x10000005, 0x431023, 0x8f420064, 0x8f43005c, -0x431023, 0x2442ffff, 0x403821, 0x87102a, -0x54400001, 0x803821, 0x8f42005c, 0x471021, -0x305000ff, 0x32c21000, 0x10400015, 0x24082000, -0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, -0x73980, 0xafa80010, 0xafb00014, 0x8f480014, -0x94980, 0x1201821, 0x1021, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x63180, -0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0, -0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, -0x73940, 0xafa80010, 0xafb00014, 0x8f480014, -0x94940, 0x1201821, 0x1021, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x63140, -0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809, -0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c, -0x8f420058, 0x14620018, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403feff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c, -0x8f420068, 0x10620033, 0x0, 0x8f430068, -0x8f42006c, 0x622023, 0x4820001, 0x24840400, -0x8f430074, 0x8f42006c, 0x43102b, 0x14400004, -0x24020400, 0x8f43006c, 0x10000005, 0x431023, -0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff, -0x405021, 0x8a102a, 0x54400001, 0x805021, -0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c, -0x8f46006c, 0x24074000, 0xafa70010, 0x84140, -0x1001821, 0x12a4821, 0x313003ff, 0xafb00014, -0x8f470014, 0x1021, 0x63140, 0x24c66cc0, -0xafa70018, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0x8f420108, 0x2e63021, 0x40f809, -0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c, -0x8f420068, 0x14620018, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8, -0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021, -0x54820004, 0x24820008, 0x3c020001, 0x34422ec8, -0x2e21021, 0x401821, 0xaf4300f8, 0xac600000, -0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020, -0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8, -0x2e21021, 0x54620004, 0x24620008, 0x3c020001, -0x34422ec8, 0x2e21021, 0x401821, 0x8c620004, -0x21140, 0xa21021, 0xaf820128, 0xac600000, -0x8ca30018, 0x30620070, 0x1040002d, 0x30620020, +0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033, +0x0, 0x8f430068, 0x8f42006c, 0x622023, +0x4820001, 0x24840400, 0x8f430074, 0x8f42006c, +0x43102b, 0x14400004, 0x24020400, 0x8f43006c, +0x10000005, 0x431023, 0x8f420074, 0x8f43006c, +0x431023, 0x2442ffff, 0x405021, 0x8a102a, +0x54400001, 0x805021, 0x8f49006c, 0x8f48006c, +0x8f440188, 0x8f45018c, 0x8f46006c, 0x24074000, +0xafa70010, 0x84140, 0x1001821, 0x12a4821, +0x313003ff, 0xafb00014, 0x8f470014, 0x1021, +0x63140, 0x24c66cc0, 0xafa70018, 0xa32821, +0xa3382b, 0x822021, 0x872021, 0x8f420108, +0x2e63021, 0x40f809, 0xa3940, 0x54400001, +0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018, +0x0, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, +0x3e00008, 0x0, 0x8f4200fc, 0x3c030001, +0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc, +0x8f850128, 0x2e31021, 0x54820004, 0x24820008, +0x3c020001, 0x34422ec8, 0x2e21021, 0x401821, +0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004, +0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128, +0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, +0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, +0x401821, 0x8c620004, 0x21140, 0xa21021, +0xaf820128, 0xac600000, 0x8ca30018, 0x30620070, +0x1040002d, 0x30620020, 0x10400004, 0x3c020010, +0x2c21024, 0x1040000d, 0x0, 0x30620040, +0x10400004, 0x3c020020, 0x2c21024, 0x10400007, +0x0, 0x30620010, 0x1040001f, 0x3c020040, +0x2c21024, 0x1440001c, 0x0, 0x8f820040, +0x30420001, 0x14400008, 0x2021, 0x8c030104, +0x24020001, 0x50620005, 0x24040001, 0x8c020264, +0x10400003, 0x801021, 0x24040001, 0x801021, +0x10400006, 0x0, 0x8f4202fc, 0x24420001, +0xaf4202fc, 0x10000008, 0x8f4202fc, 0x8f820044, +0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x3e00008, 0x0, +0x3e00008, 0x0, 0x27bdffa0, 0xafbf0058, +0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, +0xafb10044, 0xafb00040, 0x8f4200fc, 0x24420001, +0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128, +0x8d030018, 0x30620070, 0x1040002e, 0x30620020, 0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, 0x0, 0x30620040, 0x10400004, 0x3c020020, 0x2c21024, 0x10400007, 0x0, 0x30620010, -0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c, +0x10400193, 0x3c020040, 0x2c21024, 0x14400190, 0x0, 0x8f820040, 0x30420001, 0x14400008, 0x2021, 0x8c030104, 0x24020001, 0x50620005, 0x24040001, 0x8c020264, 0x10400003, 0x801021, 0x24040001, 0x801021, 0x10400006, 0x0, -0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, +0x8f4202fc, 0x24420001, 0xaf4202fc, 0x1000017c, 0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, -0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x27bdffa0, 0xafbf0058, 0xafbe0054, 0xafb50050, -0xafb3004c, 0xafb20048, 0xafb10044, 0xafb00040, -0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128, -0x25020020, 0xaf820128, 0x8d030018, 0x30620070, -0x1040002e, 0x30620020, 0x10400004, 0x3c020010, -0x2c21024, 0x1040000d, 0x0, 0x30620040, -0x10400004, 0x3c020020, 0x2c21024, 0x10400007, -0x0, 0x30620010, 0x10400193, 0x3c020040, -0x2c21024, 0x14400190, 0x0, 0x8f820040, -0x30420001, 0x14400008, 0x2021, 0x8c030104, -0x24020001, 0x50620005, 0x24040001, 0x8c020264, -0x10400003, 0x801021, 0x24040001, 0x801021, -0x10400006, 0x0, 0x8f4202fc, 0x24420001, -0xaf4202fc, 0x1000017c, 0x8f4202fc, 0x8f820044, -0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, -0xaf4202f8, 0x10000174, 0x8f4202f8, 0x30620002, -0x10400135, 0x3c020800, 0x8d0a001c, 0x1422024, -0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024, -0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c, -0x8faa0034, 0x24020001, 0x15420007, 0x24020002, -0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021, -0x10000014, 0x2e2a821, 0x15420006, 0x24020003, -0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d, -0x2e2a821, 0x8faa0034, 0x15420006, 0x0, -0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005, -0x2e2a821, 0x8faa0024, 0xa1180, 0x571021, -0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400, -0x144000c5, 0x8821, 0x10800004, 0x24091000, -0x97b1002e, 0x100000c1, 0x0, 0x8eb30018, -0x9663000c, 0x2c6205dd, 0x10400015, 0x2021, -0x32c20800, 0x10400015, 0x24020800, 0x96630014, -0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007, -0x2821, 0x96630010, 0x24020300, 0x14620004, -0xa01021, 0x96620012, 0x2c450001, 0xa01021, -0x54400006, 0x24040016, 0x10000004, 0x0, -0x24020800, 0x50620001, 0x2404000e, 0x108000a2, -0x2649021, 0x92420000, 0x3042000f, 0x28080, -0x32c20100, 0x1040001e, 0x2501821, 0x3c020020, -0x43102b, 0x1440000e, 0x2402021, 0x2821, -0x94820000, 0x24840002, 0xa22821, 0x83102b, -0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821, -0x51c02, 0x30a2ffff, 0x10000009, 0x622821, -0x8f47013c, 0x8f420110, 0x102842, 0x3c060020, -0x40f809, 0xafa80038, 0x3045ffff, 0x8fa80038, -0x50a00001, 0x3405ffff, 0x10000002, 0x37de0002, -0x2821, 0x32c20080, 0x1040007b, 0xa6a50010, -0x26430009, 0x3c02001f, 0x3442ffff, 0x43102b, -0x10400003, 0x0, 0x8f42013c, 0x621823, -0x90660000, 0x30c200ff, 0x38430006, 0x2c630001, -0x38420011, 0x2c420001, 0x621825, 0x1060006b, -0x24091000, 0x8821, 0x2602021, 0x94820000, -0x24840002, 0x2228821, 0x92102b, 0x1440fffb, -0x111c02, 0x3222ffff, 0x628821, 0x111c02, -0x3222ffff, 0x628821, 0x32c20200, 0x10400003, -0x26440006, 0x1000003e, 0x8021, 0x3c05001f, -0x34a5ffff, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x30421fff, -0x10400004, 0x2644000c, 0x96420002, 0x10000030, -0x508023, 0x96420002, 0x26430014, 0x508023, -0x3c020020, 0x43102b, 0x1440000a, 0xd08021, -0x9642000c, 0x2028021, 0x9642000e, 0x96430010, -0x96440012, 0x2028021, 0x2038021, 0x10000020, -0x2048021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x2028021, -0x3c020100, 0x2c21024, 0x1040000c, 0x33c20004, -0x1040000a, 0x0, 0x9504000e, 0x2642021, -0xc003cc8, 0x2484fffc, 0x3042ffff, 0x2228821, -0x111c02, 0x3222ffff, 0x628821, 0x8faa002c, -0x1518823, 0x111402, 0x2228821, 0x2308821, -0x111402, 0x2228821, 0x3231ffff, 0x52200001, -0x3411ffff, 0x37de0001, 0x24091000, 0x33c20004, -0xa6b10012, 0x10400002, 0xa6be000e, 0x34098000, -0x8f480044, 0x8f440190, 0x8f450194, 0xafa90010, -0x8f490044, 0x84140, 0x1001821, 0xafa90014, -0x8f48000c, 0x2a03021, 0x24070020, 0xafa80018, -0x8f48010c, 0x1021, 0xa32821, 0xa3482b, -0x822021, 0x100f809, 0x892021, 0x1440000c, -0x0, 0x8f820128, 0x8faa0024, 0x3c040001, -0x24843944, 0xafaa0014, 0xafa20010, 0x8f860124, -0x8f870120, 0x3c050007, 0xc0029d3, 0x34a59920, -0x8f420358, 0x2442ffff, 0xaf420358, 0x8f420044, -0x8f430088, 0x24420001, 0x431024, 0xaf420044, -0x8faa0034, 0x8f440358, 0x24020001, 0x15420006, -0x24020002, 0x8f42034c, 0x2442ffff, 0xaf42034c, -0x10000049, 0x8f42034c, 0x15420006, 0x0, -0x8f420354, 0x2442ffff, 0xaf420354, 0x10000042, -0x8f420354, 0x8f420350, 0x2442ffff, 0xaf420350, -0x1000003d, 0x8f420350, 0x30621000, 0x10400005, -0x30628000, 0x8f420078, 0x24420001, 0x10000036, -0xaf420078, 0x10400034, 0x0, 0x8f420078, -0x24420001, 0xaf420078, 0x8c030240, 0x43102b, -0x1440002d, 0x24070008, 0x8f440158, 0x8f45015c, -0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x24020001, -0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, -0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51300, 0x1000000b, 0x0, -0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, -0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, -0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, -0xaf420308, 0x8f420308, 0x8fbf0058, 0x8fbe0054, -0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, -0x8fb00040, 0x3e00008, 0x27bd0060, 0x3e00008, -0x0, 0x0, 0x0, 0x8f420130, +0x8f4202f8, 0x24420001, 0xaf4202f8, 0x10000174, +0x8f4202f8, 0x30620002, 0x10400135, 0x3c020800, +0x8d0a001c, 0x1422024, 0xafaa0024, 0xa5702, +0xafaa0034, 0x8faa0024, 0x314affff, 0xafaa0024, +0x950a0016, 0xafaa002c, 0x8faa0034, 0x24020001, +0x15420007, 0x24020002, 0x8faa0024, 0xa1140, +0x3403ecc0, 0x431021, 0x10000014, 0x2e2a821, +0x15420006, 0x24020003, 0x8faa0024, 0xa1140, +0x24426cc0, 0x1000000d, 0x2e2a821, 0x8faa0034, +0x15420006, 0x0, 0x8faa0024, 0xa1140, +0x24424cc0, 0x10000005, 0x2e2a821, 0x8faa0024, +0xa1180, 0x571021, 0x24550ce0, 0x96a2000e, +0x305efffc, 0x30420400, 0x144000c5, 0x8821, +0x10800004, 0x24091000, 0x97b1002e, 0x100000c1, +0x0, 0x8eb30018, 0x9663000c, 0x2c6205dd, +0x10400015, 0x2021, 0x32c20800, 0x10400015, +0x24020800, 0x96630014, 0x14620012, 0x3402aaaa, +0x9663000e, 0x14620007, 0x2821, 0x96630010, +0x24020300, 0x14620004, 0xa01021, 0x96620012, +0x2c450001, 0xa01021, 0x54400006, 0x24040016, +0x10000004, 0x0, 0x24020800, 0x50620001, +0x2404000e, 0x108000a2, 0x2649021, 0x92420000, +0x3042000f, 0x28080, 0x32c20100, 0x1040001e, +0x2501821, 0x3c020020, 0x43102b, 0x1440000e, +0x2402021, 0x2821, 0x94820000, 0x24840002, +0xa22821, 0x83102b, 0x1440fffb, 0x30a2ffff, +0x51c02, 0x622821, 0x51c02, 0x30a2ffff, +0x10000009, 0x622821, 0x8f47013c, 0x8f420110, +0x102842, 0x3c060020, 0x40f809, 0xafa80038, +0x3045ffff, 0x8fa80038, 0x50a00001, 0x3405ffff, +0x10000002, 0x37de0002, 0x2821, 0x32c20080, +0x1040007b, 0xa6a50010, 0x26430009, 0x3c02001f, +0x3442ffff, 0x43102b, 0x10400003, 0x0, +0x8f42013c, 0x621823, 0x90660000, 0x30c200ff, +0x38430006, 0x2c630001, 0x38420011, 0x2c420001, +0x621825, 0x1060006b, 0x24091000, 0x8821, +0x2602021, 0x94820000, 0x24840002, 0x2228821, +0x92102b, 0x1440fffb, 0x111c02, 0x3222ffff, +0x628821, 0x111c02, 0x3222ffff, 0x628821, +0x32c20200, 0x10400003, 0x26440006, 0x1000003e, +0x8021, 0x3c05001f, 0x34a5ffff, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x30421fff, 0x10400004, 0x2644000c, +0x96420002, 0x10000030, 0x508023, 0x96420002, +0x26430014, 0x508023, 0x3c020020, 0x43102b, +0x1440000a, 0xd08021, 0x9642000c, 0x2028021, +0x9642000e, 0x96430010, 0x96440012, 0x2028021, +0x2038021, 0x10000020, 0x2048021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x2028021, 0x3c020100, 0x2c21024, +0x1040000c, 0x33c20004, 0x1040000a, 0x0, +0x9504000e, 0x2642021, 0xc003cf8, 0x2484fffc, +0x3042ffff, 0x2228821, 0x111c02, 0x3222ffff, +0x628821, 0x8faa002c, 0x1518823, 0x111402, +0x2228821, 0x2308821, 0x111402, 0x2228821, +0x3231ffff, 0x52200001, 0x3411ffff, 0x37de0001, +0x24091000, 0x33c20004, 0xa6b10012, 0x10400002, +0xa6be000e, 0x34098000, 0x8f480044, 0x8f440190, +0x8f450194, 0xafa90010, 0x8f490044, 0x84140, +0x1001821, 0xafa90014, 0x8f48000c, 0x2a03021, +0x24070020, 0xafa80018, 0x8f48010c, 0x1021, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x1440000c, 0x0, 0x8f820128, +0x8faa0024, 0x3c040001, 0x24843a28, 0xafaa0014, +0xafa20010, 0x8f860124, 0x8f870120, 0x3c050007, +0xc002a03, 0x34a59920, 0x8f420358, 0x2442ffff, +0xaf420358, 0x8f420044, 0x8f430088, 0x24420001, +0x431024, 0xaf420044, 0x8faa0034, 0x8f440358, +0x24020001, 0x15420006, 0x24020002, 0x8f42034c, +0x2442ffff, 0xaf42034c, 0x10000049, 0x8f42034c, +0x15420006, 0x0, 0x8f420354, 0x2442ffff, +0xaf420354, 0x10000042, 0x8f420354, 0x8f420350, +0x2442ffff, 0xaf420350, 0x1000003d, 0x8f420350, +0x30621000, 0x10400005, 0x30628000, 0x8f420078, +0x24420001, 0x10000036, 0xaf420078, 0x10400034, +0x0, 0x8f420078, 0x24420001, 0xaf420078, +0x8c030240, 0x43102b, 0x1440002d, 0x24070008, +0x8f440158, 0x8f45015c, 0x8f430044, 0x8f48000c, +0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, +0x1000000b, 0x0, 0x8f4202f4, 0x24420001, +0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, +0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, +0x8f420308, 0x24420001, 0xaf420308, 0x8f420308, +0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, +0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, +0x27bd0060, 0x3e00008, 0x0, 0x8f420130, 0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130, 0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c, 0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8, 0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, -0xc002a57, 0x24060008, 0x8c020204, 0xc003dee, +0xc002a87, 0x24060008, 0x8c020204, 0xc003e1e, 0xaf820210, 0x2021, 0x8c060248, 0x24020004, -0x3c010001, 0xac223d18, 0xc004878, 0x24050004, -0x3c020001, 0x8c423d14, 0x30420001, 0x10400007, -0x24020001, 0x3c010001, 0xac223d18, 0x2021, -0x24050001, 0xc004878, 0x3c06601b, 0x3c040001, -0x24843a00, 0x8f420144, 0x8f430148, 0x3c050008, +0x3c010001, 0xac223e28, 0xc0048a8, 0x24050004, +0x3c020001, 0x8c423e24, 0x30420001, 0x10400007, +0x24020001, 0x3c010001, 0xac223e28, 0x2021, +0x24050001, 0xc0048a8, 0x3c06601b, 0x3c040001, +0x24843af0, 0x8f420144, 0x8f430148, 0x3c050008, 0x8f46014c, 0x21640, 0x31940, 0x34630403, 0x431025, 0x633c0, 0x461025, 0xaf82021c, 0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200, -0xc0029d3, 0x3821, 0x3c010001, 0xac203d10, -0x3c010001, 0xac203d28, 0x8fbf0018, 0x3e00008, +0xc002a03, 0x3821, 0x3c010001, 0xac203e20, +0x3c010001, 0xac203e38, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, -0x3c040001, 0x24843a0c, 0xc0029d3, 0x3821, +0x3c040001, 0x24843afc, 0xc002a03, 0x3821, 0x8f420400, 0x24420001, 0xaf420400, 0x8f420400, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394, 0x24420001, 0xaf420394, 0x8f420394, 0x8f900220, -0x8f4303a8, 0x3c020001, 0x8c423d28, 0x3c040001, -0x24843a18, 0x3c050008, 0xafa20014, 0xafa30010, -0x8f4703ac, 0x34a50400, 0xc0029d3, 0x2003021, +0x8f4303a8, 0x3c020001, 0x8c423e38, 0x3c040001, +0x24843b08, 0x3c050008, 0xafa20014, 0xafa30010, +0x8f4703ac, 0x34a50400, 0xc002a03, 0x2003021, 0x3c024000, 0x2021024, 0x104000e1, 0x3c040100, 0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, @@ -7243,83 +7258,81 @@ 0x8f42013c, 0x822021, 0x8f420140, 0x2c830001, 0x44102b, 0x431025, 0x50400008, 0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, -0x3c034000, 0x10000046, 0x431025, 0x3442ffff, +0x3c034000, 0x10000041, 0x431025, 0x3442ffff, 0x8f4303bc, 0x282a024, 0x24020001, 0xa34205b1, -0x24630001, 0xaf4303bc, 0x1000003e, 0x8f4203bc, -0x2041024, 0x10400013, 0x3c110200, 0x8f420398, +0x24630001, 0xaf4303bc, 0x10000039, 0x8f4203bc, +0x2041024, 0x1040000e, 0x3c110200, 0x8f420398, 0x24420001, 0xaf420398, 0x8f420398, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x441025, -0xaf820220, 0x3c020004, 0x2021024, 0x14400005, -0x3c110200, 0xc003bad, 0x0, 0x10000029, -0x0, 0x2111024, 0x50400008, 0x3c110400, -0x8f42039c, 0x24420001, 0xaf42039c, 0xc003bad, -0x8f42039c, 0x10000019, 0x0, 0x2111024, -0x1040001c, 0x0, 0x8f830224, 0x24021402, -0x14620009, 0x3c050008, 0x3c040001, 0x24843a24, -0xafa00010, 0xafa00014, 0x8f860224, 0x34a50500, -0xc0029d3, 0x3821, 0x8f4203a0, 0x24420001, -0xaf4203a0, 0x8f4203a0, 0x8f820220, 0x2002021, -0x34420002, 0xc004610, 0xaf820220, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x511025, -0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x3c020001, 0x8c423d28, 0x27bdffb0, 0xafbf0048, -0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, -0xafb10034, 0x1040000f, 0xafb00030, 0x3c040001, -0x24843a30, 0x3c050008, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50600, 0x24020001, 0x3c010001, -0xac203d28, 0x3c010001, 0xac223d1c, 0xc0029d3, -0x3821, 0x3c037fff, 0x8c020268, 0x3463ffff, -0x3c04fdff, 0x431024, 0xac020268, 0x8f420004, -0x3484ffff, 0x30420002, 0x10400092, 0x284a024, -0x3c040600, 0x34842000, 0x8f420004, 0x2821, -0x2403fffd, 0x431024, 0xaf420004, 0xafa40020, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa002c, 0x27c50001, 0x8c020228, 0xa09021, -0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, -0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x248439c8, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, +0xc003be0, 0xaf820220, 0x10000029, 0x0, +0x2111024, 0x50400008, 0x3c110400, 0x8f42039c, +0x24420001, 0xaf42039c, 0xc003be0, 0x8f42039c, +0x10000019, 0x0, 0x2111024, 0x1040001c, +0x0, 0x8f830224, 0x24021402, 0x14620009, +0x3c050008, 0x3c040001, 0x24843b14, 0xafa00010, +0xafa00014, 0x8f860224, 0x34a50500, 0xc002a03, +0x3821, 0x8f4203a0, 0x24420001, 0xaf4203a0, +0x8f4203a0, 0x8f820220, 0x2002021, 0x34420002, +0xc004640, 0xaf820220, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x511025, 0xaf820220, +0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0028, 0x3e00008, 0x0, 0x3c020001, +0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, +0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, +0x1040000f, 0xafb00030, 0x3c040001, 0x24843b20, +0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, +0x34a50600, 0x24020001, 0x3c010001, 0xac203e38, +0x3c010001, 0xac223e2c, 0xc002a03, 0x3821, +0x3c037fff, 0x8c020268, 0x3463ffff, 0x3c04fdff, +0x431024, 0xac020268, 0x8f420004, 0x3484ffff, +0x30420002, 0x10400092, 0x284a024, 0x3c040600, +0x34842000, 0x8f420004, 0x2821, 0x2403fffd, +0x431024, 0xaf420004, 0xafa40020, 0x8f5e0018, +0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa002c, +0x27c50001, 0x8c020228, 0xa09021, 0x1642000e, +0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24843ab8, +0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, +0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, +0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, +0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, +0x1040001b, 0x9821, 0xe08821, 0x263504c0, +0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004, +0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021, +0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x54400006, 0x24130001, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0, +0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, +0x24843ac4, 0x3c050009, 0xafa20014, 0x8d460000, +0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, +0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, +0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, +0x2021023, 0x2c4203e9, 0x10400016, 0x9821, +0x3c150020, 0x24110010, 0x8f42000c, 0x8f440150, +0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, +0x551025, 0xafa20018, 0x8f42010c, 0x24070008, +0x40f809, 0x24c6001c, 0x1440ffe3, 0x0, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffee, +0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x248439d4, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000035, 0x34a50600, 0x8f4202f8, -0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016, -0x9821, 0x3c150020, 0x24110010, 0x8f42000c, -0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010, -0xafb20014, 0x551025, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, -0x0, 0x8f820054, 0x2021023, 0x2c4203e9, -0x1440ffee, 0x0, 0x326200ff, 0x14400011, -0x0, 0x8f420368, 0x24420001, 0xaf420368, -0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x248439dc, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, -0x3c03821, 0x8f4202dc, 0x24420001, 0xaf4202dc, -0x8f4202dc, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x3c020001, 0x8c423d28, -0x27bdffe0, 0x1440000d, 0xafbf0018, 0x3c040001, -0x24843a3c, 0x3c050008, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50700, 0x24020001, 0x3c010001, -0xac223d28, 0xc0029d3, 0x3821, 0x3c020004, -0x2c21024, 0x10400008, 0x2021, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, -0xaf820220, 0x2021, 0xc004981, 0x24050004, -0xac020268, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x0, 0x0, 0x0, 0x86102b, +0x3c040001, 0x24843acc, 0x3c050009, 0xafa20014, +0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, +0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, +0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, +0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, +0x27bd0050, 0x3c020001, 0x8c423e38, 0x27bdffe0, +0x1440000d, 0xafbf0018, 0x3c040001, 0x24843b2c, +0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, +0x34a50700, 0x24020001, 0x3c010001, 0xac223e38, +0xc002a03, 0x3821, 0x3c020004, 0x2c21024, +0x10400008, 0x2021, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x34420008, 0xaf820220, +0x2021, 0xc0049b1, 0x24050004, 0xac020268, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x86102b, 0x50400001, 0x872023, 0xc41023, 0x24843, 0x125102b, 0x1040001b, 0x91040, 0x824021, 0x88102b, 0x10400007, 0x1821, 0x94820000, @@ -7359,7 +7372,7 @@ 0x90a20000, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x41c02, 0x3082ffff, 0x622021, 0x3e00008, 0x3082ffff, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x3c020001, 0x8c425f28, +0x34420002, 0xaf820220, 0x3c020001, 0x8c426038, 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, @@ -7406,43 +7419,43 @@ 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x10000008, 0x0, 0x10620004, 0x24020800, 0x10000004, 0x0, -0x24020700, 0x3c010001, 0xac223d2c, 0x3e00008, +0x24020700, 0x3c010001, 0xac223e3c, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030, -0xafb1002c, 0xafb00028, 0x3c010001, 0xc0045ed, -0xac203d14, 0x24040001, 0x2821, 0x27a60020, -0x34028000, 0xc00420a, 0xa7a20020, 0x8f830054, +0xafb1002c, 0xafb00028, 0x3c010001, 0xc00461d, +0xac203e24, 0x24040001, 0x2821, 0x27a60020, +0x34028000, 0xc00423a, 0xa7a20020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050002, 0xc0041c8, 0x27a60018, 0x8f830054, +0x24050002, 0xc0041f8, 0x27a60018, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050003, 0xc0041c8, 0x27a6001a, 0x97a20020, -0x10400029, 0x24020001, 0x3c020001, 0x8c423d14, -0x97a30018, 0x34420001, 0x3c010001, 0xac223d14, +0x24050003, 0xc0041f8, 0x27a6001a, 0x97a20020, +0x10400029, 0x24020001, 0x3c020001, 0x8c423e24, +0x97a30018, 0x34420001, 0x3c010001, 0xac223e24, 0x24020015, 0x14620009, 0x0, 0x97a2001a, 0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, 0x621825, 0x14600018, 0x24020003, 0x97a30018, 0x24027810, 0x14620014, 0x24020002, 0x97a3001a, 0x24020001, 0x14620010, 0x24020002, 0x1000000e, -0x24020004, 0x3c020001, 0x8c423d14, 0x34420008, -0x3c010001, 0xac223d14, 0x10000058, 0x24020004, -0x3c020001, 0x8c423d14, 0x34420004, 0x3c010001, -0x100000a9, 0xac223d14, 0x3c010001, 0xac223e70, +0x24020004, 0x3c020001, 0x8c423e24, 0x34420008, +0x3c010001, 0xac223e24, 0x10000058, 0x24020004, +0x3c020001, 0x8c423e24, 0x34420004, 0x3c010001, +0x100000a9, 0xac223e24, 0x3c010001, 0xac223f80, 0x24020e00, 0xaf820238, 0x8f840054, 0x8f820054, -0x24030008, 0x3c010001, 0xac233d18, 0x10000002, +0x24030008, 0x3c010001, 0xac233e28, 0x10000002, 0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, 0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, -0x8021, 0x24120001, 0x24110009, 0xc0040e8, -0x0, 0x3c010001, 0xac323d30, 0xc004194, -0x0, 0x3c020001, 0x8c423d30, 0x1451fffb, +0x8021, 0x24120001, 0x24110009, 0xc004118, +0x0, 0x3c010001, 0xac323e40, 0xc0041c4, +0x0, 0x3c020001, 0x8c423e40, 0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 0x0, @@ -7454,10 +7467,10 @@ 0x14440005, 0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa6, 0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, 0x3c010001, -0xac223d18, 0x8021, 0x24120009, 0x3c11ffff, -0x36313f7f, 0xc0040e8, 0x0, 0x24020001, -0x3c010001, 0xac223d30, 0xc004194, 0x0, -0x3c020001, 0x8c423d30, 0x1452fffb, 0x0, +0xac223e28, 0x8021, 0x24120009, 0x3c11ffff, +0x36313f7f, 0xc004118, 0x0, 0x24020001, +0x3c010001, 0xac223e40, 0xc0041c4, 0x0, +0x3c020001, 0x8c423e40, 0x1452fffb, 0x0, 0x8f820044, 0x511024, 0x34425080, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, @@ -7475,131 +7488,131 @@ 0x1440fffc, 0x0, 0x8f820224, 0x14440005, 0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 0x34028000, 0x1082ff56, 0x26100001, 0x2e020064, -0x1440ffb0, 0x0, 0x3c020001, 0x8c423d14, +0x1440ffb0, 0x0, 0x3c020001, 0x8c423e24, 0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, 0x3c08fff0, 0x3508bdc0, 0x8f830054, 0x97a60018, -0x3c070001, 0x8ce73e70, 0x3c040001, 0x24843b00, -0x24020001, 0x3c010001, 0xac223d1c, 0xafa60010, -0x3c060001, 0x8cc63d14, 0x97a2001a, 0x3c05000d, -0x34a50100, 0x3c010001, 0xac203d18, 0x681821, -0x3c010001, 0xac233e68, 0xc0029d3, 0xafa20014, +0x3c070001, 0x8ce73f80, 0x3c040001, 0x24843c00, +0x24020001, 0x3c010001, 0xac223e2c, 0xafa60010, +0x3c060001, 0x8cc63e24, 0x97a2001a, 0x3c05000d, +0x34a50100, 0x3c010001, 0xac203e28, 0x681821, +0x3c010001, 0xac233f78, 0xc002a03, 0xafa20014, 0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038, 0x27bdffe8, 0x24070004, -0x3c040001, 0x8c843d18, 0x3021, 0x24020001, -0x1482000a, 0xafbf0010, 0x3c020001, 0x8c425f2c, +0x3c040001, 0x8c843e28, 0x3021, 0x24020001, +0x1482000a, 0xafbf0010, 0x3c020001, 0x8c42603c, 0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, -0x8c425f2c, 0x3c05000f, 0x30428000, 0x10400003, +0x8c42603c, 0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480, 0x3c020001, -0x8c423e68, 0x8f830054, 0x451021, 0x431023, +0x8c423f78, 0x8f830054, 0x451021, 0x431023, 0x45102b, 0x1440002e, 0x0, 0x3c020001, -0x8c423d20, 0x1440002a, 0x2cc20001, 0x7182b, +0x8c423e30, 0x1440002a, 0x2cc20001, 0x7182b, 0x431024, 0x1040001d, 0x0, 0x3c090001, -0x8d293d14, 0x240b0001, 0x3c054000, 0x3c080001, -0x25085f2c, 0x250afffc, 0x42042, 0x14800002, +0x8d293e24, 0x240b0001, 0x3c054000, 0x3c080001, +0x2508603c, 0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 0x10000003, 0x451024, 0x8d420000, 0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, 0x42042, 0x3c010001, -0x10c00020, 0xac243d18, 0x8f830054, 0x24020001, -0x3c010001, 0xac223d1c, 0x3c010001, 0xac233e68, -0x3c020001, 0x8c423d1c, 0x10400004, 0x24020001, -0x3c010001, 0xac203d1c, 0xaee204b8, 0x8ee304b8, -0x24020008, 0x10620005, 0x24020001, 0xc003f91, +0x10c00020, 0xac243e28, 0x8f830054, 0x24020001, +0x3c010001, 0xac223e2c, 0x3c010001, 0xac233f78, +0x3c020001, 0x8c423e2c, 0x10400004, 0x24020001, +0x3c010001, 0xac203e2c, 0xaee204b8, 0x8ee304b8, +0x24020008, 0x10620005, 0x24020001, 0xc003fc1, 0x0, 0x1000000b, 0x0, 0x3c030001, -0x8c633d18, 0x10620007, 0x2402000e, 0x3c030001, -0x8c635ec0, 0x10620003, 0x0, 0xc004610, +0x8c633e28, 0x10620007, 0x2402000e, 0x3c030001, +0x8c635fd0, 0x10620003, 0x0, 0xc004640, 0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843d18, -0x3c020001, 0x8c423d38, 0x3463ffff, 0x283a024, +0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843e28, +0x3c020001, 0x8c423e48, 0x3463ffff, 0x283a024, 0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, -0x8c423d3c, 0x10620006, 0x0, 0x8ee204b8, -0x3c010001, 0xac243d38, 0x3c010001, 0xac223d3c, -0x3c030001, 0x8c633d18, 0x24020002, 0x1062013c, +0x8c423e4c, 0x10620006, 0x0, 0x8ee204b8, +0x3c010001, 0xac243e48, 0x3c010001, 0xac223e4c, +0x3c030001, 0x8c633e28, 0x24020002, 0x1062013c, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x0, 0x10000134, 0x0, 0x24020004, 0x1062006d, 0x24020008, 0x1062009f, 0x24020001, 0x1000012d, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 0x1040012a, 0x31080, 0x3c010001, -0x220821, 0x8c223b18, 0x400008, 0x0, -0xc0040e8, 0x0, 0x3c020001, 0x8c423d24, -0x3c010001, 0xac203cb0, 0x104000d7, 0x24020002, -0xaee204b8, 0x3c010001, 0x10000119, 0xac203d24, -0xc00424b, 0x0, 0x3c030001, 0x8c633d40, -0x1000009e, 0x24020011, 0x3c050001, 0x8ca53d18, -0x3c060001, 0x8cc65f2c, 0xc004878, 0x2021, -0x24020005, 0x3c010001, 0xac203d24, 0x10000108, -0xaee204b8, 0x3c040001, 0x24843b0c, 0x3c05000f, +0x220821, 0x8c223c18, 0x400008, 0x0, +0xc004118, 0x0, 0x3c020001, 0x8c423e34, +0x3c010001, 0xac203dc0, 0x104000d7, 0x24020002, +0xaee204b8, 0x3c010001, 0x10000119, 0xac203e34, +0xc00427b, 0x0, 0x3c030001, 0x8c633e50, +0x1000009e, 0x24020011, 0x3c050001, 0x8ca53e28, +0x3c060001, 0x8cc6603c, 0xc0048a8, 0x2021, +0x24020005, 0x3c010001, 0xac203e34, 0x10000108, +0xaee204b8, 0x3c040001, 0x24843c0c, 0x3c05000f, 0x34a50100, 0x3021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x100000fd, 0x0, +0xc002a03, 0xafa00014, 0x100000fd, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0x100000a4, 0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 0x144000ae, 0x24020007, 0x8f830054, 0x3c020001, -0x8c423e60, 0x2463d8f0, 0x431023, 0x2c422710, +0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000eb, 0x24020001, 0x100000e7, 0x0, -0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, -0xc004a4c, 0x2021, 0x3c030001, 0x8c635f24, +0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, +0xc004a7c, 0x2021, 0x3c030001, 0x8c636034, 0x46100dd, 0x24020001, 0x3c020008, 0x621024, 0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 0x431024, 0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, 0x8f820220, 0x3c030200, 0x283a025, 0x34420002, -0xaf820220, 0x24020008, 0xc003c6b, 0xaee204b8, +0xaf820220, 0x24020008, 0xc003c9e, 0xaee204b8, 0x100000c7, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 0x104000c2, 0x31080, 0x3c010001, -0x220821, 0x8c223b38, 0x400008, 0x0, -0x3c020001, 0x8c425f28, 0x30424000, 0x10400004, +0x220821, 0x8c223c38, 0x400008, 0x0, +0x3c020001, 0x8c426038, 0x30424000, 0x10400004, 0x0, 0x8f820044, 0x10000006, 0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080, 0xaf820044, 0x8f830054, 0x1000005a, -0x24020004, 0xc003d2c, 0x0, 0x104000a6, +0x24020004, 0xc003d5c, 0x0, 0x104000a6, 0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x10800005, 0xaee204b8, 0x3c020001, -0x8c423da4, 0x1040006d, 0x24020001, 0x8f820220, +0x8c423eb4, 0x1040006d, 0x24020001, 0x8f820220, 0x3c030008, 0x431024, 0x10400073, 0x3c020200, 0x10000081, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e, 0x31080, 0x3c010001, -0x220821, 0x8c223b58, 0x400008, 0x0, -0xc003bad, 0x0, 0x3c010001, 0xac203d1c, -0xaf800204, 0x3c010001, 0xc0040e8, 0xac205f10, -0x24020001, 0x3c010001, 0xac223d30, 0x24020002, -0x1000007b, 0xaee204b8, 0xc004194, 0x0, -0x3c030001, 0x8c633d30, 0x24020009, 0x14620074, +0x220821, 0x8c223c58, 0x400008, 0x0, +0xc003be0, 0x0, 0x3c010001, 0xac203e2c, +0xaf800204, 0x3c010001, 0xc004118, 0xac206020, +0x24020001, 0x3c010001, 0xac223e40, 0x24020002, +0x1000007b, 0xaee204b8, 0xc0041c4, 0x0, +0x3c030001, 0x8c633e40, 0x24020009, 0x14620074, 0x24020003, 0x10000072, 0xaee204b8, 0x3c020001, -0x8c425f28, 0x30424000, 0x10400003, 0x3c0200c8, +0x8c426038, 0x30424000, 0x10400003, 0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, 0x8f830054, 0x10000014, 0x24020004, 0x8f830054, -0x3c020001, 0x8c423e60, 0x2463d8f0, 0x431023, +0x3c020001, 0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440005e, 0x24020005, 0x1000005c, 0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac205f10, +0xaf820220, 0xaf800204, 0x3c010001, 0xac206020, 0x8f830054, 0x24020006, 0xaee204b8, 0x3c010001, -0x1000004f, 0xac233e60, 0x8f830054, 0x3c020001, -0x8c423e60, 0x2463fff6, 0x431023, 0x2c42000a, +0x1000004f, 0xac233f70, 0x8f830054, 0x3c020001, +0x8c423f70, 0x2463fff6, 0x431023, 0x2c42000a, 0x14400047, 0x0, 0x24020007, 0x10000044, -0xaee204b8, 0xc003d2c, 0x0, 0x1040003e, +0xaee204b8, 0xc003d5c, 0x0, 0x1040003e, 0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, -0x8c423da4, 0x1440000b, 0x0, 0x8f820220, +0x8c423eb4, 0x1440000b, 0x0, 0x8f820220, 0x34420002, 0xaf820220, 0x24020001, 0x3c010001, -0xac225ec0, 0xc004610, 0x8f840220, 0x10000016, +0xac225fd0, 0xc004640, 0x8f840220, 0x10000016, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x14400011, 0x3c020200, 0x282a025, 0x2402000e, -0x3c010001, 0xac225ec0, 0xc004a4c, 0x2021, -0x8f820220, 0x34420002, 0xc003c6b, 0xaf820220, -0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, -0x10000013, 0x0, 0x3c020001, 0x8c423da4, -0x1040000f, 0x0, 0x3c020001, 0x8c423da0, -0x2442ffff, 0x3c010001, 0xac223da0, 0x14400008, -0x24020002, 0x3c010001, 0xac203da4, 0x3c010001, -0x10000003, 0xac223da0, 0x3c010001, 0xac223d1c, +0x3c010001, 0xac225fd0, 0xc004a7c, 0x2021, +0x8f820220, 0x34420002, 0xc003c9e, 0xaf820220, +0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, +0x10000013, 0x0, 0x3c020001, 0x8c423eb4, +0x1040000f, 0x0, 0x3c020001, 0x8c423eb0, +0x2442ffff, 0x3c010001, 0xac223eb0, 0x14400008, +0x24020002, 0x3c010001, 0xac203eb4, 0x3c010001, +0x10000003, 0xac223eb0, 0x3c010001, 0xac223e2c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c040001, 0x8c843d18, 0x34420004, +0x8f820200, 0x3c040001, 0x8c843e28, 0x34420004, 0xaf820200, 0x24020002, 0x1082003a, 0x2c820003, 0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, 0x10000098, 0x0, 0x24020004, 0x10820059, @@ -7607,300 +7620,300 @@ 0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, 0x34a53f7f, 0x431024, 0x3c030700, 0x431025, 0xaf820050, 0x24020e00, 0xaf840200, 0xaf840220, -0xaf820238, 0x8f820044, 0x3c030001, 0x8c633d08, -0x3c040001, 0x8c843e70, 0x451024, 0x34630022, +0xaf820238, 0x8f820044, 0x3c030001, 0x8c633e18, +0x3c040001, 0x8c843f80, 0x451024, 0x34630022, 0xaf820044, 0x24020004, 0x1082000c, 0xaf830200, -0x3c020001, 0x8c423d2c, 0x3c030001, 0x8c633d10, -0x3c040001, 0x8c843d0c, 0x34428000, 0x621825, +0x3c020001, 0x8c423e3c, 0x3c030001, 0x8c633e20, +0x3c040001, 0x8c843e1c, 0x34428000, 0x621825, 0x641825, 0x1000006e, 0x34620002, 0x3c020001, -0x8c423d10, 0x3c030001, 0x8c633d2c, 0x3c040001, -0x8c843d0c, 0x431025, 0x441025, 0x10000064, +0x8c423e20, 0x3c030001, 0x8c633e3c, 0x3c040001, +0x8c843e1c, 0x431025, 0x441025, 0x10000064, 0x34420002, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843e58, 0x621824, 0x3c020d00, +0x3c040001, 0x8c843f68, 0x621824, 0x3c020d00, 0x621825, 0x24020001, 0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00, 0x10800009, 0xaf820238, -0x3c020001, 0x8c423da4, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c423d00, 0x10000005, 0x34630070, -0x3c020001, 0x8c423d00, 0x3c033f00, 0x34630072, -0x431025, 0xaf820200, 0x3c030001, 0x8c633d04, -0x3c04f700, 0x3c020001, 0x8c423d10, 0x3c050001, -0x8ca53d2c, 0x641825, 0x431025, 0x1000003c, +0x3c020001, 0x8c423eb4, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c423e10, 0x10000005, 0x34630070, +0x3c020001, 0x8c423e10, 0x3c033f00, 0x34630072, +0x431025, 0xaf820200, 0x3c030001, 0x8c633e14, +0x3c04f700, 0x3c020001, 0x8c423e20, 0x3c050001, +0x8ca53e3c, 0x641825, 0x431025, 0x1000003c, 0x451025, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843e58, 0x621824, 0x3c020a00, +0x3c040001, 0x8c843f68, 0x621824, 0x3c020a00, 0x621825, 0x24020001, 0xaf830050, 0xaf820200, -0x1080001e, 0xaf820220, 0x3c020001, 0x8c423da4, -0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423d00, +0x1080001e, 0xaf820220, 0x3c020001, 0x8c423eb4, +0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423e10, 0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, -0x8c843e58, 0x3442ffff, 0x621824, 0x1080000f, -0xaf830050, 0x3c020001, 0x8c423da4, 0x1440000b, -0x3c043f00, 0x3c030001, 0x8c633d00, 0x348400e0, +0x8c843f68, 0x3442ffff, 0x621824, 0x1080000f, +0xaf830050, 0x3c020001, 0x8c423eb4, 0x1440000b, +0x3c043f00, 0x3c030001, 0x8c633e10, 0x348400e0, 0x24020001, 0xaf820200, 0xaf820220, 0x641825, 0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, -0x8c423d00, 0x3c033f00, 0x346300e2, 0x431025, +0x8c423e10, 0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, -0x8c633d04, 0x3c020001, 0x8c423d10, 0x3c040001, -0x8c843d2c, 0x651825, 0x431025, 0x441025, +0x8c633e14, 0x3c020001, 0x8c423e20, 0x3c040001, +0x8c843e3c, 0x651825, 0x431025, 0x441025, 0xaf820220, 0x3e00008, 0x0, 0x3c030001, -0x8c633d30, 0x3c020001, 0x8c423d34, 0x10620003, -0x24020002, 0x3c010001, 0xac233d34, 0x1062001d, +0x8c633e40, 0x3c020001, 0x8c423e44, 0x10620003, +0x24020002, 0x3c010001, 0xac233e44, 0x1062001d, 0x2c620003, 0x10400025, 0x24020001, 0x14620023, -0x24020004, 0x3c030001, 0x8c633d18, 0x10620006, +0x24020004, 0x3c030001, 0x8c633e28, 0x10620006, 0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080, 0xaf820044, 0x8f830054, 0x24020002, -0x3c010001, 0xac223d30, 0x3c010001, 0x1000000b, -0xac233e64, 0x8f830054, 0x3c020001, 0x8c423e64, +0x3c010001, 0xac223e40, 0x3c010001, 0x1000000b, +0xac233f74, 0x8f830054, 0x3c020001, 0x8c423f74, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, -0x24020009, 0x3c010001, 0xac223d30, 0x3e00008, +0x24020009, 0x3c010001, 0xac223e40, 0x3e00008, 0x0, 0x0, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc0045c7, 0x24040001, +0xafbf0020, 0xa6200000, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc0045c7, 0x2021, 0xc0045c7, 0x24040001, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fffa, +0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fffa, 0x2701024, 0xc0045ed, 0x34108000, -0xc0045ed, 0x0, 0xc0045a7, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fffa, 0x2701024, 0xc00461d, 0x34108000, +0xc00461d, 0x0, 0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc0045ed, 0x0, 0x8fbf0020, 0x8fb3001c, +0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc0045c7, +0xafb00010, 0x8021, 0xafbf0020, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x2501024, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x2501024, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8fbf0020, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633d40, -0x3c020001, 0x8c423d84, 0x27bdffd8, 0xafbf0020, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633e50, +0x3c020001, 0x8c423e94, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac233d84, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c223b80, -0x400008, 0x0, 0xc0045ed, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc0045c7, +0xac233e94, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c223c80, +0x400008, 0x0, 0xc00461d, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc0045c7, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc0045f7, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc0045c7, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc0045c7, -0x2021, 0xc0045c7, 0x24040001, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x24100010, +0x8021, 0xc0045f7, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc0045f7, +0x2021, 0xc0045f7, 0x24040001, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc0045c7, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc0045ed, 0x34108000, -0xc0045ed, 0x0, 0xc0045a7, 0x0, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc0045f7, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc00461d, 0x34108000, +0xc00461d, 0x0, 0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc0045ed, 0x0, 0x97a20010, 0x30428000, +0xc00461d, 0x0, 0x97a20010, 0x30428000, 0x144002dc, 0x24020003, 0x100002d8, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc0045c7, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc0045c7, 0x24040001, 0xc0045c7, +0xc0045f7, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fff8, 0x0, 0xc0045ed, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000296, 0x24020004, -0x8f830054, 0x3c020001, 0x8c423e6c, 0x2463ff9c, +0x8f830054, 0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c633e70, 0x10620297, 0x2c620003, +0x3c030001, 0x8c633f80, 0x10620297, 0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, 0x24020004, 0x10620291, 0x2402000f, 0x1000028f, 0x24020011, 0x1000028d, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x32020012, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x32020012, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8f830054, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000248, 0x24020006, 0x8f830054, 0x3c020001, -0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400250, 0x24020007, 0x1000024c, 0x0, 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020013, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020013, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000207, 0x24020008, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400127, 0x24020012, 0x10000123, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000037, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x32020013, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x32020013, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac223d40, 0x3c010001, -0x1000000c, 0xac233e6c, 0x8f830054, 0x3c020001, -0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac223e50, 0x3c010001, +0x1000000c, 0xac233f7c, 0x8f830054, 0x3c020001, +0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac223d40, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0xac223e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 0x8f840054, 0x8f820054, 0xa32824, 0x10000002, @@ -7929,136 +7942,136 @@ 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, -0x0, 0x3c020001, 0x8c423e58, 0x14400005, -0x0, 0xc003bad, 0x8f840224, 0x100001d8, +0x0, 0x3c020001, 0x8c423f68, 0x14400005, +0x0, 0xc003be0, 0x8f840224, 0x100001d8, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 0x3c030400, 0x431024, 0x10400006, 0x0, -0x3c010001, 0xac205ed0, 0x3c010001, 0x1000000b, -0xac205ef0, 0x3c030001, 0x24635ed0, 0x8c620000, +0x3c010001, 0xac205fe0, 0x3c010001, 0x1000000b, +0xac206000, 0x3c030001, 0x24635fe0, 0x8c620000, 0x24420001, 0xac620000, 0x2c420002, 0x14400003, -0x24020001, 0x3c010001, 0xac225ef0, 0x3c020001, -0x8c425ef0, 0x10400006, 0x30820040, 0x10400004, -0x24020001, 0x3c010001, 0x10000003, 0xac225ef4, -0x3c010001, 0xac205ef4, 0x3c010001, 0xac245ecc, -0x3c010001, 0x1000000b, 0xac205f00, 0x3c010001, -0xac225f00, 0x3c010001, 0xac205ef0, 0x3c010001, -0xac205ed0, 0x3c010001, 0xac205ef4, 0x3c010001, -0xac205ecc, 0x3c030001, 0x8c635ec0, 0x3c020001, -0x8c425ec4, 0x50620004, 0x2463ffff, 0x3c010001, -0xac235ec4, 0x2463ffff, 0x2c62000e, 0x10400194, -0x31080, 0x3c010001, 0x220821, 0x8c223bd0, +0x24020001, 0x3c010001, 0xac226000, 0x3c020001, +0x8c426000, 0x10400006, 0x30820040, 0x10400004, +0x24020001, 0x3c010001, 0x10000003, 0xac226004, +0x3c010001, 0xac206004, 0x3c010001, 0xac245fdc, +0x3c010001, 0x1000000b, 0xac206010, 0x3c010001, +0xac226010, 0x3c010001, 0xac206000, 0x3c010001, +0xac205fe0, 0x3c010001, 0xac206004, 0x3c010001, +0xac205fdc, 0x3c030001, 0x8c635fd0, 0x3c020001, +0x8c425fd4, 0x50620004, 0x2463ffff, 0x3c010001, +0xac235fd4, 0x2463ffff, 0x2c62000e, 0x10400194, +0x31080, 0x3c010001, 0x220821, 0x8c223cd0, 0x400008, 0x0, 0x24020002, 0x3c010001, -0xac205ef0, 0x3c010001, 0xac205ed0, 0x3c010001, -0xac205ecc, 0x3c010001, 0xac205ef4, 0x3c010001, -0xac205ee8, 0x3c010001, 0xac205ee0, 0xaf800224, -0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425f00, -0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003bad, +0xac206000, 0x3c010001, 0xac205fe0, 0x3c010001, +0xac205fdc, 0x3c010001, 0xac206004, 0x3c010001, +0xac205ff8, 0x3c010001, 0xac205ff0, 0xaf800224, +0x3c010001, 0xac225fd0, 0x3c020001, 0x8c426010, +0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003be0, 0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, -0x431024, 0xaf820200, 0x3c010001, 0xac205f10, -0x8f830054, 0x3c020001, 0x8c425ee8, 0x24040001, -0x3c010001, 0xac245efc, 0x24420001, 0x3c010001, -0xac225ee8, 0x2c420004, 0x3c010001, 0xac235ee4, -0x14400006, 0x24020003, 0x3c010001, 0xac243d1c, -0x3c010001, 0x1000015e, 0xac205ee8, 0x3c010001, -0x1000015b, 0xac225ec0, 0x8f830054, 0x3c020001, -0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020004, 0x3c010001, 0xac225ec0, -0x3c020001, 0x8c425f00, 0x14400021, 0x3c02fdff, +0x431024, 0xaf820200, 0x3c010001, 0xac206020, +0x8f830054, 0x3c020001, 0x8c425ff8, 0x24040001, +0x3c010001, 0xac24600c, 0x24420001, 0x3c010001, +0xac225ff8, 0x2c420004, 0x3c010001, 0xac235ff4, +0x14400006, 0x24020003, 0x3c010001, 0xac243e2c, +0x3c010001, 0x1000015e, 0xac205ff8, 0x3c010001, +0x1000015b, 0xac225fd0, 0x8f830054, 0x3c020001, +0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020004, 0x3c010001, 0xac225fd0, +0x3c020001, 0x8c426010, 0x14400021, 0x3c02fdff, 0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, -0x8c843e5c, 0x3c010001, 0xc0047f8, 0xac205ed8, -0x3c020001, 0x8c425f0c, 0xaf820204, 0x3c020001, -0x8c425f00, 0x14400012, 0x3c03fdff, 0x8f820204, +0x8c843f6c, 0x3c010001, 0xc004828, 0xac205fe8, +0x3c020001, 0x8c42601c, 0xaf820204, 0x3c020001, +0x8c426010, 0x14400012, 0x3c03fdff, 0x8f820204, 0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, -0x3c030001, 0x8c635f0c, 0x24020005, 0x3c010001, -0xac225ec0, 0x3c010001, 0x10000131, 0xac235f10, -0x3c020001, 0x8c425f00, 0x10400010, 0x3c02fdff, -0x3c020001, 0x8c423d9c, 0x24420001, 0x3c010001, -0xac223d9c, 0x2c420002, 0x14400125, 0x24020001, -0x3c010001, 0xac223da4, 0x3c010001, 0xac203d9c, -0x3c010001, 0x1000011e, 0xac223d1c, 0x3c030001, -0x8c635ef0, 0x3442ffff, 0x10600119, 0x282a024, -0x3c020001, 0x8c425ecc, 0x10400115, 0x0, -0x3c010001, 0xac225ef8, 0x24020003, 0x3c010001, -0xac225ed0, 0x100000b8, 0x24020006, 0x3c010001, -0xac205ed8, 0x8f820204, 0x34420040, 0xaf820204, -0x3c020001, 0x8c425f10, 0x24030007, 0x3c010001, -0xac235ec0, 0x34420040, 0x3c010001, 0xac225f10, -0x3c020001, 0x8c425ef0, 0x10400005, 0x0, -0x3c020001, 0x8c425ecc, 0x104000f0, 0x24020002, -0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, -0x104000ea, 0x24020002, 0x3c020001, 0x8c425ef4, -0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425ecc, -0x3c030001, 0x8c635ef8, 0x441024, 0x641824, +0x3c030001, 0x8c63601c, 0x24020005, 0x3c010001, +0xac225fd0, 0x3c010001, 0x10000131, 0xac236020, +0x3c020001, 0x8c426010, 0x10400010, 0x3c02fdff, +0x3c020001, 0x8c423eac, 0x24420001, 0x3c010001, +0xac223eac, 0x2c420002, 0x14400125, 0x24020001, +0x3c010001, 0xac223eb4, 0x3c010001, 0xac203eac, +0x3c010001, 0x1000011e, 0xac223e2c, 0x3c030001, +0x8c636000, 0x3442ffff, 0x10600119, 0x282a024, +0x3c020001, 0x8c425fdc, 0x10400115, 0x0, +0x3c010001, 0xac226008, 0x24020003, 0x3c010001, +0xac225fe0, 0x100000b8, 0x24020006, 0x3c010001, +0xac205fe8, 0x8f820204, 0x34420040, 0xaf820204, +0x3c020001, 0x8c426020, 0x24030007, 0x3c010001, +0xac235fd0, 0x34420040, 0x3c010001, 0xac226020, +0x3c020001, 0x8c426000, 0x10400005, 0x0, +0x3c020001, 0x8c425fdc, 0x104000f0, 0x24020002, +0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, +0x104000ea, 0x24020002, 0x3c020001, 0x8c426004, +0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425fdc, +0x3c030001, 0x8c636008, 0x441024, 0x641824, 0x10430004, 0x24020001, 0x3c010001, 0x100000e4, -0xac225ec0, 0x24020003, 0xaca20000, 0x24020008, -0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425efc, -0x1040000c, 0x24020001, 0x3c040001, 0xc004805, -0x8c845ecc, 0x3c020001, 0x8c425f18, 0x14400005, -0x24020001, 0x3c020001, 0x8c425f14, 0x10400006, -0x24020001, 0x3c010001, 0xac223d1c, 0x3c010001, -0x100000cb, 0xac205ee8, 0x3c020001, 0x8c425ee0, -0x3c030001, 0x8c635ecc, 0x2c420001, 0x210c0, -0x30630008, 0x3c010001, 0xac225ee0, 0x3c010001, -0xac235edc, 0x8f830054, 0x24020009, 0x3c010001, -0xac225ec0, 0x3c010001, 0x100000b9, 0xac235ee4, -0x8f830054, 0x3c020001, 0x8c425ee4, 0x2463d8f0, +0xac225fd0, 0x24020003, 0xaca20000, 0x24020008, +0x3c010001, 0xac225fd0, 0x3c020001, 0x8c42600c, +0x1040000c, 0x24020001, 0x3c040001, 0xc004835, +0x8c845fdc, 0x3c020001, 0x8c426028, 0x14400005, +0x24020001, 0x3c020001, 0x8c426024, 0x10400006, +0x24020001, 0x3c010001, 0xac223e2c, 0x3c010001, +0x100000cb, 0xac205ff8, 0x3c020001, 0x8c425ff0, +0x3c030001, 0x8c635fdc, 0x2c420001, 0x210c0, +0x30630008, 0x3c010001, 0xac225ff0, 0x3c010001, +0xac235fec, 0x8f830054, 0x24020009, 0x3c010001, +0xac225fd0, 0x3c010001, 0x100000b9, 0xac235ff4, +0x8f830054, 0x3c020001, 0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440009f, 0x0, -0x3c020001, 0x8c425ef0, 0x10400005, 0x0, -0x3c020001, 0x8c425ecc, 0x104000a0, 0x24020002, -0x3c030001, 0x24635ed0, 0x8c620000, 0x2c424e21, -0x1040009a, 0x24020002, 0x3c020001, 0x8c425efc, -0x1040000e, 0x0, 0x3c020001, 0x8c425ecc, -0x3c010001, 0xac205efc, 0x30420080, 0x1040002f, +0x3c020001, 0x8c426000, 0x10400005, 0x0, +0x3c020001, 0x8c425fdc, 0x104000a0, 0x24020002, +0x3c030001, 0x24635fe0, 0x8c620000, 0x2c424e21, +0x1040009a, 0x24020002, 0x3c020001, 0x8c42600c, +0x1040000e, 0x0, 0x3c020001, 0x8c425fdc, +0x3c010001, 0xac20600c, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, 0x24020003, 0x10000029, 0x2402000c, 0x3c020001, -0x8c425ecc, 0x30420080, 0x14400005, 0x24020003, +0x8c425fdc, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, -0xac620000, 0x2402000a, 0x3c010001, 0xac225ec0, -0x3c040001, 0x24845f08, 0x8c820000, 0x3c030001, -0x8c635ee0, 0x431025, 0xaf820204, 0x8c830000, -0x3c040001, 0x8c845ee0, 0x2402000b, 0x3c010001, -0xac225ec0, 0x641825, 0x3c010001, 0xac235f10, -0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, -0x10400066, 0x24020002, 0x3c020001, 0x8c425f00, +0xac620000, 0x2402000a, 0x3c010001, 0xac225fd0, +0x3c040001, 0x24846018, 0x8c820000, 0x3c030001, +0x8c635ff0, 0x431025, 0xaf820204, 0x8c830000, +0x3c040001, 0x8c845ff0, 0x2402000b, 0x3c010001, +0xac225fd0, 0x641825, 0x3c010001, 0xac236020, +0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, +0x10400066, 0x24020002, 0x3c020001, 0x8c426010, 0x10400005, 0x0, 0x2402000c, 0x3c010001, -0x10000067, 0xac225ec0, 0x3c020001, 0x8c425ef0, -0x10400063, 0x0, 0x3c040001, 0x8c845ecc, -0x10800055, 0x30820008, 0x3c030001, 0x8c635edc, -0x1062005b, 0x24020003, 0x3c010001, 0xac245ef8, +0x10000067, 0xac225fd0, 0x3c020001, 0x8c426000, +0x10400063, 0x0, 0x3c040001, 0x8c845fdc, +0x10800055, 0x30820008, 0x3c030001, 0x8c635fec, +0x1062005b, 0x24020003, 0x3c010001, 0xac246008, 0xaca20000, 0x24020006, 0x3c010001, 0x10000054, -0xac225ec0, 0x8f820200, 0x34420002, 0xaf820200, -0x8f830054, 0x2402000d, 0x3c010001, 0xac225ec0, -0x3c010001, 0xac235ee4, 0x8f830054, 0x3c020001, -0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400031, 0x0, 0x3c020001, 0x8c425f00, -0x10400020, 0x2402000e, 0x3c030001, 0x8c635f14, -0x3c010001, 0x14600015, 0xac225ec0, 0xc003c6b, -0x0, 0x3c050001, 0x8ca53d18, 0xc004981, -0x2021, 0x3c030001, 0x8c633d18, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d14, -0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d14, -0x431024, 0x3c010001, 0xac223d14, 0x8f830224, -0x3c020200, 0x3c010001, 0xac235f1c, 0x10000020, -0x282a025, 0x3c020001, 0x8c425ef0, 0x10400005, -0x0, 0x3c020001, 0x8c425ecc, 0x1040000f, -0x24020002, 0x3c020001, 0x8c425ed0, 0x2c424e21, -0x1040000a, 0x24020002, 0x3c020001, 0x8c425ef0, -0x1040000f, 0x0, 0x3c020001, 0x8c425ecc, +0xac225fd0, 0x8f820200, 0x34420002, 0xaf820200, +0x8f830054, 0x2402000d, 0x3c010001, 0xac225fd0, +0x3c010001, 0xac235ff4, 0x8f830054, 0x3c020001, +0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400031, 0x0, 0x3c020001, 0x8c426010, +0x10400020, 0x2402000e, 0x3c030001, 0x8c636024, +0x3c010001, 0x14600015, 0xac225fd0, 0xc003c9e, +0x0, 0x3c050001, 0x8ca53e28, 0xc0049b1, +0x2021, 0x3c030001, 0x8c633e28, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c423e24, +0x10000003, 0x2403fff7, 0x3c020001, 0x8c423e24, +0x431024, 0x3c010001, 0xac223e24, 0x8f830224, +0x3c020200, 0x3c010001, 0xac23602c, 0x10000020, +0x282a025, 0x3c020001, 0x8c426000, 0x10400005, +0x0, 0x3c020001, 0x8c425fdc, 0x1040000f, +0x24020002, 0x3c020001, 0x8c425fe0, 0x2c424e21, +0x1040000a, 0x24020002, 0x3c020001, 0x8c426000, +0x1040000f, 0x0, 0x3c020001, 0x8c425fdc, 0x1440000b, 0x0, 0x24020002, 0x3c010001, -0x10000007, 0xac225ec0, 0x3c020001, 0x8c425ef0, -0x10400003, 0x0, 0xc003bad, 0x0, +0x10000007, 0xac225fd0, 0x3c020001, 0x8c426000, +0x10400003, 0x0, 0xc003be0, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, -0x24635f18, 0x8c620000, 0x10400005, 0x34422000, -0x3c010001, 0xac225f0c, 0x10000003, 0xac600000, -0x3c010001, 0xac245f0c, 0x3e00008, 0x0, +0x24636028, 0x8c620000, 0x10400005, 0x34422000, +0x3c010001, 0xac22601c, 0x10000003, 0xac600000, +0x3c010001, 0xac24601c, 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, -0xac225f14, 0x14400067, 0x3c02ffff, 0x34421f0e, +0xac226024, 0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, -0x21200, 0x3c040001, 0x8c843e5c, 0x621825, -0x331c2, 0x3c030001, 0x24633da8, 0x30828000, +0x21200, 0x3c040001, 0x8c843f6c, 0x621825, +0x331c2, 0x3c030001, 0x24633eb8, 0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, 0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, 0x0, @@ -8066,86 +8079,86 @@ 0x1062002c, 0x3c05000f, 0x10000037, 0x0, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x3c010001, 0xac205f34, 0x3c010001, -0x10000034, 0xac205f3c, 0x8f820200, 0x34420100, +0xaf820220, 0x3c010001, 0xac206044, 0x3c010001, +0x10000034, 0xac20604c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 0x24020100, 0x3c010001, -0xac225f34, 0x3c010001, 0x10000026, 0xac205f3c, +0xac226044, 0x3c010001, 0x10000026, 0xac20604c, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x3c010001, 0xac205f34, 0x3c010001, 0x10000019, -0xac235f3c, 0x8f820200, 0x34420100, 0xaf820200, +0x3c010001, 0xac206044, 0x3c010001, 0x10000019, +0xac23604c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x24020100, 0x3c010001, 0xac225f34, 0x3c010001, -0x1000000c, 0xac235f3c, 0x34a5ffff, 0x3c040001, -0x24843c08, 0xafa30010, 0xc0029d3, 0xafa00014, +0x24020100, 0x3c010001, 0xac226044, 0x3c010001, +0x1000000c, 0xac23604c, 0x34a5ffff, 0x3c040001, +0x24843d08, 0xafa30010, 0xc002a03, 0xafa00014, 0x10000004, 0x0, 0x24020030, 0x3c010001, -0xac225f18, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0xac226028, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x24843c20, -0x3c050009, 0x3c020001, 0x8c423d18, 0x34a59001, +0xafb00020, 0xc08021, 0x3c040001, 0x24843d20, +0x3c050009, 0x3c020001, 0x8c423e28, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, -0xa7a0001a, 0xafb00014, 0xc0029d3, 0xafa20010, +0xa7a0001a, 0xafb00014, 0xc002a03, 0xafa20010, 0x24020002, 0x126200eb, 0x2e620003, 0x10400005, 0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5, 0x0, 0x24020004, 0x1262006d, 0x24020008, 0x1262006c, 0x3c02ffec, 0x100000de, 0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, -0x320821, 0xac305f2c, 0x3c024000, 0x2021024, +0x320821, 0xac30603c, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, 0x101382, -0x3042000c, 0x3c030001, 0x24633d44, 0x431021, +0x3042000c, 0x3c030001, 0x24633e54, 0x431021, 0x823821, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010001, 0x320821, 0xac225f30, +0x24020100, 0x3c010001, 0x320821, 0xac226040, 0x10000005, 0x3c020080, 0x3c010001, 0x320821, -0xac205f30, 0x3c020080, 0x2021024, 0x10400006, +0xac206040, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac225f38, 0x111140, 0x3c010001, -0x220821, 0xac205f38, 0x94e30000, 0x32024000, +0x10000005, 0xac226048, 0x111140, 0x3c010001, +0x220821, 0xac206048, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, -0x34420001, 0xc00420a, 0xa4e20002, 0x24040001, -0x2821, 0xc00420a, 0x27a60018, 0x3c020001, -0x8c423d18, 0x24110001, 0x3c010001, 0xac313d24, -0x14530004, 0x32028000, 0xc003bad, 0x0, -0x32028000, 0x10400097, 0x0, 0xc003bad, -0x0, 0x24020002, 0x3c010001, 0xac313d1c, -0x3c010001, 0x1000008f, 0xac223d18, 0x24040001, -0x24050004, 0x27b0001a, 0xc00420a, 0x2003021, -0x24040001, 0x2821, 0xc00420a, 0x2003021, -0x3c020001, 0x521021, 0x8c425f24, 0x3c040001, -0x8c843d18, 0x3c03bfff, 0x3463ffff, 0x3c010001, -0xac333d24, 0x431024, 0x3c010001, 0x320821, -0x10930076, 0xac225f24, 0x10000076, 0x0, +0x34420001, 0xc00423a, 0xa4e20002, 0x24040001, +0x2821, 0xc00423a, 0x27a60018, 0x3c020001, +0x8c423e28, 0x24110001, 0x3c010001, 0xac313e34, +0x14530004, 0x32028000, 0xc003be0, 0x0, +0x32028000, 0x10400097, 0x0, 0xc003be0, +0x0, 0x24020002, 0x3c010001, 0xac313e2c, +0x3c010001, 0x1000008f, 0xac223e28, 0x24040001, +0x24050004, 0x27b0001a, 0xc00423a, 0x2003021, +0x24040001, 0x2821, 0xc00423a, 0x2003021, +0x3c020001, 0x521021, 0x8c426034, 0x3c040001, +0x8c843e28, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac333e34, 0x431024, 0x3c010001, 0x320821, +0x10930076, 0xac226034, 0x10000076, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, -0xac305f28, 0x3c022000, 0x2021024, 0x10400009, -0x0, 0x3c020001, 0x8c423da4, 0x14400005, -0x24020001, 0x3c010001, 0xac223e58, 0x10000004, -0x3c024000, 0x3c010001, 0xac203e58, 0x3c024000, +0xac306038, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c423eb4, 0x14400005, +0x24020001, 0x3c010001, 0xac223f68, 0x10000004, +0x3c024000, 0x3c010001, 0xac203f68, 0x3c024000, 0x2021024, 0x1440001a, 0x0, 0x3c020001, -0x8c423e58, 0x10400005, 0x24022020, 0x3c010001, -0xac223e5c, 0x24020001, 0xaee204b8, 0x3c04bfff, -0x111940, 0x3c020001, 0x431021, 0x8c425f20, -0x3c050001, 0x8ca53d18, 0x3484ffff, 0x441024, -0x3c010001, 0x230821, 0xac225f20, 0x24020001, +0x8c423f68, 0x10400005, 0x24022020, 0x3c010001, +0xac223f6c, 0x24020001, 0xaee204b8, 0x3c04bfff, +0x111940, 0x3c020001, 0x431021, 0x8c426030, +0x3c050001, 0x8ca53e28, 0x3484ffff, 0x441024, +0x3c010001, 0x230821, 0xac226030, 0x24020001, 0x10a20044, 0x0, 0x10000040, 0x0, -0x3c020001, 0x8c423e58, 0x1040001c, 0x24022000, -0x3c010001, 0xac223e5c, 0x3c0300a0, 0x2031024, +0x3c020001, 0x8c423f68, 0x1040001c, 0x24022000, +0x3c010001, 0xac223f6c, 0x3c0300a0, 0x2031024, 0x14430005, 0x111140, 0x3402a000, 0x3c010001, -0x1000002d, 0xac223e5c, 0x3c030001, 0x621821, -0x8c635f28, 0x3c020020, 0x621024, 0x10400004, -0x24022001, 0x3c010001, 0x10000023, 0xac223e5c, +0x1000002d, 0xac223f6c, 0x3c030001, 0x621821, +0x8c636038, 0x3c020020, 0x621024, 0x10400004, +0x24022001, 0x3c010001, 0x10000023, 0xac223f6c, 0x3c020080, 0x621024, 0x1040001f, 0x3402a001, -0x3c010001, 0x1000001c, 0xac223e5c, 0x3c020020, +0x3c010001, 0x1000001c, 0xac223f6c, 0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, -0x3c010001, 0x230821, 0xac225f34, 0x10000006, +0x3c010001, 0x230821, 0xac226044, 0x10000006, 0x3c020080, 0x111140, 0x3c010001, 0x220821, -0xac205f34, 0x3c020080, 0x2021024, 0x10400006, +0xac206044, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac225f3c, 0x111140, 0x3c010001, -0x220821, 0xac205f3c, 0x3c030001, 0x8c633d18, -0x24020001, 0x10620003, 0x0, 0xc003bad, +0x10000005, 0xac22604c, 0x111140, 0x3c010001, +0x220821, 0xac20604c, 0x3c030001, 0x8c633e28, +0x24020001, 0x10620003, 0x0, 0xc003be0, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020, @@ -8155,95 +8168,95 @@ 0x10400005, 0x24020001, 0x10a2000a, 0x158140, 0x100000ae, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, 0x152940, 0x100000a7, -0x2201021, 0x3c030001, 0x701821, 0x8c635f2c, +0x2201021, 0x3c030001, 0x701821, 0x8c63603c, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, -0x300821, 0xac315f24, 0x10000098, 0x2201021, -0x24050001, 0xc0041c8, 0x27a60010, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60010, 0x97a20010, +0x300821, 0xac316034, 0x10000098, 0x2201021, +0x24050001, 0xc0041f8, 0x27a60010, 0x24040001, +0x24050001, 0xc0041f8, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, 0x3c114000, 0x3c030001, -0x8c633e70, 0x24020003, 0x10620008, 0x2c620004, +0x8c633f80, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, 0x24020004, 0x10620014, 0x24040001, 0x10000024, 0x3c028000, 0x24040001, -0x24050011, 0x27b00012, 0xc0041c8, 0x2003021, -0x24040001, 0x24050011, 0xc0041c8, 0x2003021, +0x24050011, 0x27b00012, 0xc0041f8, 0x2003021, +0x24040001, 0x24050011, 0xc0041f8, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x10000010, 0x30628000, -0x24050014, 0x27b00012, 0xc0041c8, 0x2003021, -0x24040001, 0x24050014, 0xc0041c8, 0x2003021, +0x24050014, 0x27b00012, 0xc0041f8, 0x2003021, +0x24040001, 0x24050014, 0xc0041f8, 0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, 0x2221025, 0x2531825, 0x10000007, 0x438825, 0x3c110001, 0x2308821, -0x8e315f2c, 0x3c027fff, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0xac315f24, +0x8e31603c, 0x3c027fff, 0x3442ffff, 0x2228824, +0x151140, 0x3c010001, 0x220821, 0xac316034, 0x1000004e, 0x2201021, 0x152940, 0x3c030001, -0x651821, 0x8c635f28, 0x3c024000, 0x621024, +0x651821, 0x8c636038, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010001, 0x250821, 0xac315f20, 0x1000003f, -0x2201021, 0x3c020001, 0x8c423d28, 0x10400033, -0x3c11c00c, 0x3c020001, 0x8c423da4, 0x3c04c00c, -0x34842000, 0x3c030001, 0x8c633e58, 0x2102b, +0x3c010001, 0x250821, 0xac316030, 0x1000003f, +0x2201021, 0x3c020001, 0x8c423e38, 0x10400033, +0x3c11c00c, 0x3c020001, 0x8c423eb4, 0x3c04c00c, +0x34842000, 0x3c030001, 0x8c633f68, 0x2102b, 0x21023, 0x441024, 0x10600003, 0x518825, 0x3c022000, 0x2228825, 0x3c020001, 0x451021, -0x8c425f34, 0x10400003, 0x3c020020, 0x10000004, +0x8c426044, 0x10400003, 0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0x8c225f3c, +0x151140, 0x3c010001, 0x220821, 0x8c22604c, 0x10400003, 0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, -0x8c423d90, 0x10400002, 0x3c020800, 0x2228825, -0x3c020001, 0x8c423d94, 0x10400002, 0x3c020400, -0x2228825, 0x3c020001, 0x8c423d98, 0x10400006, +0x8c423ea0, 0x10400002, 0x3c020800, 0x2228825, +0x3c020001, 0x8c423ea4, 0x10400002, 0x3c020400, +0x2228825, 0x3c020001, 0x8c423ea8, 0x10400006, 0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, 0x151140, 0x3c010001, -0x220821, 0xac315f20, 0x2201021, 0x8fbf002c, +0x220821, 0xac316030, 0x2201021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0, 0xafb20018, 0x809021, 0xafbf001c, 0xafb10014, -0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d18, +0xafb00010, 0x8f840200, 0x3c030001, 0x8c633e28, 0x8f860220, 0x24020002, 0x106200a6, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x121940, 0x100000a0, 0x0, 0x24020004, 0x10620053, 0x24020008, 0x10620052, 0x128940, 0x10000099, -0x0, 0x3c050001, 0xa32821, 0x8ca55f2c, -0x3c100001, 0x2038021, 0x8e105f24, 0x3c024000, +0x0, 0x3c050001, 0xa32821, 0x8ca5603c, +0x3c100001, 0x2038021, 0x8e106034, 0x3c024000, 0xa21024, 0x10400038, 0x3c020008, 0x2021024, 0x10400020, 0x34840002, 0x3c020001, 0x431021, -0x8c425f30, 0x10400005, 0x34840020, 0x34840100, +0x8c426040, 0x10400005, 0x34840020, 0x34840100, 0x3c020020, 0x10000006, 0x2028025, 0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024, -0x121140, 0x3c010001, 0x220821, 0x8c225f38, +0x121140, 0x3c010001, 0x220821, 0x8c226048, 0x10400005, 0x3c020001, 0xc23025, 0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, -0x2028024, 0x3c010001, 0x230821, 0xac205f30, -0x3c010001, 0x230821, 0xac205f38, 0xaf840200, +0x2028024, 0x3c010001, 0x230821, 0xac206040, +0x3c010001, 0x230821, 0xac206048, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd, 0x621824, -0xc003bad, 0xaf830200, 0x121140, 0x3c010001, -0x220821, 0x1000004b, 0xac305f24, 0x128940, -0x3c050001, 0xb12821, 0x8ca55f28, 0x3c100001, -0x2118021, 0x8e105f20, 0x3c024000, 0xa21024, -0x14400010, 0x0, 0x3c020001, 0x8c423e58, +0xc003be0, 0xaf830200, 0x121140, 0x3c010001, +0x220821, 0x1000004b, 0xac306034, 0x128940, +0x3c050001, 0xb12821, 0x8ca56038, 0x3c100001, +0x2118021, 0x8e106030, 0x3c024000, 0xa21024, +0x14400010, 0x0, 0x3c020001, 0x8c423f68, 0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003bad, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003be0, 0x2028024, 0x3c010001, 0x310821, 0x10000031, -0xac305f20, 0x3c020001, 0x8c423e58, 0x10400005, -0x3c020020, 0x3c020001, 0x8c423da4, 0x10400025, +0xac306030, 0x3c020001, 0x8c423f68, 0x10400005, +0x3c020020, 0x3c020001, 0x8c423eb4, 0x10400025, 0x3c020020, 0xa21024, 0x10400007, 0x34840020, -0x24020100, 0x3c010001, 0x310821, 0xac225f34, +0x24020100, 0x3c010001, 0x310821, 0xac226044, 0x10000006, 0x34840100, 0x3c010001, 0x310821, -0xac205f34, 0x2402feff, 0x822024, 0x3c020080, +0xac206044, 0x2402feff, 0x822024, 0x3c020080, 0xa21024, 0x10400007, 0x121940, 0x3c020001, -0x3c010001, 0x230821, 0xac225f3c, 0x10000008, +0x3c010001, 0x230821, 0xac22604c, 0x10000008, 0xc23025, 0x121140, 0x3c010001, 0x220821, -0xac205f3c, 0x3c02fffe, 0x3442ffff, 0xc23024, +0xac20604c, 0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x121140, 0x3c010001, 0x220821, -0xac305f20, 0x8fbf001c, 0x8fb20018, 0x8fb10014, +0xac306030, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821, 0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, 0x30420001, 0x10400004, 0x0, 0x8f820044, @@ -8255,11 +8268,11 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x66776d61, 0x696e2e63, 0x2c762031, 0x2e312e32, -0x2e343520, 0x31393939, 0x2f30312f, 0x32342030, -0x303a3130, 0x3a353520, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31, +0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234, +0x2030303a, 0x31303a35, 0x35207368, 0x75616e67, +0x20457870, 0x20240000, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, @@ -8326,27 +8339,27 @@ 0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469, 0x6d657200, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x74696d65, 0x722e632c, 0x7620312e, 0x312e322e, -0x33352031, 0x3939392f, 0x30312f32, 0x37203139, -0x3a30393a, 0x35302068, 0x61796573, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x542d446d, 0x61526432, 0x0, -0x542d446d, 0x61526431, 0x0, 0x542d446d, -0x61526442, 0x0, 0x542d446d, 0x61577232, -0x0, 0x542d446d, 0x61577231, 0x0, -0x542d446d, 0x61577242, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e, +0x322e3335, 0x20313939, 0x392f3031, 0x2f323720, +0x31393a30, 0x393a3530, 0x20686179, 0x65732045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x542d446d, 0x61526432, +0x0, 0x542d446d, 0x61526431, 0x0, +0x542d446d, 0x61526442, 0x0, 0x542d446d, +0x61577232, 0x0, 0x542d446d, 0x61577231, +0x0, 0x542d446d, 0x61577242, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x636f6d6d, 0x616e642e, 0x632c7620, 0x312e312e, -0x322e3238, 0x20313939, 0x392f3031, 0x2f323020, -0x31393a34, 0x393a3439, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x65767452, 0x6e674600, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e, +0x312e322e, 0x32382031, 0x3939392f, 0x30312f32, +0x30203139, 0x3a34393a, 0x34392073, 0x6875616e, +0x67204578, 0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, @@ -8363,25 +8376,25 @@ 0x8218, 0x827c, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d636173, 0x742e632c, 0x7620312e, 0x312e322e, -0x38203139, 0x39382f31, 0x322f3038, 0x2030323a, -0x33363a33, 0x36207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x6164644d, 0x63447570, 0x0, -0x6164644d, 0x6346756c, 0x0, 0x64656c4d, -0x634e6f45, 0x0, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e, +0x322e3820, 0x31393938, 0x2f31322f, 0x30382030, +0x323a3336, 0x3a333620, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x6164644d, 0x63447570, +0x0, 0x6164644d, 0x6346756c, 0x0, +0x64656c4d, 0x634e6f45, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x646d612e, 0x632c7620, 0x312e312e, 0x322e3234, -0x20313939, 0x382f3132, 0x2f323120, 0x30303a33, -0x333a3039, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e, +0x32342031, 0x3939382f, 0x31322f32, 0x31203030, +0x3a33333a, 0x30392073, 0x6875616e, 0x67204578, +0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, @@ -8390,81 +8403,84 @@ 0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00, 0x2372446d, 0x6141544e, 0x0, 0x72446d61, 0x41544e30, 0x0, 0x72446d61, 0x41544e31, -0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e, -0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e, -0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f646d, -0x612e6300, 0x2377446d, 0x6141544e, 0x0, -0x77446d61, 0x41544e30, 0x0, 0x77446d61, -0x41544e31, 0x0, 0x0, 0x0, +0x0, 0x72446d61, 0x34476200, 0x2a50414e, +0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f, +0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63, +0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d, +0x6141544e, 0x0, 0x77446d61, 0x41544e30, +0x0, 0x77446d61, 0x41544e31, 0x0, +0x77446d61, 0x34476200, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x74726163, 0x652e632c, 0x7620312e, 0x312e322e, -0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, -0x35303a32, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x64617461, 0x2e632c76, 0x20312e31, 0x2e322e31, -0x32203139, 0x39392f30, 0x312f3230, 0x2031393a, -0x34393a35, 0x31207368, 0x75616e67, 0x20457870, -0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x2331204d, 0x6f6e2046, 0x65622031, 0x2031373a, -0x30313a30, 0x36205053, 0x54203139, 0x39390000, -0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031373a, 0x30313a30, 0x36000000, 0x46575f43, -0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, -0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, -0x4f53543a, 0x20636f6d, 0x70757465, 0x0, -0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, -0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f, -0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, -0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, -0x2e320000, 0x0, 0x12030303, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e, +0x322e3520, 0x31393938, 0x2f30392f, 0x33302031, +0x383a3530, 0x3a323820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d656d2e, 0x632c7620, 0x312e312e, 0x322e3520, -0x31393938, 0x2f30392f, 0x33302031, 0x383a3530, -0x3a303820, 0x73687561, 0x6e672045, 0x78702024, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32, +0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, +0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x46575f56, 0x45525349, +0x4f4e3a20, 0x23312054, 0x75652041, 0x70722032, +0x30203137, 0x3a32333a, 0x30322050, 0x44542031, +0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, +0x494d453a, 0x2031373a, 0x32333a30, 0x32000000, +0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, +0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, +0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, +0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44, +0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f, +0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, +0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e, +0x20322e37, 0x2e320000, 0x0, 0x12030303, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x73656e64, 0x2e632c76, 0x20312e31, 0x2e322e34, -0x34203139, 0x39382f31, 0x322f3231, 0x2030303a, -0x33333a31, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x69736e74, 0x54637055, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e, +0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, +0x35303a30, 0x38207368, 0x75616e67, 0x20457870, +0x20240000, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32, +0x2e343420, 0x31393938, 0x2f31322f, 0x32312030, +0x303a3333, 0x3a313820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x69736e74, 0x54637055, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x72656376, 0x2e632c76, 0x20312e31, 0x2e322e35, -0x33203139, 0x39392f30, 0x312f3136, 0x2030323a, -0x35353a34, 0x33207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x72784672, 0x6d324c67, 0x0, -0x72784e6f, 0x53744264, 0x0, 0x72784e6f, -0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264, -0x0, 0x7278436b, 0x446d6146, 0x0, -0x72785144, 0x6d457846, 0x0, 0x72785144, -0x6d614600, 0x72785144, 0x4c426446, 0x0, -0x72785144, 0x6d426446, 0x0, 0x72784372, -0x63506164, 0x0, 0x72536d51, 0x446d6146, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32, +0x2e353320, 0x31393939, 0x2f30312f, 0x31362030, +0x323a3535, 0x3a343320, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x72784672, 0x6d324c67, +0x0, 0x72784e6f, 0x53744264, 0x0, +0x72784e6f, 0x4d694264, 0x0, 0x72784e6f, +0x4a6d4264, 0x0, 0x7278436b, 0x446d6146, +0x0, 0x72785144, 0x6d457846, 0x0, +0x72785144, 0x6d614600, 0x72785144, 0x4c426446, +0x0, 0x72785144, 0x6d426446, 0x0, +0x72784372, 0x63506164, 0x0, 0x72536d51, +0x446d6146, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d61632e, 0x632c7620, 0x312e312e, 0x322e3232, -0x20313939, 0x382f3132, 0x2f303820, 0x30323a33, -0x363a3330, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e, +0x32322031, 0x3939382f, 0x31322f30, 0x38203032, +0x3a33363a, 0x33302073, 0x6875616e, 0x67204578, +0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, @@ -8476,32 +8492,33 @@ 0x6c696e6b, 0x55500000, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x636b7375, 0x6d2e632c, 0x7620312e, 0x312e322e, -0x39203139, 0x39392f30, 0x312f3134, 0x2030303a, -0x30333a34, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0xff04, -0xff34, 0xff4c, 0xff78, 0xffa4, -0xffb8, 0xfff4, 0x10394, 0x10174, -0x101ac, 0x100a4, 0x10200, 0x10228, -0x1025c, 0x100e8, 0x10394, 0x10174, -0x101ac, 0x101d0, 0x10200, 0x10228, -0x1025c, 0x10288, 0x0, 0x0, -0x0, 0x1097c, 0x10a4c, 0x10b24, -0x10bf4, 0x10c50, 0x10d2c, 0x10d54, -0x10e30, 0x10e58, 0x11000, 0x11028, -0x111d0, 0x113c8, 0x1165c, 0x11570, -0x1165c, 0x11688, 0x111f8, 0x113a0, -0x0, 0x1198c, 0x119cc, 0x11a5c, -0x11aa0, 0x11b04, 0x11b90, 0x11bc4, -0x11c4c, 0x11ce4, 0x11db4, 0x11df4, -0x11e78, 0x11e9c, 0x11fac, 0x646f4261, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e, +0x322e3920, 0x31393939, 0x2f30312f, 0x31342030, +0x303a3033, 0x3a343820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x0, 0x0, +0x0, 0x50726f62, 0x65506879, 0x0, +0x6c6e6b41, 0x53535254, 0x0, 0xffc4, +0xfff4, 0x1000c, 0x10038, 0x10064, +0x10078, 0x100b4, 0x10454, 0x10234, +0x1026c, 0x10164, 0x102c0, 0x102e8, +0x1031c, 0x101a8, 0x10454, 0x10234, +0x1026c, 0x10290, 0x102c0, 0x102e8, +0x1031c, 0x10348, 0x0, 0x0, +0x0, 0x10a3c, 0x10b0c, 0x10be4, +0x10cb4, 0x10d10, 0x10dec, 0x10e14, +0x10ef0, 0x10f18, 0x110c0, 0x110e8, +0x11290, 0x11488, 0x1171c, 0x11630, +0x1171c, 0x11748, 0x112b8, 0x11460, +0x0, 0x11a4c, 0x11a8c, 0x11b1c, +0x11b60, 0x11bc4, 0x11c50, 0x11c84, +0x11d0c, 0x11da4, 0x11e74, 0x11eb4, +0x11f38, 0x11f5c, 0x1206c, 0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, 0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; diff -u --recursive --new-file v2.3.14/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.3.14/linux/drivers/net/ariadne.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/ariadne.c Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ /* * Amiga Linux/m68k Ariadne Ethernet Driver * - * © Copyright 1995 by Geert Uytterhoeven - * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org) * Peter De Schrijver * (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) * diff -u --recursive --new-file v2.3.14/linux/drivers/net/ariadne.h linux/drivers/net/ariadne.h --- v2.3.14/linux/drivers/net/ariadne.h Sun May 19 21:54:28 1996 +++ linux/drivers/net/ariadne.h Thu Aug 19 10:54:10 1999 @@ -1,8 +1,7 @@ /* * Amiga Linux/m68k Ariadne Ethernet Driver * - * © Copyright 1995 by Geert Uytterhoeven - * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org) * Peter De Schrijver * (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) * diff -u --recursive --new-file v2.3.14/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.3.14/linux/drivers/net/arlan.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/arlan.c Mon Aug 23 10:10:29 1999 @@ -1291,7 +1291,7 @@ priv->command_lock = 0; add_timer(&priv->timer); - init_mutex(&priv->card_lock); + init_MUTEX(&priv->card_lock); myATOMIC_INIT(priv->card_users, 1); /* damn 2.0.33 */ priv->registrationLostCount = 0; priv->registrationLastSeen = jiffies; diff -u --recursive --new-file v2.3.14/linux/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.3.14/linux/drivers/net/cosa.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/cosa.c Mon Aug 23 10:10:29 1999 @@ -1,10 +1,7 @@ -/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */ +/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - * - * 5/25/1999 : Marcelo Tosatti - * fixed a deadlock in cosa_sppp_open * * 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 @@ -105,6 +102,13 @@ #include "syncppp.h" #include "cosa.h" +/* Linux version stuff */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) +typedef struct wait_queue *wait_queue_head_t; +#define DECLARE_WAITQUEUE(wait, current) \ + struct wait_queue wait = { current, NULL } +#endif + /* Maximum length of the identification string. */ #define COSA_MAX_ID_STRING 128 @@ -366,7 +370,7 @@ #endif { int i; - printk(KERN_INFO "cosa v1.04 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -1269,10 +1273,8 @@ debug_status_out(cosa, 0); #endif } - cosa_putdata8(cosa, 0); cosa_putdata8(cosa, status); #ifdef DEBUG_IO - debug_data_cmd(cosa, 0); debug_data_cmd(cosa, status); #endif } @@ -1647,6 +1649,14 @@ * use the round-robin approach. The newer COSA firmwares have a simple * flow-control - in the status word has bits 2 and 3 set to 1 means that the * channel 0 or 1 doesn't want to receive data. + * + * It seems there is a bug in COSA firmware (need to trace it further): + * When the driver status says that the kernel has no more data for transmit + * (e.g. at the end of TX DMA) and then the kernel changes its mind + * (e.g. new packet is queued to hard_start_xmit()), the card issues + * the TX interrupt but does not mark the channel as ready-to-transmit. + * The fix seems to be to push the packet to COSA despite its request. + * We first try to obey the card's opinion, and then fall back to forced TX. */ static inline void tx_interrupt(struct cosa_data *cosa, int status) { @@ -1658,23 +1668,35 @@ spin_lock_irqsave(&cosa->lock, flags); set_bit(TXBIT, &cosa->rxtx); if (!test_bit(IRQBIT, &cosa->rxtx)) { - /* flow control */ + /* flow control, see the comment above */ int i=0; - do { - if (i++ > cosa->nchannels) { - printk(KERN_WARNING - "%s: No channel wants data in TX IRQ\n", - cosa->name); - put_driver_status_nolock(cosa); - clear_bit(TXBIT, &cosa->rxtx); - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } + if (!cosa->txbitmap) { + printk(KERN_WARNING "%s: No channel wants data " + "in TX IRQ. Expect DMA timeout.", + cosa->name); + put_driver_status_nolock(cosa); + clear_bit(TXBIT, &cosa->rxtx); + spin_unlock_irqrestore(&cosa->lock, flags); + return; + } + while(1) { cosa->txchan++; + i++; if (cosa->txchan >= cosa->nchannels) cosa->txchan = 0; - } while ((!(cosa->txbitmap & (1<txchan))) - || status & (1<<(cosa->txchan+DRIVER_TXMAP_SHIFT))); + if (!(cosa->txbitmap & (1<txchan))) + continue; + if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT))) + break; + /* in second pass, accept first ready-to-TX channel */ + if (i > cosa->nchannels) { + /* Can be safely ignored */ + printk(KERN_DEBUG "%s: Forcing TX " + "to not-ready channel %d\n", + cosa->name, cosa->txchan); + break; + } + } cosa->txsize = cosa->chan[cosa->txchan].txsize; if (cosa_dma_able(cosa->chan+cosa->txchan, @@ -1784,6 +1806,7 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { set_bit(IRQBIT, &cosa->rxtx); + put_driver_status_nolock(cosa); cosa->rxsize = cosa_getdata8(cosa) <<8; #ifdef DEBUG_IO debug_data_in(cosa, cosa->rxsize >> 8); diff -u --recursive --new-file v2.3.14/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.3.14/linux/drivers/net/cs89x0.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/cs89x0.c Mon Aug 23 10:12:37 1999 @@ -30,7 +30,7 @@ */ static char *version = -"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; +"cs89x0.c:v1.03 11/26/96 Russell Nelson \n"; /* ======================= configure the driver here ======================= */ @@ -306,7 +306,7 @@ else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { printk("\ncs89x0: EEPROM read failed, relying on command line.\n"); } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM checksum bad, relyong on command line\n"); + printk("\ncs89x0: EEPROM checksum bad, relying on command line\n"); } else { /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; @@ -841,6 +841,13 @@ lp->send_underrun++; if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + /* transmit cycle is done, although + frame wasn't transmitted - this + avoids having to wait for the upper + layers to timeout on us, in the + event of a tx underrun */ + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ } break; case ISQ_RX_MISS_EVENT: diff -u --recursive --new-file v2.3.14/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h --- v2.3.14/linux/drivers/net/cs89x0.h Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/cs89x0.h Mon Aug 23 10:12:37 1999 @@ -319,8 +319,8 @@ #define TX_FRAME_PORT RX_FRAME_PORT #define TX_CMD_PORT 0x0004 #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ -#define TX_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */ -#define TX_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */ +#define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ #define TX_LEN_PORT 0x0006 #define ISQ_PORT 0x0008 #define ADD_PORT 0x000A diff -u --recursive --new-file v2.3.14/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.14/linux/drivers/net/de4x5.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/de4x5.c Thu Aug 19 10:54:10 1999 @@ -379,8 +379,7 @@ Fix bug in pci_probe() for 64 bit systems reported by . 0.533 9-Jan-98 Fix more 64 bit bugs reported by . - 0.534 24-Jan-98 Fix last (?) endian bug from - + 0.534 24-Jan-98 Fix last (?) endian bug from 0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040. 0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure. **Incompatible with 2.0.x from here.** diff -u --recursive --new-file v2.3.14/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.3.14/linux/drivers/net/dlci.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/dlci.c Mon Aug 23 10:01:02 1999 @@ -421,7 +421,7 @@ char buf[10]; /* validate slave device */ - slave = dev_get(dlci->devname); + slave = __dev_get_by_name(dlci->devname); if (!slave) return(-ENODEV); @@ -504,7 +504,7 @@ int i, err; /* validate slave device */ - master = dev_get(dlci->devname); + master = __dev_get_by_name(dlci->devname); if (!master) return(-ENODEV); diff -u --recursive --new-file v2.3.14/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.3.14/linux/drivers/net/eql.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/eql.c Mon Aug 23 10:01:02 1999 @@ -427,7 +427,7 @@ srq.slave_name, srq.priority); #endif master_dev = dev; /* for "clarity" */ - slave_dev = dev_get (srq.slave_name); + slave_dev = __dev_get_by_name (srq.slave_name); if (master_dev != 0 && slave_dev != 0) { @@ -481,7 +481,7 @@ printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name); #endif master_dev = dev; /* for "clarity" */ - slave_dev = dev_get (srq.slave_name); + slave_dev = __dev_get_by_name (srq.slave_name); if ( eql_is_slave (slave_dev) ) /* really is a slave */ { @@ -511,7 +511,7 @@ printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name); #endif eql = (equalizer_t *) dev->priv; - slave_dev = dev_get (sc.slave_name); + slave_dev = __dev_get_by_name (sc.slave_name); if ( eql_is_slave (slave_dev) ) { @@ -549,7 +549,7 @@ eql = (equalizer_t *) dev->priv; - slave_dev = dev_get (sc.slave_name); + slave_dev = __dev_get_by_name (sc.slave_name); if ( eql_is_slave (slave_dev) ) { diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/Makefile linux/drivers/net/fc/Makefile --- v2.3.14/linux/drivers/net/fc/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/Makefile Mon Aug 23 10:12:38 1999 @@ -0,0 +1,28 @@ + +# Makefile for linux/drivers/net/fc +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +L_TARGET := fc.a +L_OBJS := +M_OBJS := +MX_OBJS := +MOD_LIST_NAME := FC_MODULES +FC_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) + +ifeq ($(CONFIG_IPHASE5526),y) +L_OBJS += iph5526.o +else + ifeq ($(CONFIG_IPHASE5526),m) + M_OBJS += iph5526.o + endif +endif + +include $(TOPDIR)/Rules.make + +clean: + rm *.o + diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.3.14/linux/drivers/net/fc/iph5526.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/iph5526.c Mon Aug 23 10:12:38 1999 @@ -0,0 +1,4702 @@ +/********************************************************************** + * iph5526.c: IP/SCSI driver for the Interphase 5526 PCI Fibre Channel + * Card. + * Copyright (C) 1999 Vineet M Abraham + * + * 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. + *********************************************************************/ +/********************************************************************** +Log: +Vineet M Abraham +02.12.99 Support multiple cards. +03.15.99 Added Fabric support. +04.04.99 Added N_Port support. +04.15.99 Added SCSI support. +06.18.99 Added ABTS Protocol. +06.24.99 Fixed data corruption when multiple XFER_RDYs are received. +07.07.99 Can be loaded as part of the Kernel. Changed semaphores. Added + more checks before invalidating SEST entries. +07.08.99 Added Broadcast IP stuff and fixed an unicast timeout bug. +***********************************************************************/ +/* TODO: + R_T_TOV set to 15msec in Loop topology. Need to be 100 msec. + SMP testing. + Fix ADISC Tx before completing FLOGI. +*/ + +static const char *version = + "iph5526.c:v1.0 07.08.99 Vineet Abraham (vma@iol.unh.edu)\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* had the declarations for init_fcdev among others + includes if_fcdevice.h */ + +#include +#include "../../scsi/sd.h" +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../fc4/fcp.h" + +/* driver specific header files */ +#include "tach.h" +#include "tach_structs.h" +#include "iph5526_ip.h" +#include "iph5526_scsi.h" +#include "iph5526_novram.c" + +#define RUN_AT(x) (jiffies + (x)) + +#define DEBUG_5526_0 0 +#define DEBUG_5526_1 0 +#define DEBUG_5526_2 0 + +#if DEBUG_5526_0 +#define DPRINTK(format, a...) {printk("%s: ", fi->name); \ + printk(format, ##a); \ + printk("\n");} +#define ENTER(x) {printk("%s: ", fi->name); \ + printk("iph5526.c : entering %s()\n", x);} +#define LEAVE(x) {printk("%s: ", fi->name); \ + printk("iph5526.c : leaving %s()\n",x);} + +#else +#define DPRINTK(format, a...) {} +#define ENTER(x) {} +#define LEAVE(x) {} +#endif + +#if DEBUG_5526_1 +#define DPRINTK1(format, a...) {printk("%s: ", fi->name); \ + printk(format, ##a); \ + printk("\n");} +#else +#define DPRINTK1(format, a...) {} +#endif + +#if DEBUG_5526_2 +#define DPRINTK2(format, a...) {printk("%s: ", fi->name); \ + printk(format, ##a); \ + printk("\n");} +#else +#define DPRINTK2(format, a...) {} +#endif + +#define T_MSG(format, a...) {printk("%s: ", fi->name); \ + printk(format, ##a);\ + printk("\n");} + +#define ALIGNED_SFS_ADDR(addr) ((((unsigned long)(addr) + (SFS_BUFFER_SIZE - 1)) & ~(SFS_BUFFER_SIZE - 1)) - (unsigned long)(addr)) +#define ALIGNED_ADDR(addr, len) ((((unsigned long)(addr) + (len - 1)) & ~(len - 1)) - (unsigned long)(addr)) + + +#define MAX_FC_CARDS 2 +static struct fc_info *fc[MAX_FC_CARDS+1]; +static unsigned int pci_irq_line = 0; +static struct { + unsigned short vendor_id; + unsigned short device_id; + char *name; +} +clone_list[] __initdata = { + {PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_5526, "Interphase Fibre Channel HBA"}, + {PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_55x6, "Interphase Fibre Channel HBA"}, + {0,} +}; + +static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs); + +static int initialize_register_pointers(struct fc_info *fi); +void clean_up_memory(struct fc_info *fi); + +static int tachyon_init(struct fc_info *fi); +static int build_queues(struct fc_info *fi); +static void build_tachyon_header(struct fc_info *fi, u_int my_id, u_int r_ctl, u_int d_id, u_int type, u_char seq_id, u_char df_ctl, u_short ox_id, u_short rx_id, char *data); +static int get_free_header(struct fc_info *fi); +static void build_EDB(struct fc_info *fi, char *data, u_short flags, u_short len); +static int get_free_EDB(struct fc_info *fi); +static void build_ODB(struct fc_info *fi, u_char seq_id, u_int d_id, u_int len, u_int cntl, u_short mtu, u_short ox_id, u_short rx_id, int NW_header, int int_required, u_int frame_class); +static void write_to_tachyon_registers(struct fc_info *fi); +static void reset_latch(struct fc_info *fi); +static void reset_tachyon(struct fc_info *fi, u_int value); +static void take_tachyon_offline(struct fc_info *fi); +static void read_novram(struct fc_info *fi); +static void reset_ichip(struct fc_info *fi); +static void update_OCQ_indx(struct fc_info *fi); +static void update_IMQ_indx(struct fc_info *fi, int count); +static void update_SFSBQ_indx(struct fc_info *fi); +static void update_MFSBQ_indx(struct fc_info *fi, int count); +static void update_tachyon_header_indx(struct fc_info *fi); +static void update_EDB_indx(struct fc_info *fi); +static void handle_FM_interrupt(struct fc_info *fi); +static void handle_MFS_interrupt(struct fc_info *fi); +static void handle_OOO_interrupt(struct fc_info *fi); +static void handle_SFS_interrupt(struct fc_info *fi); +static void handle_OCI_interrupt(struct fc_info *fi); +static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi); +static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi); +static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi); +static void handle_Unknown_Frame_interrupt(struct fc_info *fi); +static void handle_Busied_Frame_interrupt(struct fc_info *fi); +static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi); +static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi); +static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi); +static void completion_message_handler(struct fc_info *fi, u_int imq_int_type); +static void fill_login_frame(struct fc_info *fi, u_int logi); + +static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short ox_id, u_int frame_class); +static int tx_sequence(struct fc_info *fi, char *data, u_int len, u_int mtu, u_int d_id, u_short ox_id, u_short rx_id, u_char seq_id, int NW_flag, int int_required, u_int frame_class); +static int validate_login(struct fc_info *fi, u_int *base_ptr); +static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr); +static void remove_from_address_cache(struct fc_info *fi, u_int *data, u_int cmnd_code); +static int node_logged_in_prev(struct fc_info *fi, u_int *buff_addr); +static int sid_logged_in(struct fc_info *fi, u_int s_id); +static struct fc_node_info *look_up_cache(struct fc_info *fi, char *data); +static int display_cache(struct fc_info *fi); + +static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id); +static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id); +static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id); +static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id); +static void tx_adisc(struct fc_info *fi, u_int cmnd_code, u_int d_id, u_short received_ox_id); +static void tx_ls_rjt(struct fc_info *fi, u_int d_id, u_short received_ox_id, u_short reason_code, u_short expln_code); +static u_int plogi_ok(struct fc_info *fi, u_int *buff_addr, int size); +static void tx_acc(struct fc_info *fi, u_int d_id, u_short received_ox_id); +static void tx_name_server_req(struct fc_info *fi, u_int req); +static void rscn_handler(struct fc_info *fi, u_int node_id); +static void tx_scr(struct fc_info *fi); +static void scr_timer(unsigned long data); +static void explore_fabric(struct fc_info *fi, u_int *buff_addr); +static void perform_adisc(struct fc_info *fi); +static void local_port_discovery(struct fc_info *fi); +static void add_to_ox_id_list(struct fc_info *fi, u_int transaction_id, u_int cmnd_code); +static u_int remove_from_ox_id_list(struct fc_info *fi, u_short received_ox_id); +static void add_display_cache_timer(struct fc_info *fi); + +/* Timers... */ +static void nos_ols_timer(unsigned long data); +static void loop_timer(unsigned long data); +static void fabric_explore_timer(unsigned long data); +static void port_discovery_timer(unsigned long data); +static void display_cache_timer(unsigned long data); + +/* SCSI Stuff */ +static int add_to_sest(struct fc_info *fi, Scsi_Cmnd *Cmnd, struct fc_node_info *ni); +static struct fc_node_info *resolve_target(struct fc_info *fi, u_char target); +static void update_FCP_CMND_indx(struct fc_info *fi); +static int get_free_SDB(struct fc_info *fi); +static void update_SDB_indx(struct fc_info *fi); +static void mark_scsi_sid(struct fc_info *fi, u_int *buff_addr, u_char action); +static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id); +static int abort_exchange(struct fc_info *fi, u_short ox_id); +static void flush_tachyon_cache(struct fc_info *fi, u_short ox_id); +static int get_scsi_oxid(struct fc_info *fi); +static void update_scsi_oxid(struct fc_info *fi); + +Scsi_Host_Template driver_template = IPH5526_SCSI_FC; + + +#ifdef CONFIG_PCI +static int iph5526_probe_pci(struct net_device *dev); +#endif + + +__initfunc(int iph5526_probe(struct net_device *dev)) +{ +#ifdef CONFIG_PCI + if (pci_present() && (iph5526_probe_pci(dev) == 0)) + return 0; +#endif + return -ENODEV; +} + +#ifdef CONFIG_PCI +__initfunc(static int iph5526_probe_pci(struct net_device *dev)) +{ +#ifndef MODULE +struct fc_info *fi; +static int count = 0; +#endif +#ifdef MODULE +struct fc_info *fi = (struct fc_info *)dev->priv; +#endif + +#ifndef MODULE + if(fc[count] != NULL) { + if (dev == NULL) { + dev = init_fcdev(NULL, 0); + if (dev == NULL) + return -ENOMEM; + } + fi = fc[count]; +#endif + fi->dev = dev; + dev->base_addr = fi->base_addr; + dev->irq = fi->irq; + if (dev->priv == NULL) + dev->priv = fi; + fcdev_init(dev); + /* Assign ur MAC address. + */ + dev->dev_addr[0] = (fi->g.my_port_name_high & 0x0000FF00) >> 8; + dev->dev_addr[1] = fi->g.my_port_name_high; + dev->dev_addr[2] = (fi->g.my_port_name_low & 0xFF000000) >> 24; + dev->dev_addr[3] = (fi->g.my_port_name_low & 0x00FF0000) >> 16; + dev->dev_addr[4] = (fi->g.my_port_name_low & 0x0000FF00) >> 8; + dev->dev_addr[5] = fi->g.my_port_name_low; +#ifndef MODULE + count++; + } + else + return -ENODEV; +#endif + display_cache(fi); + return 0; +} +#endif /* CONFIG_PCI */ + +__initfunc(static int fcdev_init(struct net_device *dev)) +{ + dev->open = iph5526_open; + dev->stop = iph5526_close; + dev->hard_start_xmit = iph5526_send_packet; + dev->get_stats = iph5526_get_stats; + dev->set_multicast_list = NULL; + dev->change_mtu = iph5526_change_mtu; +#ifndef MODULE + fc_setup(dev); +#endif + return 0; +} + +/* initialize tachyon and take it OnLine */ +static int tachyon_init(struct fc_info *fi) +{ + ENTER("tachyon_init"); + if (build_queues(fi) == 0) { + T_MSG("build_queues() failed"); + return 0; + } + + /* Retrieve your port/node name. + */ + read_novram(fi); + + reset_ichip(fi); + + reset_tachyon(fi, SOFTWARE_RESET); + + LEAVE("tachyon_init"); + return 1; +} + +/* Build the 4 Qs - IMQ, OCQ, MFSBQ, SFSBQ */ +/* Lots of dma_pages needed as Tachyon DMAs almost everything into + * host memory. + */ +static int build_queues(struct fc_info *fi) +{ +int i,j; +u_char *addr; + ENTER("build_queues"); + /* Initializing Queue Variables. + */ + fi->q.ptr_host_ocq_cons_indx = NULL; + fi->q.ptr_host_hpcq_cons_indx = NULL; + fi->q.ptr_host_imq_prod_indx = NULL; + + fi->q.ptr_ocq_base = NULL; + fi->q.ocq_len = 0; + fi->q.ocq_end = 0; + fi->q.ocq_prod_indx = 0; + + fi->q.ptr_imq_base = NULL; + fi->q.imq_len = 0; + fi->q.imq_end = 0; + fi->q.imq_cons_indx = 0; + fi->q.imq_prod_indx = 0; + + fi->q.ptr_mfsbq_base = NULL; + fi->q.mfsbq_len = 0; + fi->q.mfsbq_end = 0; + fi->q.mfsbq_prod_indx = 0; + fi->q.mfsbq_cons_indx = 0; + fi->q.mfsbuff_len = 0; + fi->q.mfsbuff_end = 0; + fi->g.mfs_buffer_count = 0; + + fi->q.ptr_sfsbq_base = NULL; + fi->q.sfsbq_len = 0; + fi->q.sfsbq_end = 0; + fi->q.sfsbq_prod_indx = 0; + fi->q.sfsbq_cons_indx = 0; + fi->q.sfsbuff_len = 0; + fi->q.sfsbuff_end = 0; + + fi->q.sdb_indx = 0; + fi->q.fcp_cmnd_indx = 0; + + fi->q.ptr_edb_base = NULL; + fi->q.edb_buffer_indx = 0; + fi->q.ptr_tachyon_header_base = NULL; + fi->q.tachyon_header_indx = 0; + fi->node_info_list = NULL; + fi->ox_id_list = NULL; + fi->g.loop_up = FALSE; + fi->g.ptp_up = FALSE; + fi->g.link_up = FALSE; + fi->g.fabric_present = FALSE; + fi->g.n_port_try = FALSE; + fi->g.dont_init = FALSE; + fi->g.nport_timer_set = FALSE; + fi->g.lport_timer_set = FALSE; + fi->g.no_of_targets = 0; + fi->g.sem = 0; + fi->g.perform_adisc = FALSE; + fi->g.e_i = 0; + + /* build OCQ */ + if ( (fi->q.ptr_ocq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) { + T_MSG("failed to get OCQ page"); + return 0; + } + /* set up the OCQ structures */ + for (i = 0; i < OCQ_LENGTH; i++) + fi->q.ptr_odb[i] = fi->q.ptr_ocq_base + NO_OF_ENTRIES*i; + + /* build IMQ */ + if ( (fi->q.ptr_imq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) { + T_MSG("failed to get IMQ page"); + return 0; + } + for (i = 0; i < IMQ_LENGTH; i++) + fi->q.ptr_imqe[i] = fi->q.ptr_imq_base + NO_OF_ENTRIES*i; + + /* build MFSBQ */ + if ( (fi->q.ptr_mfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) { + T_MSG("failed to get MFSBQ page"); + return 0; + } + memset((char *)fi->q.ptr_mfsbq_base, 0, MFSBQ_LENGTH * 32); + /* Allocate one huge chunk of memory... helps while reassembling + * frames. + */ + if ( (addr = (u_char *)__get_free_pages(GFP_KERNEL, 5) ) == 0) { + T_MSG("failed to get MFSBQ page"); + return 0; + } + /* fill in addresses of empty buffers */ + for (i = 0; i < MFSBQ_LENGTH; i++) { + for (j = 0; j < NO_OF_ENTRIES; j++) { + *(fi->q.ptr_mfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr)); + addr += MFS_BUFFER_SIZE; + } + } + + /* The number of entries in each MFS buffer is 8. There are 8 + * MFS buffers. That leaves us with 4096-256 bytes. We use them + * as temporary space for ELS frames. This is done to make sure that + * the addresses are aligned. + */ + fi->g.els_buffer[0] = fi->q.ptr_mfsbq_base + MFSBQ_LENGTH*NO_OF_ENTRIES; + for (i = 1; i < MAX_PENDING_FRAMES; i++) + fi->g.els_buffer[i] = fi->g.els_buffer[i-1] + 64; + + /* build SFSBQ */ + if ( (fi->q.ptr_sfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) { + T_MSG("failed to get SFSBQ page"); + return 0; + } + memset((char *)fi->q.ptr_sfsbq_base, 0, SFSBQ_LENGTH * 32); + /* fill in addresses of empty buffers */ + for (i = 0; i < SFSBQ_LENGTH; i++) + for (j = 0; j < NO_OF_ENTRIES; j++){ + addr = kmalloc(SFS_BUFFER_SIZE*2, GFP_KERNEL); + if (addr == NULL){ + T_MSG("ptr_sfs_buffer : memory not allocated"); + return 0; + } + else { + int offset = ALIGNED_SFS_ADDR(addr); + memset((char *)addr, 0, SFS_BUFFER_SIZE); + fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES +j] = (u_int *)addr; + addr += offset; + *(fi->q.ptr_sfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr)); + } + } + + /* The number of entries in each SFS buffer is 8. There are 8 + * MFS buffers. That leaves us with 4096-256 bytes. We use them + * as temporary space for ARP frames. This is done inorder to + * support HW_Types of 0x1 and 0x6. + */ + fi->g.arp_buffer = (char *)fi->q.ptr_sfsbq_base + SFSBQ_LENGTH*NO_OF_ENTRIES*4; + + /* build EDB */ + if ((fi->q.ptr_edb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5) ) == 0) { + T_MSG("failed to get EDB page"); + return 0; + } + for (i = 0; i < EDB_LEN; i++) + fi->q.ptr_edb[i] = fi->q.ptr_edb_base + 2*i; + + /* build SEST */ + + /* OX_IDs range from 0x0 - 0x4FFF. + */ + if ((fi->q.ptr_sest_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) { + T_MSG("failed to get SEST page"); + return 0; + } + for (i = 0; i < SEST_LENGTH; i++) + fi->q.ptr_sest[i] = fi->q.ptr_sest_base + NO_OF_ENTRIES*i; + + if ((fi->q.ptr_sdb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) { + T_MSG("failed to get SDB page"); + return 0; + } + for (i = 0 ; i < NO_OF_SDB_ENTRIES; i++) + fi->q.ptr_sdb_slot[i] = fi->q.ptr_sdb_base + (SDB_SIZE/4)*i; + + if ((fi->q.ptr_fcp_cmnd_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) { + T_MSG("failed to get FCP_CMND page"); + return 0; + } + for (i = 0; i < NO_OF_FCP_CMNDS; i++) + fi->q.ptr_fcp_cmnd[i] = fi->q.ptr_fcp_cmnd_base + NO_OF_ENTRIES*i; + + /* Allocate space for Tachyon Header as well... + */ + if ((fi->q.ptr_tachyon_header_base = (u_int *)__get_free_pages(GFP_KERNEL, 0) ) == 0) { + T_MSG("failed to get tachyon_header page"); + return 0; + } + for (i = 0; i < NO_OF_TACH_HEADERS; i++) + fi->q.ptr_tachyon_header[i] = fi->q.ptr_tachyon_header_base + 16*i; + + /* Allocate memory for indices. + * Indices should be aligned on 32 byte boundries. + */ + fi->q.host_ocq_cons_indx = kmalloc(2*32, GFP_KERNEL); + if (fi->q.host_ocq_cons_indx == NULL){ + T_MSG("fi->q.host_ocq_cons_indx : memory not allocated"); + return 0; + } + fi->q.ptr_host_ocq_cons_indx = fi->q.host_ocq_cons_indx; + if ((u_long)(fi->q.host_ocq_cons_indx) % 32) + fi->q.host_ocq_cons_indx++; + + fi->q.host_hpcq_cons_indx = kmalloc(2*32, GFP_KERNEL); + if (fi->q.host_hpcq_cons_indx == NULL){ + T_MSG("fi->q.host_hpcq_cons_indx : memory not allocated"); + return 0; + } + fi->q.ptr_host_hpcq_cons_indx= fi->q.host_hpcq_cons_indx; + if ((u_long)(fi->q.host_hpcq_cons_indx) % 32) + fi->q.host_hpcq_cons_indx++; + + fi->q.host_imq_prod_indx = kmalloc(2*32, GFP_KERNEL); + if (fi->q.host_imq_prod_indx == NULL){ + T_MSG("fi->q.host_imq_prod_indx : memory not allocated"); + return 0; + } + fi->q.ptr_host_imq_prod_indx = fi->q.host_imq_prod_indx; + if ((u_long)(fi->q.host_imq_prod_indx) % 32) + fi->q.host_imq_prod_indx++; + + LEAVE("build_queues"); + return 1; +} + + +static void write_to_tachyon_registers(struct fc_info *fi) +{ +u_int bus_addr, bus_indx_addr, i; + + ENTER("write_to_tachyon_registers"); + + /* Clear Queues each time Tachyon is reset */ + memset((char *)fi->q.ptr_ocq_base, 0, OCQ_LENGTH * 32); + memset((char *)fi->q.ptr_imq_base, 0, IMQ_LENGTH * 32); + memset((char *)fi->q.ptr_edb_base, 0, EDB_LEN * 8); + memset((char *)fi->q.ptr_sest_base, 0, SEST_LENGTH * 32); + memset((char *)fi->q.ptr_sdb_base, 0, NO_OF_SDB_ENTRIES * SDB_SIZE); + memset((char *)fi->q.ptr_tachyon_header_base, 0xFF, NO_OF_TACH_HEADERS * TACH_HEADER_SIZE); + for (i = 0; i < SEST_LENGTH; i++) + fi->q.free_scsi_oxid[i] = OXID_AVAILABLE; + for (i = 0; i < NO_OF_SDB_ENTRIES; i++) + fi->q.sdb_slot_status[i] = SDB_FREE; + + take_tachyon_offline(fi); + writel(readl(fi->t_r.ptr_tach_config_reg) | SCSI_ENABLE | WRITE_STREAM_SIZE | READ_STREAM_SIZE | PARITY_EVEN | OOO_REASSEMBLY_DISABLE, fi->t_r.ptr_tach_config_reg); + + /* Write OCQ registers */ + fi->q.ocq_prod_indx = 0; + *(fi->q.host_ocq_cons_indx) = 0; + + /* The Tachyon needs to be passed the "real" address */ + bus_addr = virt_to_bus(fi->q.ptr_ocq_base); + writel(bus_addr, fi->t_r.ptr_ocq_base_reg); + writel(OCQ_LENGTH - 1, fi->t_r. ptr_ocq_len_reg); + bus_indx_addr = virt_to_bus(fi->q.host_ocq_cons_indx); + writel(bus_indx_addr, fi->t_r.ptr_ocq_cons_indx_reg); + + /* Write IMQ registers */ + fi->q.imq_cons_indx = 0; + *(fi->q.host_imq_prod_indx) = 0; + bus_addr = virt_to_bus(fi->q.ptr_imq_base); + writel(bus_addr, fi->t_r.ptr_imq_base_reg); + writel(IMQ_LENGTH - 1, fi->t_r.ptr_imq_len_reg); + bus_indx_addr = virt_to_bus(fi->q.host_imq_prod_indx); + writel(bus_indx_addr, fi->t_r.ptr_imq_prod_indx_reg); + + /* Write MFSBQ registers */ + fi->q.mfsbq_prod_indx = MFSBQ_LENGTH - 1; + fi->q.mfsbuff_end = MFS_BUFFER_SIZE - 1; + fi->q.mfsbq_cons_indx = 0; + bus_addr = virt_to_bus(fi->q.ptr_mfsbq_base); + writel(bus_addr, fi->t_r.ptr_mfsbq_base_reg); + writel(MFSBQ_LENGTH - 1, fi->t_r.ptr_mfsbq_len_reg); + writel(fi->q.mfsbuff_end, fi->t_r.ptr_mfsbuff_len_reg); + /* Do this last as tachyon will prefetch the + * first entry as soon as we write to it. + */ + writel(fi->q.mfsbq_prod_indx, fi->t_r.ptr_mfsbq_prod_reg); + + /* Write SFSBQ registers */ + fi->q.sfsbq_prod_indx = SFSBQ_LENGTH - 1; + fi->q.sfsbuff_end = SFS_BUFFER_SIZE - 1; + fi->q.sfsbq_cons_indx = 0; + bus_addr = virt_to_bus(fi->q.ptr_sfsbq_base); + writel(bus_addr, fi->t_r.ptr_sfsbq_base_reg); + writel(SFSBQ_LENGTH - 1, fi->t_r.ptr_sfsbq_len_reg); + writel(fi->q.sfsbuff_end, fi->t_r.ptr_sfsbuff_len_reg); + /* Do this last as tachyon will prefetch the first + * entry as soon as we write to it. + */ + writel(fi->q.sfsbq_prod_indx, fi->t_r.ptr_sfsbq_prod_reg); + + /* Write SEST registers */ + bus_addr = virt_to_bus(fi->q.ptr_sest_base); + writel(bus_addr, fi->t_r.ptr_sest_base_reg); + writel(SEST_LENGTH - 1, fi->t_r.ptr_sest_len_reg); + /* the last 2 bits _should_ be 1 */ + writel(SEST_BUFFER_SIZE - 1, fi->t_r.ptr_scsibuff_len_reg); + + /* write AL_TIME & E_D_TOV into the registers */ + writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg); + /* Tell Tachyon to pick a Soft Assigned AL_PA */ + writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg); + + /* Read the WWN from EEPROM . But, for now we assign it here. */ + writel(WORLD_WIDE_NAME_LOW, fi->t_r.ptr_fm_wwn_low_reg); + writel(WORLD_WIDE_NAME_HIGH, fi->t_r.ptr_fm_wwn_hi_reg); + + DPRINTK1("TACHYON initializing as L_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + + LEAVE("write_to_tachyon_registers"); +} + + +static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs) +{ +struct Scsi_Host *host = dev_id; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; +struct fc_info *fi = hostdata->fi; +u_long flags; + spin_lock_irqsave(&fi->fc_lock, flags); + tachyon_interrupt_handler(irq, dev_id, regs); + spin_unlock_irqrestore(&fi->fc_lock, flags); +} + +static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs) +{ +struct Scsi_Host *host = dev_id; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; +struct fc_info *fi = hostdata->fi; +u_int *ptr_imq_entry; +u_int imq_int_type, current_IMQ_index = 0, prev_IMQ_index; +int index, no_of_entries = 0; + + DPRINTK("\n"); + ENTER("tachyon_interrupt"); + if (fi->q.host_imq_prod_indx != NULL) { + current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx)); + } + else { + /* _Should not_ happen */ + T_MSG("IMQ_indx NULL. DISABLING INTERRUPTS!!!\n"); + writel(0x0, fi->i_r.ptr_ichip_hw_control_reg); + } + + if (current_IMQ_index > fi->q.imq_cons_indx) + no_of_entries = current_IMQ_index - fi->q.imq_cons_indx; + else + if (current_IMQ_index < fi->q.imq_cons_indx) + no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index); + + if (no_of_entries == 0) { + u_int ichip_status; + ichip_status = readl(fi->i_r.ptr_ichip_hw_status_reg); + if (ichip_status & 0x20) { + /* Should _never_ happen. Might require a hard reset */ + T_MSG("Too bad... PCI Bus Error. Resetting (i)chip"); + reset_ichip(fi); + T_MSG("DISABLING INTERRUPTS!!!\n"); + writel(0x0, fi->i_r.ptr_ichip_hw_control_reg); + } + } + + prev_IMQ_index = current_IMQ_index; + for (index = 0; index < no_of_entries; index++) { + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + imq_int_type = ntohl(*ptr_imq_entry); + + completion_message_handler(fi, imq_int_type); + if ((fi->g.link_up == FALSE) && ((imq_int_type == MFS_BUF_WARN) || (imq_int_type == SFS_BUF_WARN) || (imq_int_type == IMQ_BUF_WARN))) + break; + update_IMQ_indx(fi, 1); + + /* Check for more entries */ + current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx)); + if (current_IMQ_index != prev_IMQ_index) { + no_of_entries++; + prev_IMQ_index = current_IMQ_index; + } + } /*end of for loop*/ + return; + LEAVE("tachyon_interrupt"); +} + + +static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi) +{ +int i; + ENTER("handle_SFS_BUF_WARN_interrupt"); + if (fi->g.link_up == FALSE) { + reset_tachyon(fi, SOFTWARE_RESET); + return; + } + /* Free up all but one entry in the Q. + */ + for (i = 0; i < ((SFSBQ_LENGTH - 1) * NO_OF_ENTRIES); i++) { + handle_SFS_interrupt(fi); + update_IMQ_indx(fi, 1); + } + LEAVE("handle_SFS_BUF_WARN_interrupt"); +} + +/* Untested_Code_Begin */ +static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi) +{ +int i; + ENTER("handle_MFS_BUF_WARN_interrupt"); + if (fi->g.link_up == FALSE) { + reset_tachyon(fi, SOFTWARE_RESET); + return; + } + /* FIXME: freeing up 8 entries. + */ + for (i = 0; i < NO_OF_ENTRIES; i++) { + handle_MFS_interrupt(fi); + update_IMQ_indx(fi, 1); + } + LEAVE("handle_MFS_BUF_WARN_interrupt"); +} +/*Untested_Code_End */ + +static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +u_int imq_int_type, current_IMQ_index = 0, temp_imq_cons_indx; +int index, no_of_entries = 0; + + ENTER("handle_IMQ_BUF_WARN_interrupt"); + if (fi->g.link_up == FALSE) { + reset_tachyon(fi, SOFTWARE_RESET); + return; + } + current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx)); + + if (current_IMQ_index > fi->q.imq_cons_indx) + no_of_entries = current_IMQ_index - fi->q.imq_cons_indx; + else + if (current_IMQ_index < fi->q.imq_cons_indx) + no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index); + /* We dont want to look at the same IMQ entry again. + */ + temp_imq_cons_indx = fi->q.imq_cons_indx + 1; + if (no_of_entries != 0) + no_of_entries -= 1; + for (index = 0; index < no_of_entries; index++) { + ptr_imq_entry = fi->q.ptr_imqe[temp_imq_cons_indx]; + imq_int_type = ntohl(*ptr_imq_entry); + if (imq_int_type != IMQ_BUF_WARN) + completion_message_handler(fi, imq_int_type); + temp_imq_cons_indx++; + if (temp_imq_cons_indx == IMQ_LENGTH) + temp_imq_cons_indx = 0; + } /*end of for loop*/ + if (no_of_entries != 0) + update_IMQ_indx(fi, no_of_entries); + LEAVE("handle_IMQ_BUF_WARN_interrupt"); +} + +static void completion_message_handler(struct fc_info *fi, u_int imq_int_type) +{ + switch(imq_int_type) { + case OUTBOUND_COMPLETION: + DPRINTK("OUTBOUND_COMPLETION message received"); + break; + case OUTBOUND_COMPLETION_I: + DPRINTK("OUTBOUND_COMPLETION_I message received"); + handle_OCI_interrupt(fi); + break; + case OUT_HI_PRI_COMPLETION: + DPRINTK("OUT_HI_PRI_COMPLETION message received"); + break; + case OUT_HI_PRI_COMPLETION_I: + DPRINTK("OUT_HI_PRI_COMPLETION_I message received"); + break; + case INBOUND_MFS_COMPLETION: + DPRINTK("INBOUND_MFS_COMPLETION message received"); + handle_MFS_interrupt(fi); + break; + case INBOUND_OOO_COMPLETION: + DPRINTK("INBOUND_OOO_COMPLETION message received"); + handle_OOO_interrupt(fi); + break; + case INBOUND_SFS_COMPLETION: + DPRINTK("INBOUND_SFS_COMPLETION message received"); + handle_SFS_interrupt(fi); + break; + case INBOUND_UNKNOWN_FRAME_I: + DPRINTK("INBOUND_UNKNOWN_FRAME message received"); + handle_Unknown_Frame_interrupt(fi); + break; + case INBOUND_BUSIED_FRAME: + DPRINTK("INBOUND_BUSIED_FRAME message received"); + handle_Busied_Frame_interrupt(fi); + break; + case FRAME_MGR_INTERRUPT: + DPRINTK("FRAME_MGR_INTERRUPT message received"); + handle_FM_interrupt(fi); + break; + case READ_STATUS: + DPRINTK("READ_STATUS message received"); + break; + case SFS_BUF_WARN: + DPRINTK("SFS_BUF_WARN message received"); + handle_SFS_BUF_WARN_interrupt(fi); + break; + case MFS_BUF_WARN: + DPRINTK("MFS_BUF_WARN message received"); + handle_MFS_BUF_WARN_interrupt(fi); + break; + case IMQ_BUF_WARN: + DPRINTK("IMQ_BUF_WARN message received"); + handle_IMQ_BUF_WARN_interrupt(fi); + break; + case INBOUND_C1_TIMEOUT: + DPRINTK("INBOUND_C1_TIMEOUT message received"); + break; + case BAD_SCSI_FRAME: + DPRINTK("BAD_SCSI_FRAME message received"); + handle_Bad_SCSI_Frame_interrupt(fi); + break; + case INB_SCSI_STATUS_COMPLETION: + DPRINTK("INB_SCSI_STATUS_COMPL message received"); + handle_Inbound_SCSI_Status_interrupt(fi); + break; + case INBOUND_SCSI_COMMAND: + DPRINTK("INBOUND_SCSI_COMMAND message received"); + handle_Inbound_SCSI_Command_interrupt(fi); + break; + case INBOUND_SCSI_DATA_COMPLETION: + DPRINTK("INBOUND_SCSI_DATA message received"); + /* Only for targets */ + break; + default: + T_MSG("DEFAULT message received, type = %x", imq_int_type); + return; + } + reset_latch(fi); +} + +static void handle_OCI_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +u_long transaction_id = 0; +unsigned short status, seq_count, transmitted_ox_id; +struct Scsi_Host *host = fi->host; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; +Scsi_Cmnd *Cmnd; +u_int tag; + + ENTER("handle_OCI_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + transaction_id = ntohl(*(ptr_imq_entry + 1)); + status = ntohl(*(ptr_imq_entry + 2)) >> 16; + seq_count = ntohl(*(ptr_imq_entry + 3)); + DPRINTK("transaction_id= %x", (u_int)transaction_id); + tag = transaction_id & 0xFFFF0000; + transmitted_ox_id = transaction_id; + + /* The INT could be either due to TIME_OUT | BAD_ALPA. + * But we check only for TimeOuts. Bad AL_PA will + * caught by FM_interrupt handler. + */ + + if ((status == OCM_TIMEOUT_OR_BAD_ALPA) && (!fi->g.port_discovery) && (!fi->g.perform_adisc)){ + DPRINTK("Frame TimeOut on OX_ID = %x", (u_int)transaction_id); + + /* Is it a SCSI frame that is timing out ? Not a very good check... + */ + if ((transmitted_ox_id <= MAX_SCSI_OXID) && ((tag == FC_SCSI_BAD_TARGET) || (tag < 0x00FF0000))) { + /* If it is a Bad AL_PA, we report it as BAD_TARGET. + * Else, we allow the command to time-out. A Link + * re-initialization could be taking place. + */ + if (tag == FC_SCSI_BAD_TARGET) { + Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID]; + hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL; + if (Cmnd != NULL) { + Cmnd->result = DID_BAD_TARGET << 16; + (*Cmnd->scsi_done) (Cmnd); + } + else + T_MSG("NULL Command out of handler!"); + } /* if Bad Target */ + else { + u_char missing_target = tag >> 16; + struct fc_node_info *q = fi->node_info_list; + /* A Node that we thought was logged in has gone + * away. We are the optimistic kind and we keep + * hoping that our dear little Target will come back + * to us. For now we log him out. + */ + DPRINTK2("Missing Target = %d", missing_target); + while (q != NULL) { + if (q->target_id == missing_target) { + T_MSG("Target %d Logged out", q->target_id); + q->login = LOGIN_ATTEMPTED; + if (fi->num_nodes > 0) + fi->num_nodes--; + tx_logi(fi, ELS_PLOGI, q->d_id); + break; + } + else + q = q->next; + } + } + } /* End of SCSI frame timing out. */ + else { + if (seq_count > 1) { + /* An IP frame was transmitted to a Bad AL_PA. Free up + * the skb used. + */ + dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id))); + } + } /* End of IP frame timing out. */ + } /* End of frame timing out. */ + else { + /* Frame was transmitted successfully. Check if it was an ELS + * frame or an IP frame or a Bad_Target_Notification frame (in + * case of a ptp_link). Ugly! + */ + if ((status == 0) && (seq_count == 0)) { + u_int tag = transaction_id & 0xFFFF0000; + /* Continue with port discovery after an ELS is successfully + * transmitted. (status == 0). + */ + DPRINTK("tag = %x", tag); + switch(tag) { + case ELS_FLOGI: + /* Letz use the Name Server instead */ + fi->g.explore_fabric = TRUE; + fi->g.port_discovery = FALSE; + fi->g.alpa_list_index = MAX_NODES; + add_to_ox_id_list(fi, transaction_id, tag); + break; + case ELS_PLOGI: + if (fi->g.fabric_present && (fi->g.name_server == FALSE)) + add_to_ox_id_list(fi,transaction_id,ELS_NS_PLOGI); + else + add_to_ox_id_list(fi, transaction_id, tag); + break; + case FC_SCSI_BAD_TARGET: + Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID]; + hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL; + if (Cmnd != NULL) { + Cmnd->result = DID_BAD_TARGET << 16; + (*Cmnd->scsi_done) (Cmnd); + } + else + T_MSG("NULL Command out of handler!"); + break; + default: + add_to_ox_id_list(fi, transaction_id, tag); + } + + if (fi->g.alpa_list_index >= MAX_NODES) { + if (fi->g.port_discovery == TRUE) { + fi->g.port_discovery = FALSE; + add_display_cache_timer(fi); + } + fi->g.alpa_list_index = MAX_NODES; + } + if (fi->g.port_discovery == TRUE) + local_port_discovery(fi); + } + else { + /* An IP frame has been successfully transmitted. + * Free the skb that was used for this IP frame. + */ + if ((status == 0) && (seq_count > 1)) { + dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id))); + } + } + } + LEAVE("handle_OCI_interrupt"); +} + +/* Right now we discard OOO frames */ +static void handle_OOO_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +int queue_indx, offset, payload_size; +int no_of_buffers = 1; /* header is in a separate buffer */ + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN; + /* Calculate total number of buffers */ + no_of_buffers += payload_size / MFS_BUFFER_SIZE; + if (payload_size % MFS_BUFFER_SIZE) + no_of_buffers++; + + /* provide Tachyon will another set of buffers */ + fi->g.mfs_buffer_count += no_of_buffers; + if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) { + int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; + fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count; + update_MFSBQ_indx(fi, count); + } +} + +static void handle_MFS_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry, *buff_addr; +u_int type_of_frame, s_id; +int queue_indx, offset, payload_size, starting_indx, starting_offset; +u_short received_ox_id; +int no_of_buffers = 1; /* header is in a separate buffer */ +struct sk_buff *skb; +int wrap_around = FALSE, no_of_wrap_buffs = NO_OF_ENTRIES - 1; + ENTER("handle_MFS_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + DPRINTK("queue_indx = %d, offset = %d\n", queue_indx, offset); + payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN; + DPRINTK("payload_size = %d", payload_size); + /* Calculate total number of buffers */ + no_of_buffers += payload_size / MFS_BUFFER_SIZE; + if (payload_size % MFS_BUFFER_SIZE) + no_of_buffers++; + DPRINTK("no_of_buffers = %d", no_of_buffers); + + if ((no_of_buffers - 1) <= offset) { + starting_offset = offset - (no_of_buffers - 1); + starting_indx = queue_indx; + } + else { + int temp = no_of_buffers - (offset + 1); + int no_of_queues = temp / NO_OF_ENTRIES; + starting_offset = temp % NO_OF_ENTRIES; + if (starting_offset != 0) { + no_of_wrap_buffs = starting_offset - 1; //exclude header + starting_offset = NO_OF_ENTRIES - starting_offset; + no_of_queues++; + } + starting_indx = queue_indx - no_of_queues; + if (starting_indx < 0) { + no_of_wrap_buffs -= (starting_indx + 1) * NO_OF_ENTRIES; + starting_indx = MFSBQ_LENGTH + starting_indx; + wrap_around = TRUE; + } + } + + DPRINTK("starting_indx = %d, starting offset = %d no_of_wrap_buffs = %d\n", starting_indx, starting_offset, no_of_wrap_buffs); + /* Get Tachyon Header from first buffer */ + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base + starting_indx*NO_OF_ENTRIES + starting_offset))); + + + /* extract Type of Frame */ + type_of_frame = (u_int)ntohl(*(buff_addr + 4)) & 0xFF000000; + s_id = (u_int)ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + received_ox_id = ntohl(*(buff_addr + 6)) >> 16; + buff_addr += MFS_BUFFER_SIZE/4; + DPRINTK("type_of_frame = %x, s_id = %x, ox_id = %x", type_of_frame, s_id, received_ox_id); + + switch(type_of_frame) { + case TYPE_LLC_SNAP: + skb = dev_alloc_skb(payload_size); + if (skb == NULL) { + printk(KERN_NOTICE "%s: In handle_MFS_interrupt() Memory squeeze, dropping packet.\n", fi->name); + fi->fc_stats.rx_dropped++; + fi->g.mfs_buffer_count += no_of_buffers; + if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) { + int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; + fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count; + update_MFSBQ_indx(fi, count); + return; + } + } + if (wrap_around) { + int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE; + int tail_size = payload_size - wrap_size; + DPRINTK("wrap_size = %d, tail_size = %d\n", wrap_size, tail_size); + if (no_of_wrap_buffs) + memcpy(skb_put(skb, wrap_size), buff_addr, wrap_size); + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base))); + memcpy(skb_put(skb, tail_size), buff_addr, tail_size); + } + else + memcpy(skb_put(skb, payload_size), buff_addr, payload_size); + rx_net_mfs_packet(fi, skb); + break; + default: + T_MSG("Unknown Frame Type received. Type = %x", type_of_frame); + } + + /* provide Tachyon will another set of buffers */ + fi->g.mfs_buffer_count += no_of_buffers; + if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) { + int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; + fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count; + update_MFSBQ_indx(fi, count); + } + LEAVE("handle_MFS_interrupt"); +} + +static void handle_Unknown_Frame_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +int queue_indx, offset; + ENTER("handle_Unknown_Frame_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + /* We discard the "unknown" frame */ + /* provide Tachyon will another set of buffers */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_Unknown_Frame_interrupt"); +} + +static void handle_Busied_Frame_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +int queue_indx, offset; + ENTER("handle_Busied_Frame_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + /* We discard the "busied" frame */ + /* provide Tachyon will another set of buffers */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_Busied_Frame_interrupt"); +} + +static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry, *buff_addr, *tach_header, *ptr_edb; +u_int s_id, rctl, frame_class, burst_len, transfered_len, len = 0; +int queue_indx, offset, payload_size, i; +u_short ox_id, rx_id, x_id, mtu = 512; +u_char target_id = 0xFF; + + ENTER("handle_Bad_SCSI_Frame_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + payload_size = ntohl(*(ptr_imq_entry + 2)); + + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); + + rctl = ntohl(*(buff_addr + 2)) & 0xFF000000; + s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + ox_id = ntohl(*(buff_addr + 6)) >> 16; + rx_id = ntohl(*(buff_addr + 6)); + x_id = ox_id & MAX_SCSI_XID; + + /* Any frame that comes in with OX_ID that matches an OX_ID + * that has been allocated for SCSI, will be called a Bad + * SCSI frame if the Exchange is not valid any more. + * + * We will also get a Bad SCSI frame interrupt if we receive + * a XFER_RDY with offset != 0. Tachyon washes its hands off + * this Exchange. We have to take care of ourselves. Grrr... + */ + if (rctl == DATA_DESCRIPTOR) { + struct fc_node_info *q = fi->node_info_list; + while (q != NULL) { + if (q->d_id == s_id) { + target_id = q->target_id; + mtu = q->mtu; + break; + } + else + q = q->next; + } + frame_class = target_id; + transfered_len = ntohl(*(buff_addr + 8)); + burst_len = ntohl(*(buff_addr + 9)); + + build_ODB(fi, fi->g.seq_id, s_id, burst_len, 0, mtu, ox_id, rx_id, 0, 0, frame_class << 16); + /* Update the SEQ_ID and Relative Offset in the + * Tachyon Header Structure. + */ + tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5))); + *(tach_header + 5) = htonl(fi->g.seq_id << 24); + *(tach_header + 7) = htonl(transfered_len); + fi->g.odb.hdr_addr = *(fi->q.ptr_sest[x_id] + 5); + + /* Invalidate the EDBs used + */ + ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7))); + + for (i = 0; i < EDB_LEN; i++) + if (fi->q.ptr_edb[i] == ptr_edb) + break; + ptr_edb--; + + if (i < EDB_LEN) { + int j; + do { + ptr_edb += 2; + len += (htonl(*ptr_edb) & 0xFFFF); + j = i; + fi->q.free_edb_list[i++] = EDB_FREE; + if (i == EDB_LEN) { + i = 0; + ptr_edb = fi->q.ptr_edb_base - 1; + } + } while (len < transfered_len); + if (len > transfered_len) { + ptr_edb--; + fi->q.free_edb_list[j] = EDB_BUSY; + } + else + ptr_edb++; + } + else { + T_MSG("EDB not found while freeing"); + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + return; + } + + /* Update the EDB pointer in the ODB. + */ + fi->g.odb.edb_addr = htonl(virt_to_bus(ptr_edb)); + memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB)); + /* Update the EDB pointer in the SEST entry. We might need + * this if get another XFER_RDY for the same Exchange. + */ + *(fi->q.ptr_sest[x_id] + 7) = htonl(virt_to_bus(ptr_edb)); + + update_OCQ_indx(fi); + if (fi->g.seq_id == MAX_SEQ_ID) + fi->g.seq_id = 0; + else + fi->g.seq_id++; + } + else + /* Could be a BA_ACC or a BA_RJT. + */ + if (rctl == RCTL_BASIC_ACC) { + u_int bls_type = remove_from_ox_id_list(fi, ox_id); + DPRINTK1("BA_ACC received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type); + if (bls_type == RCTL_BASIC_ABTS) { + u_int STE_bit; + /* Invalidate resources for that Exchange. + */ + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + if (STE_bit & SEST_V) { + *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); + invalidate_SEST_entry(fi, ox_id); + } + } + } + else + if (rctl == RCTL_BASIC_RJT) { + u_int bls_type = remove_from_ox_id_list(fi, ox_id); + DPRINTK1("BA_RJT received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type); + if (bls_type == RCTL_BASIC_ABTS) { + u_int STE_bit; + /* Invalidate resources for that Exchange. + */ + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + if (STE_bit & SEST_V) { + *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); + invalidate_SEST_entry(fi, ox_id); + } + } + } + else + DPRINTK1("Frame with R_CTL = %x received from S_ID 0x%x with OX_ID %x", rctl, s_id, ox_id); + + /* Else, discard the "Bad" SCSI frame. + */ + + /* provide Tachyon will another set of buffers + */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_Bad_SCSI_Frame_interrupt"); +} + +static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi) +{ +struct Scsi_Host *host = fi->host; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; +u_int *ptr_imq_entry, *buff_addr, *ptr_rsp_info, *ptr_sense_info = NULL; +int queue_indx, offset, payload_size; +u_short received_ox_id, x_id; +Scsi_Cmnd *Cmnd; +u_int fcp_status, fcp_rsp_info_len = 0, fcp_sense_info_len = 0, s_id; + ENTER("handle_SCSI_status_interrupt"); + + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); + payload_size = ntohl(*(ptr_imq_entry + 2)); + received_ox_id = ntohl(*(buff_addr + 6)) >> 16; + + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); + + fcp_status = ntohl(*(buff_addr + 10)); + ptr_rsp_info = buff_addr + 14; + if (fcp_status & FCP_STATUS_RSP_LEN) + fcp_rsp_info_len = ntohl(*(buff_addr + 13)); + + if (fcp_status & FCP_STATUS_SENSE_LEN) { + ptr_sense_info = ptr_rsp_info + fcp_rsp_info_len / 4; + fcp_sense_info_len = ntohl(*(buff_addr + 12)); + DPRINTK("sense_info = %x", (u_int)ntohl(*ptr_sense_info)); + } + DPRINTK("fcp_status = %x, fcp_rsp_len = %x", fcp_status, fcp_rsp_info_len); + x_id = received_ox_id & MAX_SCSI_XID; + Cmnd = hostdata->cmnd_handler[x_id]; + hostdata->cmnd_handler[x_id] = NULL; + if (Cmnd != NULL) { + memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); + /* Check if there is a Sense field */ + if (fcp_status & FCP_STATUS_SENSE_LEN) { + int size = sizeof(Cmnd->sense_buffer); + if (fcp_sense_info_len < size) + size = fcp_sense_info_len; + memcpy(Cmnd->sense_buffer, (char *)ptr_sense_info, size); + } + Cmnd->result = fcp_status & FCP_STATUS_MASK; + (*Cmnd->scsi_done) (Cmnd); + } + else + T_MSG("NULL Command out of handler!"); + + invalidate_SEST_entry(fi, received_ox_id); + s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + fi->q.free_scsi_oxid[x_id] = OXID_AVAILABLE; + + /* provide Tachyon will another set of buffers */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_SCSI_status_interrupt"); +} + +static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id) +{ +u_short x_id = received_ox_id & MAX_SCSI_XID; + /* Invalidate SEST entry if it is an OutBound SEST Entry + */ + if (!(received_ox_id & SCSI_READ_BIT)) { + u_int *ptr_tach_header, *ptr_edb; + u_short temp_ox_id = NOT_SCSI_XID; + int i; + *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); + + /* Invalidate the Tachyon Header structure + */ + ptr_tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5))); + for (i = 0; i < NO_OF_TACH_HEADERS; i++) + if(fi->q.ptr_tachyon_header[i] == ptr_tach_header) + break; + if (i < NO_OF_TACH_HEADERS) + memset(ptr_tach_header, 0xFF, 32); + else + T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()"); + + /* Invalidate the EDB used + */ + ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7))); + for (i = 0; i < EDB_LEN; i++) + if (fi->q.ptr_edb[i] == ptr_edb) + break; + ptr_edb--; + if (i < EDB_LEN) { + do { + ptr_edb += 2; + fi->q.free_edb_list[i++] = EDB_FREE; + if (i == EDB_LEN) { + i = 0; + ptr_edb = fi->q.ptr_edb_base - 1; + } + } while ((htonl(*ptr_edb) & 0x80000000) != 0x80000000); + } + else + T_MSG("EDB not found while freeing in invalidate_SEST_entry()"); + + /* Search for its other header structure and destroy it! + */ + if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4))) + ptr_tach_header += 16; + else + ptr_tach_header = fi->q.ptr_tachyon_header_base; + while (temp_ox_id != x_id) { + temp_ox_id = ntohl(*(ptr_tach_header + 6)) >> 16; + if (temp_ox_id == x_id) { + /* Paranoid checking... + */ + for (i = 0; i < NO_OF_TACH_HEADERS; i++) + if(fi->q.ptr_tachyon_header[i] == ptr_tach_header) + break; + if (i < NO_OF_TACH_HEADERS) + memset(ptr_tach_header, 0xFF, 32); + else + T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()"); + break; + } + else { + if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4))) + ptr_tach_header += 16; + else + ptr_tach_header = fi->q.ptr_tachyon_header_base; + } + } + } + else { + u_short sdb_table_indx; + /* An Inbound Command has completed or needs to be Aborted. + * Clear up the SDB buffers. + */ + sdb_table_indx = *(fi->q.ptr_sest[x_id] + 5); + fi->q.sdb_slot_status[sdb_table_indx] = SDB_FREE; + } +} + +static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry; +int queue_indx, offset; + ENTER("handle_Inbound_SCSI_Command_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + /* We discard the SCSI frame as we shouldn't be receiving + * a SCSI Command in the first place + */ + /* provide Tachyon will another set of buffers */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_Inbound_SCSI_Command_interrupt"); +} + +static void handle_SFS_interrupt(struct fc_info *fi) +{ +u_int *ptr_imq_entry, *buff_addr; +u_int class_of_frame, type_of_frame, s_id, els_type = 0, rctl; +int queue_indx, offset, payload_size, login_state; +u_short received_ox_id, fs_cmnd_code; + ENTER("handle_SFS_interrupt"); + ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; + offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; + queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; + queue_indx = queue_indx >> 16; + DPRINTK("queue_indx = %d, offset = %d\n", queue_indx, offset); + payload_size = ntohl(*(ptr_imq_entry + 2)); + DPRINTK("payload_size = %d", payload_size); + + buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); + + /* extract Type of Frame */ + type_of_frame = ntohl(*(buff_addr + 4)) & 0xFF000000; + s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + received_ox_id = ntohl(*(buff_addr + 6)) >> 16; + switch(type_of_frame) { + case TYPE_BLS: + rctl = ntohl(*(buff_addr + 2)) & 0xFF000000; + switch(rctl) { + case RCTL_BASIC_ABTS: + /* As an Initiator, we should never be receiving + * this. + */ + DPRINTK1("ABTS received from S_ID 0x%x with OX_ID = %x", s_id, received_ox_id); + break; + } + break; + case TYPE_ELS: + class_of_frame = ntohl(*(buff_addr + 8)); + login_state = sid_logged_in(fi, s_id); + switch(class_of_frame & 0xFF000000) { + case ELS_PLOGI: + if (s_id != fi->g.my_id) { + u_int ret_code; + DPRINTK1("PLOGI received from D_ID 0x%x with 0X_ID = %x", s_id, received_ox_id); + if ((ret_code = plogi_ok(fi, buff_addr, payload_size)) == 0){ + tx_logi_acc(fi, ELS_ACC, s_id, received_ox_id); + add_to_address_cache(fi, buff_addr); + } + else { + u_short cmnd_code = ret_code >> 16; + u_short expln_code = ret_code; + tx_ls_rjt(fi, s_id, received_ox_id, cmnd_code, expln_code); + } + } + break; + case ELS_ACC: + els_type = remove_from_ox_id_list(fi, received_ox_id); + DPRINTK1("ELS_ACC received from D_ID 0x%x in response to ELS %x", s_id, els_type); + switch(els_type) { + case ELS_PLOGI: + add_to_address_cache(fi, buff_addr); + tx_prli(fi, ELS_PRLI, s_id, OX_ID_FIRST_SEQUENCE); + break; + case ELS_FLOGI: + add_to_address_cache(fi, buff_addr); + fi->g.my_id = ntohl(*(buff_addr + 2)) & 0x00FFFFFF; + fi->g.fabric_present = TRUE; + fi->g.my_ddaa = fi->g.my_id & 0xFFFF00; + /* Login to the Name Server + */ + tx_logi(fi, ELS_PLOGI, DIRECTORY_SERVER); + break; + case ELS_NS_PLOGI: + fi->g.name_server = TRUE; + add_to_address_cache(fi, buff_addr); + tx_name_server_req(fi, FCS_RFC_4); + tx_scr(fi); + /* Some devices have a delay before + * registering with the Name Server + */ + udelay(500); + tx_name_server_req(fi, FCS_GP_ID4); + break; + case ELS_PRLI: + mark_scsi_sid(fi, buff_addr, ADD_ENTRY); + break; + case ELS_ADISC: + if (!(validate_login(fi, buff_addr))) + tx_logo(fi, s_id, OX_ID_FIRST_SEQUENCE); + break; + } + break; + case ELS_PDISC: + DPRINTK1("ELS_PDISC received from D_ID 0x%x", s_id); + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_ADISC: + DPRINTK1("ELS_ADISC received from D_ID 0x%x", s_id); + if (node_logged_in_prev(fi, buff_addr)) + tx_adisc(fi, ELS_ACC, s_id, received_ox_id); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_PRLI: + DPRINTK1("ELS_PRLI received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) { + tx_prli(fi, ELS_ACC, s_id, received_ox_id); + mark_scsi_sid(fi, buff_addr, ADD_ENTRY); + } + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_PRLO: + DPRINTK1("ELS_PRLO received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_OUT) || (login_state == NODE_NOT_PRESENT)) + tx_logo(fi, s_id, received_ox_id); + else + if (login_state == NODE_LOGGED_IN) + + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + if (login_state == NODE_PROCESS_LOGGED_IN) { + tx_prli(fi, ELS_ACC, s_id, received_ox_id); + mark_scsi_sid(fi, buff_addr, DELETE_ENTRY); + } + break; + case ELS_LS_RJT: + els_type = remove_from_ox_id_list(fi, received_ox_id); + DPRINTK1("ELS_LS_RJT received from D_ID 0x%x in response to %x", s_id, els_type); + /* We should be chking the reason code. + */ + switch (els_type) { + case ELS_ADISC: + tx_logi(fi, ELS_PLOGI, s_id); + break; + } + break; + case ELS_LOGO: + els_type = remove_from_ox_id_list(fi, received_ox_id); + DPRINTK1("ELS_LOGO received from D_ID 0x%x in response to %x", s_id, els_type); + remove_from_address_cache(fi, buff_addr, ELS_LOGO); + tx_acc(fi, s_id, received_ox_id); + if (els_type == ELS_ADISC) + tx_logi(fi, ELS_PLOGI, s_id); + break; + case ELS_RSCN: + DPRINTK1("ELS_RSCN received from D_ID 0x%x", s_id); + tx_acc(fi, s_id, received_ox_id); + remove_from_address_cache(fi, buff_addr, ELS_RSCN); + break; + case ELS_FARP_REQ: + /* We do not support FARP. + So, silently discard it */ + DPRINTK1("ELS_FARP_REQ received from D_ID 0x%x", s_id); + break; + case ELS_ABTX: + DPRINTK1("ELS_ABTX received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_FLOGI: + DPRINTK1("ELS_FLOGI received from D_ID 0x%x", s_id); + if (fi->g.ptp_up == TRUE) { + /* The node could have come up as an N_Port + * in a Loop! So,try initializing as an NL_port + */ + take_tachyon_offline(fi); + /* write AL_TIME & E_D_TOV into the registers */ + writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg); + writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg); + DPRINTK1("FLOGI received, TACHYON initializing as L_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } + else { + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + } + break; + case ELS_ADVC: + DPRINTK1("ELS_ADVC received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_ECHO: + DPRINTK1("ELS_ECHO received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_ESTC: + DPRINTK1("ELS_ESTC received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_ESTS: + DPRINTK1("ELS_ESTS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RCS: + DPRINTK1("ELS_RCS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RES: + DPRINTK1("ELS_RES received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RLS: + DPRINTK1("ELS_RLS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RRQ: + DPRINTK1("ELS_RRQ received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RSS: + DPRINTK1("ELS_RSS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RTV: + DPRINTK1("ELS_RTV received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RSI: + DPRINTK1("ELS_RSI received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_TEST: + /* No reply sequence */ + DPRINTK1("ELS_TEST received from D_ID 0x%x", s_id); + break; + case ELS_RNC: + DPRINTK1("ELS_RNC received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_RVCS: + DPRINTK1("ELS_RVCS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_TPLS: + DPRINTK1("ELS_TPLS received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_GAID: + DPRINTK1("ELS_GAID received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_FACT: + DPRINTK1("ELS_FACT received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_FAN: + /* Hmmm... You don't support FAN ??? */ + DPRINTK1("ELS_FAN received from D_ID 0x%x", s_id); + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + break; + case ELS_FDACT: + DPRINTK1("ELS_FDACT received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_NACT: + DPRINTK1("ELS_NACT received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_NDACT: + DPRINTK1("ELS_NDACT received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_QoSR: + DPRINTK1("ELS_QoSR received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + case ELS_FDISC: + DPRINTK1("ELS_FDISC received from D_ID 0x%x", s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + default: + DPRINTK1("ELS Frame %x received from D_ID 0x%x", class_of_frame, s_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) + tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN); + else + tx_logo(fi, s_id, received_ox_id); + break; + } + break; + case TYPE_FC_SERVICES: + fs_cmnd_code = (ntohl(*(buff_addr + 10)) & 0xFFFF0000) >>16; + switch(fs_cmnd_code) { + case FCS_ACC: + els_type = remove_from_ox_id_list(fi, received_ox_id); + DPRINTK1("FCS_ACC received from D_ID 0x%x in response to %x", s_id, els_type); + if (els_type == FCS_GP_ID4) + explore_fabric(fi, buff_addr); + break; + case FCS_REJECT: + DPRINTK1("FCS_REJECT received from D_ID 0x%x in response to %x", s_id, els_type); + break; + } + break; + case TYPE_LLC_SNAP: + rx_net_packet(fi, (u_char *)buff_addr, payload_size); + break; + default: + T_MSG("Frame Type %x received from %x", type_of_frame, s_id); + } + + /* provide Tachyon will another set of buffers */ + if (offset == (NO_OF_ENTRIES - 1)) + update_SFSBQ_indx(fi); + LEAVE("handle_SFS_interrupt"); +} + +static void handle_FM_interrupt(struct fc_info *fi) +{ +u_int fm_status; +u_int tachyon_status; + + ENTER("handle_FM_interrupt"); + fm_status = readl(fi->t_r.ptr_fm_status_reg); + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + DPRINTK("FM_status = %x, Tachyon_status = %x", fm_status, tachyon_status); + if (fm_status & LINK_DOWN) { + T_MSG("Fibre Channel Link DOWN"); + fm_status = readl(fi->t_r.ptr_fm_status_reg); + + del_timer(&fi->explore_timer); + del_timer(&fi->nport_timer); + del_timer(&fi->lport_timer); + del_timer(&fi->display_cache_timer); + fi->g.link_up = FALSE; + if (fi->g.ptp_up == TRUE) + fi->g.n_port_try = FALSE; + fi->g.ptp_up = FALSE; + fi->g.port_discovery = FALSE; + fi->g.explore_fabric = FALSE; + fi->g.perform_adisc = FALSE; + + /* Logout will all nodes */ + if (fi->node_info_list) { + struct fc_node_info *temp_list = fi->node_info_list; + while(temp_list) { + temp_list->login = LOGIN_ATTEMPTED; + temp_list = temp_list->next; + } + fi->num_nodes = 0; + } + + if ((fi->g.n_port_try == FALSE) && (fi->g.dont_init == FALSE)){ + take_tachyon_offline(fi); + /* write AL_TIME & E_D_TOV into the registers */ + writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg); + + if ((fi->g.fabric_present == TRUE) && (fi->g.loop_up == TRUE)) { + u_int al_pa = fi->g.my_id & 0xFF; + writel((al_pa << 24) | LOOP_INIT_FABRIC_ADDRESS | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg); + } + else + if (fi->g.loop_up == TRUE) { + u_int al_pa = fi->g.my_id & 0xFF; + writel((al_pa << 24) | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg); + } + else + writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg); + fi->g.loop_up = FALSE; + DPRINTK1("In LDWN TACHYON initializing as L_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } + } + + if (fm_status & NON_PARTICIPATING) { + T_MSG("Did not acquire an AL_PA. I am not participating"); + } + else + if ((fm_status & LINK_UP) && ((fm_status & LINK_DOWN) == 0)) { + T_MSG("Fibre Channel Link UP"); + if ((fm_status & NON_PARTICIPATING) != TRUE) { + fi->g.link_up = TRUE; + if (tachyon_status & OSM_FROZEN) { + reset_tachyon(fi, ERROR_RELEASE); + reset_tachyon(fi, OCQ_RESET); + } + init_timer(&fi->explore_timer); + init_timer(&fi->nport_timer); + init_timer(&fi->lport_timer); + init_timer(&fi->display_cache_timer); + if ((fm_status & OLD_PORT) == 0) { + fi->g.loop_up = TRUE; + fi->g.ptp_up = FALSE; + fi->g.my_id = readl(fi->t_r.ptr_fm_config_reg) >> 24; + DPRINTK1("My AL_PA = %x", fi->g.my_id); + fi->g.port_discovery = TRUE; + fi->g.explore_fabric = FALSE; + } + else + if (((fm_status & 0xF0) == OLD_PORT) && ((fm_status & 0x0F) == PORT_STATE_ACTIVE)) { + fi->g.loop_up = FALSE; + fi->g.my_id = 0x0; + /* In a point-to-point configuration, we expect to be + * connected to an F_Port. This driver does not yet support + * a configuration where it is connected to another N_Port + * directly. + */ + fi->g.explore_fabric = TRUE; + fi->g.port_discovery = FALSE; + if (fi->g.n_port_try == FALSE) { + take_tachyon_offline(fi); + /* write R_T_TOV & E_D_TOV into the registers */ + writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg); + writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg); + fi->g.n_port_try = TRUE; + DPRINTK1("In LUP TACHYON initializing as N_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } + else { + fi->g.ptp_up = TRUE; + tx_logi(fi, ELS_FLOGI, F_PORT); + } + } + fi->g.my_ddaa = 0x0; + fi->g.fabric_present = FALSE; + /* We havn't sent out any Name Server Reqs */ + fi->g.name_server = FALSE; + fi->g.alpa_list_index = 0; + fi->g.ox_id = NOT_SCSI_XID; + fi->g.my_mtu = FRAME_SIZE; + + /* Implicitly LOGO with all logged-in nodes. + */ + if (fi->node_info_list) { + struct fc_node_info *temp_list = fi->node_info_list; + while(temp_list) { + temp_list->login = LOGIN_ATTEMPTED; + temp_list = temp_list->next; + } + fi->num_nodes = 0; + fi->g.perform_adisc = TRUE; + //fi->g.perform_adisc = FALSE; + fi->g.port_discovery = FALSE; + tx_logi(fi, ELS_FLOGI, F_PORT); + } + else { + /* If Link coming up for the _first_ time or no nodes + * were logged in before... + */ + fi->g.scsi_oxid = 0; + fi->g.seq_id = 0x00; + fi->g.perform_adisc = FALSE; + } + + /* reset OX_ID table */ + while (fi->ox_id_list) { + struct ox_id_els_map *temp = fi->ox_id_list; + fi->ox_id_list = fi->ox_id_list->next; + kfree(temp); + } + fi->ox_id_list = NULL; + } /* End of if partipating */ + } + + if (fm_status & ELASTIC_STORE_ERROR) { + /* Too much junk on the Link + */ + /* Trying to clear it up by Txing PLOGI to urself */ + if (fi->g.link_up == TRUE) + tx_logi(fi, ELS_PLOGI, fi->g.my_id); + } + + if (fm_status & LOOP_UP) { + if (tachyon_status & OSM_FROZEN) { + reset_tachyon(fi, ERROR_RELEASE); + reset_tachyon(fi, OCQ_RESET); + } + } + + if (fm_status & NOS_OLS_RECEIVED){ + if (fi->g.nport_timer_set == FALSE) { + DPRINTK("NOS/OLS Received"); + DPRINTK("FM_status = %x", fm_status); + fi->nport_timer.function = nos_ols_timer; + fi->nport_timer.data = (unsigned long)fi; + fi->nport_timer.expires = RUN_AT((3*HZ)/100); /* 30 msec */ + init_timer(&fi->nport_timer); + add_timer(&fi->nport_timer); + fi->g.nport_timer_set = TRUE; + } + } + + if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) { + DPRINTK1("Link Fail-I in OLD-PORT."); + take_tachyon_offline(fi); + reset_tachyon(fi, SOFTWARE_RESET); + } + + if (fm_status & LOOP_STATE_TIMEOUT){ + if ((fm_status & 0xF0) == ARBITRATING) + DPRINTK1("ED_TOV timesout.In ARBITRATING state..."); + if ((fm_status & 0xF0) == ARB_WON) + DPRINTK1("ED_TOV timesout.In ARBITRATION WON state..."); + if ((fm_status & 0xF0) == OPEN) + DPRINTK1("ED_TOV timesout.In OPEN state..."); + if ((fm_status & 0xF0) == OPENED) + DPRINTK1("ED_TOV timesout.In OPENED state..."); + if ((fm_status & 0xF0) == TX_CLS) + DPRINTK1("ED_TOV timesout.In XMITTED CLOSE state..."); + if ((fm_status & 0xF0) == RX_CLS) + DPRINTK1("ED_TOV timesout.In RECEIVED CLOSE state..."); + if ((fm_status & 0xF0) == INITIALIZING) + DPRINTK1("ED_TOV timesout.In INITIALIZING state..."); + DPRINTK1("Initializing Loop..."); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } + + if ((fm_status & BAD_ALPA) && (fi->g.loop_up == TRUE)) { + u_char bad_alpa = (readl(fi->t_r.ptr_fm_rx_al_pa_reg) & 0xFF00) >> 8; + if (tachyon_status & OSM_FROZEN) { + reset_tachyon(fi, ERROR_RELEASE); + reset_tachyon(fi, OCQ_RESET); + } + /* Fix for B34 */ + tx_logi(fi, ELS_PLOGI, fi->g.my_id); + + if (!fi->g.port_discovery && !fi->g.perform_adisc) { + if (bad_alpa != 0xFE) + DPRINTK("Bad AL_PA = %x", bad_alpa); + } + else { + if ((fi->g.perform_adisc == TRUE) && (bad_alpa == 0x00)) { + DPRINTK1("Performing ADISC..."); + fi->g.fabric_present = FALSE; + perform_adisc(fi); + } + } + } + + if (fm_status & LIPF_RECEIVED){ + DPRINTK("LIP(F8) Received"); + } + + if (fm_status & LINK_FAILURE) { + if (fm_status & LOSS_OF_SIGNAL) + DPRINTK1("Detected Loss of Signal."); + if (fm_status & OUT_OF_SYNC) + DPRINTK1("Detected Loss of Synchronization."); + } + + if (fm_status & TRANSMIT_PARITY_ERROR) { + /* Bad! Should not happen. Solution-> Hard Reset. + */ + T_MSG("Parity Error. Perform Hard Reset!"); + } + + if (fi->g.alpa_list_index >= MAX_NODES){ + if (fi->g.port_discovery == TRUE) { + fi->g.port_discovery = FALSE; + add_display_cache_timer(fi); + } + fi->g.alpa_list_index = MAX_NODES; + } + + if (fi->g.port_discovery == TRUE) + local_port_discovery(fi); + + LEAVE("handle_FM_interrupt"); + return; +} + +static void local_port_discovery(struct fc_info *fi) +{ + if (fi->g.loop_up == TRUE) { + /* If this is not here, some of the Bad AL_PAs are missed. + */ + udelay(20); + if ((fi->g.alpa_list_index == 0) && (fi->g.fabric_present == FALSE)){ + tx_logi(fi, ELS_FLOGI, F_PORT); + } + else { + int login_state = sid_logged_in(fi, fi->g.my_ddaa | alpa_list[fi->g.alpa_list_index]); + while ((fi->g.alpa_list_index == 0) || ((fi->g.alpa_list_index < MAX_NODES) && ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN) || (alpa_list[fi->g.alpa_list_index] == (fi->g.my_id & 0xFF))))) + fi->g.alpa_list_index++; + if (fi->g.alpa_list_index < MAX_NODES) + tx_logi(fi, ELS_PLOGI, alpa_list[fi->g.alpa_list_index]); + } + fi->g.alpa_list_index++; + if (fi->g.alpa_list_index >= MAX_NODES){ + if (fi->g.port_discovery == TRUE) { + fi->g.port_discovery = FALSE; + add_display_cache_timer(fi); + } + fi->g.alpa_list_index = MAX_NODES; + } + } +} + +static void nos_ols_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info*)data; +u_int fm_status; + fm_status = readl(fi->t_r.ptr_fm_status_reg); + DPRINTK1("FM_status in timer= %x", fm_status); + fi->g.nport_timer_set = FALSE; + del_timer(&fi->nport_timer); + if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE)) + return; + if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_ACTIVE) || ((fm_status & 0x0F) == PORT_STATE_OFFLINE))) { + DPRINTK1("In OLD-PORT after E_D_TOV."); + take_tachyon_offline(fi); + /* write R_T_TOV & E_D_TOV into the registers */ + writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg); + writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg); + fi->g.n_port_try = TRUE; + DPRINTK1("In timer, TACHYON initializing as N_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } + else + if ((fi->g.lport_timer_set == FALSE) && ((fm_status & 0xF0) == LOOP_FAIL)) { + DPRINTK1("Loop Fail after E_D_TOV."); + fi->lport_timer.function = loop_timer; + fi->lport_timer.data = (unsigned long)fi; + fi->lport_timer.expires = RUN_AT((8*HZ)/100); + init_timer(&fi->lport_timer); + add_timer(&fi->lport_timer); + fi->g.lport_timer_set = TRUE; + take_tachyon_offline(fi); + reset_tachyon(fi, SOFTWARE_RESET); + } + else + if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) { + DPRINTK1("Link Fail-II in OLD-PORT."); + take_tachyon_offline(fi); + reset_tachyon(fi, SOFTWARE_RESET); + } +} + +static void loop_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info*)data; + fi->g.lport_timer_set = FALSE; + del_timer(&fi->lport_timer); + if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE)) + return; +} + +static void add_display_cache_timer(struct fc_info *fi) +{ + fi->display_cache_timer.function = display_cache_timer; + fi->display_cache_timer.data = (unsigned long)fi; + fi->display_cache_timer.expires = RUN_AT(fi->num_nodes * HZ); + init_timer(&fi->display_cache_timer); + add_timer(&fi->display_cache_timer); +} + +static void display_cache_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info*)data; + del_timer(&fi->display_cache_timer); + display_cache(fi); + return; +} + +static void reset_tachyon(struct fc_info *fi, u_int value) +{ +u_int tachyon_status, reset_done = OCQ_RESET_STATUS | SCSI_FREEZE_STATUS; +int not_done = 1, i = 0; + writel(value, fi->t_r.ptr_tach_control_reg); + if (value == OCQ_RESET) + fi->q.ocq_prod_indx = 0; + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + + /* Software resets are immediately done, whereas other aren't. It + about 30 clocks to do the reset */ + if (value != SOFTWARE_RESET) { + while(not_done) { + if (i++ > 100000) { + T_MSG("Reset was unsuccessful! Tachyon Status = %x", tachyon_status); + break; + } + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + if ((tachyon_status & reset_done) == 0) + not_done = 0; + } + } + else { + write_to_tachyon_registers(fi); + } +} + +static void take_tachyon_offline(struct fc_info *fi) +{ +u_int fm_status = readl(fi->t_r.ptr_fm_status_reg); + + /* The first two conditions will never be true. The Manual and + * the errata say this. But the current implementation is + * decently stable. + */ + //if ((fm_status & 0xF0) == LOOP_FAIL) { + if (fm_status == LOOP_FAIL) { + // workaround as in P. 89 + writel(HOST_CONTROL, fi->t_r.ptr_fm_control_reg); + if (fi->g.loop_up == TRUE) + writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg); + else { + writel(OFFLINE, fi->t_r.ptr_fm_control_reg); + writel(EXIT_HOST_CONTROL, fi->t_r.ptr_fm_control_reg); + } + } + else + //if ((fm_status & LOOP_UP) == LOOP_UP) { + if (fm_status == LOOP_UP) { + writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg); + } + else + writel(OFFLINE, fi->t_r.ptr_fm_control_reg); +} + + +static void read_novram(struct fc_info *fi) +{ +int off = 0; + fi->n_r.ptr_novram_hw_control_reg = fi->i_r.ptr_ichip_hw_control_reg; + fi->n_r.ptr_novram_hw_status_reg = fi->i_r.ptr_ichip_hw_status_reg; + iph5526_nr_do_init(fi); + if (fi->clone_id == PCI_VENDOR_ID_INTERPHASE) + off = 32; + + fi->g.my_node_name_high = (fi->n_r.data[off] << 16) | fi->n_r.data[off+1]; + fi->g.my_node_name_low = (fi->n_r.data[off+2] << 16) | fi->n_r.data[off+3]; + fi->g.my_port_name_high = (fi->n_r.data[off+4] << 16) | fi->n_r.data[off+5]; + fi->g.my_port_name_low = (fi->n_r.data[off+6] << 16) | fi->n_r.data[off+7]; + DPRINTK("node_name = %x %x", fi->g.my_node_name_high, fi->g.my_node_name_low); + DPRINTK("port_name = %x %x", fi->g.my_port_name_high, fi->g.my_port_name_low); +} + +static void reset_ichip(struct fc_info *fi) +{ + /* (i)chip reset */ + writel(ICHIP_HCR_RESET, fi->i_r.ptr_ichip_hw_control_reg); + /*wait for chip to get reset */ + udelay(10000); + /*de-assert reset */ + writel(ICHIP_HCR_DERESET, fi->i_r.ptr_ichip_hw_control_reg); + + /* enable INT lines on the (i)chip */ + writel(ICHIP_HCR_ENABLE_INTA , fi->i_r.ptr_ichip_hw_control_reg); + /* enable byte swap */ + writel(ICHIP_HAMR_BYTE_SWAP_ADDR_TR, fi->i_r.ptr_ichip_hw_addr_mask_reg); +} + +static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id) +{ +int int_required = 1; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +u_int r_ctl = RCTL_ELS_UCTL; +u_int type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_logi"); + /* We dont want interrupted for our own logi. + * It screws up the port discovery process. + */ + if (d_id == fi->g.my_id) + int_required = 0; + fill_login_frame(fi, logi); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN)); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, ox_id, logi); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_logi"); + return; +} + +static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id) +{ +int int_required = 0; +u_int r_ctl = RCTL_ELS_SCTL; +u_int type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_logi_acc"); + fill_login_frame(fi, logi); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN)); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, logi); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_logi_acc"); + return; +} + +static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id) +{ +int int_required = 1; +u_int r_ctl = RCTL_ELS_UCTL; +u_int type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_prli"); + if (command_code == ELS_PRLI) + fi->g.prli.cmnd_code = htons((ELS_PRLI | PAGE_LEN) >> 16); + else { + fi->g.prli.cmnd_code = htons((ELS_ACC | PAGE_LEN) >> 16); + int_required = 0; + type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE; + r_ctl = RCTL_ELS_SCTL; + } + fi->g.prli.payload_length = htons(PRLI_LEN); + fi->g.prli.type_code = htons(FCP_TYPE_CODE); + fi->g.prli.est_image_pair = htons(IMAGE_PAIR); + fi->g.prli.responder_pa = 0; + fi->g.prli.originator_pa = 0; + fi->g.prli.service_params = htonl(INITIATOR_FUNC | READ_XFER_RDY_DISABLED); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.prli, sizeof(PRLI)); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]), sizeof(PRLI), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, command_code); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_prli"); + return; +} + +static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id) +{ +int int_required = 1; +u_int r_ctl = RCTL_ELS_UCTL; +u_int type = TYPE_ELS | EXCHANGE_RESPONDER | SEQUENCE_RESPONDER | FIRST_SEQUENCE | END_SEQUENCE | SEQUENCE_INITIATIVE; +int size = sizeof(LOGO); +char fc_id[3]; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_logo"); + fi->g.logo.logo_cmnd = htonl(ELS_LOGO); + fi->g.logo.reserved = 0; + memcpy(fc_id, &(fi->g.my_id), 3); + fi->g.logo.n_port_id_0 = fc_id[0]; + fi->g.logo.n_port_id_1 = fc_id[1]; + fi->g.logo.n_port_id_2 = fc_id[2]; + fi->g.logo.port_name_up = htonl(N_PORT_NAME_HIGH); + fi->g.logo.port_name_low = htonl(N_PORT_NAME_LOW); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.logo, sizeof(LOGO)); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_LOGO); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_logo"); +} + +static void tx_adisc(struct fc_info *fi, u_int cmnd_code, u_int d_id, u_short received_ox_id) +{ +int int_required = 0; +u_int r_ctl = RCTL_ELS_SCTL; +u_int type = TYPE_ELS | EXCHANGE_RESPONDER | SEQUENCE_RESPONDER | FIRST_SEQUENCE | END_SEQUENCE; +int size = sizeof(ADISC); +u_int my_mtu = fi->g.my_mtu; + fi->g.adisc.ls_cmnd_code = htonl(cmnd_code); + fi->g.adisc.hard_address = htonl(0); + fi->g.adisc.port_name_high = htonl(N_PORT_NAME_HIGH); + fi->g.adisc.port_name_low = htonl(N_PORT_NAME_LOW); + fi->g.adisc.node_name_high = htonl(NODE_NAME_HIGH); + fi->g.adisc.node_name_low = htonl(NODE_NAME_LOW); + fi->g.adisc.n_port_id = htonl(fi->g.my_id); + if (cmnd_code == ELS_ADISC) { + int_required = 1; + r_ctl = RCTL_ELS_UCTL; + type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; + } + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.adisc, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, cmnd_code); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; +} + +static void tx_ls_rjt(struct fc_info *fi, u_int d_id, u_short received_ox_id, u_short reason_code, u_short expln_code) +{ +int int_required = 0; +u_int r_ctl = RCTL_ELS_SCTL; +u_int type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE; +int size = sizeof(LS_RJT); +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_ls_rjt"); + fi->g.ls_rjt.cmnd_code = htonl(ELS_LS_RJT); + fi->g.ls_rjt.reason_code = htonl((reason_code << 16) | expln_code); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.ls_rjt, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_LS_RJT); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_ls_rjt"); +} + +static void tx_abts(struct fc_info *fi, u_int d_id, u_short ox_id) +{ +int int_required = 1; +u_int r_ctl = RCTL_BASIC_ABTS; +u_int type = TYPE_BLS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; +int size = 0; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_abts"); + fi->g.type_of_frame = FC_BLS; + tx_exchange(fi, NULL, size, r_ctl, type, d_id, my_mtu, int_required, ox_id, RCTL_BASIC_ABTS); + LEAVE("tx_abts"); +} + +static u_int plogi_ok(struct fc_info *fi, u_int *buff_addr, int size) +{ +int ret_code = 0; +u_short mtu = ntohl(*(buff_addr + 10)) & 0x00000FFF; +u_short class3 = ntohl(*(buff_addr + 25)) >> 16; +u_short class3_conc_seq = ntohl(*(buff_addr + 27)) >> 16; +u_short open_seq = ntohl(*(buff_addr + 28)) >> 16; + DPRINTK1("mtu = %x class3 = %x conc_seq = %x open_seq = %x", mtu, class3, class3_conc_seq, open_seq); + size -= TACHYON_HEADER_LEN; + if (!(class3 & 0x8000)) { + DPRINTK1("Received PLOGI with class3 = %x", class3); + ret_code = (LOGICAL_ERR << 16) | NO_EXPLN; + return ret_code; + } + if (mtu < 256) { + DPRINTK1("Received PLOGI with MTU set to %x", mtu); + ret_code = (LOGICAL_ERR << 16) | RECV_FIELD_SIZE; + return ret_code; + } + if (size != PLOGI_LEN) { + DPRINTK1("Received PLOGI of size %x", size); + ret_code = (LOGICAL_ERR << 16) | INV_PAYLOAD_LEN; + return ret_code; + } + if (class3_conc_seq == 0) { + DPRINTK1("Received PLOGI with conc_seq == 0"); + ret_code = (LOGICAL_ERR << 16) | CONC_SEQ; + return ret_code; + } + if (open_seq == 0) { + DPRINTK1("Received PLOGI with open_seq == 0"); + ret_code = (LOGICAL_ERR << 16) | NO_EXPLN; + return ret_code; + } + + /* Could potentially check for more fields, but might end up + not talking to most of the devices. ;-) */ + /* Things that could get checked are: + common_features = 0x8800 + total_concurrent_seq = at least 1 + */ + return ret_code; +} + +static void tx_acc(struct fc_info *fi, u_int d_id, u_short received_ox_id) +{ +int int_required = 0; +u_int r_ctl = RCTL_ELS_SCTL; +u_int type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE; +int size = sizeof(ACC); +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_acc"); + fi->g.acc.cmnd_code = htonl(ELS_ACC); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.acc, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_ACC); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_acc"); +} + + +static void tx_name_server_req(struct fc_info *fi, u_int req) +{ +int int_required = 1, i, size = 0; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +u_int type = TYPE_FC_SERVICES | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; +u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_CONTROL; +u_int my_mtu = fi->g.my_mtu, d_id = DIRECTORY_SERVER; +CT_HDR ct_hdr; + ENTER("tx_name_server_req"); + /* Fill up CT_Header */ + ct_hdr.rev_in_id = htonl(FC_CT_REV); + ct_hdr.fs_type = DIRECTORY_SERVER_APP; + ct_hdr.fs_subtype = NAME_SERVICE; + ct_hdr.options = 0; + ct_hdr.resv1 = 0; + ct_hdr.cmnd_resp_code = htons(req >> 16); + ct_hdr.max_res_size = 0; + ct_hdr.resv2 = 0; + ct_hdr.reason_code = 0; + ct_hdr.expln_code = 0; + ct_hdr.vendor_unique = 0; + + fi->g.type_of_frame = FC_ELS; + switch(req) { + case FCS_RFC_4: + memcpy(&(fi->g.rfc_4.ct_hdr), &ct_hdr, sizeof(CT_HDR)); + fi->g.rfc_4.s_id = htonl(fi->g.my_id); + for (i = 0; i < 32; i++) + fi->g.rfc_4.bit_map[i] = 0; + /* We support IP & SCSI */ + fi->g.rfc_4.bit_map[2] = 0x01; + fi->g.rfc_4.bit_map[3] = 0x20; + size = sizeof(RFC_4); + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.rfc_4, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, req); + break; + case FCS_GP_ID4: + memcpy(&(fi->g.gp_id4.ct_hdr), &ct_hdr, sizeof(CT_HDR)); + fi->g.gp_id4.port_type = htonl(PORT_TYPE_NX_PORTS); + size = sizeof(GP_ID4); + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.gp_id4, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, req); + break; + } + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_name_server_req"); +} + +static void tx_scr(struct fc_info *fi) +{ +int int_required = 1, size = sizeof(SCR); +u_short ox_id = OX_ID_FIRST_SEQUENCE; +u_int type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE; +u_int r_ctl = RCTL_ELS_UCTL; +u_int my_mtu = fi->g.my_mtu, d_id = FABRIC_CONTROLLER; + ENTER("tx_scr"); + fi->g.scr.cmnd_code = htonl(ELS_SCR); + fi->g.scr.reg_function = htonl(FULL_REGISTRATION); + fi->g.type_of_frame = FC_ELS; + memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.scr, size); + tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, ox_id, ELS_SCR); + fi->g.e_i++; + if (fi->g.e_i == MAX_PENDING_FRAMES) + fi->g.e_i = 0; + LEAVE("tx_scr"); +} + +static void perform_adisc(struct fc_info *fi) +{ +int count = 0; + /* Will be set to TRUE when timer expires in a PLDA environment. + */ + fi->g.port_discovery = FALSE; + + if (fi->node_info_list) { + struct fc_node_info *temp_list = fi->node_info_list; + while(temp_list) { + /* Tx ADISC to all non-fabric based + * entities. + */ + if ((temp_list->d_id & 0xFF0000) != 0xFF0000) + tx_adisc(fi, ELS_ADISC, temp_list->d_id, OX_ID_FIRST_SEQUENCE); + temp_list = temp_list->next; + udelay(20); + count++; + } + } + /* Perform Port Discovery after timer expires. + * We are giving time for the ADISCed nodes to respond + * so that we dont have to perform PLOGI to those whose + * login are _still_ valid. + */ + fi->explore_timer.function = port_discovery_timer; + fi->explore_timer.data = (unsigned long)fi; + fi->explore_timer.expires = RUN_AT((count*3*HZ)/100); + init_timer(&fi->explore_timer); + add_timer(&fi->explore_timer); +} + +static void explore_fabric(struct fc_info *fi, u_int *buff_addr) +{ +u_int *addr = buff_addr + 12; /* index into payload */ +u_char control_code; +u_int d_id; +int count = 0; + ENTER("explore_fabric"); + DPRINTK1("entering explore_fabric"); + + /*fi->g.perform_adisc = TRUE; + fi->g.explore_fabric = TRUE; + perform_adisc(fi);*/ + + do { + d_id = ntohl(*addr) & 0x00FFFFFF; + if (d_id != fi->g.my_id) { + if (sid_logged_in(fi, d_id) == NODE_NOT_PRESENT) + tx_logi(fi, ELS_PLOGI, d_id); + else + if (sid_logged_in(fi, d_id) == NODE_LOGGED_OUT) + tx_adisc(fi, ELS_ADISC, d_id, OX_ID_FIRST_SEQUENCE); + count++; + } + control_code = (ntohl(*addr) & 0xFF000000) >> 24; + addr++; + DPRINTK1("cc = %x, d_id = %x", control_code, d_id); + } while (control_code != 0x80); + + fi->explore_timer.function = fabric_explore_timer; + fi->explore_timer.data = (unsigned long)fi; + /* We give 30 msec for each device to respond and then send out + * our SCSI enquiries. + */ + fi->explore_timer.expires = RUN_AT((count*3*HZ)/100); + init_timer(&fi->explore_timer); + add_timer(&fi->explore_timer); + + DPRINTK1("leaving explore_fabric"); + LEAVE("explore_fabric"); +} + +static void fabric_explore_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info*)data; + del_timer(&fi->explore_timer); + + if ((fi->g.loop_up == TRUE) && (fi->g.ptp_up == FALSE)) { + /* Initiate Local Port Discovery on the Local Loop. + */ + fi->g.port_discovery = TRUE; + fi->g.alpa_list_index = 1; + local_port_discovery(fi); + } + fi->g.explore_fabric = FALSE; + return; +} + +static void port_discovery_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info*)data; + del_timer(&fi->explore_timer); + + if ((fi->g.loop_up == TRUE) && (fi->g.explore_fabric != TRUE)) { + fi->g.port_discovery = TRUE; + fi->g.alpa_list_index = 1; + local_port_discovery(fi); + } + fi->g.perform_adisc = FALSE; + return; +} + +static void add_to_ox_id_list(struct fc_info *fi, u_int transaction_id, u_int cmnd_code) +{ +struct ox_id_els_map *p, *q = fi->ox_id_list, *r = NULL; +int size = sizeof(struct ox_id_els_map); + while (q != NULL) { + r = q; + q = q->next; + } + p = (struct ox_id_els_map *)kmalloc(size, GFP_ATOMIC); + if (p == NULL) { + T_MSG("kmalloc failed in add_to_ox_id_list()"); + return; + } + p->ox_id = transaction_id; + p->els = cmnd_code; + p->next = NULL; + if (fi->ox_id_list == NULL) + fi->ox_id_list = p; + else + r->next = p; + return; +} + +static u_int remove_from_ox_id_list(struct fc_info *fi, u_short received_ox_id) +{ +struct ox_id_els_map *p = fi->ox_id_list, *q = fi->ox_id_list; +u_int els_type; + while (q != NULL) { + if (q->ox_id == received_ox_id) { + + if (q == fi->ox_id_list) + fi->ox_id_list = fi->ox_id_list->next; + else + if (q->next == NULL) + p->next = NULL; + else + p->next = q->next; + + els_type = q->els; + kfree(q); + return els_type; + } + p = q; + q = q->next; + } + if (q == NULL) + DPRINTK2("Could not find ox_id %x in ox_id_els_map", received_ox_id); + return 0; +} + +static void build_tachyon_header(struct fc_info *fi, u_int my_id, u_int r_ctl, u_int d_id, u_int type, u_char seq_id, u_char df_ctl, u_short ox_id, u_short rx_id, char *data) +{ +u_char alpa = d_id & 0x0000FF; +u_int dest_ddaa = d_id &0xFFFF00; + + ENTER("build_tachyon_header"); + DPRINTK("d_id = %x, my_ddaa = %x", d_id, fi->g.my_ddaa); + /* Does it have to go to/thru a Fabric? */ + if ((dest_ddaa != 0) && ((d_id == F_PORT) || (fi->g.fabric_present && (dest_ddaa != fi->g.my_ddaa)))) + alpa = 0x00; + fi->g.tach_header.resv = 0x00000000; + fi->g.tach_header.sof_and_eof = SOFI3 | EOFN; + fi->g.tach_header.dest_alpa = alpa; + /* Set LCr properly to have enuff credit */ + if (alpa == REPLICATE) + fi->g.tach_header.lcr_and_time_stamp = htons(0xC00);/* LCr=3 */ + else + fi->g.tach_header.lcr_and_time_stamp = 0; + fi->g.tach_header.r_ctl_and_d_id = htonl(r_ctl | d_id); + fi->g.tach_header.vc_id_and_s_id = htonl(my_id); + fi->g.tach_header.type_and_f_cntl = htonl(type); + fi->g.tach_header.seq_id = seq_id; + fi->g.tach_header.df_cntl = df_ctl; + fi->g.tach_header.seq_cnt = 0; + fi->g.tach_header.ox_id = htons(ox_id); + fi->g.tach_header.rx_id = htons(rx_id); + fi->g.tach_header.ro = 0; + if (data) { + /* We use the Seq_Count to keep track of IP frames in the + * OCI_interrupt handler. Initial Seq_Count of IP frames is 1. + */ + if (fi->g.type_of_frame == FC_BROADCAST) + fi->g.tach_header.seq_cnt = htons(0x1); + else + fi->g.tach_header.seq_cnt = htons(0x2); + fi->g.tach_header.nw_header.d_naa = htons(0x1000); + fi->g.tach_header.nw_header.s_naa = htons(0x1000); + memcpy(&(fi->g.tach_header.nw_header.dest_high), data, 2); + memcpy(&(fi->g.tach_header.nw_header.dest_low), data + 2, 4); + memcpy(&(fi->g.tach_header.nw_header.source_high), data + 6, 2); + memcpy(&(fi->g.tach_header.nw_header.source_low), data + 8, 4); + } + LEAVE("build_tachyon_header"); +} + +static void build_EDB(struct fc_info *fi, char *data, u_short flags, u_short len) +{ + fi->g.edb.buf_addr = ntohl((u_int)virt_to_bus(data)); + fi->g.edb.ehf = ntohs(flags); + if (len % 4) + len += (4 - (len % 4)); + fi->g.edb.buf_len = ntohs(len); +} + +static void build_ODB(struct fc_info *fi, u_char seq_id, u_int d_id, u_int len, u_int cntl, u_short mtu, u_short ox_id, u_short rx_id, int NW_header, int int_required, u_int frame_class) +{ + fi->g.odb.seq_d_id = htonl(seq_id << 24 | d_id); + fi->g.odb.tot_len = len; + if (NW_header) + fi->g.odb.tot_len += NW_HEADER_LEN; + if (fi->g.odb.tot_len % 4) + fi->g.odb.tot_len += (4 - (fi->g.odb.tot_len % 4)); + fi->g.odb.tot_len = htonl(fi->g.odb.tot_len); + switch(int_required) { + case NO_COMP_AND_INT: + fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | ODB_NO_COMP | cntl); + break; + case INT_AND_COMP_REQ: + fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | cntl); + break; + case NO_INT_COMP_REQ: + fi->g.odb.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | cntl); + break; + } + fi->g.odb.rx_id = htons(rx_id); + fi->g.odb.cs_enable = 0; + fi->g.odb.cs_seed = htons(1); + + fi->g.odb.hdr_addr = htonl(virt_to_bus(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx])); + fi->g.odb.frame_len = htons(mtu); + + if (NW_header) { + /* The pointer to the sk_buff is in here. Freed up when the + * OCI_interrupt is received. + */ + fi->g.odb.trans_id = htonl(frame_class); + fi->g.odb.hdr_len = TACHYON_HEADER_LEN + NW_HEADER_LEN; + } + else { + /* helps in tracking transmitted OX_IDs */ + fi->g.odb.trans_id = htonl((frame_class & 0xFFFF0000) | ox_id); + fi->g.odb.hdr_len = TACHYON_HEADER_LEN; + } + fi->g.odb.hdr_len = htons(fi->g.odb.hdr_len); + + fi->g.odb.edb_addr = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx])); +} + +static void fill_login_frame(struct fc_info *fi, u_int logi) +{ +int i; + fi->g.login.ls_cmnd_code= htonl(logi); + fi->g.login.fc_ph_version = htons(PH_VERSION); + if (fi->g.loop_up) + fi->g.login.buff_to_buff_credit = htons(LOOP_BB_CREDIT); + else + if (fi->g.ptp_up) + fi->g.login.buff_to_buff_credit = htons(PT2PT_BB_CREDIT); + if ((logi != ELS_FLOGI) || (logi == ELS_ACC)) + fi->g.login.common_features = htons(PLOGI_C_F); + else + if (logi == ELS_FLOGI) + fi->g.login.common_features = htons(FLOGI_C_F); + fi->g.login.recv_data_field_size = htons(FRAME_SIZE); + fi->g.login.n_port_total_conc_seq = htons(CONCURRENT_SEQUENCES); + fi->g.login.rel_off_by_info_cat = htons(RO_INFO_CATEGORY); + fi->g.login.ED_TOV = htonl(E_D_TOV); + fi->g.login.n_port_name_high = htonl(N_PORT_NAME_HIGH); + fi->g.login.n_port_name_low = htonl(N_PORT_NAME_LOW); + fi->g.login.node_name_high = htonl(NODE_NAME_HIGH); + fi->g.login.node_name_low = htonl(NODE_NAME_LOW); + + /* Fill Class 1 parameters */ + fi->g.login.c_of_s[0].service_options = htons(0); + fi->g.login.c_of_s[0].initiator_ctl = htons(0); + fi->g.login.c_of_s[0].recipient_ctl = htons(0); + fi->g.login.c_of_s[0].recv_data_field_size = htons(0); + fi->g.login.c_of_s[0].concurrent_sequences = htons(0); + fi->g.login.c_of_s[0].n_port_end_to_end_credit = htons(0); + fi->g.login.c_of_s[0].open_seq_per_exchange = htons(0); + fi->g.login.c_of_s[0].resv = htons(0); + + /* Fill Class 2 parameters */ + fi->g.login.c_of_s[1].service_options = htons(0); + fi->g.login.c_of_s[1].initiator_ctl = htons(0); + fi->g.login.c_of_s[1].recipient_ctl = htons(0); + fi->g.login.c_of_s[1].recv_data_field_size = htons(0); + fi->g.login.c_of_s[1].concurrent_sequences = htons(0); + fi->g.login.c_of_s[1].n_port_end_to_end_credit = htons(0); + fi->g.login.c_of_s[1].open_seq_per_exchange = htons(0); + fi->g.login.c_of_s[1].resv = htons(0); + + /* Fill Class 3 parameters */ + if (logi == ELS_FLOGI) + fi->g.login.c_of_s[2].service_options = htons(SERVICE_VALID | SEQUENCE_DELIVERY); + else + fi->g.login.c_of_s[2].service_options = htons(SERVICE_VALID); + fi->g.login.c_of_s[2].initiator_ctl = htons(0); + fi->g.login.c_of_s[2].recipient_ctl = htons(0); + fi->g.login.c_of_s[2].recv_data_field_size = htons(FRAME_SIZE); + fi->g.login.c_of_s[2].concurrent_sequences = htons(CLASS3_CONCURRENT_SEQUENCE); + fi->g.login.c_of_s[2].n_port_end_to_end_credit = htons(0); + fi->g.login.c_of_s[2].open_seq_per_exchange = htons(CLASS3_OPEN_SEQUENCE); + fi->g.login.c_of_s[2].resv = htons(0); + + for(i = 0; i < 4; i++) { + fi->g.login.resv[i] = 0; + fi->g.login.vendor_version_level[i] = 0; + } +} + + +/* clear the Interrupt Latch on the (i)chip, so that you can receive + * Interrupts from Tachyon in future + */ +static void reset_latch(struct fc_info *fi) +{ + writel(readl(fi->i_r.ptr_ichip_hw_status_reg) | ICHIP_HSR_INT_LATCH, fi->i_r.ptr_ichip_hw_status_reg); +} + +static void update_OCQ_indx(struct fc_info *fi) +{ + fi->q.ocq_prod_indx++; + if (fi->q.ocq_prod_indx == OCQ_LENGTH) + fi->q.ocq_prod_indx = 0; + writel(fi->q.ocq_prod_indx, fi->t_r.ptr_ocq_prod_indx_reg); +} + +static void update_IMQ_indx(struct fc_info *fi, int count) +{ + fi->q.imq_cons_indx += count; + if (fi->q.imq_cons_indx >= IMQ_LENGTH) + fi->q.imq_cons_indx -= IMQ_LENGTH; + writel(fi->q.imq_cons_indx, fi->t_r.ptr_imq_cons_indx_reg); +} + +static void update_SFSBQ_indx(struct fc_info *fi) +{ + fi->q.sfsbq_prod_indx++; + if (fi->q.sfsbq_prod_indx == SFSBQ_LENGTH) + fi->q.sfsbq_prod_indx = 0; + writel(fi->q.sfsbq_prod_indx, fi->t_r.ptr_sfsbq_prod_reg); +} + +static void update_MFSBQ_indx(struct fc_info *fi, int count) +{ + fi->q.mfsbq_prod_indx += count; + if (fi->q.mfsbq_prod_indx >= MFSBQ_LENGTH) + fi->q.mfsbq_prod_indx -= MFSBQ_LENGTH; + writel(fi->q.mfsbq_prod_indx, fi->t_r.ptr_mfsbq_prod_reg); +} + + +static void update_tachyon_header_indx(struct fc_info *fi) +{ + fi->q.tachyon_header_indx++; + if (fi->q.tachyon_header_indx == NO_OF_TACH_HEADERS) + fi->q.tachyon_header_indx = 0; +} + +static void update_EDB_indx(struct fc_info *fi) +{ + fi->q.edb_buffer_indx++; + if (fi->q.edb_buffer_indx == EDB_LEN) + fi->q.edb_buffer_indx = 0; +} + +static int iph5526_open(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + return 0; +} + +static int iph5526_close(struct net_device *dev) +{ + dev->tbusy = 1; + dev->start = 0; + MOD_DEC_USE_COUNT; + return 0; +} + +static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev) +{ +struct fc_info *fi = (struct fc_info*)dev->priv; +int status = 0; +short type = 0; +u_long flags; + ENTER("iph5526_send_packet"); + if (dev->tbusy) { + printk(KERN_WARNING "%s: DEVICE BUSY\n", dev->name); + dev->tbusy = 0; + fi->fc_stats.rx_dropped++; + dev->trans_start = jiffies; + return 0; + } + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", +dev->name); + fi->fc_stats.rx_dropped++; + return 1; + } + else { + struct fcllc *fcllc; + /* Strip off the pseudo header. + */ + skb->data = skb->data + 2*FC_ALEN; + skb->len = skb->len - 2*FC_ALEN; + fcllc = (struct fcllc *)skb->data; + type = ntohs(fcllc->ethertype); + + spin_lock_irqsave(&fi->fc_lock, flags); + switch(type) { + case ETH_P_IP: + status = tx_ip_packet(skb, skb->len, fi); + break; + case ETH_P_ARP: + status = tx_arp_packet(skb->data, skb->len, fi); + break; + default: + T_MSG("WARNING!!! Received Unknown Packet Type... Discarding..."); + fi->fc_stats.rx_dropped++; + break; + } + spin_unlock_irqrestore(&fi->fc_lock, flags); + } + + if (status) { + fi->fc_stats.tx_bytes += skb->len; + fi->fc_stats.tx_packets++; + } + else + fi->fc_stats.rx_dropped++; + dev->trans_start = jiffies; + dev->tbusy = 0; + /* We free up the IP buffers in the OCI_interrupt handler. + * status == 0 implies that the frame was not transmitted. So the + * skb is freed here. + */ + if ((type == ETH_P_ARP) || (status == 0)) + dev_kfree_skb(skb); + mark_bh(NET_BH); + LEAVE("iph5526_send_packet"); + return 0; +} + +static int iph5526_change_mtu(struct net_device *dev, int mtu) +{ + return 0; +} + +static int tx_ip_packet(struct sk_buff *skb, unsigned long len, struct fc_info *fi) +{ +u_int d_id; +int int_required = 1; +u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_DATA; +u_int type = TYPE_LLC_SNAP; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +u_int mtu; +struct fc_node_info *q; + + ENTER("tx_ip_packet"); + q = look_up_cache(fi, skb->data - 2*FC_ALEN); + if (q != NULL) { + d_id = q->d_id; + DPRINTK("Look-Up Cache Succeeded for d_id = %x", d_id); + mtu = q->mtu; + if (q->login == LOGIN_COMPLETED){ + fi->g.type_of_frame = FC_IP; + return tx_exchange(fi, skb->data, len, r_ctl, type, d_id, mtu, int_required, ox_id, virt_to_bus(skb)); + } + + if (q->d_id == BROADCAST) { + struct fc_node_info *p = fi->node_info_list; + int return_value = FALSE; + fi->g.type_of_frame = FC_BROADCAST; + /* Do unicast to local nodes. + */ + int_required = 0; + while(p != NULL) { + d_id = p->d_id; + if ((d_id & 0xFFFF00) == fi->g.my_ddaa) + return_value |= tx_exchange(fi, skb->data, len, r_ctl, type, d_id, fi->g.my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + p = p->next; + } + kfree(q); + return return_value; + } + + if (q->login != LOGIN_COMPLETED) { + DPRINTK1("Node not logged in... Txing PLOGI to %x", d_id); + /* FIXME: we are dumping the frame here */ + tx_logi(fi, ELS_PLOGI, d_id); + } + } + DPRINTK2("Look-Up Cache Failed"); + LEAVE("tx_ip_packet"); + return 0; +} + +static int tx_arp_packet(char *data, unsigned long len, struct fc_info *fi) +{ +u_int opcode = data[ARP_OPCODE_0]; +u_int d_id; +int int_required = 0, return_value = FALSE; +u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_DATA; +u_int type = TYPE_LLC_SNAP; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +u_int my_mtu = fi->g.my_mtu; + ENTER("tx_arp_packet"); + + opcode = opcode << 8 | data[ARP_OPCODE_1]; + fi->g.type_of_frame = FC_IP; + + if (opcode == ARPOP_REQUEST) { + struct fc_node_info *q = fi->node_info_list; + d_id = BROADCAST; + return_value |= tx_exchange(fi, data, len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + /* Some devices support HW_TYPE 0x01 */ + memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN); + fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01; + return_value |= tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + + /* Do unicast to local nodes. + */ + while(q != NULL) { + fi->g.type_of_frame = FC_BROADCAST; + d_id = q->d_id; + if ((d_id & 0xFFFF00) == fi->g.my_ddaa) { + return_value |= tx_exchange(fi, data, len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + // Some devices support HW_TYPE 0x01 + memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN); + fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01; + return_value |= tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + } + q = q->next; + } + return return_value; + } + else + if (opcode == ARPOP_REPLY) { + struct fc_node_info *q; u_int mtu; + DPRINTK("We are sending out an ARP reply"); + q = look_up_cache(fi, data - 2*FC_ALEN); + if (q != NULL) { + d_id = q->d_id; + DPRINTK("Look-Up Cache Succeeded for d_id = %x", d_id); + mtu = q->mtu; + if (q->login == LOGIN_COMPLETED){ + tx_exchange(fi, data, len, r_ctl, type, d_id, mtu, int_required, ox_id, TYPE_LLC_SNAP); + /* Some devices support HW_TYPE 0x01 */ + memcpy(fi->g.arp_buffer, data - 2*FC_ALEN, len + 2*FC_ALEN); + fi->g.arp_buffer[9 + 2*FC_ALEN] = 0x01; + return tx_exchange(fi, (char *)(fi->g.arp_buffer + 2*FC_ALEN), len, r_ctl, type, d_id, my_mtu, int_required, ox_id, TYPE_LLC_SNAP); + } + else { + DPRINTK1("Node not logged in... Txing PLOGI to %x", d_id); + tx_logi(fi, ELS_PLOGI, d_id); /* FIXME: we are dumping the frame here */ + } + } + DPRINTK2("Look-Up Cache Failed"); + } + else { + T_MSG("Warning!!! Invalid Opcode in ARP Packet!"); + } + LEAVE("tx_arp_packet"); + return 0; +} + + +static void rx_net_packet(struct fc_info *fi, u_char *buff_addr, int payload_size) +{ +struct net_device *dev = fi->dev; +struct sk_buff *skb; +u_int skb_size = 0; +struct fch_hdr fch; + ENTER("rx_net_packet"); + skb_size = payload_size - TACHYON_HEADER_LEN; + DPRINTK("skb_size = %d", skb_size); + fi->fc_stats.rx_bytes += skb_size - 2; + skb = dev_alloc_skb(skb_size); + if (skb == NULL) { + printk(KERN_NOTICE "%s: In rx_net_packet() Memory squeeze, dropping packet.\n", dev->name); + fi->fc_stats.rx_dropped++; + return; + } + /* Skip over the Tachyon Frame Header. + */ + buff_addr += TACHYON_HEADER_LEN; + + memcpy(fch.daddr, buff_addr + 2, FC_ALEN); + memcpy(fch.saddr, buff_addr + 10, FC_ALEN); + buff_addr += 2; + memcpy(buff_addr, fch.daddr, FC_ALEN); + memcpy(buff_addr + 6, fch.saddr, FC_ALEN); + skb_reserve(skb, 2); + memcpy(skb_put(skb, skb_size - 2), buff_addr, skb_size - 2); + skb->dev = dev; + skb->protocol = fc_type_trans(skb, dev); + DPRINTK("protocol = %x", skb->protocol); + + /* Hmmm... to accept HW Type 0x01 as well... + */ + if (skb->protocol == ntohs(ETH_P_ARP)) + skb->data[1] = 0x06; + netif_rx(skb); + fi->fc_stats.rx_packets++; + LEAVE("rx_net_packet"); +} + + +static void rx_net_mfs_packet(struct fc_info *fi, struct sk_buff *skb) +{ +struct net_device *dev = fi->dev; +struct fch_hdr fch; + ENTER("rx_net_mfs_packet"); + /* Construct your Hard Header */ + memcpy(fch.daddr, skb->data + 2, FC_ALEN); + memcpy(fch.saddr, skb->data + 10, FC_ALEN); + skb_pull(skb, 2); + memcpy(skb->data, fch.daddr, FC_ALEN); + memcpy(skb->data + 6, fch.saddr, FC_ALEN); + skb->dev = dev; + skb->protocol = fc_type_trans(skb, dev); + DPRINTK("protocol = %x", skb->protocol); + netif_rx(skb); + LEAVE("rx_net_mfs_packet"); +} + +unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev) +{ +struct fch_hdr *fch=(struct fch_hdr *)skb->data; +struct fcllc *fcllc; + skb->mac.raw = skb->data; + fcllc = (struct fcllc *)(skb->data + sizeof(struct fch_hdr) + 2); + skb_pull(skb,sizeof(struct fch_hdr) + 2); + + if(*fch->daddr & 1) { + if(!memcmp(fch->daddr,dev->broadcast,FC_ALEN)) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + else if(dev->flags & IFF_PROMISC) { + if(memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) + skb->pkt_type=PACKET_OTHERHOST; + } + + /* Strip the SNAP header from ARP packets since we don't + * pass them through to the 802.2/SNAP layers. + */ + + if (fcllc->dsap == EXTENDED_SAP && + (fcllc->ethertype == ntohs(ETH_P_IP) || + fcllc->ethertype == ntohs(ETH_P_ARP))) { + skb_pull(skb, sizeof(struct fcllc)); + return fcllc->ethertype; + } + return ntohs(ETH_P_802_2); +} + +static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short tx_ox_id, u_int frame_class) +{ +u_char df_ctl; +int NW_flag = 0, h_size, return_value; +u_short rx_id = RX_ID_FIRST_SEQUENCE; +u_int tachyon_status; +u_int my_id = fi->g.my_id; + ENTER("tx_exchange"); + + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + DPRINTK("Tachyon Status = %x len = %d MTU = %d", tachyon_status, len, mtu); + if (tachyon_status & OSM_FROZEN) { + reset_tachyon(fi, ERROR_RELEASE); + reset_tachyon(fi, OCQ_RESET); + DPRINTK("Tachyon Status = %x len = %d MTU = %d", tachyon_status, len, mtu); + } + if (tx_ox_id == OX_ID_FIRST_SEQUENCE) { + switch(fi->g.type_of_frame) { + case FC_SCSI_READ: + tx_ox_id = fi->g.scsi_oxid | SCSI_READ_BIT; + break; + case FC_SCSI_WRITE: + tx_ox_id = fi->g.scsi_oxid; + break; + default: + tx_ox_id = fi->g.ox_id; + break; + } + } + else { + switch(fi->g.type_of_frame) { + case FC_SCSI_READ: + rx_id = fi->g.scsi_oxid | SCSI_READ_BIT; + break; + case FC_SCSI_WRITE: + rx_id = fi->g.scsi_oxid; + break; + case FC_BLS: + rx_id = RX_ID_FIRST_SEQUENCE; + break; + default: + rx_id = fi->g.ox_id; + break; + } + } + + if (type == TYPE_LLC_SNAP) { + df_ctl = 0x20; + NW_flag = 1; + /* Multi Frame Sequence ? If yes, set RO bit */ + if (len > mtu) + type |= RELATIVE_OFF_PRESENT; + build_tachyon_header(fi, my_id, r_ctl, d_id, type, fi->g.seq_id, df_ctl, tx_ox_id, rx_id, data - 2*FC_ALEN); + } + else { + df_ctl = 0; + /* Multi Frame Sequence ? If yes, set RO bit */ + if (len > mtu) + type |= RELATIVE_OFF_PRESENT; + build_tachyon_header(fi, my_id, r_ctl, d_id, type, fi->g.seq_id, df_ctl, tx_ox_id, rx_id, NULL); + } + + /* Get free Tachyon Headers and EDBs */ + if (get_free_header(fi) || get_free_EDB(fi)) + return 0; + + if ((type & 0xFF000000) == TYPE_LLC_SNAP) { + h_size = TACHYON_HEADER_LEN + NW_HEADER_LEN; + memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), h_size); + } + else + memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), TACHYON_HEADER_LEN); + + return_value = tx_sequence(fi, data, len, mtu, d_id, tx_ox_id, rx_id, fi->g.seq_id, NW_flag, int_required, frame_class); + + switch(fi->g.type_of_frame) { + case FC_SCSI_READ: + case FC_SCSI_WRITE: + update_scsi_oxid(fi); + break; + case FC_BLS: + break; + default: + fi->g.ox_id++; + if (fi->g.ox_id == 0xFFFF) + fi->g.ox_id = NOT_SCSI_XID; + break; + } + + if (fi->g.seq_id == MAX_SEQ_ID) + fi->g.seq_id = 0; + else + fi->g.seq_id++; + LEAVE("tx_exchange"); + return return_value; +} + +static int tx_sequence(struct fc_info *fi, char *data, u_int len, u_int mtu, u_int d_id, u_short ox_id, u_short rx_id, u_char seq_id, int NW_flag, int int_required, u_int frame_class) +{ +u_int cntl = 0; +int return_value; + ENTER("tx_sequence"); + build_EDB(fi, data, EDB_END, len); + memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB)); + build_ODB(fi, seq_id, d_id, len, cntl, mtu, ox_id, rx_id, NW_flag, int_required, frame_class); + memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB)); + if (fi->g.link_up != TRUE) { + DPRINTK2("Fibre Channel Link not up. Dropping Exchange!"); + return_value = FALSE; + } + else { + /* To be on the safe side, a check should be included + * at this point to check if we are overrunning + * Tachyon. + */ + update_OCQ_indx(fi); + return_value = TRUE; + } + update_EDB_indx(fi); + update_tachyon_header_indx(fi); + LEAVE("tx_sequence"); + return return_value; +} + +static int get_free_header(struct fc_info *fi) +{ +u_short temp_ox_id; +u_int *tach_header, initial_indx = fi->q.tachyon_header_indx; + /* Check if the header is in use. + * We could have an outstanding command. + * We should find a free slot as we can queue a + * maximum of 32 SCSI commands only. + */ + tach_header = fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx]; + temp_ox_id = ntohl(*(tach_header + 6)) >> 16; + /* We care about the SCSI writes only. Those are the wicked ones + * that need an additional set of buffers. + */ + while(temp_ox_id <= MAX_SCSI_XID) { + update_tachyon_header_indx(fi); + if (fi->q.tachyon_header_indx == initial_indx) { + /* Should never happen. + */ + T_MSG("No free Tachyon headers available"); + reset_tachyon(fi, SOFTWARE_RESET); + return 1; + } + tach_header = fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx]; + temp_ox_id = ntohl(*(tach_header + 6)) >> 16; + } + return 0; +} + +static int get_free_EDB(struct fc_info *fi) +{ +unsigned int initial_indx = fi->q.edb_buffer_indx; + /* Check if the EDB is in use. + * We could have an outstanding SCSI Write command. + * We should find a free slot as we can queue a + * maximum of 32 SCSI commands only. + */ + while (fi->q.free_edb_list[fi->q.edb_buffer_indx] != EDB_FREE) { + update_EDB_indx(fi); + if (fi->q.edb_buffer_indx == initial_indx) { + T_MSG("No free EDB buffers avaliable") + reset_tachyon(fi, SOFTWARE_RESET); + return 1; + } + } + return 0; +} + +static int validate_login(struct fc_info *fi, u_int *base_ptr) +{ +struct fc_node_info *q = fi->node_info_list; +char n_port_name[PORT_NAME_LEN]; +char node_name[NODE_NAME_LEN]; +u_int s_id; + ENTER("validate_login"); + /*index to Port Name in the payload. We need the 8 byte Port Name */ + memcpy(n_port_name, base_ptr + 10, PORT_NAME_LEN); + memcpy(node_name, base_ptr + 12, NODE_NAME_LEN); + s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF; + + /* check if Fibre Channel IDs have changed */ + while(q != NULL) { + if (memcmp(n_port_name, q->hw_addr, PORT_NAME_LEN) == 0) { + if ((s_id != q->d_id) || (memcmp(node_name, q->node_name, NODE_NAME_LEN) != 0)) { + DPRINTK1("Fibre Channel ID of Node has changed. Txing LOGO."); + return 0; + } + q->login = LOGIN_COMPLETED; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return 1; + } + q = q->next; + } + DPRINTK1("Port Name does not match. Txing LOGO."); + return 0; + LEAVE("validate_login"); +} + +static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr) +{ +int size = sizeof(struct fc_node_info); +struct fc_node_info *p, *q = fi->node_info_list, *r = NULL; +char n_port_name[PORT_NAME_LEN]; +u_int s_id; + ENTER("add_to_address_cache"); + /*index to Port Name in the payload. We need the 8 byte Port Name */ + memcpy(n_port_name, base_ptr + 13, PORT_NAME_LEN); + s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF; + + /* check if info already exists */ + while(q != NULL) { + if (memcmp(n_port_name, q->hw_addr, PORT_NAME_LEN) == 0) { + if (s_id != q->d_id) { + memcpy(&(q->c_of_s[0]), base_ptr + 17, 3 * sizeof(CLASS_OF_SERVICE)); + q->mtu = ntohl(*(base_ptr + 10)) & 0x00000FFF; + q->d_id = s_id; + memcpy(q->node_name, base_ptr + 15, NODE_NAME_LEN); + } + q->login = LOGIN_COMPLETED; + q->scsi = FALSE; + fi->num_nodes++; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return; + } + r = q; + q = q->next; + } + p = (struct fc_node_info *)kmalloc(size, GFP_ATOMIC); + if (p == NULL) { + T_MSG("kmalloc failed in add_to_address_cache()"); + return; + } + memcpy(&(p->c_of_s[0]), base_ptr + 17, 3 * sizeof(CLASS_OF_SERVICE)); + p->mtu = ntohl(*(base_ptr + 10)) & 0x00000FFF; + p->d_id = s_id; + memcpy(p->hw_addr, base_ptr + 13, PORT_NAME_LEN); + memcpy(p->node_name, base_ptr + 15, NODE_NAME_LEN); + p->login = LOGIN_COMPLETED; + p->scsi = FALSE; + p->target_id = 0xFF; + p->next = NULL; + if (fi->node_info_list == NULL) + fi->node_info_list = p; + else + r->next = p; + fi->num_nodes++; +#if DEBUG_5526_2 + display_cache(fi); +#endif + LEAVE("add_to_address_cache"); + return; +} + +static void remove_from_address_cache(struct fc_info *fi, u_int *base_ptr, u_int cmnd_code) +{ +struct fc_node_info *q = fi->node_info_list; +u_int s_id; + ENTER("remove_from_address_cache"); + s_id = ntohl(*(base_ptr + 3)) & 0x00FFFFFF; + switch(cmnd_code) { + case ELS_LOGO: + /* check if info exists */ + while (q != NULL) { + if (s_id == q->d_id) { + if (q->login == LOGIN_COMPLETED) + q->login = LOGIN_ATTEMPTED; + if (fi->num_nodes > 0) + fi->num_nodes--; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return; + } + q = q->next; + } + DPRINTK1("ELS_LOGO received from node 0x%x which is not logged-in", s_id); + break; + case ELS_RSCN: + { + int payload_len = ntohl(*(base_ptr + 8)) & 0xFF; + int no_of_pages, i; + u_char address_format; + u_short received_ox_id = ntohl(*(base_ptr + 6)) >> 16; + u_int node_id, mask, *page_ptr = base_ptr + 9; + if ((payload_len < 4) || (payload_len > 256)) { + DPRINTK1("RSCN with invalid payload length received"); + tx_ls_rjt(fi, s_id, received_ox_id, LOGICAL_ERR, RECV_FIELD_SIZE); + return; + } + /* Page_size includes the Command Code */ + no_of_pages = (payload_len / 4) - 1; + for (i = 0; i < no_of_pages; i++) { + address_format = ntohl(*page_ptr) >> 24; + node_id = ntohl(*page_ptr) & 0x00FFFFFF; + switch(address_format) { + case PORT_ADDRESS_FORMAT: + rscn_handler(fi, node_id); + break; + case AREA_ADDRESS_FORMAT: + case DOMAIN_ADDRESS_FORMAT: + if (address_format == AREA_ADDRESS_FORMAT) + mask = 0xFFFF00; + else + mask = 0xFF0000; + while(q != NULL) { + if ((q->d_id & mask) == (node_id & mask)) + rscn_handler(fi, q->d_id); + q = q->next; + } + /* There might be some new nodes to be + * discovered. But, some of the earlier + * requests as a result of the RSCN might be + * in progress. We dont want to duplicate that + * effort. So letz call SCR after a lag. + */ + fi->explore_timer.function = scr_timer; + fi->explore_timer.data = (unsigned long)fi; + fi->explore_timer.expires = RUN_AT((no_of_pages*3*HZ)/100); + init_timer(&fi->explore_timer); + add_timer(&fi->explore_timer); + break; + default: + T_MSG("RSCN with invalid address format received"); + tx_ls_rjt(fi, s_id, received_ox_id, LOGICAL_ERR, NO_EXPLN); + } + page_ptr += 1; + } /* end of for loop */ + } /* end of case RSCN: */ + break; + } +#if DEBUG_5526_2 + display_cache(fi); +#endif + LEAVE("remove_from_address_cache"); +} + +static void rscn_handler(struct fc_info *fi, u_int node_id) +{ +struct fc_node_info *q = fi->node_info_list; +int login_state = sid_logged_in(fi, node_id); + if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) { + while(q != NULL) { + if (q->d_id == node_id) { + q->login = LOGIN_ATTEMPTED; + if (fi->num_nodes > 0) + fi->num_nodes--; + break; + } + else + q = q->next; + } + } + else + if (login_state == NODE_LOGGED_OUT) + tx_adisc(fi, ELS_ADISC, node_id, OX_ID_FIRST_SEQUENCE); + else + if (login_state == NODE_LOGGED_OUT) + tx_logi(fi, ELS_PLOGI, node_id); +} + +static void scr_timer(unsigned long data) +{ +struct fc_info *fi = (struct fc_info *)data; + del_timer(&fi->explore_timer); + tx_name_server_req(fi, FCS_GP_ID4); +} + +static int sid_logged_in(struct fc_info *fi, u_int s_id) +{ +struct fc_node_info *temp = fi->node_info_list; + while(temp != NULL) + if ((temp->d_id == s_id) && (temp->login == LOGIN_COMPLETED)) { + if (temp->scsi != FALSE) + return NODE_PROCESS_LOGGED_IN; + else + return NODE_LOGGED_IN; + } + else + if ((temp->d_id == s_id) && (temp->login != LOGIN_COMPLETED)) + return NODE_LOGGED_OUT; + else + temp = temp->next; + return NODE_NOT_PRESENT; +} + +static void mark_scsi_sid(struct fc_info *fi, u_int *buff_addr, u_char action) +{ +struct fc_node_info *temp = fi->node_info_list; +u_int s_id; +u_int service_params; + s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + service_params = ntohl(*(buff_addr + 12)) & 0x000000F0; + while(temp != NULL) + if ((temp->d_id == s_id) && (temp->login == LOGIN_COMPLETED)) { + if (action == DELETE_ENTRY) { + temp->scsi = FALSE; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return; + } + /* Check if it is a SCSI Target */ + if (!(service_params & TARGET_FUNC)) { + temp->scsi = INITIATOR; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return; + } + temp->scsi = TARGET; + /* This helps to maintain the target_id no matter what your + * Fibre Channel ID is. + */ + if (temp->target_id == 0xFF) { + if (fi->g.no_of_targets <= MAX_SCSI_TARGETS) + temp->target_id = fi->g.no_of_targets++; + else + T_MSG("MAX TARGETS reached!"); + } + else + DPRINTK1("Target_id %d already present", temp->target_id); +#if DEBUG_5526_2 + display_cache(fi); +#endif + return; + } + else + temp = temp->next; + return; +} + +static int node_logged_in_prev(struct fc_info *fi, u_int *buff_addr) +{ +struct fc_node_info *temp; +u_char *data = (u_char *)buff_addr; +u_int s_id; +char node_name[NODE_NAME_LEN]; + s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; + memcpy(node_name, buff_addr + 12, NODE_NAME_LEN); + /* point to port_name in the ADISC payload */ + data += 10 * 4; + /* point to last 6 bytes of port_name */ + data += 2; + temp = look_up_cache(fi, data); + if (temp != NULL) { + if ((temp->d_id == s_id) && (memcmp(node_name, temp->node_name, NODE_NAME_LEN) == 0)) { + temp->login = LOGIN_COMPLETED; +#if DEBUG_5526_2 + display_cache(fi); +#endif + return TRUE; + } + } + return FALSE; +} + +static struct fc_node_info *look_up_cache(struct fc_info *fi, char *data) +{ +struct fc_node_info *temp_list = fi->node_info_list, *q; +u_char n_port_name[FC_ALEN], temp_addr[FC_ALEN]; + ENTER("look_up_cache"); + memcpy(n_port_name, data, FC_ALEN); + while(temp_list) { + if (memcmp(n_port_name, &(temp_list->hw_addr[2]), FC_ALEN) == 0) + return temp_list; + else + temp_list = temp_list->next; + } + + /* Broadcast IP ? + */ + temp_addr[0] = temp_addr[1] = temp_addr[2] = 0xFF; + temp_addr[3] = temp_addr[4] = temp_addr[5] = 0xFF; + if (memcmp(n_port_name, temp_addr, FC_ALEN) == 0) { + q = (struct fc_node_info *)kmalloc(sizeof(struct fc_node_info), GFP_ATOMIC); + if (q == NULL) { + T_MSG("kmalloc failed in look_up_cache()"); + return NULL; + } + q->d_id = BROADCAST; + return q; + } + LEAVE("look_up_cache"); + return NULL; +} + +static int display_cache(struct fc_info *fi) +{ +struct fc_node_info *q = fi->node_info_list; +#if DEBUG_5526_2 +struct ox_id_els_map *temp_ox_id_list = fi->ox_id_list; +#endif +int count = 0, j; + printk("\nFibre Channel Node Information for %s\n", fi->name); + printk("My FC_ID = %x, My WWN = %x %x, ", fi->g.my_id, fi->g.my_node_name_high, fi->g.my_node_name_low); + if (fi->g.ptp_up == TRUE) + printk("Port_Type = N_Port\n"); + if (fi->g.loop_up == TRUE) + printk("Port_Type = L_Port\n"); + while(q != NULL) { + printk("WWN = "); + for (j = 0; j < PORT_NAME_LEN; j++) + printk("%x ", q->hw_addr[j]); + printk("FC_ID = %x, ", q->d_id); + printk("Login = "); + if (q->login == LOGIN_COMPLETED) + printk("ON "); + else + printk("OFF "); + if (q->scsi == TARGET) + printk("Target_ID = %d ", q->target_id); + printk("\n"); + q = q->next; + count++; + } + +#if DEBUG_5526_2 + printk("OX_ID -> ELS Map\n"); + while(temp_ox_id_list) { + printk("ox_id = %x, ELS = %x\n", temp_ox_id_list->ox_id, temp_ox_id_list->els); + temp_ox_id_list = temp_ox_id_list->next; + } +#endif + + return 0; +} + +static struct net_device_stats * iph5526_get_stats(struct net_device *dev) +{ +struct fc_info *fi = (struct fc_info*)dev->priv; + return (struct net_device_stats *) &fi->fc_stats; +} + + +/* SCSI stuff starts here */ + +static struct proc_dir_entry proc_scsi_iph5526 = { + PROC_SCSI_IPH5526_FC, 7, "iph5526", S_IFDIR, S_IRUGO | S_IXUGO, 2 +}; + + +int iph5526_detect(Scsi_Host_Template *tmpt) +{ +struct Scsi_Host *host = NULL; +struct iph5526_hostdata *hostdata; +struct fc_info *fi = NULL; +int no_of_hosts = 0, timeout, i, j, count = 0; +u_int pci_maddr = 0; +struct pci_dev *pdev = NULL; + + tmpt->proc_dir = &proc_scsi_iph5526; + if (pci_present() == 0) { + printk("iph5526: PCI not present\n"); + return 0; + } + + for (i = 0; i <= MAX_FC_CARDS; i++) + fc[i] = NULL; + + for (i = 0; i < clone_list[i].vendor_id != 0; i++) + while ((pdev = pci_find_device(clone_list[i].vendor_id, clone_list[i].device_id, pdev))) { + unsigned short pci_command; + if (count < MAX_FC_CARDS) { + fc[count] = kmalloc(sizeof(struct fc_info), GFP_ATOMIC); + if (fc[count] == NULL) { + printk("iph5526.c: Unable to register card # %d\n", count + 1); + return no_of_hosts; + } + memset(fc[count], 0, sizeof(struct fc_info)); + } + else { + printk("iph5526.c: Maximum Number of cards reached.\n"); + return no_of_hosts; + } + + fi = fc[count]; + sprintf(fi->name, "fc%d", count); + + host = scsi_register(tmpt, sizeof(struct iph5526_hostdata)); + hostdata = (struct iph5526_hostdata *)host->hostdata; + memset(hostdata, 0 , sizeof(struct iph5526_hostdata)); + for (j = 0; j < MAX_SCSI_TARGETS; j++) + hostdata->tag_ages[j] = jiffies; + hostdata->fi = fi; + fi->host = host; + //host->max_id = MAX_SCSI_TARGETS; + host->max_id = 5; + host->hostt->use_new_eh_code = 1; + host->this_id = tmpt->this_id; + + pci_maddr = pdev->resource[0].start; + if ( (pdev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { + printk("iph5526.c : Cannot find proper PCI device base address.\n"); + scsi_unregister(host); + kfree(fc[count]); + fc[count] = NULL; + continue; + } + + DPRINTK("pci_maddr = %x", pci_maddr); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + + pci_irq_line = pdev->irq; + printk("iph5526.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", clone_list[i].name, pci_maddr, pci_irq_line); + fi->g.mem_base = ioremap(pci_maddr & PAGE_MASK, 1024); + + /* We use Memory Mapped IO. The initial space contains the + * PCI Configuration registers followed by the (i) chip + * registers followed by the Tachyon registers. + */ + /* Thatz where (i)chip maps Tachyon Address Space. + */ + fi->g.tachyon_base = (u_long)fi->g.mem_base + TACHYON_OFFSET + ( pci_maddr & ~PAGE_MASK ); + DPRINTK("fi->g.tachyon_base = %x", (u_int)fi->g.tachyon_base); + if (fi->g.mem_base == NULL) { + printk("iph5526.c : ioremap failed!!!\n"); + scsi_unregister(host); + kfree(fc[count]); + fc[count] = NULL; + continue; + } + DPRINTK("IRQ1 = %d\n", pci_irq_line); + printk(version); + fi->base_addr = (long) pdev; + + if (pci_irq_line) { + int irqval = 0; + /* Found it, get IRQ. + */ + irqval = request_irq(pci_irq_line, &tachyon_interrupt, pci_irq_line ? SA_SHIRQ : 0, fi->name, host); + if (irqval) { + printk("iph5526.c : Unable to get IRQ %d (irqval = %d).\n", pci_irq_line, irqval); + scsi_unregister(host); + kfree(fc[count]); + fc[count] = NULL; + continue; + } + host->irq = fi->irq = pci_irq_line; + pci_irq_line = 0; + fi->clone_id = clone_list[i].vendor_id; + } + + if (!initialize_register_pointers(fi) || !tachyon_init(fi)) { + printk("iph5526.c: TACHYON initialization failed for card # %d!!!\n", count + 1); + free_irq(host->irq, host); + scsi_unregister(host); + if (fi) + clean_up_memory(fi); + kfree(fc[count]); + fc[count] = NULL; + break; + } + DPRINTK1("Fibre Channel card initialized"); + /* Wait for the Link to come up and the login process + * to complete. + */ + for(timeout = jiffies + 10*HZ; (timeout > jiffies) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));) + barrier(); + + count++; + no_of_hosts++; + } + DPRINTK1("no_of_hosts = %d",no_of_hosts); + + /* This is to make sure that the ACC to the PRLI comes in + * for the last ALPA. + */ + udelay(1000000); /* Ugly! Let the Gods forgive me */ + + DPRINTK1("leaving iph5526_detect\n"); + return no_of_hosts; +} + + +int iph5526_biosparam(Disk * disk, kdev_t n, int ip[]) +{ +int size = disk->capacity; + 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]); + } + return 0; +} + +int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *)) +{ +int int_required = 0; +u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_COMMAND; +u_int type = TYPE_FCP | SEQUENCE_INITIATIVE; +u_int frame_class = Cmnd->target; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +struct Scsi_Host *host = Cmnd->host; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata*)host->hostdata; +struct fc_info *fi = hostdata->fi; +struct fc_node_info *q; +u_long flags; + ENTER("iph5526_queuecommand"); + + spin_lock_irqsave(&fi->fc_lock, flags); + Cmnd->scsi_done = done; + + if (Cmnd->device->tagged_supported) { + switch(Cmnd->tag) { + case SIMPLE_QUEUE_TAG: + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_SIMPLE; + break; + case HEAD_OF_QUEUE_TAG: + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_HEAD_OF_Q; + break; + case ORDERED_QUEUE_TAG: + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_ORDERED; + break; + default: + if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (5 * HZ)) { + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_ORDERED; + hostdata->tag_ages[Cmnd->target] = jiffies; + } + else + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_SIMPLE; + break; + } + } + /*else + hostdata->cmnd.fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED; + */ + + hostdata->cmnd.fcp_addr[3] = 0; + hostdata->cmnd.fcp_addr[2] = 0; + hostdata->cmnd.fcp_addr[1] = 0; + hostdata->cmnd.fcp_addr[0] = htons(Cmnd->lun); + + memcpy(&hostdata->cmnd.fcp_cdb, Cmnd->cmnd, Cmnd->cmd_len); + hostdata->cmnd.fcp_data_len = htonl(Cmnd->request_bufflen); + + /* Get an used OX_ID. We could have pending commands. + */ + if (get_scsi_oxid(fi)) + return 1; + fi->q.free_scsi_oxid[fi->g.scsi_oxid] = OXID_INUSE; + + /* Maintain a handler so that we can associate the done() function + * on completion of the SCSI command. + */ + hostdata->cmnd_handler[fi->g.scsi_oxid] = Cmnd; + + switch(Cmnd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + fi->g.type_of_frame = FC_SCSI_WRITE; + hostdata->cmnd.fcp_cntl = htonl(FCP_CNTL_WRITE | hostdata->cmnd.fcp_cntl); + break; + default: + fi->g.type_of_frame = FC_SCSI_READ; + hostdata->cmnd.fcp_cntl = htonl(FCP_CNTL_READ | hostdata->cmnd.fcp_cntl); + } + + memcpy(fi->q.ptr_fcp_cmnd[fi->q.fcp_cmnd_indx], &(hostdata->cmnd), sizeof(fcp_cmd)); + + q = resolve_target(fi, Cmnd->target); + + if (q == NULL) { + u_int bad_id = fi->g.my_ddaa | 0xFE; + /* We transmit to an non-existant AL_PA so that the "done" + * function can be called while receiving the interrupt + * due to a Timeout for a bad AL_PA. In a PTP configuration, + * the int_required field is set, since there is no notion + * of AL_PAs. This approach sucks, but works alright! + */ + if (fi->g.ptp_up == TRUE) + int_required = 1; + tx_exchange(fi, (char *)(&(hostdata->cmnd)), sizeof(fcp_cmd), r_ctl, type, bad_id, fi->g.my_mtu, int_required, ox_id, FC_SCSI_BAD_TARGET); + spin_unlock_irqrestore(&fi->fc_lock, flags); + DPRINTK1("Target ID %x not present", Cmnd->target); + return 0; + } + if (q->login == LOGIN_COMPLETED) { + if (add_to_sest(fi, Cmnd, q)) { + DPRINTK1("add_to_sest() failed."); + spin_unlock_irqrestore(&fi->fc_lock, flags); + return 0; + } + tx_exchange(fi, (char *)(fi->q.ptr_fcp_cmnd[fi->q.fcp_cmnd_indx]), sizeof(fcp_cmd), r_ctl, type, q->d_id, q->mtu, int_required, ox_id, frame_class << 16); + update_FCP_CMND_indx(fi); + } + spin_unlock_irqrestore(&fi->fc_lock, flags); + /* If q != NULL, then we have a SCSI Target. + * If q->login != LOGIN_COMPLETED, then that device could be + * offline temporarily. So we let the command to time-out. + */ + LEAVE("iph5526_queuecommand"); + return 0; +} + +int iph5526_abort(Scsi_Cmnd *Cmnd) +{ +struct Scsi_Host *host = Cmnd->host; +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; +struct fc_info *fi = hostdata->fi; +struct fc_node_info *q; +u_int r_ctl = FC4_DEVICE_DATA | UNSOLICITED_COMMAND; +u_int type = TYPE_FCP | SEQUENCE_INITIATIVE; +u_short ox_id = OX_ID_FIRST_SEQUENCE; +int int_required = 1, i, abort_status = FALSE; +u_long flags; + + ENTER("iph5526_abort"); + + spin_lock_irqsave(&fi->fc_lock, flags); + + q = resolve_target(fi, Cmnd->target); + if (q == NULL) { + u_int bad_id = fi->g.my_ddaa | 0xFE; + /* This should not happen as we should always be able to + * resolve a target id. But, jus in case... + * We transmit to an non-existant AL_PA so that the done + * function can be called while receiving the interrupt + * for a bad AL_PA. + */ + DPRINTK1("Unresolved Target ID!"); + tx_exchange(fi, (char *)(&(hostdata->cmnd)), sizeof(fcp_cmd), r_ctl, type, bad_id, fi->g.my_mtu, int_required, ox_id, FC_SCSI_BAD_TARGET); + DPRINTK1("Target ID %x not present", Cmnd->target); + spin_unlock_irqrestore(&fi->fc_lock, flags); + return FAILED; + } + + /* If q != NULL, then we have a SCSI Target. If + * q->login != LOGIN_COMPLETED, then that device could + * be offline temporarily. So we let the command to time-out. + */ + + /* Get the OX_ID for the Command to be aborted. + */ + for (i = 0; i <= MAX_SCSI_XID; i++) { + if (hostdata->cmnd_handler[i] == Cmnd) { + hostdata->cmnd_handler[i] = NULL; + ox_id = i; + break; + } + } + if (i > MAX_SCSI_XID) { + T_MSG("Command could not be resolved to OX_ID"); + spin_unlock_irqrestore(&fi->fc_lock, flags); + return FAILED; + } + + switch(Cmnd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + break; + default: + ox_id |= SCSI_READ_BIT; + } + abort_status = abort_exchange(fi, ox_id); + + if ((q->login == LOGIN_COMPLETED) && (abort_status == TRUE)) { + /* Then, transmit an ABTS to the target. The rest + * is done when the BA_ACC is received for the ABTS. + */ + tx_abts(fi, q->d_id, ox_id); + } + else { + u_int STE_bit; + u_short x_id; + /* Invalidate resources for that Exchange. + */ + x_id = ox_id & MAX_SCSI_XID; + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + if (STE_bit & SEST_V) { + *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); + invalidate_SEST_entry(fi, ox_id); + } + } + + LEAVE("iph5526_abort"); + spin_unlock_irqrestore(&fi->fc_lock, flags); + return SUCCESS; +} + +static int abort_exchange(struct fc_info *fi, u_short ox_id) +{ +u_short x_id; +volatile u_int flush_SEST, STE_bit; + x_id = ox_id & MAX_SCSI_XID; + DPRINTK1("Aborting Exchange %x", ox_id); + + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + /* Is the Exchange still active?. + */ + if (STE_bit & SEST_V) { + if (ox_id & SCSI_READ_BIT) { + /* If the Exchange to be aborted is Inbound, + * Flush the SEST Entry from Tachyon's Cache. + */ + *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); + flush_tachyon_cache(fi, ox_id); + flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg); + while ((flush_SEST & 0x80000000) != 0) + flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg); + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + while ((STE_bit & 0x80000000) != 0) + STE_bit = ntohl(*fi->q.ptr_sest[x_id]); + flush_SEST = readl(fi->t_r.ptr_tach_flush_oxid_reg); + invalidate_SEST_entry(fi, ox_id); + } + else { + int i; + u_int *ptr_edb; + /* For In-Order Reassembly, the following is done: + * First, write zero as the buffer length in the EDB. + */ + ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7))); + for (i = 0; i < EDB_LEN; i++) + if (fi->q.ptr_edb[i] == ptr_edb) + break; + if (i < EDB_LEN) + *ptr_edb = *ptr_edb & 0x0000FFFF; + else + T_MSG("EDB not found while clearing in abort_exchange()"); + } + DPRINTK1("Exchange %x invalidated", ox_id); + return TRUE; + } + else { + DPRINTK1("SEST Entry for exchange %x not valid", ox_id); + return FALSE; + } +} + +static void flush_tachyon_cache(struct fc_info *fi, u_short ox_id) +{ +volatile u_int tachyon_status; + if (fi->g.loop_up == TRUE) { + writel(HOST_CONTROL, fi->t_r.ptr_fm_control_reg); + /* Make sure that the Inbound FIFO is empty. + */ + do { + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + udelay(200); + }while ((tachyon_status & RECEIVE_FIFO_EMPTY) == 0); + /* Ok. Go ahead and flushhhhhhhhh! + */ + writel(0x80000000 | ox_id, fi->t_r.ptr_tach_flush_oxid_reg); + writel(EXIT_HOST_CONTROL, fi->t_r.ptr_fm_control_reg); + return; + } + if (fi->g.ptp_up == TRUE) { + take_tachyon_offline(fi); + /* Make sure that the Inbound FIFO is empty. + */ + do { + tachyon_status = readl(fi->t_r.ptr_tach_status_reg); + udelay(200); + }while ((tachyon_status & RECEIVE_FIFO_EMPTY) == 0); + writel(0x80000000 | ox_id, fi->t_r.ptr_tach_flush_oxid_reg); + /* Write the Initialize command to the FM Control reg. + */ + fi->g.n_port_try = TRUE; + DPRINTK1("In abort_exchange, TACHYON initializing as N_Port...\n"); + writel(INITIALIZE, fi->t_r.ptr_fm_control_reg); + } +} + +static struct fc_node_info *resolve_target(struct fc_info *fi, u_char target) +{ +struct fc_node_info *temp = fi->node_info_list; + while(temp != NULL) + if (temp->target_id == target) { + if ((temp->scsi == TARGET) && (temp->login == LOGIN_COMPLETED)) + return temp; + else { + if (temp->login != LOGIN_COMPLETED) { + /* The Target is not currently logged in. + * It could be a Target on the Local Loop or + * on a Remote Loop connected through a switch. + * In either case, we will know whenever the Target + * comes On-Line again. We let the command to + * time-out so that it gets retried. + */ + T_MSG("Target %d not logged in.", temp->target_id); + tx_logi(fi, ELS_PLOGI, temp->d_id); + return temp; + } + else { + if (temp->scsi != TARGET) { + /* For some reason, we did not get a response to + * PRLI. Letz try it again... + */ + DPRINTK1("Node not PRLIied. Txing PRLI..."); + tx_prli(fi, ELS_PRLI, temp->d_id, OX_ID_FIRST_SEQUENCE); + } + } + return temp; + } + } + else + temp = temp->next; + return NULL; +} + +static int add_to_sest(struct fc_info *fi, Scsi_Cmnd *Cmnd, struct fc_node_info *ni) +{ +/* we have at least 1 buffer, the terminator */ +int no_of_sdb_buffers = 1, i; +int no_of_edb_buffers = 0; +u_int *req_buffer = (u_int *)Cmnd->request_buffer; +u_int *ptr_sdb = NULL; +struct scatterlist *sl1, *sl2 = NULL; +int no_of_sg = 0; + + switch(fi->g.type_of_frame) { + case FC_SCSI_READ: + fi->g.inb_sest_entry.flags_and_byte_offset = htonl(INB_SEST_VED); + fi->g.inb_sest_entry.byte_count = 0; + fi->g.inb_sest_entry.no_of_recvd_frames = 0; + fi->g.inb_sest_entry.no_of_expected_frames = 0; + fi->g.inb_sest_entry.last_fctl = 0; + + if (Cmnd->use_sg) { + no_of_sg = Cmnd->use_sg; + sl1 = sl2 = (struct scatterlist *)Cmnd->request_buffer; + for (i = 0; i < no_of_sg; i++) { + no_of_sdb_buffers += sl1->length / SEST_BUFFER_SIZE; + if (sl1->length % SEST_BUFFER_SIZE) + no_of_sdb_buffers++; + sl1++; + } + } + else { + no_of_sdb_buffers += Cmnd->request_bufflen / SEST_BUFFER_SIZE; + if (Cmnd->request_bufflen % SEST_BUFFER_SIZE) + no_of_sdb_buffers++; + } /* if !use_sg */ + + /* We are working with the premise that at the max we would + * get a scatter-gather buffer containing 63 buffers + * of size 1024 bytes each. Is it a _bad_ assumption? + */ + if (no_of_sdb_buffers > 512) { + T_MSG("Number of SDB buffers needed = %d", no_of_sdb_buffers); + T_MSG("Disable Scatter-Gather!!!"); + return 1; + } + + + /* Store it in the sdb_table so that we can retrieve that + * free up the memory when the Read Command completes. + */ + if (get_free_SDB(fi)) + return 1; + ptr_sdb = fi->q.ptr_sdb_slot[fi->q.sdb_indx]; + fi->q.sdb_slot_status[fi->q.sdb_indx] = SDB_BUSY; + fi->g.inb_sest_entry.sdb_address = htonl(virt_to_bus(ptr_sdb)); + + if (Cmnd->use_sg) { + int count = 0, j; + for(i = 0; i < no_of_sg; i++) { + char *addr_ptr = sl2->address; + count = sl2->length / SEST_BUFFER_SIZE; + if (sl2->length % SEST_BUFFER_SIZE) + count++; + for (j = 0; j < count; j++) { + *(ptr_sdb) = htonl(virt_to_bus(addr_ptr)); + addr_ptr += SEST_BUFFER_SIZE; + ptr_sdb++; + } + count = 0; + sl2++; + } + } + else { + for (i = 0; i < no_of_sdb_buffers - 1; i++) { + *(ptr_sdb) = htonl(virt_to_bus(req_buffer)); + req_buffer += SEST_BUFFER_SIZE/4; + ptr_sdb++; + } + } + *(ptr_sdb) = htonl(0x1); /* Terminator */ + + /* The scratch pad is used to hold the index into the SDB. + */ + fi->g.inb_sest_entry.scratch_pad = fi->q.sdb_indx; + fi->g.inb_sest_entry.expected_ro = 0; + fi->g.inb_sest_entry.buffer_index = 0; + fi->g.inb_sest_entry.buffer_offset = 0; + memcpy(fi->q.ptr_sest[fi->g.scsi_oxid], &fi->g.inb_sest_entry, sizeof(INB_SEST_ENTRY)); + break; + case FC_SCSI_WRITE: + fi->g.outb_sest_entry.flags_and_did = htonl(OUTB_SEST_VED | ni->d_id); + fi->g.outb_sest_entry.max_frame_len = htons(ni->mtu << 4); + fi->g.outb_sest_entry.cntl = htons(ODB_CLASS_3 | ODB_EE_CREDIT | ODB_NO_INT | ODB_NO_COMP); + fi->g.outb_sest_entry.total_seq_length = INV_SEQ_LEN; + fi->g.outb_sest_entry.link = htons(OUTB_SEST_LINK); + fi->g.outb_sest_entry.transaction_id = htonl(fi->g.scsi_oxid); + fi->g.outb_sest_entry.seq_id = fi->g.seq_id; + fi->g.outb_sest_entry.reserved = 0x0; + fi->g.outb_sest_entry.header_length = htons(TACHYON_HEADER_LEN); + + { + u_char df_ctl = 0; + u_short rx_id = RX_ID_FIRST_SEQUENCE; + u_int r_ctl = FC4_DEVICE_DATA | SOLICITED_DATA; + u_int type = TYPE_FCP | SEQUENCE_INITIATIVE; + /* Multi Frame Sequence ? If yes, set RO bit. + */ + if (Cmnd->request_bufflen > ni->mtu) + type |= RELATIVE_OFF_PRESENT; + build_tachyon_header(fi, fi->g.my_id, r_ctl, ni->d_id, type, fi->g.seq_id, df_ctl, fi->g.scsi_oxid, rx_id, NULL); + if (get_free_header(fi) || get_free_EDB(fi)) + return 1; + memcpy(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx], &(fi->g.tach_header), TACHYON_HEADER_LEN); + fi->g.outb_sest_entry.header_address = htonl(virt_to_bus(fi->q.ptr_tachyon_header[fi->q.tachyon_header_indx])); + update_tachyon_header_indx(fi); + } + + if (Cmnd->use_sg) { + no_of_sg = Cmnd->use_sg; + sl1 = sl2 = (struct scatterlist *)Cmnd->request_buffer; + for (i = 0; i < no_of_sg; i++) { + no_of_edb_buffers += sl1->length / SEST_BUFFER_SIZE; + if (sl1->length % SEST_BUFFER_SIZE) + no_of_edb_buffers++; + sl1++; + } + } + else { + no_of_edb_buffers += Cmnd->request_bufflen / SEST_BUFFER_SIZE; + if (Cmnd->request_bufflen % SEST_BUFFER_SIZE) + no_of_edb_buffers++; + } /* if !use_sg */ + + + /* We need "no_of_edb_buffers" _contiguous_ EDBs + * that are FREE. Check for that first. + */ + for (i = 0; i < no_of_edb_buffers; i++) { + int j; + if ((fi->q.edb_buffer_indx + no_of_edb_buffers) >= EDB_LEN) + fi->q.edb_buffer_indx = 0; + if (fi->q.free_edb_list[fi->q.edb_buffer_indx + i] != EDB_FREE) { + for (j = 0; j < i; j++) + update_EDB_indx(fi); + if (get_free_EDB(fi)) + return 1; + i = 0; + } + } + + /* We got enuff FREE EDBs. + */ + if (Cmnd->use_sg) { + fi->g.outb_sest_entry.edb_address = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx])); + sl1 = (struct scatterlist *)Cmnd->request_buffer; + for(i = 0; i < no_of_sg; i++) { + int count = 0, j; + count = sl1->length / SEST_BUFFER_SIZE; + for (j = 0; j < count; j++) { + build_EDB(fi, (char *)sl1->address, 0, SEST_BUFFER_SIZE); + memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB)); + /* Mark this EDB as being in use */ + fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY; + /* We have already made sure that we have enuff + * free EDBs that are contiguous. So this is + * safe. + */ + update_EDB_indx(fi); + sl1->address += SEST_BUFFER_SIZE; + } + /* Just in case itz not a multiple of + * SEST_BUFFER_SIZE bytes. + */ + if (sl1->length % SEST_BUFFER_SIZE) { + build_EDB(fi, (char *)sl1->address, 0, sl1->length % SEST_BUFFER_SIZE); + memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB)); + fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY; + update_EDB_indx(fi); + } + sl1++; + } + /* The last EDB is special. It needs the "end bit" to + * be set. + */ + *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) = *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) | ntohs(EDB_END); + } + else { + int count = 0, j; + fi->g.outb_sest_entry.edb_address = htonl(virt_to_bus(fi->q.ptr_edb[fi->q.edb_buffer_indx])); + count = Cmnd->request_bufflen / SEST_BUFFER_SIZE; + for (j = 0; j < count; j++) { + build_EDB(fi, (char *)req_buffer, 0, SEST_BUFFER_SIZE); + memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB)); + /* Mark this EDB as being in use */ + fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY; + /* We have already made sure that we have enuff + * free EDBs that are contiguous. So this is + * safe. + */ + update_EDB_indx(fi); + req_buffer += SEST_BUFFER_SIZE; + } + /* Just in case itz not a multiple of + * SEST_BUFFER_SIZE bytes. + */ + if (Cmnd->request_bufflen % SEST_BUFFER_SIZE) { + build_EDB(fi, (char *)req_buffer, EDB_END, Cmnd->request_bufflen % SEST_BUFFER_SIZE); + memcpy(fi->q.ptr_edb[fi->q.edb_buffer_indx], &(fi->g.edb), sizeof(EDB)); + fi->q.free_edb_list[fi->q.edb_buffer_indx] = EDB_BUSY; + update_EDB_indx(fi); + } + else { + /* Mark the last EDB as the "end edb". + */ + *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) = *(fi->q.ptr_edb[fi->q.edb_buffer_indx - 1] + 1) | htons(EDB_END); + } + } + + /* Finally we have something to send!. + */ + memcpy(fi->q.ptr_sest[fi->g.scsi_oxid], &fi->g.outb_sest_entry, sizeof(OUTB_SEST_ENTRY)); + break; + } + return 0; +} + +static void update_FCP_CMND_indx(struct fc_info *fi) +{ + fi->q.fcp_cmnd_indx++; + if (fi->q.fcp_cmnd_indx == NO_OF_FCP_CMNDS) + fi->q.fcp_cmnd_indx = 0; +} + +static int get_scsi_oxid(struct fc_info *fi) +{ +u_short initial_oxid = fi->g.scsi_oxid; + /* Check if the OX_ID is in use. + * We could have an outstanding SCSI command. + */ + while (fi->q.free_scsi_oxid[fi->g.scsi_oxid] != OXID_AVAILABLE) { + update_scsi_oxid(fi); + if (fi->g.scsi_oxid == initial_oxid) { + T_MSG("No free OX_IDs avaliable") + reset_tachyon(fi, SOFTWARE_RESET); + return 1; + } + } + return 0; +} + +static void update_scsi_oxid(struct fc_info *fi) +{ + fi->g.scsi_oxid++; + if (fi->g.scsi_oxid == (MAX_SCSI_XID + 1)) + fi->g.scsi_oxid = 0; +} + +static int get_free_SDB(struct fc_info *fi) +{ +unsigned int initial_indx = fi->q.sdb_indx; + /* Check if the SDB is in use. + * We could have an outstanding SCSI Read command. + * We should find a free slot as we can queue a + * maximum of 32 SCSI commands only. + */ + while (fi->q.sdb_slot_status[fi->q.sdb_indx] != SDB_FREE) { + update_SDB_indx(fi); + if (fi->q.sdb_indx == initial_indx) { + T_MSG("No free SDB buffers avaliable") + reset_tachyon(fi, SOFTWARE_RESET); + return 1; + } + } + return 0; +} + +static void update_SDB_indx(struct fc_info *fi) +{ + fi->q.sdb_indx++; + if (fi->q.sdb_indx == NO_OF_SDB_ENTRIES) + fi->q.sdb_indx = 0; +} + +int iph5526_release(struct Scsi_Host *host) +{ +struct iph5526_hostdata *hostdata = (struct iph5526_hostdata*)host->hostdata; +struct fc_info *fi = hostdata->fi; + free_irq(host->irq, host); + iounmap(fi->g.mem_base); + return 0; +} + +const char *iph5526_info(struct Scsi_Host *host) +{ +static char buf[80]; + sprintf(buf, "Interphase 5526 Fibre Channel PCI SCSI Adapter using IRQ %d\n", host->irq); + return buf; +} + +#ifdef MODULE + +#define NAMELEN 8 /* # of chars for storing dev->name */ + +static struct net_device *dev_fc[MAX_FC_CARDS]; + +static int io = 0; +static int irq = 0; +static int bad = 0; /* 0xbad = bad sig or no reset ack */ +static int scsi_registered; + + +int init_module(void) +{ +int i = 0; + + driver_template.module = &__this_module; + scsi_register_module(MODULE_SCSI_HA, &driver_template); + if (driver_template.present) + scsi_registered = TRUE; + else { + printk("iph5526: SCSI registeration failed!!!\n"); + scsi_registered = FALSE; + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + } + + while(fc[i] != NULL) { + dev_fc[i] = NULL; + dev_fc[i] = init_fcdev(dev_fc[i], 0); + if (dev_fc[i] == NULL) { + printk("iph5526.c: init_fcdev failed for card #%d\n", i+1); + break; + } + dev_fc[i]->irq = irq; + dev_fc[i]->mem_end = bad; + dev_fc[i]->base_addr = io; + dev_fc[i]->init = iph5526_probe; + dev_fc[i]->priv = fc[i]; + fc[i]->dev = dev_fc[i]; + if (register_fcdev(dev_fc[i]) != 0) { + kfree_s(dev_fc[i], sizeof(struct net_device)); + dev_fc[i] = NULL; + if (i == 0) { + printk("iph5526.c: IP registeration failed!!!\n"); + return -ENODEV; + } + } + i++; + } + if (i == 0) + return -ENODEV; + + return 0; +} + +void cleanup_module(void) +{ +int i = 0; + while(fc[i] != NULL) { + struct net_device *dev = fc[i]->dev; + void *priv = dev->priv; + fc[i]->g.dont_init = TRUE; + take_tachyon_offline(fc[i]); + unregister_fcdev(dev); + clean_up_memory(fc[i]); + if (dev->priv) + kfree(priv); + kfree(dev); + dev = NULL; + i++; + } + if (scsi_registered == TRUE) + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); +} +#endif /* MODULE */ + +void clean_up_memory(struct fc_info *fi) +{ +int i,j; + ENTER("clean_up_memory"); + if (fi->q.ptr_mfsbq_base) + free_pages((u_long)bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base))), 5); + DPRINTK("after kfree2"); + for (i = 0; i < SFSBQ_LENGTH; i++) + for (j = 0; j < NO_OF_ENTRIES; j++) + if (fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES + j]) + kfree(fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES + j]); + DPRINTK("after kfree1"); + if (fi->q.ptr_ocq_base) + free_page((u_long)fi->q.ptr_ocq_base); + if (fi->q.ptr_imq_base) + free_page((u_long)fi->q.ptr_imq_base); + if (fi->q.ptr_mfsbq_base) + free_page((u_long)fi->q.ptr_mfsbq_base); + if (fi->q.ptr_sfsbq_base) + free_page((u_long)fi->q.ptr_sfsbq_base); + if (fi->q.ptr_edb_base) + free_pages((u_long)fi->q.ptr_edb_base, 5); + if (fi->q.ptr_sest_base) + free_pages((u_long)fi->q.ptr_sest_base, 5); + if (fi->q.ptr_tachyon_header_base) + free_page((u_long)fi->q.ptr_tachyon_header_base); + if (fi->q.ptr_sdb_base) + free_pages((u_long)fi->q.ptr_sdb_base, 5); + if (fi->q.ptr_fcp_cmnd_base) + free_page((u_long)fi->q.ptr_fcp_cmnd_base); + DPRINTK("after free_pages"); + if (fi->q.ptr_host_ocq_cons_indx) + kfree(fi->q.ptr_host_ocq_cons_indx); + if (fi->q.ptr_host_hpcq_cons_indx) + kfree(fi->q.ptr_host_hpcq_cons_indx); + if (fi->q.ptr_host_imq_prod_indx) + kfree(fi->q.ptr_host_imq_prod_indx); + DPRINTK("after kfree3"); + while (fi->node_info_list) { + struct fc_node_info *temp_list = fi->node_info_list; + fi->node_info_list = fi->node_info_list->next; + kfree(temp_list); + } + while (fi->ox_id_list) { + struct ox_id_els_map *temp = fi->ox_id_list; + fi->ox_id_list = fi->ox_id_list->next; + kfree(temp); + } + LEAVE("clean_up_memory"); +} + +static int initialize_register_pointers(struct fc_info *fi) +{ +ENTER("initialize_register_pointers"); +if(fi->g.tachyon_base == 0) + return -ENOMEM; + +fi->i_r.ptr_ichip_hw_control_reg = ICHIP_HW_CONTROL_REG_OFF + fi->g.tachyon_base; +fi->i_r.ptr_ichip_hw_status_reg = ICHIP_HW_STATUS_REG_OFF + fi->g.tachyon_base; +fi->i_r.ptr_ichip_hw_addr_mask_reg = ICHIP_HW_ADDR_MASK_REG_OFF + fi->g.tachyon_base; +fi->t_r.ptr_ocq_base_reg = OCQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_ocq_len_reg = OCQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_ocq_prod_indx_reg = OCQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_ocq_cons_indx_reg = OCQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_imq_base_reg = IMQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_imq_len_reg = IMQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_imq_cons_indx_reg = IMQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_imq_prod_indx_reg = IMQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_mfsbq_base_reg = MFSBQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_mfsbq_len_reg = MFSBQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_mfsbq_prod_reg = MFSBQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_mfsbq_cons_reg = MFSBQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_mfsbuff_len_reg = MFS_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sfsbq_base_reg = SFSBQ_BASE_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sfsbq_len_reg = SFSBQ_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sfsbq_prod_reg = SFSBQ_PRODUCER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sfsbq_cons_reg = SFSBQ_CONSUMER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sfsbuff_len_reg = SFS_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sest_base_reg = SEST_BASE_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_sest_len_reg = SEST_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_scsibuff_len_reg = SCSI_LENGTH_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_tach_config_reg = TACHYON_CONFIG_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_tach_control_reg = TACHYON_CONTROL_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_tach_status_reg = TACHYON_STATUS_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_tach_flush_oxid_reg = TACHYON_FLUSH_SEST_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_config_reg = FMGR_CONFIG_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_control_reg = FMGR_CONTROL_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_status_reg = FMGR_STATUS_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_tov_reg = FMGR_TIMER_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_wwn_hi_reg = FMGR_WWN_HI_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_wwn_low_reg = FMGR_WWN_LO_REGISTER_OFFSET + fi->g.tachyon_base; +fi->t_r.ptr_fm_rx_al_pa_reg = FMGR_RCVD_ALPA_REGISTER_OFFSET + fi->g.tachyon_base; + +LEAVE("initialize_register_pointers"); +return 1; +} + + + +/* + * Local variables: + * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c iph5526.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/iph5526_ip.h linux/drivers/net/fc/iph5526_ip.h --- v2.3.14/linux/drivers/net/fc/iph5526_ip.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/iph5526_ip.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,25 @@ +#ifndef IPH5526_IP_H +#define IPH5526_IP_H + +#define LLC_SNAP_LEN 0x8 + +/* Offsets into the ARP frame */ +#define ARP_OPCODE_0 (0x6 + LLC_SNAP_LEN) +#define ARP_OPCODE_1 (0x7 + LLC_SNAP_LEN) + +int iph5526_probe(struct net_device *dev); +static int fcdev_init(struct net_device *dev); +static int iph5526_open(struct net_device *dev); +static int iph5526_close(struct net_device *dev); +static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats * iph5526_get_stats(struct net_device *dev); +static int iph5526_change_mtu(struct net_device *dev, int mtu); + + +static void rx_net_packet(struct fc_info *fi, u_char *buff_addr, int payload_size); +static void rx_net_mfs_packet(struct fc_info *fi, struct sk_buff *skb); +unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev); +static int tx_ip_packet(struct sk_buff *skb, unsigned long len, struct fc_info *fi); +static int tx_arp_packet(char *data, unsigned long len, struct fc_info *fi); +#endif + diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/iph5526_novram.c linux/drivers/net/fc/iph5526_novram.c --- v2.3.14/linux/drivers/net/fc/iph5526_novram.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/iph5526_novram.c Mon Aug 23 10:12:38 1999 @@ -0,0 +1,278 @@ +/********************************************************************** + * Reading the NVRAM on the Interphase 5526 PCI Fibre Channel Card. + * All contents in this file : courtesy Interphase Corporation. + * Special thanks to Kevin Quick, kquick@iphase.com. + **********************************************************************/ + +#define FF_MAGIC 0x4646 +#define DB_MAGIC 0x4442 +#define DL_MAGIC 0x444d + + +#define CMD_LEN 9 + +/*********** + * + * Switches and defines for header files. + * + * The following defines are used to turn on and off + * various options in the header files. Primarily useful + * for debugging. + * + ***********/ + +static const unsigned short novram_default[4] = { + FF_MAGIC, + DB_MAGIC, + DL_MAGIC, + 0 }; + + +/* + * a list of the commands that can be sent to the NOVRAM + */ + +#define NR_EXTEND 0x100 +#define NR_WRITE 0x140 +#define NR_READ 0x180 +#define NR_ERASE 0x1c0 + +#define EWDS 0x00 +#define WRAL 0x10 +#define ERAL 0x20 +#define EWEN 0x30 + +/* + * Defines for the pins on the NOVRAM + */ + +#define BIT(x) (1 << (x)) + +#define NVDI_B 31 +#define NVDI BIT(NVDI_B) +#define NVDO BIT(9) +#define NVCE BIT(30) +#define NVSK BIT(29) +#define NV_MANUAL BIT(28) + +/*********** + * + * Include files. + * + ***********/ + +#define KeStallExecutionProcessor(x) {volatile int d, p;\ + for (d=0; dn_r.ptr_novram_hw_control_reg); \ + t &= (val); \ + writel(t, fi->n_r.ptr_novram_hw_control_reg); \ + } + +/*********************** + * + * This define ors the value and the current config register and puts + * the result in the config register + * + ***********************/ + +#define CFG_OR(val) { volatile int t; \ + t = readl(fi->n_r.ptr_novram_hw_control_reg); \ + t |= (val); \ + writel(t, fi->n_r.ptr_novram_hw_control_reg); \ + } + +/*********************** + * + * Send a command to the NOVRAM, the command is in cmd. + * + * clear CE and SK. Then assert CE. + * Clock each of the command bits out in the correct order with SK + * exit with CE still asserted + * + ***********************/ + +#define NVRAM_CMD(cmd) { int i; \ + int c = cmd; \ + CFG_AND(~(NVCE|NVSK)); \ + CFG_OR(NVCE); \ + for (i=0; in_r.ptr_novram_hw_status_reg) & NVDO) ? 1 : 0; \ + } + +/*********** + * + * Function Prototypes + * + ***********/ + +static int iph5526_nr_get(struct fc_info *fi, int addr); +static void iph5526_nr_do_init(struct fc_info *fi); +static void iph5526_nr_checksum(struct fc_info *fi); + + +/******************************************************************* + * + * Local routine: iph5526_nr_do_init + * Purpose: initialize novram server + * Description: + * + * iph5526_nr_do_init reads the novram into the temporary holding place. + * A checksum is done on the area and the Magic Cookies are checked. + * If any of them are bad, the NOVRAM is initialized with the + * default values and a warning message is displayed. + * + *******************************************************************/ + +static void iph5526_nr_do_init(struct fc_info *fi) +{ + int i; + unsigned short chksum = 0; + int bad = 0; + + for (i=0; in_r.data[i] = iph5526_nr_get(fi, i); + chksum += fi->n_r.data[i]; + } + + if (chksum) + bad = 1; + + if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 4] != FF_MAGIC) + bad = 1; + if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 3] != DB_MAGIC) + bad = 1; + if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 2] != DL_MAGIC) + bad = 1; + + if (bad) { + for (i=0; in_r.data[i] = 0xffff; + } else { + fi->n_r.data[i] = novram_default[i - (IPH5526_NOVRAM_SIZE - 4)]; + } + } + iph5526_nr_checksum(fi); + } +} + + +/******************************************************************* + * + * Local routine: iph5526_nr_get + * Purpose: read a single word of NOVRAM + * Description: + * + * read the 16 bits that make up a word addr of the novram. + * The 16 bits of data that are read are returned as the return value + * + *******************************************************************/ + +static int iph5526_nr_get(struct fc_info *fi, int addr) +{ + int i; + int t; + int val = 0; + + CFG_OR(NV_MANUAL); + + /* + * read the first bit that was clocked with the falling edge of the + * the last command data clock + */ + + NVRAM_CMD(NR_READ + addr); + + /* + * Now read the rest of the bits, the next bit read is D1, then D2, + * and so on + */ + + val = 0; + for (i=0; i<16; i++) { + NVRAM_CLKIN(t); + val <<= 1; + val |= t; + } + NVRAM_CLR_CE; + + CFG_OR(NVDI); + CFG_AND(~NV_MANUAL); + + return(val); +} + + + + +/******************************************************************* + * + * Local routine: iph5526_nr_checksum + * Purpose: calculate novram checksum on fi->n_r.data + * Description: + * + * calculate a checksum for the novram on the image that is + * currently in fi->n_r.data + * + *******************************************************************/ + +static void iph5526_nr_checksum(struct fc_info *fi) +{ + int i; + unsigned short chksum = 0; + + for (i=0; i<(IPH5526_NOVRAM_SIZE - 1); i++) + chksum += fi->n_r.data[i]; + + fi->n_r.data[i] = -chksum; +} diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/iph5526_scsi.h linux/drivers/net/fc/iph5526_scsi.h --- v2.3.14/linux/drivers/net/fc/iph5526_scsi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/iph5526_scsi.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,31 @@ +#ifndef IPH5526_SCSI_H +#define IPH5526_SCSI_H + +#define IPH5526_CAN_QUEUE 32 +#define IPH5526_SCSI_FC { \ + name: "Interphase 5526 Fibre Channel SCSI Adapter", \ + detect: iph5526_detect, \ + release: iph5526_release, \ + info: iph5526_info, \ + queuecommand: iph5526_queuecommand, \ + bios_param: iph5526_biosparam, \ + can_queue: IPH5526_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 255, \ + cmd_per_lun: 8, \ + use_clustering: DISABLE_CLUSTERING, \ + eh_abort_handler: iph5526_abort, \ + eh_device_reset_handler:NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ +} + +int iph5526_detect(Scsi_Host_Template *tmpt); +int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *)); +int iph5526_release(struct Scsi_Host *host); +int iph5526_abort(Scsi_Cmnd *Cmnd); +const char *iph5526_info(struct Scsi_Host *host); +int iph5526_biosparam(Disk * disk, kdev_t n, int ip[]); + +#endif + diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/tach.h linux/drivers/net/fc/tach.h --- v2.3.14/linux/drivers/net/fc/tach.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/tach.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,475 @@ +/********************************************************************** + * Defines for the Tachyon Fibre Channel Controller and the Interphase + * (i)chip TPI. + *********************************************************************/ + +#ifndef _TACH_H +#define _TACH_H + +#define MY_PAGE_SIZE 4096 +#define REPLICATE 0xFF +#define MAX_NODES 127 +#define BROADCAST 0xFFFFFF +#define BROADCAST_ADDR 0xFFFFFFFFFFFF +#define LOGIN_COMPLETED 2 +#define LOGIN_ATTEMPTED 1 +#define LOGIN_NOT_ATTEMPTED 0 +#define TRUE 1 +#define FALSE 0 + +#define TACHYON_LIMIT 0x01EF +#define TACHYON_OFFSET 0x200 + +/* Offsets to the (i) chip */ +#define ICHIP_HW_CONTROL_REG_OFF (0x080 - TACHYON_OFFSET) +#define ICHIP_HW_STATUS_REG_OFF (0x084 - TACHYON_OFFSET) +#define ICHIP_HW_ADDR_MASK_REG_OFF (0x090 - TACHYON_OFFSET) + +/* (i)chip Hardware Control Register defines */ +#define ICHIP_HCR_RESET 0x01 +#define ICHIP_HCR_DERESET 0x0 +#define ICHIP_HCR_ENABLE_INTA 0x0000003E +#define ICHIP_HCR_ENABLE_INTB 0x003E0000 +#define ICHIP_HCR_IWDATA_FIFO 0x800000 + +/* (i)chip Hardware Status Register defines */ +#define ICHIP_HSR_INT_LATCH 0x02 + +/* (i)chip Hardware Address Mask Register defines */ +#define ICHIP_HAMR_BYTE_SWAP_ADDR_TR 0x08 +#define ICHIP_HAMR_BYTE_SWAP_NO_ADDR_TR 0x04 + +/* NOVRAM defines */ +#define IPH5526_NOVRAM_SIZE 64 + + +/* Offsets for the registers that correspond to the + * Qs on the Tachyon (As defined in the Tachyon Manual). + */ + +/* Outbound Command Queue (OCQ). + */ +#define OCQ_BASE_REGISTER_OFFSET 0x000 +#define OCQ_LENGTH_REGISTER_OFFSET 0x004 +#define OCQ_PRODUCER_REGISTER_OFFSET 0x008 +#define OCQ_CONSUMER_REGISTER_OFFSET 0x00C + +/* Inbound Message Queue (IMQ). + */ +#define IMQ_BASE_REGISTER_OFFSET 0x080 +#define IMQ_LENGTH_REGISTER_OFFSET 0x084 +#define IMQ_CONSUMER_REGISTER_OFFSET 0x088 +#define IMQ_PRODUCER_REGISTER_OFFSET 0x08C + +/* Multiframe Sequence Buffer Queue (MFSBQ) + */ +#define MFSBQ_BASE_REGISTER_OFFSET 0x0C0 +#define MFSBQ_LENGTH_REGISTER_OFFSET 0x0C4 +#define MFSBQ_PRODUCER_REGISTER_OFFSET 0x0C8 +#define MFSBQ_CONSUMER_REGISTER_OFFSET 0x0CC +#define MFS_LENGTH_REGISTER_OFFSET 0x0D0 + +/* Single Frame Sequence Buffer Queue (SFSBQ) + */ +#define SFSBQ_BASE_REGISTER_OFFSET 0x100 +#define SFSBQ_LENGTH_REGISTER_OFFSET 0x104 +#define SFSBQ_PRODUCER_REGISTER_OFFSET 0x108 +#define SFSBQ_CONSUMER_REGISTER_OFFSET 0x10C +#define SFS_LENGTH_REGISTER_OFFSET 0x110 + +/* SCSI Exchange State Table (SEST) + */ +#define SEST_BASE_REGISTER_OFFSET 0x140 +#define SEST_LENGTH_REGISTER_OFFSET 0x144 +#define SCSI_LENGTH_REGISTER_OFFSET 0x148 + +/* Length of the various Qs + */ +#define NO_OF_ENTRIES 8 +#define OCQ_LENGTH (MY_PAGE_SIZE/32) +#define IMQ_LENGTH (MY_PAGE_SIZE/32) +#define MFSBQ_LENGTH 8 +#define SFSBQ_LENGTH 8 +#define SEST_LENGTH MY_PAGE_SIZE + +/* Size of the various buffers. + */ +#define FRAME_SIZE 2048 +#define MFS_BUFFER_SIZE FRAME_SIZE +#define SFS_BUFFER_SIZE (FRAME_SIZE + TACHYON_HEADER_LEN) +#define SEST_BUFFER_SIZE 512 +#define TACH_HEADER_SIZE 64 +#define NO_OF_TACH_HEADERS ((MY_PAGE_SIZE)/TACH_HEADER_SIZE) + +#define NO_OF_FCP_CMNDS (MY_PAGE_SIZE/32) +#define SDB_SIZE 2048 +#define NO_OF_SDB_ENTRIES ((32*MY_PAGE_SIZE)/SDB_SIZE) + + +/* Offsets to the other Tachyon registers. + * (As defined in the Tachyon manual) + */ +#define TACHYON_CONFIG_REGISTER_OFFSET 0x184 +#define TACHYON_CONTROL_REGISTER_OFFSET 0x188 +#define TACHYON_STATUS_REGISTER_OFFSET 0x18C +#define TACHYON_FLUSH_SEST_REGISTER_OFFSET 0x190 + +/* Defines for the Tachyon Configuration register. + */ +#define SCSI_ENABLE 0x40000000 +#define WRITE_STREAM_SIZE 0x800 /* size = 16 */ +#define READ_STREAM_SIZE 0x300 /* size = 64 */ +#define PARITY_EVEN 0x2 +#define OOO_REASSEMBLY_DISABLE 0x40 + +/* Defines for the Tachyon Control register. + */ +#define SOFTWARE_RESET 0x80000000 +#define OCQ_RESET 0x4 +#define ERROR_RELEASE 0x2 + +/* Defines for the Tachyon Status register. + */ +#define RECEIVE_FIFO_EMPTY 0x10 +#define OSM_FROZEN 0x1 +#define OCQ_RESET_STATUS 0x20 +#define SCSI_FREEZE_STATUS 0x40 + + +/* Offsets to the Frame Manager registers. + */ +#define FMGR_CONFIG_REGISTER_OFFSET 0x1C0 +#define FMGR_CONTROL_REGISTER_OFFSET 0x1C4 +#define FMGR_STATUS_REGISTER_OFFSET 0x1C8 +#define FMGR_TIMER_REGISTER_OFFSET 0x1CC +#define FMGR_WWN_HI_REGISTER_OFFSET 0x1E0 +#define FMGR_WWN_LO_REGISTER_OFFSET 0x1E4 +#define FMGR_RCVD_ALPA_REGISTER_OFFSET 0x1E8 + +/* Defines for the Frame Manager Configuration register. + */ +#define BB_CREDIT 0x10000 +#define NPORT 0x8000 +#define LOOP_INIT_FABRIC_ADDRESS 0x400 +#define LOOP_INIT_PREVIOUS_ADDRESS 0x200 +#define LOOP_INIT_SOFT_ADDRESS 0x80 + +/* Defines for the Frame Manager Control register. + */ +#define HOST_CONTROL 0x02 +#define EXIT_HOST_CONTROL 0x03 +#define OFFLINE 0x05 +#define INITIALIZE 0x06 +#define CLEAR_LF 0x07 + +/* Defines for the Frame Manager Status register. + */ +#define LOOP_UP 0x80000000 +#define TRANSMIT_PARITY_ERROR 0x40000000 +#define NON_PARTICIPATING 0x20000000 +#define OUT_OF_SYNC 0x02000000 +#define LOSS_OF_SIGNAL 0x01000000 +#define NOS_OLS_RECEIVED 0x00080000 +#define LOOP_STATE_TIMEOUT 0x00040000 +#define LIPF_RECEIVED 0x00020000 +#define BAD_ALPA 0x00010000 +#define LINK_FAILURE 0x00001000 +#define ELASTIC_STORE_ERROR 0x00000400 +#define LINK_UP 0x00000200 +#define LINK_DOWN 0x00000100 +#define ARBITRATING 0x00000010 +#define ARB_WON 0x00000020 +#define OPEN 0x00000030 +#define OPENED 0x00000040 +#define TX_CLS 0x00000050 +#define RX_CLS 0x00000060 +#define TRANSFER 0x00000070 +#define INITIALIZING 0x00000080 +#define LOOP_FAIL 0x000000D0 +#define OLD_PORT 0x000000F0 +#define PORT_STATE_ACTIVE 0x0000000F +#define PORT_STATE_OFFLINE 0x00000000 +#define PORT_STATE_LF1 0x00000009 +#define PORT_STATE_LF2 0x0000000A + +/* Completion Message Types + * (defined in P.177 of the Tachyon manual) + */ +#define OUTBOUND_COMPLETION 0x000 +#define OUTBOUND_COMPLETION_I 0x100 +#define OUT_HI_PRI_COMPLETION 0x001 +#define OUT_HI_PRI_COMPLETION_I 0x101 +#define INBOUND_MFS_COMPLETION 0x102 +#define INBOUND_OOO_COMPLETION 0x003 +#define INBOUND_SFS_COMPLETION 0x104 +#define INBOUND_C1_TIMEOUT 0x105 +#define INBOUND_UNKNOWN_FRAME_I 0x106 +#define INBOUND_BUSIED_FRAME 0x006 +#define SFS_BUF_WARN 0x107 +#define MFS_BUF_WARN 0x108 +#define IMQ_BUF_WARN 0x109 +#define FRAME_MGR_INTERRUPT 0x10A +#define READ_STATUS 0x10B +#define INBOUND_SCSI_DATA_COMPLETION 0x10C +#define INBOUND_SCSI_COMMAND 0x10D +#define BAD_SCSI_FRAME 0x10E +#define INB_SCSI_STATUS_COMPLETION 0x10F + +/* One of the things that we care about when we receive an + * Outbound Completion Message (OCM). + */ +#define OCM_TIMEOUT_OR_BAD_ALPA 0x0800 + +/* Defines for the Tachyon Header structure. + */ +#define SOFI3 0x70 +#define SOFN3 0xB0 +#define EOFN 0x5 + +/* R_CTL */ +#define FC4_DEVICE_DATA 0 +#define EXTENDED_LINK_DATA 0x20000000 +#define FC4_LINK_DATA 0x30000000 +#define BASIC_LINK_DATA 0x80000000 +#define LINK_CONTROL 0xC0000000 +#define SOLICITED_DATA 0x1000000 +#define UNSOLICITED_CONTROL 0x2000000 +#define SOLICITED_CONTROL 0x3000000 +#define UNSOLICITED_DATA 0x4000000 +#define DATA_DESCRIPTOR 0x5000000 +#define UNSOLICITED_COMMAND 0x6000000 + +#define RCTL_ELS_UCTL 0x22000000 +#define RCTL_ELS_SCTL 0x23000000 +#define RCTL_BASIC_ABTS 0x81000000 +#define RCTL_BASIC_ACC 0x84000000 +#define RCTL_BASIC_RJT 0x85000000 + +/* TYPE */ +#define TYPE_BLS 0x00000000 +#define TYPE_ELS 0x01000000 +#define TYPE_FC_SERVICES 0x20000000 +#define TYPE_LLC_SNAP 0x05000000 +#define TYPE_FCP 0x08000000 + +/* F_CTL */ +#define EXCHANGE_RESPONDER 0x800000 +#define SEQUENCE_RESPONDER 0x400000 +#define FIRST_SEQUENCE 0x200000 +#define LAST_SEQUENCE 0x100000 +#define SEQUENCE_INITIATIVE 0x10000 +#define RELATIVE_OFF_PRESENT 0x8 +#define END_SEQUENCE 0x80000 + +#define TACHYON_HEADER_LEN 32 +#define NW_HEADER_LEN 16 +/* Defines for the Outbound Descriptor Block (ODB). + */ +#define ODB_CLASS_3 0xC000 +#define ODB_NO_COMP 0x400 +#define ODB_NO_INT 0x200 +#define ODB_EE_CREDIT 0xF + +/* Defines for the Extended Descriptor Block (EDB). + */ +#define EDB_LEN ((32*MY_PAGE_SIZE)/8) +#define EDB_END 0x8000 +#define EDB_FREE 0 +#define EDB_BUSY 1 + +/* Command Codes */ +#define ELS_LS_RJT 0x01000000 +#define ELS_ACC 0x02000000 +#define ELS_PLOGI 0x03000000 +#define ELS_FLOGI 0x04000000 +#define ELS_LOGO 0x05000000 +#define ELS_TPRLO 0x24000000 +#define ELS_ADISC 0x52000000 +#define ELS_PDISC 0x50000000 +#define ELS_PRLI 0x20000000 +#define ELS_PRLO 0x21000000 +#define ELS_SCR 0x62000000 +#define ELS_RSCN 0x61000000 +#define ELS_FARP_REQ 0x54000000 +#define ELS_ABTX 0x06000000 +#define ELS_ADVC 0x0D000000 +#define ELS_ECHO 0x10000000 +#define ELS_ESTC 0x0C000000 +#define ELS_ESTS 0x0B000000 +#define ELS_RCS 0x07000000 +#define ELS_RES 0x08000000 +#define ELS_RLS 0x0F000000 +#define ELS_RRQ 0x12000000 +#define ELS_RSS 0x09000000 +#define ELS_RTV 0x0E000000 +#define ELS_RSI 0x0A000000 +#define ELS_TEST 0x11000000 +#define ELS_RNC 0x53000000 +#define ELS_RVCS 0x41000000 +#define ELS_TPLS 0x23000000 +#define ELS_GAID 0x30000000 +#define ELS_FACT 0x31000000 +#define ELS_FAN 0x60000000 +#define ELS_FDACT 0x32000000 +#define ELS_NACT 0x33000000 +#define ELS_NDACT 0x34000000 +#define ELS_QoSR 0x40000000 +#define ELS_FDISC 0x51000000 + +#define ELS_NS_PLOGI 0x03FFFFFC + +/* LS_RJT reason codes. + */ +#define INV_LS_CMND_CODE 0x0001 +#define LOGICAL_ERR 0x0003 +#define LOGICAL_BUSY 0x0005 +#define PROTOCOL_ERR 0x0007 +#define UNABLE_TO_PERFORM 0x0009 +#define CMND_NOT_SUPP 0x000B + +/* LS_RJT explanation codes. + */ +#define NO_EXPLN 0x0000 +#define RECV_FIELD_SIZE 0x0700 +#define CONC_SEQ 0x0900 +#define REQ_NOT_SUPPORTED 0x2C00 +#define INV_PAYLOAD_LEN 0x2D00 + +/* Payload Length defines. + */ +#define PLOGI_LEN 116 + +#define CONCURRENT_SEQUENCES 0x01 +#define RO_INFO_CATEGORY 0xFE +#define E_D_TOV 0x07D0 /* 2 Secs */ +#define AL_TIME 0x0010 /* ~15 msec */ +#define TOV_VALUES (AL_TIME << 16) | E_D_TOV +#define RT_TOV 0x64 /* 100 msec */ +#define PTP_TOV_VALUES (RT_TOV << 16) | E_D_TOV +#define SERVICE_VALID 0x8000 +#define SEQUENCE_DELIVERY 0x0800 +#define CLASS3_CONCURRENT_SEQUENCE 0x01 +#define CLASS3_OPEN_SEQUENCE 0x01 + +/* These are retrieved from the NOVRAM. + */ +#define WORLD_WIDE_NAME_LOW fi->g.my_port_name_low +#define WORLD_WIDE_NAME_HIGH fi->g.my_port_name_high +#define N_PORT_NAME_HIGH fi->g.my_port_name_high +#define N_PORT_NAME_LOW fi->g.my_port_name_low +#define NODE_NAME_HIGH fi->g.my_node_name_high +#define NODE_NAME_LOW fi->g.my_node_name_low + +#define PORT_NAME_LEN 8 +#define NODE_NAME_LEN 8 + + +#define PH_VERSION 0x0909 + +#define LOOP_BB_CREDIT 0x00 +#define PT2PT_BB_CREDIT 0x01 +#define FLOGI_C_F 0x0800 /* Alternate BB_Credit Mgmnt */ +#define PLOGI_C_F 0x8800 /* Continuously Increasing + Alternate BB_Credit Management */ + +/* Fabric defines */ +#define DIRECTORY_SERVER 0xFFFFFC +#define FABRIC_CONTROLLER 0xFFFFFD +#define F_PORT 0xFFFFFE + +#define FLOGI_DID 0xFFFE +#define NS_PLOGI_DID 0xFFFC + +/* Fibre Channel Services defines */ +#define FCS_RFC_4 0x02170000 +#define FCS_GP_ID4 0x01A10000 +#define FCS_ACC 0x8002 +#define FCS_REJECT 0x8001 + +/* CT Header defines */ +#define FC_CT_REV 0x01000000 +#define DIRECTORY_SERVER_APP 0xFC +#define NAME_SERVICE 0x02 + +/* Port Type defines */ +#define PORT_TYPE_IP 0x05000000 +#define PORT_TYPE_NX_PORTS 0x7F000000 + +/* SCR defines */ +#define FABRIC_DETECTED_REG 0x00000001 +#define N_PORT_DETECTED_REG 0x00000002 +#define FULL_REGISTRATION 0x00000003 +#define CLEAR_REGISTRATION 0x000000FF + +/* Command structure has only one byte to address targets + */ +#define MAX_SCSI_TARGETS 0xFF + +#define FC_SCSI_READ 0x80 +#define FC_SCSI_WRITE 0x81 +#define FC_ELS 0x01 +#define FC_BLS 0x00 +#define FC_IP 0x05 +#define FC_BROADCAST 0xFF + +/* SEST defines. + */ +#define SEST_V 0x80000000 /* V = 1 */ +#define INB_SEST_VED 0xA0000000 /* V = 1, D = 1 */ +#define SEST_INV 0x7FFFFFFF +#define OUTB_SEST_VED 0x80000000 /* V = 1 */ +#define INV_SEQ_LEN 0xFFFFFFFF +#define OUTB_SEST_LINK 0xFFFF + +/* PRLI defines. + */ +#define PAGE_LEN 0x100000 /* 3rd byte - 0x10 */ +#define PRLI_LEN 0x0014 /* 20 bytes */ +#define FCP_TYPE_CODE 0x0800 /* FCP-SCSI */ +#define IMAGE_PAIR 0x2000 /* establish image pair */ +#define INITIATOR_FUNC 0x00000020 +#define TARGET_FUNC 0x00000010 +#define READ_XFER_RDY_DISABLED 0x00000002 + +#define NODE_PROCESS_LOGGED_IN 0x3 +#define NODE_NOT_PRESENT 0x2 +#define NODE_LOGGED_IN 0x1 +#define NODE_LOGGED_OUT 0x0 + +/* Defines to determine what should be returned when a SCSI frame + * times out. + */ +#define FC_SCSI_BAD_TARGET 0xFFFE0000 + +/* RSCN Address formats */ +#define PORT_ADDRESS_FORMAT 0x00 +#define AREA_ADDRESS_FORMAT 0x01 +#define DOMAIN_ADDRESS_FORMAT 0x02 + +/* Defines used to determine whether a frame transmission should + * be indicated by an interrupt or not. + */ +#define NO_COMP_AND_INT 0 +#define INT_AND_COMP_REQ 1 +#define NO_INT_COMP_REQ 2 + +/* Other junk... + */ +#define SDB_FREE 0 +#define SDB_BUSY 1 +#define MAX_PENDING_FRAMES 15 +#define RX_ID_FIRST_SEQUENCE 0xFFFF +#define OX_ID_FIRST_SEQUENCE 0xFFFF +#define NOT_SCSI_XID 0x8000 +#define MAX_SCSI_XID 0x0FFF /* X_IDs are from 0-4095 */ +#define SCSI_READ_BIT 0x4000 +#define MAX_SCSI_OXID 0x4FFF +#define OXID_AVAILABLE 0 +#define OXID_INUSE 1 +#define MAX_SEQ_ID 0xFF + +#define INITIATOR 2 +#define TARGET 1 +#define DELETE_ENTRY 1 +#define ADD_ENTRY 2 + +#endif /* _TACH_H */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/fc/tach_structs.h linux/drivers/net/fc/tach_structs.h --- v2.3.14/linux/drivers/net/fc/tach_structs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fc/tach_structs.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,428 @@ +/********************************************************************** + * iph5526.c: Structures for the Interphase 5526 PCI Fibre Channel + * IP/SCSI driver. + * Copyright (C) 1999 Vineet M Abraham + **********************************************************************/ + +#ifndef _TACH_STRUCT_H +#define _TACH_STRUCT_H + +typedef struct { + u_short cmnd_code; + u_short payload_length; + u_short type_code; + u_short est_image_pair; + u_int originator_pa; + u_int responder_pa; + u_int service_params; +} PRLI; + +typedef struct { + u_int flags_and_byte_offset; + u_int byte_count; + u_short no_of_recvd_frames; + u_short no_of_expected_frames; + u_int last_fctl; + u_int sdb_address; + u_int scratch_pad; + u_int expected_ro; + u_short buffer_index; + u_short buffer_offset; + } INB_SEST_ENTRY; + +typedef struct { + u_int flags_and_did; + u_short max_frame_len; + u_short cntl; + u_int total_seq_length; + u_short link; + u_short rx_id; + u_int transaction_id; + u_int header_address; + u_char seq_id; + u_char reserved; + u_short header_length; + u_int edb_address; + } OUTB_SEST_ENTRY; + +typedef struct { + u_short d_naa; + u_short dest_high; + u_int dest_low; + u_short s_naa; + u_short source_high; + u_int source_low; + } NW_HEADER; + +typedef struct { + u_int resv; + u_char sof_and_eof; + u_char dest_alpa; + u_short lcr_and_time_stamp; + u_int r_ctl_and_d_id; + u_int vc_id_and_s_id; + u_int type_and_f_cntl; + u_char seq_id; + u_char df_cntl; + u_short seq_cnt; + u_short ox_id; + u_short rx_id; + u_int ro; + NW_HEADER nw_header; + } TACHYON_HEADER; + +typedef struct { + u_short service_options; + u_short initiator_ctl; + u_short recipient_ctl; + u_short recv_data_field_size; + u_short concurrent_sequences; + u_short n_port_end_to_end_credit; + u_short open_seq_per_exchange; + u_short resv; + }CLASS_OF_SERVICE; + +typedef struct { + u_int logo_cmnd; + u_char reserved; + u_char n_port_id_2; + u_char n_port_id_1; + u_char n_port_id_0; + u_int port_name_up; + u_int port_name_low; + } LOGO; + +typedef struct { + u_int ls_cmnd_code; + u_int hard_address; + u_int port_name_high; + u_int port_name_low; + u_int node_name_high; + u_int node_name_low; + u_int n_port_id; + } ADISC; + +typedef struct { + u_int cmnd_code; + u_int reason_code; + } LS_RJT; + +typedef struct { + u_int cmnd_code; + } ACC; + +typedef struct { + u_int seq_d_id; + u_int tot_len; + u_short cntl; + u_short rx_id; + u_short cs_enable; + u_short cs_seed; + u_int trans_id; + u_int hdr_addr; + u_short frame_len; + u_short hdr_len; + u_int edb_addr; + }ODB; + +typedef struct { + u_int cmnd_code; + u_int reg_function; /* in the last byte */ + } SCR; + +typedef struct { + u_int rev_in_id; + u_char fs_type; + u_char fs_subtype; + u_char options; + u_char resv1; + u_short cmnd_resp_code; + u_short max_res_size; + u_char resv2; + u_char reason_code; + u_char expln_code; + u_char vendor_unique; + } CT_HDR; + +typedef struct { + CT_HDR ct_hdr; + u_int s_id; + u_char bit_map[32]; /* 32 byte bit map */ + } RFC_4; + +typedef struct { + u_int ls_cmnd_code; + u_short fc_ph_version; + u_short buff_to_buff_credit; + u_short common_features; + u_short recv_data_field_size; + u_short n_port_total_conc_seq; + u_short rel_off_by_info_cat; + u_int ED_TOV; + u_int n_port_name_high; + u_int n_port_name_low; + u_int node_name_high; + u_int node_name_low; + CLASS_OF_SERVICE c_of_s[3]; + u_int resv[4]; + u_int vendor_version_level[4]; + }LOGIN; + +typedef struct { + CT_HDR ct_hdr; + u_int port_type; /* in the first byte */ + } GP_ID4; + +typedef struct { + u_int buf_addr; + u_short ehf; + u_short buf_len; + }EDB; + +/* (i)chip Registers */ +struct i_chip_regs { + u_int ptr_ichip_hw_control_reg; + u_int ptr_ichip_hw_status_reg; + u_int ptr_ichip_hw_addr_mask_reg; +}; + +struct iph5526_novram { + u_int ptr_novram_hw_control_reg; + u_int ptr_novram_hw_status_reg; + u_short data[IPH5526_NOVRAM_SIZE]; +}; + +/* Tachyon Registers */ +struct tachyon_regs { + u_int ptr_ocq_base_reg; + u_int ptr_ocq_len_reg; + u_int ptr_ocq_prod_indx_reg; + u_int ptr_ocq_cons_indx_reg; + + u_int ptr_imq_base_reg; + u_int ptr_imq_len_reg; + u_int ptr_imq_cons_indx_reg; + u_int ptr_imq_prod_indx_reg; + + u_int ptr_mfsbq_base_reg; + u_int ptr_mfsbq_len_reg; + u_int ptr_mfsbq_prod_reg; + u_int ptr_mfsbq_cons_reg; + u_int ptr_mfsbuff_len_reg; + + u_int ptr_sfsbq_base_reg; + u_int ptr_sfsbq_len_reg; + u_int ptr_sfsbq_prod_reg; + u_int ptr_sfsbq_cons_reg; + u_int ptr_sfsbuff_len_reg; + + u_int ptr_sest_base_reg; + u_int ptr_sest_len_reg; + u_int ptr_scsibuff_len_reg; + + u_int ptr_tach_config_reg; + u_int ptr_tach_control_reg; + u_int ptr_tach_status_reg; + u_int ptr_tach_flush_oxid_reg; + + u_int ptr_fm_config_reg; + u_int ptr_fm_control_reg; + u_int ptr_fm_status_reg; + u_int ptr_fm_tov_reg; + u_int ptr_fm_wwn_hi_reg; + u_int ptr_fm_wwn_low_reg; + u_int ptr_fm_rx_al_pa_reg; +}; + +struct globals { + u_long tachyon_base; + u_int *mem_base; + u_short ox_id; /* OX_ID used for IP and ELS frames */ + u_short scsi_oxid; /* OX_ID for SEST entry */ + u_char seq_id; + u_int my_id; + u_int my_ddaa; /* my domain and area in a fabric */ + volatile u_char loop_up; + volatile u_char ptp_up; /* we have a point-to-point link */ + volatile u_char link_up; + volatile u_char n_port_try; + volatile u_char nport_timer_set; + volatile u_char lport_timer_set; + /* Hmmm... We dont want to Initialize while closing */ + u_char dont_init; + u_int my_node_name_high; + u_int my_node_name_low; + u_int my_port_name_high; + u_int my_port_name_low; + u_char fabric_present; + u_char explore_fabric; + u_char name_server; + u_int my_mtu; + u_int *els_buffer[MAX_PENDING_FRAMES]; /* temp space for ELS frames */ + char *arp_buffer; /* temp space for ARP frames */ + u_int mfs_buffer_count; /* keep track of MFS buffers used*/ + u_char scsi_registered; + /* variables for port discovery */ + volatile u_char port_discovery; + volatile u_char perform_adisc; + u_short alpa_list_index; + u_short type_of_frame; /* Could be IP/SCSI Read/SCSI Write*/ + u_char no_of_targets; /* used to assign target_ids */ + u_long sem; /* to synchronize between IP and SCSI */ + u_char e_i; + + /* the frames */ + TACHYON_HEADER tach_header; + LOGIN login; + PRLI prli; + LOGO logo; + ADISC adisc; + LS_RJT ls_rjt; + ODB odb; + INB_SEST_ENTRY inb_sest_entry; + OUTB_SEST_ENTRY outb_sest_entry; + ACC acc; + SCR scr; + EDB edb; + RFC_4 rfc_4; + GP_ID4 gp_id4; +}; + +struct queue_variables { + /* Indices maintained in host memory. + */ + u_int *host_ocq_cons_indx, *host_hpcq_cons_indx, *host_imq_prod_indx; + u_int *ptr_host_ocq_cons_indx, *ptr_host_hpcq_cons_indx, *ptr_host_imq_prod_indx; + + /* Variables for Outbound Command Queue (OCQ). + */ + u_int *ptr_ocq_base; + u_int ocq_len, ocq_end; + u_int ocq_prod_indx; + u_int *ptr_odb[OCQ_LENGTH]; + + /* Variables for Inbound Message Queue (IMQ). + */ + u_int *ptr_imq_base; + u_int imq_len, imq_end; + u_int imq_cons_indx; + u_int imq_prod_indx; + u_int *ptr_imqe[IMQ_LENGTH]; + + u_int *ptr_mfsbq_base; + u_int mfsbq_len, mfsbq_end; + u_int mfsbq_prod_indx; + u_int mfsbq_cons_indx; + u_int mfsbuff_len, mfsbuff_end; + + u_int *ptr_sfsbq_base; + u_int sfsbq_len, sfsbq_end; + u_int sfsbq_prod_indx; + u_int sfsbq_cons_indx; + u_int sfsbuff_len, sfsbuff_end; + u_int *ptr_sfs_buffers[SFSBQ_LENGTH * NO_OF_ENTRIES]; + + /* Tables for SCSI Transactions */ + u_int *ptr_sest_base; + u_int *ptr_sest[SEST_LENGTH]; + u_char free_scsi_oxid[SEST_LENGTH]; + u_int *ptr_sdb_base; + u_int *ptr_sdb_slot[NO_OF_SDB_ENTRIES]; + u_char sdb_slot_status[NO_OF_SDB_ENTRIES]; + u_int sdb_indx; + u_int *ptr_fcp_cmnd_base; + u_int *ptr_fcp_cmnd[NO_OF_FCP_CMNDS]; + u_int fcp_cmnd_indx; + + /* Table for data to be transmitted. + */ + u_int *ptr_edb_base; + u_int *ptr_edb[EDB_LEN]; + u_int edb_buffer_indx; + volatile u_char free_edb_list[EDB_LEN]; + + /* Table of Tachyon Headers. + */ + u_int *ptr_tachyon_header[NO_OF_TACH_HEADERS]; + u_int *ptr_tachyon_header_base; + u_int tachyon_header_indx; +}; + +/* Used to match incoming ACCs to ELS requests sent out */ +struct ox_id_els_map { + u_short ox_id; + u_int els; + struct ox_id_els_map *next; +}; + + +/* Carries info about individual nodes... stores the info got at login + * time. Also maintains mapping between MAC->FC addresses + */ +struct fc_node_info { + /* Itz the WWN (8 bytes), the last 6 bytes is the MAC address */ + u_char hw_addr[PORT_NAME_LEN]; + u_char node_name[NODE_NAME_LEN]; + u_int d_id; /*real FC address, 3 bytes */ + int mtu; + /* login = 1 if login attempted + * login = 2 if login completed + */ + int login; + u_char scsi; /* = 1 if device is a SCSI Target */ + u_char target_id; + CLASS_OF_SERVICE c_of_s[3]; + struct fc_node_info *next; +}; + +struct fc_info { + char name[8]; + u_long base_addr; + int irq; + struct net_device_stats fc_stats; + struct fc_node_info *node_info_list; + int num_nodes; + struct ox_id_els_map *ox_id_list; + struct i_chip_regs i_r; + struct tachyon_regs t_r; + struct queue_variables q; + struct globals g; + struct iph5526_novram n_r; + u_short clone_id; + struct timer_list nport_timer; + struct timer_list lport_timer; + struct timer_list explore_timer; + struct timer_list display_cache_timer; + struct net_device *dev; + struct Scsi_Host *host; + spinlock_t fc_lock; +}; + +struct iph5526_hostdata { + struct fc_info *fi; + fcp_cmd cmnd; + Scsi_Cmnd *cmnd_handler[SEST_LENGTH]; + u_int tag_ages[MAX_SCSI_TARGETS]; +}; + +/* List of valid AL_PAs */ +u_char alpa_list[127] = { + 0x00, 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, + 0x18, 0x1B, 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, + 0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A, 0x3C, + 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, + 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, + 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, + 0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, + 0x9D, 0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, + 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB9, 0xBA, 0xBC, 0xC3, 0xC5, + 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, + 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, 0xDA, + 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF +}; + +#endif /* _TACH_STRUCT_H */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.3.14/linux/drivers/net/hamradio/Config.in Thu Aug 12 12:18:32 1999 +++ linux/drivers/net/hamradio/Config.in Mon Aug 23 11:15:27 1999 @@ -15,7 +15,6 @@ dep_tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX $CONFIG_AX25 dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_PARPORT $CONFIG_AX25 dep_tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP $CONFIG_PARPORT $CONFIG_AX25 -dep_tristate 'BAYCOM eppflex driver for AX.25' CONFIG_BAYCOM_EPPFLEX $CONFIG_PARPORT $CONFIG_AX25 dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_PARPORT $CONFIG_AX25 if [ "$CONFIG_SOUNDMODEM" != "n" ]; then diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.3.14/linux/drivers/net/hamradio/baycom_epp.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/hamradio/baycom_epp.c Mon Aug 23 11:15:27 1999 @@ -33,6 +33,7 @@ * 0.4 26.07.99 Adapted to new lowlevel parport driver interface * 0.5 03.08.99 adapt to Linus' new __setup/__initcall * removed some pre-2.2 kernel compatibility cruft + * 0.6 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts * */ @@ -370,7 +371,7 @@ * eppconfig_path should be setable via /proc/sys. */ -char eppconfig_path[256] = "/usr/sbin/eppfpga"; +static char eppconfig_path[256] = "/usr/sbin/eppfpga"; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; @@ -1044,6 +1045,11 @@ return -ENXIO; } #endif + if ((~pp->modes) & (PARPORT_MODE_TRISTATE | PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { + printk(KERN_ERR "%s: parport at 0x%lx cannot be used\n", + bc_drvname, pp->base); + return -EIO; + } memset(&bc->modem, 0, sizeof(bc->modem)); if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup, epp_interrupt, PARPORT_DEV_EXCL, dev))) { @@ -1055,13 +1061,6 @@ parport_unregister_device(bc->pdev); return -EBUSY; } - if (!(pp->modes & PARPORT_MODE_TRISTATE)) { - printk(KERN_ERR "%s: parport at 0x%lx does not support bidirectional data transfer\n", - bc_drvname, pp->base); - parport_release(bc->pdev); - parport_unregister_device(bc->pdev); - return -EIO; - } dev->irq = /*pp->irq*/ 0; bc->run_bh = run_bh; bc->bh_running = 1; @@ -1418,12 +1417,17 @@ static const char *mode[NR_PORTS] = { "", }; static int iobase[NR_PORTS] = { 0x378, }; +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); + /* --------------------------------------------------------------------- */ -#ifndef MODULE -static -#endif -int __init init_module(void) +static int __init init_baycomepp(void) { struct net_device *dev; int i, found = 0; @@ -1476,19 +1480,7 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "baycom operating mode"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "baycom io base address"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); - -void cleanup_module(void) +static void __exit cleanup_baycomepp(void) { struct net_device *dev; struct baycom_state *bc; @@ -1507,7 +1499,12 @@ } } -#else /* MODULE */ +module_init(init_baycomepp); +module_exit(cleanup_baycomepp); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE /* * format: baycom_epp=io,mode @@ -1517,11 +1514,11 @@ static int __init baycom_epp_setup(char *str) { static unsigned __initdata nr_dev = 0; - int ints[11]; + int ints[2]; if (nr_dev >= NR_PORTS) return 0; - str = get_options(str, ints); + str = get_options(str, 2, ints); if (ints[0] < 1) return 0; mode[nr_dev] = str; @@ -1531,7 +1528,6 @@ } __setup("baycom_epp=", baycom_epp_setup); -__initcall(init_module); #endif /* MODULE */ /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.3.14/linux/drivers/net/hamradio/baycom_par.c Wed Aug 18 11:38:50 1999 +++ linux/drivers/net/hamradio/baycom_par.c Mon Aug 23 11:15:27 1999 @@ -60,6 +60,7 @@ * 0.5 11.11.97 split into separate files for ser12/par96 * 0.6 03.08.99 adapt to Linus' new __setup/__initcall * removed some pre-2.2 kernel compatibility cruft + * 0.7 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts */ /*****************************************************************************/ @@ -336,6 +337,10 @@ printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base); return -ENXIO; } + if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { + printk(KERN_ERR "baycom_par: parport at 0x%lx cannot be used\n", pp->base); + return -ENXIO; + } memset(&bc->modem, 0, sizeof(bc->modem)); bc->hdrv.par.bitrate = 9600; if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, par96_wakeup, @@ -489,12 +494,17 @@ static const char *mode[NR_PORTS] = { "picpar", }; static int iobase[NR_PORTS] = { 0x378, }; +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); + /* --------------------------------------------------------------------- */ -#ifndef MODULE -static -#endif -int __init init_module(void) +static int __init init_baycompar(void) { int i, j, found = 0; char set_hw = 1; @@ -530,19 +540,7 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "baycom io base address"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); - -void cleanup_module(void) +static void __exit cleanup_baycompar(void) { int i; @@ -560,7 +558,12 @@ } } -#else /* MODULE */ +module_init(init_baycompar); +module_exit(cleanup_baycompar); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE /* * format: baycom_par=io,mode @@ -570,11 +573,11 @@ static int __init baycom_par_setup(char *str) { static unsigned __initdata nr_dev = 0; - int ints[11]; + int ints[2]; if (nr_dev >= NR_PORTS) return 0; - str = get_options(str, ints); + str = get_options(str, 2, ints); if (ints[0] < 1) return 0; mode[nr_dev] = str; @@ -584,7 +587,6 @@ } __setup("baycom_par=", baycom_par_setup); -__initcall(init_module); #endif /* MODULE */ /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c --- v2.3.14/linux/drivers/net/hamradio/baycom_ser_fdx.c Wed Aug 18 11:38:50 1999 +++ linux/drivers/net/hamradio/baycom_ser_fdx.c Mon Aug 23 11:15:27 1999 @@ -45,7 +45,10 @@ * * Command line options (insmod command line) * - * mode * enables software DCD. + * mode ser# hardware DCD + * ser#* software DCD + * ser#+ hardware DCD, inverted signal at DCD pin + * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 * baud baud rate (between 300 and 4800) * irq interrupt line of the port; common values are 4,3 @@ -61,6 +64,7 @@ * reduced interrupt load in transmit case * reworked receiver * 0.7 03.08.99 adapt to Linus' new __setup/__initcall + * 0.8 10.08.99 use module_init/module_exit */ /*****************************************************************************/ @@ -79,11 +83,6 @@ #define BAYCOM_DEBUG -/* - * modem options; bit mask - */ -#define BAYCOM_OPTIONS_SOFTDCD 1 - /* --------------------------------------------------------------------- */ static const char bc_drvname[] = "baycom_ser_fdx"; @@ -122,7 +121,7 @@ struct hdlcdrv_state hdrv; unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout; - unsigned int options; + int opt_dcd; struct modem_state { unsigned char flags; @@ -251,7 +250,7 @@ bc->modem.shreg >>= 1; } if (bc->modem.ser12.dcd_time <= 0) { - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) + if (!bc->opt_dcd) hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + bc->modem.ser12.dcd_sum1 + bc->modem.ser12.dcd_sum2) < 0); @@ -300,8 +299,8 @@ do_gettimeofday(&tv); msr = inb(MSR(dev->base_addr)); /* delta DCD */ - if ((msr & 8) && !(bc->options & BAYCOM_OPTIONS_SOFTDCD)) - hdlcdrv_setdcd(&bc->hdrv, !(msr & 0x80)); + if ((msr & 8) && bc->opt_dcd) + hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); do { switch (iir & 6) { case 6: @@ -334,8 +333,8 @@ default: msr = inb(MSR(dev->base_addr)); /* delta DCD */ - if ((msr & 8) && !(bc->options & BAYCOM_OPTIONS_SOFTDCD)) - hdlcdrv_setdcd(&bc->hdrv, !(msr & 0x80)); + if ((msr & 8) && bc->opt_dcd) + hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); break; } iir = inb(IIR(dev->base_addr)); @@ -455,9 +454,8 @@ */ outb(0x00, THR(dev->base_addr)); hdlcdrv_setdcd(&bc->hdrv, 0); - printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u options " - "0x%x baud %u uart %s\n", bc_drvname, dev->base_addr, dev->irq, - bc->options, bc->baud, uart_str[u]); + printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n", + bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]); MOD_INC_USE_COUNT; return 0; } @@ -514,7 +512,12 @@ if (baud >= 3 && baud <= 48) bc->baud = baud*100; } - bc->options = !!strchr(modestr, '*'); + if (strchr(modestr, '*')) + bc->opt_dcd = 0; + else if (strchr(modestr, '+')) + bc->opt_dcd = -1; + else + bc->opt_dcd = 1; return 0; } @@ -544,8 +547,8 @@ case HDLCDRVCTL_GETMODE: sprintf(hi->data.modename, "ser%u", bc->baud / 100); - if (bc->options & 1) - strcat(hi->data.modename, "*"); + if (bc->opt_dcd <= 0) + strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+"); if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) return -EFAULT; return 0; @@ -598,12 +601,21 @@ static int irq[NR_PORTS] = { 4, }; static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 }; +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); +MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(irq, "baycom irq number"); +MODULE_PARM(baud, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); + /* --------------------------------------------------------------------- */ -#ifndef MODULE -static -#endif -int __init init_module(void) +static int __init init_baycomserfdx(void) { int i, j, found = 0; char set_hw = 1; @@ -641,23 +653,7 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "baycom io base address"); -MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(irq, "baycom irq number"); -MODULE_PARM(baud, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); - -void cleanup_module(void) +static void __exit cleanup_baycomserfdx(void) { int i; @@ -675,22 +671,29 @@ } } -#else /* MODULE */ +module_init(init_baycomserfdx); +module_exit(cleanup_baycomserfdx); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE /* * format: baycom_ser_fdx=io,irq,mode - * mode: [*] - * * indicates sofware DCD + * mode: ser# hardware DCD + * ser#* software DCD + * ser#+ hardware DCD, inverted signal at DCD pin + * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' */ static int __init baycom_ser_fdx_setup(char *str) { static unsigned __initdata nr_dev = 0; - int ints[11]; + int ints[4]; if (nr_dev >= NR_PORTS) return 0; - str = get_options(str, ints); + str = get_options(str, 4, ints); if (ints[0] < 2) return 0; mode[nr_dev] = str; @@ -703,7 +706,6 @@ } __setup("baycom_ser_fdx=", baycom_ser_fdx_setup); -__initcall(init_module); #endif /* MODULE */ /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c --- v2.3.14/linux/drivers/net/hamradio/baycom_ser_hdx.c Wed Aug 18 11:38:50 1999 +++ linux/drivers/net/hamradio/baycom_ser_hdx.c Mon Aug 23 11:15:27 1999 @@ -37,7 +37,11 @@ * * Command line options (insmod command line) * - * mode * enables software DCD. + * mode ser12 hardware DCD + * ser12* software DCD + * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware + * mutes audio input to the modem + * ser12+ hardware DCD, inverted signal at DCD pin * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 * irq interrupt line of the port; common values are 4,3 * @@ -50,6 +54,7 @@ * 0.5 11.11.97 ser12/par96 split into separate files * 0.6 14.04.98 cleanups * 0.7 03.08.99 adapt to Linus' new __setup/__initcall + * 0.8 10.08.99 use module_init/module_exit */ /*****************************************************************************/ @@ -68,11 +73,6 @@ #define BAYCOM_DEBUG -/* - * modem options; bit mask - */ -#define BAYCOM_OPTIONS_SOFTDCD 1 - /* --------------------------------------------------------------------- */ static const char bc_drvname[] = "baycom_ser_hdx"; @@ -110,7 +110,7 @@ struct baycom_state { struct hdlcdrv_state hdrv; - unsigned int options; + int opt_dcd; struct modem_state { short arb_divider; @@ -195,10 +195,9 @@ /* * must call the TX arbitrator every 10ms */ -#define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ - 36 : 24) -#define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \ - 240 : 12) +#define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36) + +#define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240) static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc) { @@ -230,7 +229,7 @@ (cur_s != bc->modem.ser12.last_sample); bc->modem.ser12.last_sample = cur_s; if(bc->modem.ser12.dcd_shreg & 1) { - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { + if (!bc->opt_dcd) { unsigned int dcdspos, dcdsneg; dcdspos = dcdsneg = 0; @@ -256,7 +255,7 @@ bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); } bc->modem.ser12.dcd_time--; - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { + if (!bc->opt_dcd) { /* * PLL code for the improved software DCD algorithm */ @@ -360,9 +359,12 @@ bc->modem.shreg = 0x10000; } if(!bc->modem.ser12.dcd_time) { - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); + if (bc->opt_dcd & 1) + hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80)); + else + hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + + bc->modem.ser12.dcd_sum1 + + bc->modem.ser12.dcd_sum2) < 0); bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; /* offset to ensure DCD off on silent input */ @@ -499,10 +501,9 @@ * we get exactly (hopefully) 2 or 3 interrupts per radio symbol, * depending on the usage of the software DCD routine */ - ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6); - printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options " - "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq, - bc->options, uart_str[u]); + ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4); + printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n", + bc_drvname, dev->base_addr, dev->irq, uart_str[u]); MOD_INC_USE_COUNT; return 0; } @@ -552,7 +553,14 @@ static int baycom_setmode(struct baycom_state *bc, const char *modestr) { - bc->options = !!strchr(modestr, '*'); + if (strchr(modestr, '*')) + bc->opt_dcd = 0; + else if (strchr(modestr, '+')) + bc->opt_dcd = -1; + else if (strchr(modestr, '@')) + bc->opt_dcd = -2; + else + bc->opt_dcd = 1; return 0; } @@ -582,8 +590,8 @@ case HDLCDRVCTL_GETMODE: strcpy(hi->data.modename, "ser12"); - if (bc->options & 1) - strcat(hi->data.modename, "*"); + if (bc->opt_dcd <= 0) + strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+"); if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) return -EFAULT; return 0; @@ -635,12 +643,19 @@ static int iobase[NR_PORTS] = { 0x3f8, }; static int irq[NR_PORTS] = { 4, }; +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); +MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(irq, "baycom irq number"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); + /* --------------------------------------------------------------------- */ -#ifndef MODULE -static -#endif -int __init init_module(void) +static int __init init_baycomserhdx(void) { int i, j, found = 0; char set_hw = 1; @@ -677,21 +692,7 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "baycom io base address"); -MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(irq, "baycom irq number"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); - -void cleanup_module(void) +static void __exit cleanup_baycomserhdx(void) { int i; @@ -709,22 +710,30 @@ } } -#else /* MODULE */ +module_init(init_baycomserhdx); +module_exit(cleanup_baycomserhdx); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE /* * format: baycom_ser_hdx=io,irq,mode - * mode: [*] - * * indicates sofware DCD + * mode: ser12 hardware DCD + * ser12* software DCD + * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware + * mutes audio input to the modem + * ser12+ hardware DCD, inverted signal at DCD pin */ static int __init baycom_ser_hdx_setup(char *str) { static unsigned __initdata nr_dev = 0; - int ints[11]; + int ints[3]; if (nr_dev >= NR_PORTS) return 0; - str = get_options(str, ints); + str = get_options(str, 3, ints); if (ints[0] < 2) return 0; mode[nr_dev] = str; @@ -735,7 +744,6 @@ } __setup("baycom_ser_hdx=", baycom_ser_hdx_setup); -__initcall(init_module); #endif /* MODULE */ /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.3.14/linux/drivers/net/hamradio/bpqether.c Wed Aug 18 11:38:50 1999 +++ linux/drivers/net/hamradio/bpqether.c Mon Aug 23 10:01:02 1999 @@ -76,7 +76,7 @@ #include #include #include -#include +#include #include #include #include @@ -525,7 +525,7 @@ sprintf(buf, "bpq%d", k); - if ((odev = dev_get(buf)) == NULL || bpq_check_devices(odev)) + if ((odev = __dev_get_by_name(buf)) == NULL || bpq_check_devices(odev)) break; } diff -u --recursive --new-file v2.3.14/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c --- v2.3.14/linux/drivers/net/hamradio/soundmodem/sm.c Wed Aug 18 11:38:50 1999 +++ linux/drivers/net/hamradio/soundmodem/sm.c Mon Aug 23 11:15:27 1999 @@ -44,6 +44,7 @@ * 0.9 03.08.99 adapt to Linus' new __setup/__initcall * use parport lowlevel drivers instead of directly writing to a parallel port * removed some pre-2.2 kernel compatibility cruft + * 0.10 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts */ /*****************************************************************************/ @@ -56,6 +57,7 @@ #include #include #include +#include #include "sm.h" /* --------------------------------------------------------------------- */ @@ -300,6 +302,8 @@ pp = pp->next; if (!pp) printk(KERN_WARNING "%s: parport at address 0x%x not found\n", sm_drvname, sm->hdrv.ptt_out.pariobase); + else if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) + printk(KERN_WARNING "%s: parport at address 0x%x cannot be used\n", sm_drvname, sm->hdrv.ptt_out.pariobase); else { sm->pardev = parport_register_device(pp, sm->hdrv.ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); if (!sm->pardev) { @@ -609,12 +613,29 @@ static int pario[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 }; static int midiio[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 }; +MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); +MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); +MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(iobase, "soundmodem base address"); +MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(irq, "soundmodem interrupt"); +MODULE_PARM(dma, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(dma, "soundmodem dma channel"); +MODULE_PARM(dma2, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); +MODULE_PARM(serio, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); +MODULE_PARM(pario, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); +MODULE_PARM(midiio, "1-" __MODULE_STRING(NR_PORTS) "i"); +MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); + /* --------------------------------------------------------------------- */ -#ifndef MODULE -static -#endif -int __init init_module(void) +static int __init init_soundmodem(void) { int i, j, found = 0; char set_hw = 1; @@ -669,31 +690,7 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "soundmodem base address"); -MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(irq, "soundmodem interrupt"); -MODULE_PARM(dma, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(dma, "soundmodem dma channel"); -MODULE_PARM(dma2, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); -MODULE_PARM(serio, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); -MODULE_PARM(pario, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); -MODULE_PARM(midiio, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); - -void cleanup_module(void) +static void __exit cleanup_soundmodem(void) { int i; @@ -713,7 +710,12 @@ } } -#else /* MODULE */ +module_init(init_soundmodem); +module_exit(cleanup_soundmodem); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE /* * format: soundmodem=io,irq,dma[,dma2[,serio[,pario]]],mode @@ -725,11 +727,11 @@ static int __init sm_setup(char *str) { static unsigned __initdata nr_dev = 0; - int ints[11]; + int ints[8]; if (nr_dev >= NR_PORTS) return 0; - str = get_options(str, ints); + str = get_options(str, 8, ints); mode[nr_dev] = str; if (ints[0] >= 1) iobase[nr_dev] = ints[1]; @@ -750,7 +752,6 @@ } __setup("soundmodem=", sm_setup); -__initcall(init_module); #endif /* MODULE */ /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.3.14/linux/drivers/net/hydra.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/hydra.c Thu Aug 19 10:54:10 1999 @@ -3,7 +3,7 @@ /* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi) */ /* The code is mostly based on the linux/68k Ariadne driver */ -/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */ +/* copyrighted by Geert Uytterhoeven (geert@linux-m68k.org) */ /* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) */ /* This file is subject to the terms and conditions of the GNU General */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.3.14/linux/drivers/net/lapbether.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/lapbether.c Mon Aug 23 10:01:02 1999 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include @@ -436,7 +436,7 @@ sprintf(buf, "lapb%d", k); - if ((odev = dev_get(buf)) == NULL || lapbeth_check_devices(odev)) + if ((odev = __dev_get_by_name(buf)) == NULL || lapbeth_check_devices(odev)) break; } diff -u --recursive --new-file v2.3.14/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.14/linux/drivers/net/net_init.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/net_init.c Mon Aug 23 10:12:38 1999 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,7 @@ /* Use an existing correctly named device in Space.c:dev_base. */ if (dev == NULL) { - int alloc_size = sizeof(struct net_device) + sizeof("eth%d ") + int alloc_size = sizeof(struct net_device) + IFNAMSIZ + sizeof_priv + 3; struct net_device *cur_dev; char pname[8]; /* Putative name for the device. */ @@ -207,7 +208,7 @@ /* Use an existing correctly named device in Space.c:dev_base. */ if (dev == NULL) { - int alloc_size = sizeof(struct net_device) + sizeof("hip%d ") + int alloc_size = sizeof(struct net_device) + IFNAMSIZ + sizeof_priv + 3; struct net_device *cur_dev; char pname[8]; @@ -540,7 +541,7 @@ /* Use an existing correctly named device in Space.c:dev_base. */ if (dev == NULL) { - int alloc_size = sizeof(struct net_device) + sizeof("tr%d ") + int alloc_size = sizeof(struct net_device) + IFNAMSIZ + sizeof_priv + 3; struct net_device *cur_dev; char pname[8]; /* Putative name for the device. */ @@ -657,7 +658,130 @@ } #endif - + +#ifdef CONFIG_NET_FC + +#define MAX_FC_CARDS 2 +static struct net_device *fcdev_index[MAX_FC_CARDS]; + +void fc_setup(struct net_device *dev) +{ +int i; + + /* register boot-defined "fc" devices */ + if (dev->name && (strncmp(dev->name, "fc", 2) == 0)) { + i = simple_strtoul(dev->name + 2, NULL, 0); + if (fcdev_index[i] == NULL) { + fcdev_index[i] = dev; + } + else if (dev != fcdev_index[i]) { + /* Really shouldn't happen! */ + printk("fc_setup: Ouch! Someone else took %s\n", + dev->name); + } + } + + dev->hard_header = fc_header; + dev->rebuild_header = fc_rebuild_header; + + dev->type = ARPHRD_IEEE802; + dev->hard_header_len = FC_HLEN; + dev->mtu = 2024; + dev->addr_len = FC_ALEN; + dev->tx_queue_len = 100; /* Long queues on fc */ + + memset(dev->broadcast,0xFF, FC_ALEN); + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + dev_init_buffers(dev); + return; +} + + +struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv) +{ +int new_device = 0; +int i; + /* Use an existing correctly named device in Space.c:dev_base. */ + if (dev == NULL) { + int alloc_size = sizeof(struct net_device) + sizeof("fc%d ") + sizeof_priv + 3; + struct net_device *cur_dev; + char pname[8]; /* Putative name for the device. */ + + for (i = 0; i < MAX_FC_CARDS; ++i) + if (fcdev_index[i] == NULL) { + sprintf(pname, "fc%d", i); + for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next) + if (strcmp(pname, cur_dev->name) == 0) { + dev = cur_dev; + dev->init = NULL; + sizeof_priv = (sizeof_priv + 3) &~3; + dev->priv = sizeof_priv + ? kmalloc(sizeof_priv, GFP_KERNEL) + : NULL; + if (dev->priv) memset(dev->priv, 0, sizeof_priv); + goto fcfound; + } + } + + alloc_size &= ~3; /* Round to dword boundary. */ + dev = (struct net_device *)kmalloc(alloc_size, GFP_KERNEL); + memset(dev, 0, alloc_size); + if (sizeof_priv) + dev->priv = (void *) (dev + 1); + dev->name = sizeof_priv + (char *)(dev + 1); + new_device = 1; + } + +fcfound: /* From the double loop */ + + for (i = 0; i < MAX_FC_CARDS; ++i) + if (fcdev_index[i] == NULL) { + sprintf(dev->name, "fc%d", i); + fcdev_index[i] = dev; + break; + } + + fc_setup(dev); + if (new_device) + register_netdevice(dev); + + return dev; +} + +void fc_freedev(struct net_device *dev) +{ +int i; + for (i = 0; i < MAX_FC_CARDS; ++i) { + if (fcdev_index[i] == dev) { + fcdev_index[i] = NULL; + break; + } + } +} + + +int register_fcdev(struct net_device *dev) +{ + dev_init_buffers(dev); + if (dev->init && dev->init(dev) != 0) { + unregister_fcdev(dev); + return -EIO; + } + return 0; +} + +void unregister_fcdev(struct net_device *dev) +{ + rtnl_lock(); + unregister_netdevice(dev); + rtnl_unlock(); + fc_freedev(dev); +} + +#endif /* CONFIG_NET_FC */ + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c" diff -u --recursive --new-file v2.3.14/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c --- v2.3.14/linux/drivers/net/ppp_async.c Fri Aug 6 10:44:11 1999 +++ linux/drivers/net/ppp_async.c Wed Aug 25 15:40:14 1999 @@ -313,7 +313,7 @@ switch (cmd) { case PPPIOCGFLAGS: val = ap->flags | ap->rbits; - if (put_user(ap->flags, (int *) arg)) + if (put_user(val, (int *) arg)) break; err = 0; break; diff -u --recursive --new-file v2.3.14/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c --- v2.3.14/linux/drivers/net/sb1000.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sb1000.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,1293 @@ +/* sb1000.c: A General Instruments SB1000 driver for linux. */ +/* + Written 1998 by Franco Venturi. + + Copyright 1998 by Franco Venturi. + Copyright 1994,1995 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This driver is for the General Instruments SB1000 (internal SURFboard) + + The author may be reached as fventuri@mediaone.net + + This program is free software; you can redistribute it + and/or modify it under the terms of the GNU General + Public License as published by the Free Software + Foundation; either version 2 of the License, or (at + your option) any later version. + + Changes: + + 981115 Steven Hirsch + + Linus changed the timer interface. Should work on all recent + development kernels. + + 980608 Steven Hirsch + + Small changes to make it work with 2.1.x kernels. Hopefully, + nothing major will change before official release of Linux 2.2. + + Merged with 2.2 - Alan Cox +*/ + +static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for udelay() */ +#include + +#include +#include +#include +#include + +/* for SIOGCM/SIOSCM stuff */ +#include + +#ifdef SB1000_DEBUG +int sb1000_debug = SB1000_DEBUG; +#else +int sb1000_debug = 1; +#endif + +static const int SB1000_IO_EXTENT = 8; +/* SB1000 Maximum Receive Unit */ +static const int SB1000_MRU = 1500; /* octects */ + +#define NPIDS 4 +struct sb1000_private { + struct sk_buff *rx_skb[NPIDS]; + short rx_dlen[NPIDS]; + unsigned int rx_bytes; + unsigned int rx_frames; + short rx_error_count; + short rx_error_dpc_count; + unsigned char rx_session_id[NPIDS]; + unsigned char rx_frame_id[NPIDS]; + unsigned char rx_pkt_type[NPIDS]; + struct net_device_stats stats; +}; + +/* prototypes for Linux interface */ +extern int sb1000_probe(struct net_device *dev); +static int sb1000_open(struct net_device *dev); +static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct enet_statistics *sb1000_stats(struct net_device *dev); +static int sb1000_close(struct net_device *dev); + +/* Plug-n-Play routine */ +static inline unsigned char read_resource_data(void); + +/* SB1000 hardware routines to be used during open/configuration phases */ +static inline void nicedelay(unsigned long usecs); +static inline int card_wait_for_busy_clear(const int ioaddr[], + const char* name); +static inline int card_wait_for_ready(const int ioaddr[], const char* name, + unsigned char in[]); +static inline int card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]); + +/* SB1000 hardware routines to be used during frame rx interrupt */ +static inline int sb1000_wait_for_ready(const int ioaddr[], const char* name); +static inline int sb1000_wait_for_ready_clear(const int ioaddr[], + const char* name); +static inline void sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]); +static inline void sb1000_read_status(const int ioaddr[], unsigned char in[]); +static inline void sb1000_issue_read_command(const int ioaddr[], + const char* name); + +/* SB1000 commands for open/configuration */ +static inline int sb1000_reset(const int ioaddr[], const char* name); +static inline int sb1000_check_CRC(const int ioaddr[], const char* name); +static inline int sb1000_start_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_end_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_activate(const int ioaddr[], const char* name); +static inline int sb1000_get_firmware_version(const int ioaddr[], + const char* name, unsigned char version[], int do_end); +static inline int sb1000_get_frequency(const int ioaddr[], const char* name, + int* frequency); +static inline int sb1000_set_frequency(const int ioaddr[], const char* name, + int frequency); +static inline int sb1000_get_PIDs(const int ioaddr[], const char* name, + short PID[]); +static inline int sb1000_set_PIDs(const int ioaddr[], const char* name, + const short PID[]); + +/* SB1000 commands for frame rx interrupt */ +static inline int sb1000_rx(struct net_device *dev); +static inline void sb1000_error_dpc(struct net_device *dev); + + +/* Plug-n-Play constants */ +static const int READ_DATA_PORT = 0x203; /* This port number may change!!! */ +static const int ADDRESS_PORT = 0x279; +static const int WRITE_DATA_PORT = 0xa79; + +/* Plug-n-Play read resource mechanism */ +static inline unsigned char +read_resource_data(void) { + /* poll */ + outb(0x05, ADDRESS_PORT); /* Select PnP status register. */ + while (!(inb(READ_DATA_PORT) & 0x1)) ; + /* read resource data */ + outb(0x04, ADDRESS_PORT); /* Select PnP resource data register. */ + return inb(READ_DATA_PORT); +} + +/* probe for SB1000 using Plug-n-Play mechanism */ +int +sb1000_probe(struct net_device *dev) +{ + + unsigned short ioaddr[2], irq; + short i, csn; + unsigned int serial_number; + + const unsigned char initiation_key[] = { 0x00, 0x00, 0x6a, 0xb5, 0xda, + 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, + 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, + 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; + const unsigned char sb1000_vendor_ID[] = { + 0x1d, 0x23, 0x10, 0x00 }; /* "GIC1000" */ + + /* Reset the ISA PnP mechanism */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* send initiation key */ + for (i = 0; i < sizeof(initiation_key) / sizeof(initiation_key[0]); i++) { + outb(initiation_key[i], ADDRESS_PORT); + } + + /* set card CSN into configuration mode */ + for (csn = 1; csn <= 255; csn++) { + outb(0x03, ADDRESS_PORT); /* Select PnP wake[CSN] register. */ + outb(csn, WRITE_DATA_PORT); /* Wake[CSN] */ + /* check card ID */ + for (i = 0; i < 4; i++) { + if (read_resource_data() != sb1000_vendor_ID[i]) break; + } + if (i == 4) break; + } + + /* SB1000 not found */ + if (csn > 255) { + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT);/* Return to WaitForKey state. */ + return -ENODEV; + } + + /* found: get serial number and skip checksum */ + serial_number = 0; + for (i = 0; i < 4; i++) { + serial_number |= read_resource_data() << (8 * i); + } + read_resource_data(); + + /* get I/O port base address */ + outb(0x60, ADDRESS_PORT); /* Select PnP I/O port base address 0. */ + ioaddr[0] = inb(READ_DATA_PORT) << 8; + outb(0x61, ADDRESS_PORT); + ioaddr[0] |= inb(READ_DATA_PORT); + outb(0x62, ADDRESS_PORT); /* Select PnP I/O port base address 1. */ + ioaddr[1] = inb(READ_DATA_PORT) << 8; + outb(0x63, ADDRESS_PORT); + ioaddr[1] |= inb(READ_DATA_PORT); + + /* get IRQ */ + outb(0x70, ADDRESS_PORT); /* Select PnP IRQ level select 0. */ + irq = inb(READ_DATA_PORT); + + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* check I/O base and IRQ */ + if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) { + return -ENODEV; + } + if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) { + return -ENODEV; + } + if (dev->irq != 0 && dev->irq != irq) { + return -ENODEV; + } + + dev->base_addr = ioaddr[0]; + /* rmem_end holds the second I/O address - fv */ + dev->rmem_end = ioaddr[1]; + dev->irq = irq; + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), csn %d, " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->rmem_end, csn, serial_number, dev->irq); + + dev = init_etherdev(dev, 0); + + /* Make up a SB1000-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct sb1000_private)); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* Fill in the generic fields of the device structure. */ + dev->change_mtu = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->header_cache_update= NULL; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = 0; + dev->mtu = 1500; + dev->addr_len = ETH_ALEN; + /* hardware address is 0:0:serial_number */ + dev->dev_addr[0] = 0; + dev->dev_addr[1] = 0; + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + dev->tx_queue_len = 0; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; + return 0; +} + + +/* + * SB1000 hardware routines to be used during open/configuration phases + */ +const int TimeOutJiffies = (int)(8.75 * HZ); + +static inline void nicedelay(unsigned long usecs) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + return; +} + +/* Card Wait For Busy Clear (cannot be used during an interrupt) */ +static inline int +card_wait_for_busy_clear(const int ioaddr[], const char* name) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[0] + 7); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || a & 0x40) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[0] + 7); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_busy_clear timeout\n", + name); + return -ETIME; + } + } + + return 0; +} + +/* Card Wait For Ready (cannot be used during an interrupt) */ +static inline int +card_wait_for_ready(const int ioaddr[], const char* name, unsigned char in[]) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[1] + 6); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || !(a & 0x40)) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[1] + 6); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + in[6] = inb(ioaddr[0] + 6); + in[5] = inb(ioaddr[1] + 6); + return 0; +} + +/* Card Send Command (cannot be used during an interrupt) */ +static inline int +card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]) +{ + int status, x; + + if ((status = card_wait_for_busy_clear(ioaddr, name))) + return status; + outb(0xa0, ioaddr[0] + 6); + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(0xa0, ioaddr[0] + 6); + outb(out[0], ioaddr[0] + 7); + if (out[0] != 0x20 && out[0] != 0x30) { + if ((status = card_wait_for_ready(ioaddr, name, in))) + return status; + inb(ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x " + "in: %02x%02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5], + in[0], in[1], in[2], in[3], in[4], in[5], in[6]); + } else { + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5]); + } + + if (out[1] == 0x1b) { + x = (out[2] == 0x02); + } else { + if (out[0] >= 0x80 && in[0] != (out[1] | 0x80)) + return -EIO; + } + return 0; +} + + +/* + * SB1000 hardware routines to be used during frame rx interrupt + */ +const int Sb1000TimeOutJiffies = 7 * HZ; + +/* Card Wait For Ready (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (!(inb(ioaddr[1] + 6) & 0x40)) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + inb(ioaddr[0] + 7); + return 0; +} + +/* Card Wait For Ready Clear (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready_clear(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x40) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + return 0; +} + +/* Card Send Command (to be used during frame rx) */ +static inline void +sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]) +{ + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(out[0], ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: sb1000_send_command out: %02x%02x%02x%02x" + "%02x%02x\n", name, out[0], out[1], out[2], out[3], out[4], out[5]); + return; +} + +/* Card Read Status (to be used during frame rx) */ +static inline void +sb1000_read_status(const int ioaddr[], unsigned char in[]) +{ + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + return; +} + +/* Issue Read Command (to be used during frame rx) */ +static inline void +sb1000_issue_read_command(const int ioaddr[], const char* name) +{ + const unsigned char Command0[6] = {0x20, 0x00, 0x00, 0x01, 0x00, 0x00}; + + sb1000_wait_for_ready_clear(ioaddr, name); + outb(0xa0, ioaddr[0] + 6); + sb1000_send_command(ioaddr, name, Command0); + return; +} + + +/* + * SB1000 commands for open/configuration + */ +/* reset SB1000 card */ +static inline int +sb1000_reset(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int port, status; + const unsigned char Command0[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + port = ioaddr[1] + 6; + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + nicedelay(60000); + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + udelay(0); + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[3] != 0xf0) + return -EIO; + return 0; +} + +/* check SB1000 firmware CRC */ +static inline int +sb1000_check_CRC(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int crc, status; + const unsigned char Command0[6] = {0x80, 0x1f, 0x00, 0x00, 0x00, 0x00}; + + /* check CRC */ + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[1] != st[3] || st[2] != st[4]) + return -EIO; + crc = st[1] << 8 | st[2]; + return 0; +} + +static inline int +sb1000_start_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + const unsigned char Command0[6] = {0x80, 0x1b, 0x00, 0x00, 0x00, 0x00}; + + return card_send_command(ioaddr, name, Command0, st); +} + +static inline int +sb1000_end_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x1b, 0x02, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + return card_send_command(ioaddr, name, Command1, st); +} + +static inline int +sb1000_activate(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + nicedelay(50000); + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + if (st[3] != 0xf1) { + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + return -EIO; + } + udelay(1000); + return sb1000_start_get_set_command(ioaddr, name); +} + +/* get SB1000 firmware version */ +static inline int +sb1000_get_firmware_version(const int ioaddr[], const char* name, + unsigned char version[], int do_end) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x23, 0x00, 0x00, 0x00, 0x00}; + + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[0] != 0xa3) + return -EIO; + version[0] = st[1]; + version[1] = st[2]; + if (do_end) + return sb1000_end_get_set_command(ioaddr, name); + else + return 0; +} + +/* get SB1000 frequency */ +static inline int +sb1000_get_frequency(const int ioaddr[], const char* name, int* frequency) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x44, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + *frequency = ((st[1] << 8 | st[2]) << 8 | st[3]) << 8 | st[4]; + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 frequency */ +static inline int +sb1000_set_frequency(const int ioaddr[], const char* name, int frequency) +{ + unsigned char st[7]; + int status; + unsigned char Command0[6] = {0x80, 0x29, 0x00, 0x00, 0x00, 0x00}; + + const int FrequencyLowerLimit = 57000; + const int FrequencyUpperLimit = 804000; + + if (frequency < FrequencyLowerLimit || frequency > FrequencyUpperLimit) { + printk(KERN_ERR "%s: frequency chosen (%d kHz) is not in the range " + "[%d,%d] kHz\n", name, frequency, FrequencyLowerLimit, + FrequencyUpperLimit); + return -EINVAL; + } + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + Command0[5] = frequency & 0xff; + frequency >>= 8; + Command0[4] = frequency & 0xff; + frequency >>= 8; + Command0[3] = frequency & 0xff; + frequency >>= 8; + Command0[2] = frequency & 0xff; + return card_send_command(ioaddr, name, Command0, st); +} + +/* get SB1000 PIDs */ +static inline int +sb1000_get_PIDs(const int ioaddr[], const char* name, short PID[]) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x40, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x41, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command2[6] = {0x80, 0x42, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command3[6] = {0x80, 0x43, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + PID[0] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + PID[1] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + PID[2] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + PID[3] = st[1] << 8 | st[2]; + + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 PIDs */ +static inline int +sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[]) +{ + unsigned char st[7]; + short p; + int status; + unsigned char Command0[6] = {0x80, 0x31, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command1[6] = {0x80, 0x32, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command2[6] = {0x80, 0x33, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command3[6] = {0x80, 0x34, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command4[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + p = PID[0]; + Command0[3] = p & 0xff; + p >>= 8; + Command0[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + + p = PID[1]; + Command1[3] = p & 0xff; + p >>= 8; + Command1[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + + p = PID[2]; + Command2[3] = p & 0xff; + p >>= 8; + Command2[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + + p = PID[3]; + Command3[3] = p & 0xff; + p >>= 8; + Command3[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + + if ((status = card_send_command(ioaddr, name, Command4, st))) + return status; + return sb1000_end_get_set_command(ioaddr, name); +} + + +static inline void +sb1000_print_status_buffer(const char* name, unsigned char st[], + unsigned char buffer[], int size) +{ + int i, j, k; + + printk(KERN_DEBUG "%s: status: %02x %02x\n", name, st[0], st[1]); + if (buffer[24] == 0x08 && buffer[25] == 0x00 && buffer[26] == 0x45) { + printk(KERN_DEBUG "%s: length: %d protocol: %d from: %d.%d.%d.%d:%d " + "to %d.%d.%d.%d:%d\n", name, buffer[28] << 8 | buffer[29], + buffer[35], buffer[38], buffer[39], buffer[40], buffer[41], + buffer[46] << 8 | buffer[47], + buffer[42], buffer[43], buffer[44], buffer[45], + buffer[48] << 8 | buffer[49]); + } else { + for (i = 0, k = 0; i < (size + 7) / 8; i++) { + printk(KERN_DEBUG "%s: %s", name, i ? " " : "buffer:"); + for (j = 0; j < 8 && k < size; j++, k++) + printk(" %02x", buffer[k]); + printk("\n"); + } + } + return; +} + +/* + * SB1000 commands for frame rx interrupt + */ +/* receive a single frame and assemble datagram + * (this is the heart of the interrupt routine) + */ +static inline int +sb1000_rx(struct net_device *dev) +{ + +#define FRAMESIZE 184 + unsigned char st[2], buffer[FRAMESIZE], session_id, frame_id; + short dlen; + int ioaddr, ns; + unsigned int skbsize; + struct sk_buff *skb; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct enet_statistics *stats = &lp->stats; + + /* SB1000 frame constants */ + const int FrameSize = FRAMESIZE; + const int NewDatagramHeaderSkip = 8; + const int NewDatagramHeaderSize = NewDatagramHeaderSkip + 18; + const int NewDatagramDataSize = FrameSize - NewDatagramHeaderSize; + const int ContDatagramHeaderSkip = 7; + const int ContDatagramHeaderSize = ContDatagramHeaderSkip + 1; + const int ContDatagramDataSize = FrameSize - ContDatagramHeaderSize; + const int TrailerSize = 4; + + ioaddr = dev->base_addr; + + insw(ioaddr, (unsigned short*) st, 1); +#ifdef XXXDEBUG +printk("cm0: received: %02x %02x\n", st[0], st[1]); +#endif /* XXXDEBUG */ + lp->rx_frames++; + + /* decide if it is a good or bad frame */ + for (ns = 0; ns < NPIDS; ns++) { + session_id = lp->rx_session_id[ns]; + frame_id = lp->rx_frame_id[ns]; + if (st[0] == session_id) { + if (st[1] == frame_id || (!frame_id && (st[1] & 0xf0) == 0x30)) { + goto good_frame; + } else if ((st[1] & 0xf0) == 0x30 && (st[0] & 0x40)) { + goto skipped_frame; + } else { + goto bad_frame; + } + } else if (st[0] == (session_id | 0x40)) { + if ((st[1] & 0xf0) == 0x30) { + goto skipped_frame; + } else { + goto bad_frame; + } + } + } + goto bad_frame; + +skipped_frame: + stats->rx_frame_errors++; + skb = lp->rx_skb[ns]; + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: missing frame(s): got %02x %02x " + "expecting %02x %02x\n", dev->name, st[0], st[1], + skb ? session_id : session_id | 0x40, frame_id); + if (skb) { + dev_kfree_skb(skb); + skb = 0; + } + +good_frame: + lp->rx_frame_id[ns] = 0x30 | ((st[1] + 1) & 0x0f); + /* new datagram */ + if (st[0] & 0x40) { + /* get data length */ + insw(ioaddr, buffer, NewDatagramHeaderSize / 2); +#ifdef XXXDEBUG +printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[30], buffer[31], buffer[32], buffer[33]); +#endif /* XXXDEBUG */ + if (buffer[0] != NewDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: new datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + NewDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + dlen = ((buffer[NewDatagramHeaderSkip + 3] & 0x0f) << 8 | + buffer[NewDatagramHeaderSkip + 4]) - 17; + if (dlen > SB1000_MRU) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: datagram length (%d) greater " + "than MRU (%d)\n", dev->name, dlen, SB1000_MRU); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + lp->rx_dlen[ns] = dlen; + /* compute size to allocate for datagram */ + skbsize = dlen + FrameSize; + if ((skb = alloc_skb(skbsize, GFP_ATOMIC)) == NULL) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: can't allocate %d bytes long " + "skbuff\n", dev->name, skbsize); + stats->rx_dropped++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto dropped_frame; + } + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16]; + insw(ioaddr, skb_put(skb, NewDatagramDataSize), + NewDatagramDataSize / 2); + lp->rx_skb[ns] = skb; + } else { + /* continuation of previous datagram */ + insw(ioaddr, buffer, ContDatagramHeaderSize / 2); + if (buffer[0] != ContDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: cont datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + ContDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, ContDatagramDataSize / 2); + goto bad_frame_next; + } + skb = lp->rx_skb[ns]; + insw(ioaddr, skb_put(skb, ContDatagramDataSize), + ContDatagramDataSize / 2); + dlen = lp->rx_dlen[ns]; + } + if (skb->len < dlen + TrailerSize) { + lp->rx_session_id[ns] &= ~0x40; + return 0; + } + + /* datagram completed: send to upper level */ + skb_trim(skb, dlen); + netif_rx(skb); + stats->rx_packets++; + lp->rx_bytes += dlen; + lp->rx_skb[ns] = 0; + lp->rx_session_id[ns] |= 0x40; + return 0; + +bad_frame: + insw(ioaddr, buffer, FrameSize / 2); + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: frame error: got %02x %02x\n", + dev->name, st[0], st[1]); + stats->rx_frame_errors++; +bad_frame_next: + if (sb1000_debug > 2) + sb1000_print_status_buffer(dev->name, st, buffer, FrameSize); +dropped_frame: + stats->rx_errors++; + if (ns < NPIDS) { + if ((skb = lp->rx_skb[ns])) { + dev_kfree_skb(skb); + lp->rx_skb[ns] = 0; + } + lp->rx_session_id[ns] |= 0x40; + } + return -1; +} + +static inline void +sb1000_error_dpc(struct net_device *dev) +{ + char *name; + unsigned char st[5]; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00}; + const int ErrorDpcCounterInitialize = 200; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_read_status(ioaddr, st); + if (st[1] & 0x10) + lp->rx_error_dpc_count = ErrorDpcCounterInitialize; + return; +} + + +/* + * Linux interface functions + */ +static int +sb1000_open(struct net_device *dev) +{ + char *name; + int ioaddr[2], status; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned short FirmwareVersion[] = {0x01, 0x01}; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + request_region(ioaddr[0], SB1000_IO_EXTENT, "sb1000"); + request_region(ioaddr[1], SB1000_IO_EXTENT, "sb1000"); + + /* initialize sb1000 */ + if ((status = sb1000_reset(ioaddr, name))) + return status; + nicedelay(200000); + if ((status = sb1000_check_CRC(ioaddr, name))) + return status; + + /* initialize private data before board can catch interrupts */ + lp->rx_skb[0] = NULL; + lp->rx_skb[1] = NULL; + lp->rx_skb[2] = NULL; + lp->rx_skb[3] = NULL; + lp->rx_dlen[0] = 0; + lp->rx_dlen[1] = 0; + lp->rx_dlen[2] = 0; + lp->rx_dlen[3] = 0; + lp->rx_bytes = 0; + lp->rx_frames = 0; + lp->rx_error_count = 0; + lp->rx_error_dpc_count = 0; + lp->rx_session_id[0] = 0x50; + lp->rx_session_id[0] = 0x48; + lp->rx_session_id[0] = 0x44; + lp->rx_session_id[0] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + if (request_irq(dev->irq, &sb1000_interrupt, 0, "sb1000", dev)) { + return -EAGAIN; + } + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Opening, IRQ %d\n", name, dev->irq); + + /* Activate board and check firmware version */ + udelay(1000); + if ((status = sb1000_activate(ioaddr, name))) + return status; + udelay(0); + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 0))) + return status; + if (version[0] != FirmwareVersion[0] || version[1] != FirmwareVersion[1]) + printk(KERN_WARNING "%s: found firmware version %x.%02x " + "(should be %x.%02x)\n", name, version[0], version[1], + FirmwareVersion[0], FirmwareVersion[1]); + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + return 0; /* Always succeed */ +} + +static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + char* name; + unsigned char version[2]; + short PID[4]; + int ioaddr[2], status, frequency; + unsigned int stats[5]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (!(dev && dev->flags & IFF_UP)) + return -ENODEV; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + switch (cmd) { + case SIOCGCMSTATS: /* get statistics */ + stats[0] = lp->rx_bytes; + stats[1] = lp->rx_frames; + stats[2] = lp->stats.rx_packets; + stats[3] = lp->stats.rx_errors; + stats[4] = lp->stats.rx_dropped; + if(copy_to_user(ifr->ifr_data, stats, sizeof(stats))) + return -EFAULT; + status = 0; + break; + + case SIOCGCMFIRMWARE: /* get firmware version */ + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 1))) + return status; + if(copy_to_user(ifr->ifr_data, version, sizeof(version))) + return -EFAULT; + break; + + case SIOCGCMFREQUENCY: /* get frequency */ + if ((status = sb1000_get_frequency(ioaddr, name, &frequency))) + return status; + if(put_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + break; + + case SIOCSCMFREQUENCY: /* set frequency */ + if (!suser()) + return -EPERM; + if(get_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + if ((status = sb1000_set_frequency(ioaddr, name, frequency))) + return status; + break; + + case SIOCGCMPIDS: /* get PIDs */ + if ((status = sb1000_get_PIDs(ioaddr, name, PID))) + return status; + if(copy_to_user(ifr->ifr_data, PID, sizeof(PID))) + return -EFAULT; + break; + + case SIOCSCMPIDS: /* set PIDs */ + if (!suser()) + return -EPERM; + if(copy_from_user(PID, ifr->ifr_data, sizeof(PID))) + return -EFAULT; + if ((status = sb1000_set_PIDs(ioaddr, name, PID))) + return status; + /* set session_id, frame_id and pkt_type too */ + lp->rx_session_id[0] = 0x50 | (PID[0] & 0x0f); + lp->rx_session_id[1] = 0x48; + lp->rx_session_id[2] = 0x44; + lp->rx_session_id[3] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + break; + + default: + status = -EINVAL; + break; + } + return status; +} + +/* transmit function: do nothing since SB1000 can't send anything out */ +static int +sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); + /* sb1000 can't xmit datagrams */ + dev_kfree_skb(skb); + return 0; +} + +/* SB1000 interrupt handler. */ +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char *name; + unsigned char st; + int ioaddr[2]; + struct net_device *dev = (struct net_device *) dev_id; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + const int MaxRxErrorCount = 6; + + if (dev == NULL) { + printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n", + irq); + return; + } + if (dev->interrupt) + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", + dev->name); + dev->interrupt = 1; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + /* is it a good interrupt? */ + st = inb(ioaddr[1] + 6); + if (!(st & 0x08 && st & 0x20)) { + dev->interrupt = 0; + return; + } + + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: entering interrupt\n", dev->name); + + st = inb(ioaddr[0] + 7); + if (sb1000_rx(dev)) + lp->rx_error_count++; +#ifdef SB1000_DELAY + udelay(SB1000_DELAY); +#endif /* SB1000_DELAY */ + sb1000_issue_read_command(ioaddr, name); + if (st & 0x01) { + sb1000_error_dpc(dev); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_dpc_count && !(--lp->rx_error_dpc_count)) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_count >= MaxRxErrorCount) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command1); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + lp->rx_error_count = 0; + } + + dev->interrupt = 0; + return; +} + +static struct net_device_stats *sb1000_stats(struct net_device *dev) +{ + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + return &lp->stats; +} + +static int sb1000_close(struct net_device *dev) +{ + int i; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name); + + dev->tbusy = 1; + dev->start = 0; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + + free_irq(dev->irq, dev); + /* If we don't do this, we can't re-insmod it later. */ + release_region(ioaddr[1], SB1000_IO_EXTENT); + release_region(ioaddr[0], SB1000_IO_EXTENT); + + /* free rx_skb's if needed */ + for (i=0; i<4; i++) { + if (lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i]); + } + } + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE +MODULE_AUTHOR("Franco Venturi "); +MODULE_DESCRIPTION("General Instruments SB1000 driver"); +MODULE_PARM(io, "1-2i"); +MODULE_PARM(irq, "i"); + +static char devname[8] = {0, }; +static struct net_device dev_sb1000 = { + devname, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, sb1000_probe }; + +static int io[2] = {0, 0}; +static int irq = 0; + +int +init_module(void) +{ + int i; + for (i = 0; i < 100; i++) { + sprintf(devname, "cm%d", i); + if (dev_get(devname) == NULL) break; + } + if (i == 100) { + printk(KERN_ERR "sb1000: can't register any device cm\n"); + return -ENFILE; + } + dev_sb1000.base_addr = io[0]; + /* rmem_end holds the second I/O address - fv */ + dev_sb1000.rmem_end = io[1]; + dev_sb1000.irq = irq; + if (register_netdev(&dev_sb1000) != 0) { + printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x " + "irq: %d)\n", io[0], io[1], irq); + return -EIO; + } + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_sb1000); + kfree_s(dev_sb1000.priv, sizeof(struct sb1000_private)); + dev_sb1000.priv = NULL; +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O -m486 -c sb1000.c" + * version-control: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.3.14/linux/drivers/net/shaper.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/shaper.c Mon Aug 23 10:01:02 1999 @@ -561,7 +561,7 @@ { case SHAPER_SET_DEV: { - struct net_device *them=dev_get(ss->ss_name); + struct net_device *them=__dev_get_by_name(ss->ss_name); if(them==NULL) return -ENODEV; if(sh->dev) diff -u --recursive --new-file v2.3.14/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.3.14/linux/drivers/net/sis900.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sis900.c Mon Aug 23 10:12:38 1999 @@ -0,0 +1,1909 @@ +/*****************************************************************************/ +/* sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux. */ +/* */ +/* Silicon Integrated System Corporation */ +/* Revision: 1.05 Aug 7 1999 */ +/* */ +/*****************************************************************************/ + +/* + Modified from the driver which is originally written by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + The author may be reached as becker@tidalwave.net, or + Donald Becker + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Support and updates [to the original skeleton] available at + http://www.tidalwave.net/~becker/pci-skeleton.html +*/ + +static const char *version = +"sis900.c:v1.05 8/07/99\n"; + +static int max_interrupt_work = 20; +#define sis900_debug debug +static int sis900_debug = 0; + +static int multicast_filter_limit = 128; + +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int speeds[MAX_UNITS] = {100, 100, 100, 100, 100, 100, 100, 100}; +static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1}; + +#define TX_BUF_SIZE 1536 +#define RX_BUF_SIZE 1536 + +#define TX_DMA_BURST 0 +#define RX_DMA_BURST 0 +#define TX_FIFO_THRESH 16 +#define TxDRNT_100 (1536>>5) +#define TxDRNT_10 16 +#define RxDRNT_100 8 +#define RxDRNT_10 8 +#define TRUE 1 +#define FALSE 0 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +#define RUN_AT(x) (jiffies + (x)) + +#include + +#if LINUX_VERSION_CODE < 0x20123 +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif +#if LINUX_VERSION_CODE <= 0x20139 +#define net_device_stats enet_statistics +#else +#define NETSTATS_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) +/* Grrrr, the PCI code changed, but did not consider CardBus... */ +#include +#define PCI_SUPPORT_VER1 +#else +#define PCI_SUPPORT_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20159 +#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); +#else +#define dev_free_skb(skb) dev_kfree_skb(skb); +#endif + +/* The I/O extent. */ +#define SIS900_TOTAL_SIZE 0x100 + +/* This table drives the PCI probe routines. It's mostly boilerplate in all + of the drivers, and will likely be provided by some future kernel. + Note the matching code -- the first table entry matchs all 56** cards but + second only the 1234 card. +*/ + +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, +}; + +struct pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt); +}; + +static struct net_device * sis900_probe1(int pci_bus, int pci_devfn, + struct net_device *dev, long ioaddr, + int irq, int chp_idx, int fnd_cnt); + +static struct pci_id_info pci_tbl[] = +{{ "SiS 900 PCI Fast Ethernet", + 0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, + { "SiS 7016 PCI Fast Ethernet", + 0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, + {0,}, /* 0 terminated list. */ +}; + +/* The capability table matches the chip table above. */ +enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; +static int sis_cap_tbl[] = { + HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, + HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, +}; + +/* The rest of these values should never change. */ +#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ +#define NUM_RX_DESC 8 /* Number of Rx descriptor registers. */ + +/* Symbolic offsets to registers. */ +enum SIS900_registers { + cr=0x0, //Command Register + cfg=0x4, //Configuration Register + mear=0x8, //EEPROM Access Register + ptscr=0xc, //PCI Test Control Register + isr=0x10, //Interrupt Status Register + imr=0x14, //Interrupt Mask Register + ier=0x18, //Interrupt Enable Register + epar=0x18, //Enhanced PHY Access Register + txdp=0x20, //Transmit Descriptor Pointer Register + txcfg=0x24, //Transmit Configuration Register + rxdp=0x30, //Receive Descriptor Pointer Register + rxcfg=0x34, //Receive Configuration Register + flctrl=0x38, //Flow Control Register + rxlen=0x3c, //Receive Packet Length Register + rfcr=0x48, //Receive Filter Control Register + rfdr=0x4C, //Receive Filter Data Register + pmctrl=0xB0, //Power Management Control Register + pmer=0xB4 //Power Management Wake-up Event Register +}; + +#define RESET 0x00000100 +#define SWI 0x00000080 +#define RxRESET 0x00000020 +#define TxRESET 0x00000010 +#define RxDIS 0x00000008 +#define RxENA 0x00000004 +#define TxDIS 0x00000002 +#define TxENA 0x00000001 + +#define BISE 0x80000000 +#define EUPHCOM 0x00000100 +#define REQALG 0x00000080 +#define SB 0x00000040 +#define POW 0x00000020 +#define EXD 0x00000010 +#define PESEL 0x00000008 +#define LPM 0x00000004 +#define BEM 0x00000001 + +/* Interrupt register bits, using my own meaningful names. */ +#define WKEVT 0x10000000 +#define TxPAUSEEND 0x08000000 +#define TxPAUSE 0x04000000 +#define TxRCMP 0x02000000 +#define RxRCMP 0x01000000 +#define DPERR 0x00800000 +#define SSERR 0x00400000 +#define RMABT 0x00200000 +#define RTABT 0x00100000 +#define RxSOVR 0x00010000 +#define HIBERR 0x00008000 +#define SWINT 0x00001000 +#define MIBINT 0x00000800 +#define TxURN 0x00000400 +#define TxIDLE 0x00000200 +#define TxERR 0x00000100 +#define TxDESC 0x00000080 +#define TxOK 0x00000040 +#define RxORN 0x00000020 +#define RxIDLE 0x00000010 +#define RxEARLY 0x00000008 +#define RxERR 0x00000004 +#define RxDESC 0x00000002 +#define RxOK 0x00000001 + +#define IE 0x00000001 + +#define TxCSI 0x80000000 +#define TxHBI 0x40000000 +#define TxMLB 0x20000000 +#define TxATP 0x10000000 +#define TxIFG 0x0C000000 +#define TxMXF 0x03800000 +#define TxMXF_shift 0x23 +#define TxMXDMA 0x00700000 +#define TxMXDMA_shift 20 +#define TxRTCNT 0x000F0000 +#define TxRTCNT_shift 16 +#define TxFILLT 0x00007F00 +#define TxFILLT_shift 8 +#define TxDRNT 0x0000007F + +#define RxAEP 0x80000000 +#define RxARP 0x40000000 +#define RxATP 0x10000000 +#define RxAJAB 0x08000000 +#define RxMXF 0x03800000 +#define RxMXF_shift 23 +#define RxMXDMA 0x00700000 +#define RxMXDMA_shift 20 +#define RxDRNT 0x0000007F + +#define RFEN 0x80000000 +#define RFAAB 0x40000000 +#define RFAAM 0x20000000 +#define RFAAP 0x10000000 +#define RFPromiscuous (RFAAB|RFAAM|RFAAP) +#define RFAA_shift 28 +#define RFEP 0x00070000 +#define RFEP_shift 16 + +#define RFDAT 0x0000FFFF + +#define OWN 0x80000000 +#define MORE 0x40000000 +#define INTR 0x20000000 +#define OK 0x08000000 +#define DSIZE 0x00000FFF + +#define SUPCRC 0x10000000 +#define ABORT 0x04000000 +#define UNDERRUN 0x02000000 +#define NOCARRIER 0x01000000 +#define DEFERD 0x00800000 +#define EXCDEFER 0x00400000 +#define OWCOLL 0x00200000 +#define EXCCOLL 0x00100000 +#define COLCNT 0x000F0000 + +#define INCCRC 0x10000000 +// ABORT 0x04000000 +#define OVERRUN 0x02000000 +#define DEST 0x01800000 +#define BCAST 0x01800000 +#define MCAST 0x01000000 +#define UNIMATCH 0x00800000 +#define TOOLONG 0x00400000 +#define RUNT 0x00200000 +#define RXISERR 0x00100000 +#define CRCERR 0x00080000 +#define FAERR 0x00040000 +#define LOOPBK 0x00020000 +#define RXCOL 0x00010000 + +#define EuphLiteEEMACAddr 0x08 +#define EuphLiteEEVendorID 0x02 +#define EuphLiteEEDeviceID 0x03 +#define EuphLiteEECardTypeRev 0x0b +#define EuphLiteEEPlexusRev 0x0c +#define EuphLiteEEChecksum 0x0f + +#define RXSTS_shift 18 +#define OWN 0x80000000 +#define MORE 0x40000000 +#define INTR 0x20000000 +#define OK 0x08000000 +#define DSIZE 0x00000FFF +/* MII register offsets */ +#define MII_CONTROL 0x0000 +#define MII_STATUS 0x0001 +#define MII_PHY_ID0 0x0002 +#define MII_PHY_ID1 0x0003 +#define MII_ANAR 0x0004 +#define MII_ANLPAR 0x0005 +#define MII_ANER 0x0006 +/* MII Control register bit definitions. */ +#define MIICNTL_FDX 0x0100 +#define MIICNTL_RST_AUTO 0x0200 +#define MIICNTL_ISOLATE 0x0400 +#define MIICNTL_PWRDWN 0x0800 +#define MIICNTL_AUTO 0x1000 +#define MIICNTL_SPEED 0x2000 +#define MIICNTL_LPBK 0x4000 +#define MIICNTL_RESET 0x8000 +/* MII Status register bit significance. */ +#define MIISTAT_EXT 0x0001 +#define MIISTAT_JAB 0x0002 +#define MIISTAT_LINK 0x0004 +#define MIISTAT_CAN_AUTO 0x0008 +#define MIISTAT_FAULT 0x0010 +#define MIISTAT_AUTO_DONE 0x0020 +#define MIISTAT_CAN_T 0x0800 +#define MIISTAT_CAN_T_FDX 0x1000 +#define MIISTAT_CAN_TX 0x2000 +#define MIISTAT_CAN_TX_FDX 0x4000 +#define MIISTAT_CAN_T4 0x8000 +/* MII NWAY Register Bits ... +** valid for the ANAR (Auto-Negotiation Advertisement) and +** ANLPAR (Auto-Negotiation Link Partner) registers */ +#define MII_NWAY_NODE_SEL 0x001f +#define MII_NWAY_CSMA_CD 0x0001 +#define MII_NWAY_T 0x0020 +#define MII_NWAY_T_FDX 0x0040 +#define MII_NWAY_TX 0x0080 +#define MII_NWAY_TX_FDX 0x0100 +#define MII_NWAY_T4 0x0200 +#define MII_NWAY_RF 0x2000 +#define MII_NWAY_ACK 0x4000 +#define MII_NWAY_NP 0x8000 + +/* MII Auto-Negotiation Expansion Register Bits */ +#define MII_ANER_PDF 0x0010 +#define MII_ANER_LP_NP_ABLE 0x0008 +#define MII_ANER_NP_ABLE 0x0004 +#define MII_ANER_RX_PAGE 0x0002 +#define MII_ANER_LP_AN_ABLE 0x0001 +#define HALF_DUPLEX 1 +#define FDX_CAPABLE_DUPLEX_UNKNOWN 2 +#define FDX_CAPABLE_HALF_SELECTED 3 +#define FDX_CAPABLE_FULL_SELECTED 4 +#define HW_SPEED_UNCONFIG 0 +#define HW_SPEED_10_MBPS 10 +#define HW_SPEED_100_MBPS 100 +#define HW_SPEED_DEFAULT (HW_SPEED_10_MBPS) + +#define ACCEPT_ALL_PHYS 0x01 +#define ACCEPT_ALL_MCASTS 0x02 +#define ACCEPT_ALL_BCASTS 0x04 +#define ACCEPT_ALL_ERRORS 0x08 +#define ACCEPT_CAM_QUALIFIED 0x10 +#define MAC_LOOPBACK 0x20 +//#define FDX_CAPABLE_FULL_SELECTED 4 +#define CRC_SIZE 4 +#define MAC_HEADER_SIZE 14 + +typedef struct _EuphLiteDesc { + u32 llink; + unsigned char* buf; + u32 physAddr; + /* Hardware sees the physical address of descriptor */ + u32 plink; + u32 cmdsts; + u32 bufPhys; +} EuphLiteDesc; + +struct sis900_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct net_device *next_module; + int chip_id; + int chip_revision; + unsigned char pci_bus, pci_devfn; +#if LINUX_VERSION_CODE > 0x20139 + struct net_device_stats stats; +#else + struct enet_statistics stats; +#endif + struct timer_list timer; /* Media selection timer. */ + unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ + unsigned int cur_tx, dirty_tx, tx_flag; + + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[NUM_TX_DESC]; + EuphLiteDesc tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + EuphLiteDesc rx_buf[NUM_RX_DESC]; + unsigned char *rx_bufs; + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + char phys[4]; /* MII device addresses. */ + int phy_idx; /* Support Max 4 PHY */ + u16 pmd_status; + unsigned int tx_full; /* The Tx queue is full. */ + int MediaSpeed; /* user force speed */ + int MediaDuplex; /* user force duplex */ + int full_duplex; /* Full/Half-duplex. */ + int speeds; /* 100/10 Mbps. */ + u16 LinkOn; + u16 LinkChange; +}; + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Jim Huang "); +MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); +MODULE_PARM(speeds, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(multicast_filter_limit, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(debug, "i"); +#endif +#endif + +static int sis900_open(struct net_device *dev); +static u16 read_eeprom(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int val); +static void sis900_timer(unsigned long data); +static void sis900_tx_timeout(struct net_device *dev); +static void sis900_init_ring(struct net_device *dev); +static int sis900_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int sis900_rx(struct net_device *dev); +static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sis900_close(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct enet_statistics *sis900_get_stats(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); +static void sis900_reset(struct net_device *dev); +static u16 elAutoNegotiate(struct net_device *dev, int phy_id, int *duplex, int *speed); +static void elSetCapability(struct net_device *dev, int phy_id, int duplex, int speed); +static u16 elPMDreadMode(struct net_device *dev, int phy_id, int *speed, int *duplex); +static u16 elMIIpollBit(struct net_device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value); +static void elSetMediaType(struct net_device *dev, int speed, int duplex); + +/* A list of all installed SiS900 devices, for removing the driver module. */ +static struct net_device *root_sis900_dev = NULL; + +/* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well when dynamically adding drivers. So instead we detect just the + SiS 900 cards in slot order. */ + +int sis900_probe(struct net_device *dev) +{ + int cards_found = 0; + int pci_index = 0; + unsigned char pci_bus, pci_device_fn; + + if ( ! pcibios_present()) + return -ENODEV; + + for (;pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command, new_command; + int chip_idx, irq; + long ioaddr; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) { + break; + } + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, + &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, + &device); + + for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pci_tbl[chip_idx].vendor_id && + (device & pci_tbl[chip_idx].device_id_mask) == + pci_tbl[chip_idx].device_id) + break; + if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ + continue; + + { + struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->resource[0].start; + irq = pdev->irq; + } + + if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && + check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + + /* Activate the card: fix for brain-damaged Win98 BIOSes. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_tbl[chip_idx].flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d!" + "Updating PCI command %4.4x->%4.4x.\n", + pci_bus, pci_device_fn, + pci_command, new_command); + + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + + dev = pci_tbl[chip_idx].probe1(pci_bus, + pci_device_fn, + dev, + ioaddr, + irq, + chip_idx, + cards_found); + + if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { + u8 pci_latency; + + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 32) { + printk(KERN_NOTICE " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to 64 clocks.\n", + pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 64); + } + } + dev = 0; + cards_found++; + } + return cards_found ? 0 : -ENODEV; +} + +static struct net_device * sis900_probe1( int pci_bus, + int pci_devfn, + struct net_device *dev, + long ioaddr, + int irq, + int chip_idx, + int found_cnt) +{ + static int did_version = 0; /* Already printed version info. */ + struct sis900_private *tp; + u16 status; + int duplex = found_cnt < MAX_UNITS ? full_duplex[found_cnt] : 0 ; + int speed = found_cnt < MAX_UNITS ? speeds[found_cnt] : 0 ; + int phy=0, phy_idx=0, i; + + if (did_version++ == 0) + printk(KERN_INFO "%s", version); + + dev = init_etherdev(dev, 0); + + if(dev==NULL) + return NULL; + + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, pci_tbl[chip_idx].name, ioaddr, irq); + + if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) { + for (i = 0; i < 3; i++) + ((u16 *)(dev->dev_addr))[i] = + read_eeprom(ioaddr,i+EuphLiteEEMACAddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + } else + printk(KERN_INFO "Error EEPROM read\n"); + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Some data structures must be quadword aligned. */ + tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + if(tp==NULL) + { + release_region(ioaddr, pci_tbl[chip_idx].io_size); + return NULL; + } + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + + tp->next_module = root_sis900_dev; + root_sis900_dev = dev; + + tp->chip_id = chip_idx; + tp->pci_bus = pci_bus; + tp->pci_devfn = pci_devfn; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) { + for (phy = 0, phy_idx = 0; + phy < 32 && phy_idx < sizeof(tp->phys); phy++) + { + int mii_status ; + mii_status = mdio_read(dev, phy, MII_STATUS); + + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phy_idx = phy_idx; + tp->phys[phy_idx++] = phy; + tp->pmd_status=mdio_read(dev, phy, MII_STATUS); + printk(KERN_INFO "%s: MII transceiver found " + "at address %d.\n", + dev->name, phy); + break; + } + } + + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found!\n", + dev->name); + tp->phys[0] = -1; + tp->pmd_status = 0; + } + } else { + tp->phys[0] = -1; + tp->pmd_status = 0; + } + + if ((tp->pmd_status > 0) && (phy_idx > 0)) { + if (sis900_debug > 1) { + printk(KERN_INFO "duplex=%d, speed=%d\n", + duplex, speed); + } + if (!duplex && !speed) { + // auto-config media type + // Set full capability + if (sis900_debug > 1) { + printk(KERN_INFO "Auto Config ...\n"); + } + elSetCapability(dev, tp->phys[tp->phy_idx], 1, 100); + tp->pmd_status=elAutoNegotiate(dev, + tp->phys[tp->phy_idx], + &tp->full_duplex, + &tp->speeds); + } else { + tp->MediaSpeed = speed; + tp->MediaDuplex = duplex; + elSetCapability(dev, tp->phys[tp->phy_idx], + duplex, speed); + elAutoNegotiate(dev, tp->phys[tp->phy_idx], + &tp->full_duplex, + &tp->speeds); + status = mdio_read(dev, phy, MII_ANLPAR); + if ( !(status & (MII_NWAY_T | MII_NWAY_T_FDX | + MII_NWAY_TX | MII_NWAY_TX_FDX ))) + { + u16 cmd=0; + cmd |= ( speed == 100 ? + MIICNTL_SPEED : 0 ); + cmd |= ( duplex ? MIICNTL_FDX : 0 ); + mdio_write(dev, phy, MII_CONTROL, cmd); + elSetMediaType(dev, speed==100 ? + HW_SPEED_100_MBPS : + HW_SPEED_10_MBPS, + duplex ? + FDX_CAPABLE_FULL_SELECTED: + FDX_CAPABLE_HALF_SELECTED); + elMIIpollBit(dev, phy, MII_STATUS, + MIISTAT_LINK, TRUE, &status); + } else { + status = mdio_read(dev, phy, MII_STATUS); + } + } + + if (tp->pmd_status & MIISTAT_LINK) + tp->LinkOn = TRUE; + else + tp->LinkOn = FALSE; + + tp->LinkChange = FALSE; + + } + + if (sis900_debug > 1) { + if (tp->full_duplex == FDX_CAPABLE_FULL_SELECTED) { + printk(KERN_INFO "%s: Media type is Full Duplex.\n", + dev->name); + } else { + printk(KERN_INFO "%s: Media type is Half Duplex.\n", + dev->name); + } + if (tp->speeds == HW_SPEED_100_MBPS) { + printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name); + } else { + printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name); + } + } + + /* The SiS900-specific entries in the device structure. */ + dev->open = &sis900_open; + dev->hard_start_xmit = &sis900_start_xmit; + dev->stop = &sis900_close; + dev->get_stats = &sis900_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + return dev; +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EECLK 0x00000004 /* EEPROM shift clock. */ +#define EECS 0x00000008 /* EEPROM chip select. */ +#define EEDO 0x00000002 /* EEPROM chip data out. */ +#define EEDI 0x00000001 /* EEPROM chip data in. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. + */ + +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EEread 0x0180 +#define EEwrite 0x0140 +#define EEerase 0x01C0 +#define EEwriteEnable 0x0130 +#define EEwriteDisable 0x0100 +#define EEeraseAll 0x0120 +#define EEwriteAll 0x0110 +#define EEaddrMask 0x013F +#define EEcmdShift 16 + +static u16 read_eeprom(long ioaddr, int location) +{ + int i; + u16 retval = 0; + long ee_addr = ioaddr + mear; + u32 read_cmd = location | EEread; + + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + eeprom_delay(); + + /* Shift the read command bits out. */ + for (i = 8; i >= 0; i--) { + u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; + outl(dataval, ee_addr); + eeprom_delay(); + outl(dataval | EECLK, ee_addr); + eeprom_delay(); + } + outb(EECS, ee_addr); + eeprom_delay(); + + for (i = 16; i > 0; i--) { + outl(EECS, ee_addr); + eeprom_delay(); + outl(EECS | EECLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + return (retval); +} + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ + +#define mdio_delay() inl(mdio_addr) + +#define MIIread 0x6000 +#define MIIwrite 0x6002 +#define MIIpmdMask 0x0F80 +#define MIIpmdShift 7 +#define MIIregMask 0x007C +#define MIIregShift 2 +#define MIIturnaroundBits 2 +#define MIIcmdLen 16 +#define MIIcmdShift 16 +#define MIIreset 0xFFFFFFFF +#define MIIwrLen 32 + +#define MDC 0x00000040 +#define MDDIR 0x00000020 +#define MDIO 0x00000010 + +static void mdio_idle(long mdio_addr) +{ + outl(MDIO | MDDIR, mdio_addr); + mdio_delay(); + outl(MDIO | MDDIR | MDC, mdio_addr); +} + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_reset(long mdio_addr) +{ + int i; + + for (i = 31; i >= 0; i--) { + outl(MDDIR | MDIO, mdio_addr); + mdio_delay(); + outl(MDDIR | MDIO | MDC, mdio_addr); + mdio_delay(); + } + return; +} + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + mear; + int mii_cmd = MIIread|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + outl(dataval | MDC, mdio_addr); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 16; i > 0; i--) { + outl(0, mdio_addr); + //mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); + outl(MDC, mdio_addr); + mdio_delay(); + } + return retval; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + mear; + int mii_cmd = MIIwrite|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outb(dataval, mdio_addr); + mdio_delay(); + outb(dataval | MDC, mdio_addr); + mdio_delay(); + } + mdio_delay(); + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + outb(MDC, mdio_addr); + mdio_delay(); + } + return; +} + +static int +sis900_open(struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (sis900_debug > 0) + printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n", + dev->name, (unsigned int)ioaddr, dev->irq); + + /* Soft reset the chip. */ + outl(0, ioaddr + imr); + outl(0, ioaddr + ier); + outl(0, ioaddr + rfcr); + outl(RESET | RxRESET | TxRESET, ioaddr + cr); + + if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev)) + { + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); + tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); + if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) { + if (tp->tx_bufs) + kfree(tp->tx_bufs); + if (tp->rx_bufs) + kfree(tp->rx_bufs); + if (!tp->tx_bufs) { + printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n", + dev->name, TX_BUF_SIZE * NUM_TX_DESC); + } + if (!tp->rx_bufs) { + printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n", + dev->name, RX_BUF_SIZE * NUM_RX_DESC); + } + return -ENOMEM; + } + + { + u32 rfcrSave; + u32 w; + u32 i; + + rfcrSave = inl(rfcr); + outl(rfcrSave & ~RFEN, rfcr); + for (i=0 ; i<3 ; i++) { + w = (u16)*((u16*)(dev->dev_addr)+i); + outl((((u32) i) << RFEP_shift), ioaddr + rfcr); + outl((u32)w, ioaddr + rfdr); + if (sis900_debug > 4) { + printk(KERN_INFO "Filter Addr[%d]=%x\n", + i, inl(ioaddr + rfdr)); + } + } + outl(rfcrSave, rfcr); + } + + sis900_init_ring(dev); + outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp); + outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp); + + if (sis900_debug > 4) + printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp)); + + /* Check that the chip has finished the reset. */ + { + u32 status; + int j=0; + status = TxRCMP | RxRCMP; + while (status && (j++ < 30000)) { + status ^= (inl(isr) & status); + } + } + + outl(PESEL, ioaddr + cfg); + + /* Must enable Tx/Rx before setting transfer thresholds! */ + /* + * #define TX_DMA_BURST 0 + * #define RX_DMA_BURST 0 + * #define TX_FIFO_THRESH 16 + * #define TxDRNT_100 (1536>>5) + * #define TxDRNT_10 (1536>>5) + * #define RxDRNT_100 (1536>>5) + * #define RxDRNT_10 (1536>>5) + */ + outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg); + outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10, + ioaddr + txcfg); + if (sis900_debug > 1) + { + if (tp->LinkOn) { + printk(KERN_INFO"%s: Media Type %s%s-duplex.\n", + dev->name, + tp->speeds==HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + tp->full_duplex== FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + else printk(KERN_INFO"%s: Media Link Off\n", dev->name); + } + set_rx_mode(dev); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); + outl(RxENA, ioaddr + cr); + outl(IE, ioaddr + ier); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n", + dev->name, ioaddr, dev->irq); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &sis900_timer; /* timer handler */ + add_timer(&tp->timer); + + return 0; +} + +static void sis900_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int next_tick = 0; + u16 status; + + if (!tp->LinkOn) { + status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS); + if (status & MIISTAT_LINK) { + elPMDreadMode(dev, tp->phys[tp->phy_idx], + &tp->speeds, &tp->full_duplex); + tp->LinkOn = TRUE; + printk(KERN_INFO "%s: Media Link On %s%s-duplex ", + dev->name, + tp->speeds == HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + tp->full_duplex==FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + } else { // previous link on + status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS); + if (!(status & MIISTAT_LINK)) { + tp->LinkOn = FALSE; + printk(KERN_INFO "%s: Media Link Off\n", dev->name); + } + } + next_tick = 2*HZ; + + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void sis900_tx_timeout(struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + if (sis900_debug > 0) + printk(KERN_INFO "%s: Transmit timeout, status %2.2x %4.4x \n", + dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); + + /* Emit info to figure out what went wrong. */ + if (sis900_debug > 1) { + printk(KERN_INFO "%s:Tx queue start entry %d dirty entry %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + for (i = 0; i < NUM_TX_DESC; i++) + printk(KERN_INFO "%s: Tx descriptor %d is %8.8x.%s\n", + dev->name, i, (unsigned int)&tp->tx_buf[i], + i == tp->dirty_tx % NUM_TX_DESC ? + " (queue head)" : ""); + } + + /* Soft reset the chip. */ + //outb(RESET, ioaddr + cr); + /* Check that the chip has finished the reset. */ + /* + for (i = 1000; i > 0; i--) + if ((inb(ioaddr + cr) & RESET) == 0) + break; + */ + + tp->cur_rx = 0; + /* Must enable Tx/Rx before setting transfer thresholds! */ + /* + set_rx_mode(dev); + */ + { /* Save the unsent Tx packets. */ + struct sk_buff *saved_skb[NUM_TX_DESC], *skb; + int j; + for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) + saved_skb[j]=tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC]; + tp->dirty_tx = tp->cur_tx = 0; + + for (i = 0; i < j; i++) { + skb = tp->tx_skbuff[i] = saved_skb[i]; + /* Always alignment */ + memcpy((unsigned char*)(tp->tx_buf[i].buf), + skb->data, skb->len); + tp->tx_buf[i].cmdsts = OWN | skb->len; + /* Note: the chip doesn't have auto-pad! */ + /* + outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN), + ioaddr + TxStatus0 + i*4); + */ + } + outl(TxENA, ioaddr + cr); + tp->cur_tx = i; + while (i < NUM_TX_DESC) + tp->tx_skbuff[i++] = 0; + if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + dev->tbusy = 0; + tp->tx_full = 0; + } else { + tp->tx_full = 1; + } + } + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +sis900_init_ring(struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = 0; + tp->dirty_tx = tp->cur_tx = 0; + + /* Tx Buffer */ + for (i = 0; i < NUM_TX_DESC; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE]; + tp->tx_buf[i].bufPhys = + virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]); + } + + /* Tx Descriptor */ + for (i = 0; i< NUM_TX_DESC; i++) { + tp->tx_buf[i].llink = (u32) + &(tp->tx_buf[((i+1) < NUM_TX_DESC) ? (i+1) : 0]); + tp->tx_buf[i].plink = (u32) + virt_to_bus(&(tp->tx_buf[((i+1) < NUM_TX_DESC) ? + (i+1) : 0].plink)); + tp->tx_buf[i].physAddr= + virt_to_bus(&(tp->tx_buf[i].plink)); + tp->tx_buf[i].cmdsts=0; + } + + /* Rx Buffer */ + for (i = 0; i < NUM_RX_DESC; i++) { + tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE]; + tp->rx_buf[i].bufPhys = + virt_to_bus(&tp->rx_bufs[i*RX_BUF_SIZE]); + } + + /* Rx Descriptor */ + for (i = 0; i< NUM_RX_DESC; i++) { + tp->rx_buf[i].llink = (u32) + &(tp->rx_buf[((i+1) < NUM_RX_DESC) ? (i+1) : 0]); + tp->rx_buf[i].plink = (u32) + virt_to_bus(&(tp->rx_buf[((i+1) < NUM_RX_DESC) ? + (i+1) : 0].plink)); + tp->rx_buf[i].physAddr= + virt_to_bus(&(tp->rx_buf[i].plink)); + tp->rx_buf[i].cmdsts=RX_BUF_SIZE; + } +} + +static int +sis900_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + int entry; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + sis900_tx_timeout(dev); + return 1; + } + + /* Calculate the next Tx descriptor entry. ????? */ + entry = tp->cur_tx % NUM_TX_DESC; + + tp->tx_skbuff[entry] = skb; + + if (sis900_debug > 5) { + int i; + printk(KERN_INFO "%s: SKB Tx Frame contents:(len=%d)", + dev->name,skb->len); + + for (i = 0; i < skb->len; i++) { + printk("%2.2x ", + (u8)skb->data[i]); + } + printk(".\n"); + } + + memcpy(tp->tx_buf[entry].buf, + skb->data, skb->len); + + tp->tx_buf[entry].cmdsts=(OWN | skb->len); + + //tp->tx_buf[entry].plink = 0; + outl(TxENA, ioaddr + cr); + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + clear_bit(0, (void*)&dev->tbusy); + } else { + tp->tx_full = 1; + } + + /* Note: the chip doesn't have auto-pad! */ + + dev->trans_start = jiffies; + if (sis900_debug > 4) + printk(KERN_INFO "%s: Queued Tx packet at " + "%p size %d to slot %d.\n", + dev->name, skb->data, (int)skb->len, entry); + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int boguscnt = max_interrupt_work; + int status; + long ioaddr = dev->base_addr; + +#if defined(__i386__) + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_INFO "%s: SMP simultaneous entry of " + "an interrupt handler.\n", dev->name); + dev->interrupt = 0; /* Avoid halting machine. */ + return; + } +#else + if (dev->interrupt) { + printk(KERN_INFO "%s: Re-entering the " + "interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; +#endif + + do { + status = inl(ioaddr + isr); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status, ioaddr + isr); // ????? + + if (sis900_debug > 4) + printk(KERN_INFO "%s: interrupt status=%#4.4x " + "new intstat=%#4.4x.\n", + dev->name, status, inl(ioaddr + isr)); + + if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) { + break; + } + + if (status & (RxOK|RxORN|RxERR)) /* Rx interrupt */ + sis900_rx(dev); + + if (status & (TxOK | TxERR)) { + unsigned int dirty_tx; + + if (sis900_debug > 5) { + printk(KERN_INFO "TxOK:tp->cur_tx:%d," + "tp->dirty_tx:%x\n", + tp->cur_tx, tp->dirty_tx); + } + for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; + dirty_tx++) + { + int i; + int entry = dirty_tx % NUM_TX_DESC; + int txstatus = tp->tx_buf[entry].cmdsts; + + if (sis900_debug > 4) { + printk(KERN_INFO "%s: Tx Frame contents:" + "(len=%d)", + dev->name, (txstatus & DSIZE)); + + for (i = 0; i < (txstatus & DSIZE) ; + i++) { + printk("%2.2x ", + (u8)(tp->tx_buf[entry].buf[i])); + } + printk(".\n"); + } + if ( ! (txstatus & (OK | UNDERRUN))) + { + if (sis900_debug > 1) + printk(KERN_INFO "Tx NOT (OK," + "UnderRun)\n"); + break; /* It still hasn't been Txed */ + } + + /* Note: TxCarrierLost is always asserted + at 100mbps. */ + if (txstatus & (OWCOLL | ABORT)) { + /* There was an major error, log it. */ + if (sis900_debug > 1) + printk(KERN_INFO "Tx Out of " + " Window,Abort\n"); +#ifndef final_version + if (sis900_debug > 1) + printk(KERN_INFO "%s: Transmit " + "error, Tx status %8.8x.\n", + dev->name, txstatus); +#endif + tp->stats.tx_errors++; + if (txstatus & ABORT) { + tp->stats.tx_aborted_errors++; + } + if (txstatus & NOCARRIER) + tp->stats.tx_carrier_errors++; + if (txstatus & OWCOLL) + tp->stats.tx_window_errors++; +#ifdef ETHER_STATS + if ((txstatus & COLCNT)==COLCNT) + tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + /* No count for tp->stats.tx_deferred */ +#endif + if (txstatus & UNDERRUN) { + if (sis900_debug > 2) + printk(KERN_INFO "Tx UnderRun\n"); + } + tp->stats.collisions += + (txstatus >> 16) & 0xF; +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.tx_bytes += txstatus & DSIZE; +#endif + if (sis900_debug > 2) + printk(KERN_INFO "Tx Transmit OK\n"); + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + if (sis900_debug > 2) + printk(KERN_INFO "Free original skb\n"); + dev_free_skb(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + } // for dirty + +#ifndef final_version + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { + printk(KERN_INFO"%s: Out-of-sync dirty pointer," + " %d vs. %d, full=%d.\n", + dev->name, dirty_tx, + tp->cur_tx, tp->tx_full); + dirty_tx += NUM_TX_DESC; + } +#endif + + if (tp->tx_full && dirty_tx > tp->cur_tx-NUM_TX_DESC) { + /* The ring is no longer full, clear tbusy. */ + if (sis900_debug > 3) + printk(KERN_INFO "Tx Ring NO LONGER Full\n"); + tp->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + tp->dirty_tx = dirty_tx; + if (sis900_debug > 2) + printk(KERN_INFO "TxOK,tp->cur_tx:%d,tp->dirty:%d\n", + tp->cur_tx, tp->dirty_tx); + } // if (TxOK | TxERR) + + /* Check uncommon events with one test. */ + if (status & (RxORN | TxERR | RxERR)) { + if (sis900_debug > 2) + printk(KERN_INFO "%s: Abnormal interrupt," + "status %8.8x.\n", dev->name, status); + + if (status == 0xffffffff) + break; + if (status & (RxORN | RxERR)) + tp->stats.rx_errors++; + + + if (status & RxORN) { + tp->stats.rx_over_errors++; + } + } + if (--boguscnt < 0) { + printk(KERN_INFO "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", + dev->name, status); + break; + } + } while (1); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, inl(ioaddr + isr)); + +#if defined(__i386__) + clear_bit(0, (void*)&dev->interrupt); +#else + dev->interrupt = 0; +#endif + return; +} + +/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the + field alignments and semantics. */ +static int sis900_rx(struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 cur_rx = tp->cur_rx % NUM_RX_DESC; + int rx_status=tp->rx_buf[cur_rx].cmdsts; + + if (sis900_debug > 4) + printk(KERN_INFO "%s: sis900_rx, current %4.4x," + " rx status=%8.8x\n", + dev->name, cur_rx, + rx_status); + + while (rx_status & OWN) { + int rx_size = rx_status & DSIZE; + rx_size -= CRC_SIZE; + + if (sis900_debug > 4) { + int i; + printk(KERN_INFO "%s: sis900_rx, rx status %8.8x," + " size %4.4x, cur %4.4x.\n", + dev->name, rx_status, rx_size, cur_rx); + printk(KERN_INFO "%s: Rx Frame contents:", dev->name); + + for (i = 0; i < rx_size; i++) { + printk("%2.2x ", + (u8)(tp->rx_buf[cur_rx].buf[i])); + } + + printk(".\n"); + } + if (rx_status & TOOLONG) { + if (sis900_debug > 1) + printk(KERN_INFO "%s: Oversized Ethernet frame," + " status %4.4x!\n", + dev->name, rx_status); + tp->stats.rx_length_errors++; + } else if (rx_status & (RXISERR | RUNT | CRCERR | FAERR)) { + if (sis900_debug > 1) + printk(KERN_INFO"%s: Ethernet frame had errors," + " status %4.4x.\n", + dev->name, rx_status); + tp->stats.rx_errors++; + if (rx_status & (RXISERR | FAERR)) + tp->stats.rx_frame_errors++; + if (rx_status & (RUNT | TOOLONG)) + tp->stats.rx_length_errors++; + if (rx_status & CRCERR) tp->stats.rx_crc_errors++; + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + struct sk_buff *skb; + + skb = dev_alloc_skb(rx_size + 2); + if (skb == NULL) { + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + dev->name); + /* We should check that some rx space is free. + If not, + free one and mark stats->rx_dropped++. */ + tp->stats.rx_dropped++; + tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; + break; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP fields. */ + if (rx_size+CRC_SIZE > RX_BUF_SIZE) { + /* + int semi_count = RX_BUF_LEN - ring_offset - 4; + memcpy(skb_put(skb, semi_count), + &rx_bufs[ring_offset + 4], semi_count); + memcpy(skb_put(skb, rx_size-semi_count), + rx_bufs, rx_size - semi_count); + if (sis900_debug > 4) { + int i; + printk(KERN_DEBUG"%s: Frame wrap @%d", + dev->name, semi_count); + for (i = 0; i < 16; i++) + printk(" %2.2x", rx_bufs[i]); + printk(".\n"); + memset(rx_bufs, 0xcc, 16); + } + */ + } else { +#if 0 /* USE_IP_COPYSUM */ + eth_copy_and_sum(skb, + tp->rx_buf[cur_rx].buf, rx_size, 0); + skb_put(skb, rx_size); +#else + memcpy(skb_put(skb, rx_size), + tp->rx_buf[cur_rx].buf, rx_size); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.rx_bytes += rx_size; +#endif + tp->stats.rx_packets++; + } + tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; + + cur_rx = ((cur_rx+1) % NUM_RX_DESC); + rx_status = tp->rx_buf[cur_rx].cmdsts; + } // while + if (sis900_debug > 4) + printk(KERN_INFO "%s: Done sis900_rx(), current %4.4x " + "Cmd %2.2x.\n", + dev->name, cur_rx, + inb(ioaddr + cr)); + tp->cur_rx = cur_rx; + return 0; +} + +static int +sis900_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (sis900_debug > 1) + printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, inl(ioaddr + isr)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); + + /* Stop the chip's Tx and Rx DMA processes. */ + outl(0x00, ioaddr + cr); + + del_timer(&tp->timer); + + free_irq(dev->irq, dev); + + for (i = 0; i < NUM_TX_DESC; i++) { + if (tp->tx_skbuff[i]) + dev_free_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + kfree(tp->rx_bufs); + kfree(tp->tx_bufs); + + /* Green! Put the chip in low-power mode. */ + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = tp->phys[tp->phy_idx]; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static struct enet_statistics * +sis900_get_stats(struct net_device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ + +static u16 elComputeHashTableIndex(u8 *addr) +{ +#define POLYNOMIAL 0x04C11DB6L + u32 crc = 0xffffffff, msb; + int i, j; + u8 byte; + + for( i=0; i<6; i++ ) { + byte = *addr++; + for( j=0; j<8; j++ ) { + msb = crc >> 31; + crc <<= 1; + if( msb ^ ( byte & 1 )) { + crc ^= POLYNOMIAL; + crc |= 1; + } + byte >>= 1; + } + } + // 7 bit crc for 128 bit hash table + return( (int)(crc >> 25) ); +} + +static u16 elMIIpollBit(struct net_device *dev, + int phy_id, + int location, + u16 mask, + u16 polarity, + u16 *value) +{ + u32 i; + i=0; + while (1) { + *value = mdio_read(dev, phy_id, location); + if (polarity) { + if (mask & *value) return(TRUE); + } else { + if (mask & ~(*value)) return(TRUE); + } + if (++i == 1200) break; + } + return(FALSE); +} + +static u16 elPMDreadMode(struct net_device *dev, + int phy_id, + int *speed, + int *duplex) +{ + u16 status, OurCap; + + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + + status = mdio_read(dev, phy_id, MII_ANLPAR); + OurCap = mdio_read(dev, phy_id, MII_ANAR); + if (sis900_debug > 1) { + printk(KERN_INFO "Link Part Status %4X\n", status); + printk(KERN_INFO "Our Status %4X\n", OurCap); + printk(KERN_INFO "Status Reg %4X\n", + mdio_read(dev, phy_id, MII_STATUS)); + } + status &= OurCap; + + if ( !( status & + (MII_NWAY_T|MII_NWAY_T_FDX | MII_NWAY_TX | MII_NWAY_TX_FDX ))) { + if (sis900_debug > 1) { + printk(KERN_INFO "The other end NOT support NWAY...\n"); + } + while (( status = mdio_read(dev, phy_id, 18)) & 0x4000) ; + while (( status = mdio_read(dev, phy_id, 18)) & 0x0020) ; + if (status & 0x80) + *speed = HW_SPEED_100_MBPS; + if (status & 0x40) + *duplex = FDX_CAPABLE_FULL_SELECTED; + if (sis900_debug > 3) { + printk(KERN_INFO"%s: Setting %s%s-duplex.\n", + dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + } else { + if (sis900_debug > 1) { + printk(KERN_INFO "The other end support NWAY...\n"); + } + + if (status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) { + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + if (status & (MII_NWAY_TX_FDX | MII_NWAY_TX)) { + *speed = HW_SPEED_100_MBPS; + } + if (sis900_debug > 3) { + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability.\n", + dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + } + return (status); +} + +static u16 elAutoNegotiate(struct net_device *dev, int phy_id, int *duplex, int *speed) +{ + u16 status, retnVal; + + if (sis900_debug > 1) { + printk(KERN_INFO "AutoNegotiate...\n"); + } + mdio_write(dev, phy_id, MII_CONTROL, 0); + mdio_write(dev, phy_id, MII_CONTROL, MIICNTL_AUTO | MIICNTL_RST_AUTO); + retnVal = elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO, + FALSE,&status); + if (!retnVal) { + printk(KERN_INFO "Not wait for Reset Complete\n"); + } + retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE, + TRUE, &status); + if (!retnVal) { + printk(KERN_INFO "Not wait for AutoNego Complete\n"); + } + retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK, + TRUE, &status); + if (!retnVal) { + printk(KERN_INFO "Not wait for Link Complete\n"); + } + if (status & MIISTAT_LINK) { + elPMDreadMode(dev, phy_id, speed, duplex); + elSetMediaType(dev, *speed, *duplex); + } + return(status); +} + +static void elSetCapability(struct net_device *dev, int phy_id, + int duplex, int speed) +{ + u16 cap = ( MII_NWAY_T | MII_NWAY_T_FDX | + MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_CSMA_CD ); + + if (speed != 100) { + cap &= ~( MII_NWAY_TX | MII_NWAY_TX_FDX ); + if (sis900_debug > 1) { + printk(KERN_INFO "UNSET 100Mbps\n"); + } + } + + if (!duplex) { + cap &= ~( MII_NWAY_T_FDX | MII_NWAY_TX_FDX ); + if (sis900_debug > 1) { + printk(KERN_INFO "UNSET full-duplex\n"); + } + } + + mdio_write(dev, phy_id, MII_ANAR, cap); +} + +static void elSetMediaType(struct net_device *dev, int speed, int duplex) +{ + long ioaddr = dev->base_addr; + u32 txCfgOn = 0, txCfgOff = TxDRNT; + u32 rxCfgOn = 0, rxCfgOff = 0; + + if (speed == HW_SPEED_100_MBPS) { + txCfgOn |= (TxDRNT_100 | TxHBI); + } else { + txCfgOn |= TxDRNT_10; + } + + if (duplex == FDX_CAPABLE_FULL_SELECTED) { + txCfgOn |= (TxCSI | TxHBI); + rxCfgOn |= RxATP; + } else { + txCfgOff |= (TxCSI | TxHBI); + rxCfgOff |= RxATP; + } + outl( (inl(ioaddr + txcfg) & ~txCfgOff) | txCfgOn, ioaddr + txcfg); + outl( (inl(ioaddr + rxcfg) & ~rxCfgOff) | rxCfgOn, ioaddr + rxcfg); +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u16 mc_filter[8]; + int i; + int rx_mode; + u32 rxCfgOn = 0, rxCfgOff = 0; + u32 txCfgOn = 0, txCfgOff = 0; + + if (sis900_debug > 3) + printk(KERN_INFO "%s: set_rx_mode (%4.4x) done--" + "RxCfg %8.8x.\n", + dev->name, dev->flags, inl(ioaddr + rxcfg)); + + /* Note: do not reorder, GCC is clever about common statements. */ + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_PHYS; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0xffff; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0xffff; + } else { + struct dev_mc_list *mclist; + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(elComputeHashTableIndex(mclist->dmi_addr), + mc_filter); + } + + for (i=0 ; i<8 ; i++) { + outl((u32)(0x00000004+i) << 16, ioaddr + rfcr); + outl(mc_filter[i], ioaddr + rfdr); + } + /* We can safely update without stopping the chip. */ + //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS | ACCEPT_ALL_PHYS; + //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS; + outl(RFEN | ((rx_mode & (ACCEPT_ALL_MCASTS | ACCEPT_ALL_BCASTS | + ACCEPT_ALL_PHYS)) << RFAA_shift), ioaddr + rfcr); + + if (rx_mode & ACCEPT_ALL_ERRORS) { + rxCfgOn = RxAEP | RxARP | RxAJAB; + } else { + rxCfgOff = RxAEP | RxARP | RxAJAB; + } + if (rx_mode & MAC_LOOPBACK) { + rxCfgOn |= RxATP; + txCfgOn |= TxMLB; + } else { + if (!(( (struct sis900_private *)(dev->priv) )->full_duplex)) + rxCfgOff |= RxATP; + txCfgOff |= TxMLB; + } + + if (sis900_debug > 2) { + printk(KERN_INFO "Before Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); + printk(KERN_INFO "Before Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); + } + + outl((inl(ioaddr + rxcfg) | rxCfgOn) & ~rxCfgOff, ioaddr + rxcfg); + outl((inl(ioaddr + txcfg) | txCfgOn) & ~txCfgOff, ioaddr + txcfg); + + if (sis900_debug > 2) { + printk(KERN_INFO "After Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); + printk(KERN_INFO "After Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); + printk(KERN_INFO "Receive Filter Register:%8.8x\n", + inl(ioaddr + rfcr)); + } + return; +} + +static void sis900_reset(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + + outl(0, ioaddr + ier); + outl(0, ioaddr + imr); + outl(0, ioaddr + rfcr); + + outl(RxRESET | TxRESET | RESET, ioaddr + cr); + outl(PESEL, ioaddr + cfg); + + set_rx_mode(dev); +} + +#ifdef MODULE +int init_module(void) +{ + return sis900_probe(0); +} + +void +cleanup_module(void) +{ + struct net_device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_sis900_dev) { + struct sis900_private *tp = + (struct sis900_private *)root_sis900_dev->priv; + next_dev = tp->next_module; + unregister_netdev(root_sis900_dev); + release_region(root_sis900_dev->base_addr, + pci_tbl[tp->chip_id].io_size); + kfree(tp); + kfree(root_sis900_dev); + root_sis900_dev = next_dev; + } +} + +#endif /* MODULE */ +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c --- v2.3.14/linux/drivers/net/sk_mca.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sk_mca.c Mon Aug 23 13:44:03 1999 @@ -62,9 +62,14 @@ implemented LANCE multicast filter Jun 6th, 1999 additions for Linux 2.2 + Aug 2nd, 1999 + small fixes (David Weinehall) *************************************************************************/ +#include +#include + #include #include #include @@ -79,11 +84,6 @@ #include #include -#ifdef MODULE -#include -#include -#endif - #include #include #include @@ -871,7 +871,7 @@ return &(priv->stat); } -/* we don't support runtime reconfiguration, since am MCA card can +/* we don't support runtime reconfiguration, since an MCA card can be unambigously identified by its POS registers. */ static int skmca_config(struct net_device *dev, struct ifmap *map) @@ -962,9 +962,6 @@ getaddrs(slot, junior, &base, &irq, &medium); -#if 0 - /* this should work, but it doesn't with 2.2.9 :-( - somehow 'mca_is_adapter_used()' is missing in kernel syms... */ #if LINUX_VERSION_CODE >= 0x020200 /* slot already in use ? */ @@ -973,7 +970,6 @@ slot = dofind(&junior, slot + 1); continue; } -#endif #endif /* were we looking for something different ? */ diff -u --recursive --new-file v2.3.14/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.3.14/linux/drivers/net/slip.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/slip.c Mon Aug 23 10:01:02 1999 @@ -89,7 +89,7 @@ typedef struct slip_ctrl { - char if_name[8]; /* "sl0\0" .. "sl99999\0" */ + char if_name[16]; /* "sl0\0" .. "sl99999\0" */ struct slip ctrl; /* SLIP things */ struct net_device dev; /* the device */ } slip_ctrl_t; diff -u --recursive --new-file v2.3.14/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.3.14/linux/drivers/net/strip.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/strip.c Mon Aug 23 10:01:02 1999 @@ -1464,9 +1464,18 @@ */ if (haddr.c[0] == 0xFF) { - struct in_device *in_dev = strip_info->dev.ip_ptr; + u32 brd = 0; + struct in_device *in_dev = in_dev_get(&strip_info->dev); + if (in_dev == NULL) + return NULL; + read_lock(&in_dev->lock); + if (in_dev->ifa_list) + brd = in_dev->ifa_list->ifa_broadcast; + read_unlock(&in_dev->lock); + in_dev_put(in_dev); + /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ - if (!arp_query(haddr.c, in_dev->ifa_list->ifa_broadcast, &strip_info->dev)) + if (!arp_query(haddr.c, brd, &strip_info->dev)) { printk(KERN_ERR "%s: Unable to send packet (no broadcast hub configured)\n", strip_info->dev.name); @@ -1510,7 +1519,7 @@ unsigned char *ptr = strip_info->tx_buff; int doreset = (long)jiffies - strip_info->watchdog_doreset >= 0; int doprobe = (long)jiffies - strip_info->watchdog_doprobe >= 0 && !doreset; - struct in_device *in_dev = strip_info->dev.ip_ptr; + u32 addr, brd; /* * 1. If we have a packet, encapsulate it and put it in the buffer @@ -1594,6 +1603,21 @@ */ if (doreset) { ResetRadio(strip_info); return; } + if (1) { + struct in_device *in_dev = in_dev_get(&strip_info->dev); + brd = addr = 0; + if (in_dev) { + read_lock(&in_dev->lock); + if (in_dev->ifa_list) { + brd = in_dev->ifa_list->ifa_broadcast; + addr = in_dev->ifa_list->ifa_local; + } + read_unlock(&in_dev->lock); + in_dev_put(in_dev); + } + } + + /* * 6. If it is time for a periodic ARP, queue one up to be sent. * We only do this if: @@ -1610,7 +1634,7 @@ */ if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 && memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && - arp_query(haddr.c, in_dev->ifa_list->ifa_broadcast, &strip_info->dev)) + arp_query(haddr.c, brd, &strip_info->dev)) { /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev.name, strip_info->arp_interval / HZ);*/ @@ -1618,12 +1642,12 @@ strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; - if (in_dev && in_dev->ifa_list) + if (addr) arp_send( ARPOP_REPLY, ETH_P_ARP, - in_dev->ifa_list->ifa_address, /* Target address of ARP packet is our address */ + addr, /* Target address of ARP packet is our address */ &strip_info->dev, /* Device to send packet on */ - in_dev->ifa_list->ifa_address, /* Source IP address this ARP packet comes from */ + addr, /* Source IP address this ARP packet comes from */ NULL, /* Destination HW address is NULL (broadcast it) */ strip_info->dev.dev_addr, /* Source HW address is our HW address */ strip_info->dev.dev_addr); /* Target HW address is our HW address (redundant) */ @@ -2471,7 +2495,9 @@ static int strip_open_low(struct net_device *dev) { struct strip *strip_info = (struct strip *)(dev->priv); +#if 0 struct in_device *in_dev = dev->ip_ptr; +#endif if (strip_info->tty == NULL) return(-ENODEV); @@ -2488,12 +2514,17 @@ strip_info->next_command = CompatibilityCommand; strip_info->user_baud = get_baud(strip_info->tty); +#if 0 /* * Needed because address '0' is special + * + * --ANK Needed it or not needed, it does not matter at all. + * Make it at user level, guys. */ if (in_dev->ifa_list->ifa_address == 0) in_dev->ifa_list->ifa_address = ntohl(0xC0A80001); +#endif dev->tbusy = 0; dev->start = 1; diff -u --recursive --new-file v2.3.14/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.3.14/linux/drivers/net/syncppp.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/syncppp.c Mon Aug 23 10:12:38 1999 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "syncppp.h" @@ -705,19 +706,23 @@ /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ { struct in_device *in_dev; - struct in_ifaddr *ifa, **ifap; + struct in_ifaddr *ifa; u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ - if ((in_dev=dev->ip_ptr) != NULL) + if ((in_dev=in_dev_get(dev)) != NULL) { - for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; - ifap=&ifa->ifa_next) + read_lock(&in_dev->lock); + for (ifa=in_dev->ifa_list; ifa != NULL; + ifa=ifa->ifa_next) { if (strcmp(dev->name, ifa->ifa_label) == 0) { addr = ifa->ifa_local; mask = ifa->ifa_mask; break; } + } + read_unlock(&in_dev->lock); + in_dev_put(in_dev); } /* I hope both addr and mask are in the net order */ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); @@ -771,7 +776,7 @@ } sp->obytes += skb->len; /* Control is high priority so it doesnt get queued behind data */ - skb->priority=1; + skb->priority=TC_PRIO_CONTROL; skb->dev = dev; dev_queue_xmit(skb); } @@ -813,7 +818,7 @@ dev->name, ntohl (ch->type), ch->par1, ch->par2, ch->rel, ch->time0, ch->time1); sp->obytes += skb->len; - skb->priority=1; + skb->priority=TC_PRIO_CONTROL; skb->dev = dev; dev_queue_xmit(skb); } diff -u --recursive --new-file v2.3.14/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.14/linux/drivers/net/via-rhine.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/via-rhine.c Mon Aug 23 10:12:38 1999 @@ -86,6 +86,9 @@ #if defined(__i386__) && !defined(VIA_USE_MEMORY) #define VIA_USE_IO #endif +#if defined(__alpha__) +#define VIA_USE_IO +#endif #ifdef VIA_USE_IO #undef readb #undef readw diff -u --recursive --new-file v2.3.14/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.3.14/linux/drivers/net/wavelan.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/wavelan.c Mon Aug 23 10:12:38 1999 @@ -1616,11 +1616,8 @@ if((frequency->e == 0) && (frequency->m >= 0) && (frequency->m < BAND_NUM)) { - /* frequency in units of 250 kHz (as read in the offset register) */ - short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 }; - /* Get frequency offset. */ - freq = bands[frequency->m] >> 1; + freq = channel_bands[frequency->m] >> 1; } /* Verify that the frequency is allowed. */ @@ -1791,6 +1788,7 @@ u_short table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ + int c = 0; /* Channel number */ /* Read the frequency table. */ fee_read(ioaddr, 0x71 /* frequency table */, table, 10); @@ -1801,6 +1799,12 @@ /* Look in the table if the frequency is allowed */ if(table[9 - (freq / 16)] & (1 << (freq % 16))) { + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < NELS(channel_bands))) + c++; + list[i].i = c; /* Set the list index */ + /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; list[i++].e = 1; @@ -1969,14 +1973,12 @@ } else { - int bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa, (unsigned char *)&psa.psa_subband, 1); if(psa.psa_subband <= 4) { - wrq->u.freq.m = bands[psa.psa_subband]; + wrq->u.freq.m = fixed_bands[psa.psa_subband]; wrq->u.freq.e = (psa.psa_subband != 0); } else @@ -1986,9 +1988,9 @@ case SIOCSIWSENS: /* Set the level threshold. */ - if(!suser()) - return -EPERM; - psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); /* update the Wavelan checksum */ @@ -2000,7 +2002,8 @@ /* Read the level threshold. */ psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); - wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; break; case SIOCSIWENCODE: @@ -2110,6 +2113,9 @@ range.max_qual.qual = MMR_SGNL_QUAL; range.max_qual.level = MMR_SIGNAL_LVL; range.max_qual.noise = MMR_SILENCE_LVL; + + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ /* Copy structure to the user buffer. */ if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) diff -u --recursive --new-file v2.3.14/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h --- v2.3.14/linux/drivers/net/wavelan.h Wed Mar 10 16:51:35 1999 +++ linux/drivers/net/wavelan.h Mon Aug 23 10:12:38 1999 @@ -19,6 +19,8 @@ #ifndef _WAVELAN_H #define _WAVELAN_H +/************************** MAGIC NUMBERS ***************************/ + /* Detection of the WaveLAN card is done by reading the MAC * address from the card and checking it. If you have a non-AT&T * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), @@ -38,6 +40,25 @@ #define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ #define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + /*************************** PC INTERFACE ****************************/ diff -u --recursive --new-file v2.3.14/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.3.14/linux/drivers/net/wavelan.p.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/wavelan.p.h Mon Aug 23 10:12:38 1999 @@ -32,7 +32,7 @@ * Web page * -------- * I try to maintain a web page with the Wireless LAN Howto at : - * http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * * Debugging and options * --------------------- @@ -164,7 +164,7 @@ * Marc Meertens , * Pauline Middelink , * Robert Morris , - * Jean Tourrilhes , + * Jean Tourrilhes , * Girish Welling , * Clark Woodworth * Yongguang Zhang @@ -292,9 +292,17 @@ * - Rectify a lot of (useless) debugging code * - Change the way to `#ifdef SET_PSA_CRC' * + * Changes made for release in 2.2.11 & 2.3.13 : + * ------------------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * * Wishes & dreams: * ---------------- - * - roaming + * - roaming (see Pcmcia driver) */ /***************************** INCLUDES *****************************/ @@ -382,11 +390,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v19 (wireless extensions) 20/4/99\n"; +static const char *version = "wavelan.c : v20 (wireless extensions) 29/7/99\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES 256 /* TODO: express in HZ. */ +#define WATCHDOG_JIFFIES (256*HZ/100) /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) diff -u --recursive --new-file v2.3.14/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c --- v2.3.14/linux/drivers/net/x25_asy.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/x25_asy.c Mon Aug 23 10:01:02 1999 @@ -663,9 +663,7 @@ if (sl->dev->flags & IFF_UP) { - dev_lock_wait(); (void) dev_close(sl->dev); - dev_unlock_list(); } tty->disc_data = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/pci/Makefile linux/drivers/pci/Makefile --- v2.3.14/linux/drivers/pci/Makefile Thu Aug 12 10:39:20 1999 +++ linux/drivers/pci/Makefile Mon Aug 23 10:59:10 1999 @@ -15,20 +15,16 @@ ifeq ($(CONFIG_MODULES),y) O_TARGET = pci_syms.o OX_OBJS = pcisyms.o -O_OBJS = pci.o names.o +O_OBJS = pci.o L_OBJS := pci_syms.o else -L_OBJS := pci.o names.o +L_OBJS := pci.o endif ifdef CONFIG_PROC_FS L_OBJS += proc.o endif -ifdef CONFIG_PCI_QUIRKS -L_OBJS += quirks.o -endif - -L_OBJS += compat.o +L_OBJS += compat.o quirks.o names.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.14/linux/drivers/pci/compat.c linux/drivers/pci/compat.c --- v2.3.14/linux/drivers/pci/compat.c Thu Aug 5 18:44:28 1999 +++ linux/drivers/pci/compat.c Mon Aug 23 10:59:10 1999 @@ -3,7 +3,7 @@ * * PCI Bus Services -- Function For Backward Compatibility * - * Copyright 1998 Martin Mares + * Copyright 1998, 1999 Martin Mares */ #include @@ -11,6 +11,12 @@ #include int +pcibios_present(void) +{ + return !!pci_devices; +} + +int pcibios_find_class(unsigned int class, unsigned short index, unsigned char *bus, unsigned char *devfn) { struct pci_dev *dev = NULL; @@ -41,3 +47,19 @@ } return PCIBIOS_DEVICE_NOT_FOUND; } + +#define PCI_OP(rw,size,type) \ +int pcibios_##rw##_config_##size (unsigned char bus, unsigned char dev_fn, \ + unsigned char where, unsigned type val) \ +{ \ + struct pci_dev *dev = pci_find_slot(bus, dev_fn); \ + if (!dev) return PCIBIOS_DEVICE_NOT_FOUND; \ + return pci_##rw##_config_##size(dev, where, val); \ +} + +PCI_OP(read, byte, char *) +PCI_OP(read, word, short *) +PCI_OP(read, dword, int *) +PCI_OP(write, byte, char) +PCI_OP(write, word, short) +PCI_OP(write, dword, int) diff -u --recursive --new-file v2.3.14/linux/drivers/pci/names.c linux/drivers/pci/names.c --- v2.3.14/linux/drivers/pci/names.c Fri Aug 6 11:16:54 1999 +++ linux/drivers/pci/names.c Mon Aug 23 13:48:42 1999 @@ -10,12 +10,7 @@ #include #include #include -#include -#include #include -#include - -#include struct pci_device_info { unsigned short device; @@ -56,19 +51,20 @@ #define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info)) -void __init pci_namedevice(struct pci_dev *dev) +void __init pci_name_device(struct pci_dev *dev) { const struct pci_vendor_info *vendor_p = pci_vendor_list; int i = VENDORS; - + char *name = dev->name; + do { if (vendor_p->vendor == dev->vendor) goto match_vendor; vendor_p++; } while (--i); - /* Coulding find either the vendor nor the device */ - sprintf(dev->name, "PCI<%d:%04x> %04x:%04x", dev->bus->number, dev->devfn, dev->vendor, dev->device); + /* Couldn't find either the vendor nor the device */ + sprintf(name, "PCI device %04x:%04x", dev->vendor, dev->device); return; match_vendor: { @@ -83,12 +79,12 @@ } /* Ok, found the vendor, but unknown device */ - sprintf(dev->name, "PCI<%d:%04x> %04x:%04x (%s)", dev->bus->number, dev->devfn, dev->vendor, dev->device, vendor_p->name); + sprintf(name, " PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); return; /* Full match */ match_device: { - char *n = dev->name + sprintf(dev->name, "%s %s", vendor_p->name, device_p->name); + char *n = name + sprintf(name, " %s %s", vendor_p->name, device_p->name); int nr = device_p->seen + 1; device_p->seen = nr; if (nr > 1) diff -u --recursive --new-file v2.3.14/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.14/linux/drivers/pci/pci.c Thu Aug 12 11:50:14 1999 +++ linux/drivers/pci/pci.c Mon Aug 23 13:47:35 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -27,13 +28,10 @@ #define DBG(x...) #endif -extern void pci_namedevice(struct pci_dev *); - -struct pci_bus pci_root; +struct pci_bus *pci_root; struct pci_dev *pci_devices = NULL; -int pci_reverse __initdata = 0; - static struct pci_dev **pci_last_dev_p = &pci_devices; +static int pci_reverse __initdata = 0; struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) @@ -48,29 +46,37 @@ struct pci_dev * -pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +pci_find_subsys(unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from) { - struct pci_dev *next; + struct pci_dev *dev; - next = pci_devices; if (from) - next = from->next; - - while (next) { - struct pci_dev *dev = next; - next = next->next; - if (vendor != PCI_ANY_ID && dev->vendor != vendor) - continue; - if (device != PCI_ANY_ID && dev->device != device) - continue; + dev = from->next; + else + dev = pci_devices; - return dev; + while (dev) { + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device) && + (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) && + (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)) + return dev; + dev = dev->next; } return NULL; } struct pci_dev * +pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); +} + + +struct pci_dev * pci_find_class(unsigned int class, struct pci_dev *from) { if (!from) @@ -83,41 +89,41 @@ } -int -pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val) -{ - return pcibios_read_config_byte(dev->bus->number, dev->devfn, where, val); -} - -int -pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val) -{ - return pcibios_read_config_word(dev->bus->number, dev->devfn, where, val); -} - -int -pci_read_config_dword(struct pci_dev *dev, u8 where, u32 *val) -{ - return pcibios_read_config_dword(dev->bus->number, dev->devfn, where, val); -} - -int -pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val) -{ - return pcibios_write_config_byte(dev->bus->number, dev->devfn, where, val); -} - -int -pci_write_config_word(struct pci_dev *dev, u8 where, u16 val) -{ - return pcibios_write_config_word(dev->bus->number, dev->devfn, where, val); -} - -int -pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val) -{ - return pcibios_write_config_dword(dev->bus->number, dev->devfn, where, val); -} +/* + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ + +static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; + +/* + * Wrappers for all PCI configuration access functions. They just check + * alignment, do locking and call the low-level functions pointed to + * by pci_dev->ops. + */ + +#define PCI_byte_BAD 0 +#define PCI_word_BAD (pos & 1) +#define PCI_dword_BAD (pos & 3) + +#define PCI_OP(rw,size,type) \ +int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \ +{ \ + int res; \ + unsigned long flags; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + res = dev->bus->ops->rw##_##size(dev, pos, value); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return res; \ +} + +PCI_OP(read, byte, u8 *) +PCI_OP(read, word, u16 *) +PCI_OP(read, dword, u32 *) +PCI_OP(write, byte, u8) +PCI_OP(write, word, u16) +PCI_OP(write, dword, u32) void @@ -128,86 +134,116 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); if (! (cmd & PCI_COMMAND_MASTER)) { - printk("PCI: Enabling bus mastering for device %02x:%02x\n", - dev->bus->number, dev->devfn); + printk("PCI: Enabling bus mastering for device %s\n", dev->name); cmd |= PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, cmd); } pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); if (lat < 16) { - printk("PCI: Increasing latency timer of device %02x:%02x to 64\n", - dev->bus->number, dev->devfn); + printk("PCI: Increasing latency timer of device %s to 64\n", dev->name); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); } } -void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany) +/* + * Translate the low bits of the PCI base + * to the resource type + */ +static inline unsigned int pci_resource_flags(unsigned int flags) { - unsigned int reg; - u32 l; + if (flags & PCI_BASE_ADDRESS_SPACE_IO) + return IORESOURCE_IO | flags; - for(reg=0; reg < howmany; reg++) { - struct resource *res = dev->resource + reg; - unsigned int mask, newval, size; + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) + return IORESOURCE_MEM | IORESOURCE_PREFETCH; - res->name = dev->name; - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l); - if (l == 0xffffffff) - continue; + return IORESOURCE_MEM; +} - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), 0xffffffff); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &newval); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), l); - - mask = PCI_BASE_ADDRESS_MEM_MASK; - if (l & PCI_BASE_ADDRESS_SPACE_IO) - mask = PCI_BASE_ADDRESS_IO_MASK; +void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) +{ + unsigned int pos, reg, next; + u32 l, sz, tmp; + u16 cmd; + struct resource *res; - newval &= mask; - if (!newval) + /* Disable IO and memory while we fiddle */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, tmp); + + for(pos=0; posresource[pos]; + res->name = dev->name; + reg = PCI_BASE_ADDRESS_0 + (pos << 2); + pci_read_config_dword(dev, reg, &l); + pci_write_config_dword(dev, reg, ~0); + pci_read_config_dword(dev, reg, &sz); + pci_write_config_dword(dev, reg, l); + if (!sz || sz == 0xffffffff) continue; - - res->start = l & mask; - res->flags = l & ~mask; - - size = 1; - do { - size <<= 1; - } while (!(size & newval)); - - /* 64-bit memory? */ + if (l == 0xffffffff) + l = 0; + if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + res->start = l & PCI_BASE_ADDRESS_MEM_MASK; + sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK); + } else { + res->start = l & PCI_BASE_ADDRESS_IO_MASK; + sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; + } + res->end = res->start + sz; + res->flags |= (l & 0xf) | pci_resource_flags(l); if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { - unsigned int high; - reg++; - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &high); - if (high) { + pci_read_config_dword(dev, reg+4, &l); + next++; #if BITS_PER_LONG == 64 - res->start |= ((unsigned long) high) << 32; + res->start |= ((unsigned long) l) << 32; + res->end = res->start + sz; + pci_write_config_dword(dev, reg+4, ~0); + pci_read_config_dword(dev, reg+4, &tmp); + pci_write_config_dword(dev, reg+4, l); + if (l) + res->end = res->start + (((unsigned long) ~l) << 32); #else - printk("PCI: Unable to handle 64-bit address for device %02x:%02x\n", - dev->bus->number, dev->devfn); - res->flags = 0; + if (l) { + printk("PCI: Unable to handle 64-bit address for device %s\n", dev->name); res->start = 0; - res->end = 0; + res->flags = 0; continue; -#endif } +#endif } - res->end = res->start + size - 1; - request_resource((l & PCI_BASE_ADDRESS_SPACE_IO) ? &ioport_resource : &iomem_resource, res); } + if (rom) { + res = &dev->resource[PCI_ROM_RESOURCE]; + pci_read_config_dword(dev, rom, &l); + pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); + pci_read_config_dword(dev, rom, &sz); + pci_write_config_dword(dev, rom, l); + if (l == 0xffffffff) + l = 0; + if (sz && sz != 0xffffffff) { + res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | + IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + res->start = l & PCI_ROM_ADDRESS_MASK; + res->end = res->start + (~(sz & PCI_ROM_ADDRESS_MASK)); + } + res->name = dev->name; + } + pci_write_config_word(dev, PCI_COMMAND, cmd); } - -unsigned int __init pci_scan_bus(struct pci_bus *bus) +static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) { unsigned int devfn, l, max, class; unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; struct pci_dev *dev, **bus_last; struct pci_bus *child; + struct pci_dev *dev_cache = NULL; - DBG("pci_scan_bus for bus %d\n", bus->number); + DBG("pci_do_scan_bus for bus %d\n", bus->number); bus_last = &bus->devices; max = bus->secondary; for (devfn = 0; devfn < 0xff; ++devfn) { @@ -215,37 +251,39 @@ /* not a multi-function device */ continue; } - if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type)) + if (!dev_cache) { + dev_cache = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev_cache) + continue; + } + dev = dev_cache; + memset(dev, 0, sizeof(*dev)); + dev->bus = bus; + dev->devfn = devfn; + + if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) continue; if (!PCI_FUNC(devfn)) is_multi = hdr_type & 0x80; - if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) || + if (pci_read_config_dword(dev, PCI_VENDOR_ID, &l) || /* some broken boards return 0 if a slot is empty: */ l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) continue; - dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if(dev==NULL) - { - printk(KERN_ERR "pci: out of memory.\n"); - continue; - } - memset(dev, 0, sizeof(*dev)); - dev->bus = bus; - dev->devfn = devfn; + dev_cache = NULL; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; - pci_namedevice(dev); + pci_name_device(dev); /* non-destructively determine if device can be a master: */ - pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd); - pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); - pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp); + pci_read_config_byte(dev, PCI_COMMAND, &cmd); + pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); + pci_read_config_byte(dev, PCI_COMMAND, &tmp); dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); - pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd); + pci_write_config_byte(dev, PCI_COMMAND, cmd); - pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class); + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; class >>= 8; @@ -259,29 +297,29 @@ * If the card generates interrupts, read IRQ number * (some architectures change it during pcibios_fixup()) */ - pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq); if (irq) - pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); dev->irq = irq; /* * read base address registers, again pcibios_fixup() can * tweak these */ - pci_read_bases(dev, 6); - pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l); - dev->rom_address = (l == 0xffffffff) ? 0 : l; + pci_read_bases(dev, 6, PCI_ROM_ADDRESS); + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); break; case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ if (class != PCI_CLASS_BRIDGE_PCI) goto bad; - pci_read_bases(dev, 2); - pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l); - dev->rom_address = (l == 0xffffffff) ? 0 : l; + pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); break; case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ if (class != PCI_CLASS_BRIDGE_CARDBUS) goto bad; - pci_read_bases(dev, 1); + pci_read_bases(dev, 1, 0); + pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); + pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device); break; default: /* unknown header */ bad: @@ -311,16 +349,21 @@ *bus_last = dev; bus_last = &dev->sibling; + /* Fix up broken headers */ + pci_fixup_device(PCI_FIXUP_HEADER, dev); + #if 0 /* * Setting of latency timer in case it was less than 32 was * a great idea, but it confused several broken devices. Grrr. */ - pcibios_read_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, &tmp); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp); if (tmp < 32) - pcibios_write_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, 32); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); #endif } + if (dev_cache) + kfree(dev_cache); /* * After performing arch-dependent fixup of the bus, look behind @@ -333,23 +376,18 @@ */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { unsigned int buses; - unsigned int devfn = dev->devfn; unsigned short cr; /* * Insert it into the tree of buses. */ - child = kmalloc(sizeof(*child), GFP_ATOMIC); - if(child==NULL) - { - printk(KERN_ERR "pci: out of memory for bridge.\n"); - continue; - } + child = kmalloc(sizeof(*child), GFP_KERNEL); memset(child, 0, sizeof(*child)); child->next = bus->children; bus->children = child; child->self = dev; child->parent = bus; + child->ops = bus->ops; /* * Set up the primary, secondary and subordinate @@ -362,16 +400,16 @@ * Clear all status bits and turn off memory, * I/O and master enables. */ - pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr); - pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000); - pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff); + pci_read_config_word(dev, PCI_COMMAND, &cr); + pci_write_config_word(dev, PCI_COMMAND, 0x0000); + pci_write_config_word(dev, PCI_STATUS, 0xffff); /* * Read the existing primary/secondary/subordinate bus * number configuration to determine if the PCI bridge * has already been configured by the system. If so, * do not modify the configuration, merely note it. */ - pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); + pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); if ((buses & 0xFFFFFF) != 0) { unsigned int cmax; @@ -380,7 +418,7 @@ child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; child->number = child->secondary; - cmax = pci_scan_bus(child); + cmax = pci_do_scan_bus(child); if (cmax > max) max = cmax; } else @@ -393,11 +431,11 @@ (((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16)); - pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); + pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); /* * Now we can scan all subordinate buses: */ - max = pci_scan_bus(child); + max = pci_do_scan_bus(child); /* * Set the subordinate bus number to its real * value: @@ -405,9 +443,9 @@ child->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int)(child->subordinate) << 16); - pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); + pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); } - pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); + pci_write_config_word(dev, PCI_COMMAND, cr); } /* @@ -417,43 +455,36 @@ * * Return how far we've got finding sub-buses. */ - DBG("PCI: pci_scan_bus returning with max=%02x\n", max); + DBG("PCI: pci_do_scan_bus returning with max=%02x\n", max); return max; } -struct pci_bus * __init pci_scan_peer_bridge(int bus) +struct pci_bus * __init pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; b = kmalloc(sizeof(*b), GFP_KERNEL); memset(b, 0, sizeof(*b)); - b->next = pci_root.next; - pci_root.next = b; + if (pci_root) { + b->next = pci_root->next; + pci_root->next = b; + } else + pci_root = b; b->number = b->secondary = bus; - b->subordinate = pci_scan_bus(b); + b->sysdata = sysdata; + b->ops = ops; + b->subordinate = pci_do_scan_bus(b); return b; } void __init pci_init(void) { - pcibios_init(); - - if (!pci_present()) { - printk("PCI: No PCI bus detected\n"); - return; - } - - printk("PCI: Probing PCI hardware\n"); - - memset(&pci_root, 0, sizeof(pci_root)); - pci_root.subordinate = pci_scan_bus(&pci_root); + struct pci_dev *dev; - /* give BIOS a chance to apply platform specific fixes: */ - pcibios_fixup(); + pcibios_init(); -#ifdef CONFIG_PCI_QUIRKS - pci_quirks_init(); -#endif + for(dev=pci_devices; dev; dev=dev->next) + pci_fixup_device(PCI_FIXUP_FINAL, dev); } static int __init pci_setup(char *str) diff -u --recursive --new-file v2.3.14/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c --- v2.3.14/linux/drivers/pci/pcisyms.c Thu Aug 5 18:44:28 1999 +++ linux/drivers/pci/pcisyms.c Mon Aug 23 10:59:10 1999 @@ -11,13 +11,6 @@ #include #include /* isa_dma_bridge_buggy */ -EXPORT_SYMBOL(pcibios_present); -EXPORT_SYMBOL(pcibios_read_config_byte); -EXPORT_SYMBOL(pcibios_read_config_word); -EXPORT_SYMBOL(pcibios_read_config_dword); -EXPORT_SYMBOL(pcibios_write_config_byte); -EXPORT_SYMBOL(pcibios_write_config_word); -EXPORT_SYMBOL(pcibios_write_config_dword); EXPORT_SYMBOL(pci_read_config_byte); EXPORT_SYMBOL(pci_read_config_word); EXPORT_SYMBOL(pci_read_config_dword); @@ -35,14 +28,18 @@ EXPORT_SYMBOL(pci_proc_detach_device); #endif -/* Backward compatibility */ +/* Obsolete functions */ +EXPORT_SYMBOL(pcibios_present); +EXPORT_SYMBOL(pcibios_read_config_byte); +EXPORT_SYMBOL(pcibios_read_config_word); +EXPORT_SYMBOL(pcibios_read_config_dword); +EXPORT_SYMBOL(pcibios_write_config_byte); +EXPORT_SYMBOL(pcibios_write_config_word); +EXPORT_SYMBOL(pcibios_write_config_dword); EXPORT_SYMBOL(pcibios_find_class); EXPORT_SYMBOL(pcibios_find_device); /* Quirk info */ -#ifdef CONFIG_PCI_QUIRKS EXPORT_SYMBOL(isa_dma_bridge_buggy); -#endif - diff -u --recursive --new-file v2.3.14/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.3.14/linux/drivers/pci/proc.c Sat Aug 7 12:59:40 1999 +++ linux/drivers/pci/proc.c Mon Aug 23 10:59:10 1999 @@ -47,8 +47,6 @@ struct proc_dir_entry *dp = ino->u.generic_ip; struct pci_dev *dev = dp->data; int pos = *ppos; - unsigned char bus = dev->bus->number; - unsigned char dfn = dev->devfn; int cnt, size; /* @@ -77,7 +75,7 @@ if ((pos & 1) && cnt) { unsigned char val; - pcibios_read_config_byte(bus, dfn, pos, &val); + pci_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -86,7 +84,7 @@ if ((pos & 3) && cnt > 2) { unsigned short val; - pcibios_read_config_word(bus, dfn, pos, &val); + pci_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short *) buf); buf += 2; pos += 2; @@ -95,7 +93,7 @@ while (cnt >= 4) { unsigned int val; - pcibios_read_config_dword(bus, dfn, pos, &val); + pci_read_config_dword(dev, pos, &val); __put_user(cpu_to_le32(val), (unsigned int *) buf); buf += 4; pos += 4; @@ -104,7 +102,7 @@ if (cnt >= 2) { unsigned short val; - pcibios_read_config_word(bus, dfn, pos, &val); + pci_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short *) buf); buf += 2; pos += 2; @@ -113,7 +111,7 @@ if (cnt) { unsigned char val; - pcibios_read_config_byte(bus, dfn, pos, &val); + pci_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -131,8 +129,6 @@ struct proc_dir_entry *dp = ino->u.generic_ip; struct pci_dev *dev = dp->data; int pos = *ppos; - unsigned char bus = dev->bus->number; - unsigned char dfn = dev->devfn; int cnt; if (pos >= PCI_CFG_SPACE_SIZE) @@ -149,7 +145,7 @@ if ((pos & 1) && cnt) { unsigned char val; __get_user(val, buf); - pcibios_write_config_byte(bus, dfn, pos, val); + pci_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -158,7 +154,7 @@ if ((pos & 3) && cnt > 2) { unsigned short val; __get_user(val, (unsigned short *) buf); - pcibios_write_config_word(bus, dfn, pos, le16_to_cpu(val)); + pci_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -167,7 +163,7 @@ while (cnt >= 4) { unsigned int val; __get_user(val, (unsigned int *) buf); - pcibios_write_config_dword(bus, dfn, pos, le32_to_cpu(val)); + pci_write_config_dword(dev, pos, le32_to_cpu(val)); buf += 4; pos += 4; cnt -= 4; @@ -176,7 +172,7 @@ if (cnt >= 2) { unsigned short val; __get_user(val, (unsigned short *) buf); - pcibios_write_config_word(bus, dfn, pos, le16_to_cpu(val)); + pci_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -185,7 +181,7 @@ if (cnt) { unsigned char val; __get_user(val, buf); - pcibios_write_config_byte(bus, dfn, pos, val); + pci_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -232,6 +228,12 @@ NULL /* revalidate */ }; +#if BITS_PER_LONG == 32 +#define LONG_FORMAT "\t%08lx" +#else +#define LONG_FORMAT "\t%16lx" +#endif + int get_pci_dev_info(char *buf, char **start, off_t pos, int count, int wr) { @@ -247,22 +249,13 @@ dev->vendor, dev->device, dev->irq); - for(i=0; i<6; i++) { - len += sprintf(buf+len, -#if BITS_PER_LONG == 32 - "\t%08lx", -#else - "\t%016lx", -#endif - dev->resource[i].start | (dev->resource[i].flags & 0xf)); - } - len += sprintf(buf+len, -#if BITS_PER_LONG == 32 - "\t%08lx", -#else - "\t%016lx", -#endif - dev->rom_address); + /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ + for(i=0; i<7; i++) + len += sprintf(buf+len, LONG_FORMAT, + dev->resource[i].start | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); + for(i=0; i<7; i++) + len += sprintf(buf+len, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ? + dev->resource[i].end - dev->resource[i].start + 1 : 0); buf[len++] = '\n'; at += len; if (at >= pos) { @@ -335,6 +328,10 @@ } } +/* + * Backward compatible /proc/pci interface. + */ + static const char *pci_strclass (unsigned int class) { switch (class >> 8) { @@ -557,15 +554,8 @@ { int nprinted, len, size; struct pci_dev *dev; - static int complained = 0; # define MSG "\nwarning: page-size limit reached!\n" - if (!complained) { - complained++; - printk(KERN_INFO "%s uses obsolete /proc/pci interface\n", - current->comm); - } - /* reserve same for truncation warning message: */ size = PAGE_SIZE - (strlen(MSG) + 1); len = sprintf(buf, "PCI devices found:\n"); @@ -591,7 +581,7 @@ if (pci_present()) { proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus); proc_register(proc_bus_pci_dir, &proc_pci_devices); - proc_bus_pci_add(&pci_root); + proc_bus_pci_add(pci_root); proc_register(&proc_root, &proc_old_pci); } return 0; diff -u --recursive --new-file v2.3.14/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.3.14/linux/drivers/pci/quirks.c Thu Aug 5 18:44:28 1999 +++ linux/drivers/pci/quirks.c Mon Aug 23 13:44:03 1999 @@ -1,114 +1,27 @@ /* * $Id: quirks.c,v 1.5 1998/05/02 19:24:14 mj Exp $ * - * PCI Chipset-Specific Quirks + * This file contains work-arounds for many known PCI hardware + * bugs. Devices present only on certain architectures (host + * bridges et cetera) should be handled in arch-specific code. * - * Extracted from pci.c and rewritten by Martin Mares + * Copyright (c) 1999 Martin Mares * - * This is the right place for all special fixups for on-board - * devices not depending on system architecture -- for example - * bus bridges. + * The bridge optimization stuff has been removed. If you really + * have a silly BIOS which is unable to set your host bridge right, + * use the PowerTweak utility (see http://linux.powertweak.com/). */ -#include #include #include #include -#include #include #undef DEBUG -#ifdef CONFIG_PCI_OPTIMIZE - -/* - * The PCI Bridge Optimization -- Some BIOS'es are too lazy - * and are unable to turn on several features which can burst - * system performance. - */ - -/* - * An item of this structure has the following meaning: - * for each optimization, the register address, the mask - * and value to write to turn it on. - */ -struct optimization_type { - const char *type; - const char *off; - const char *on; -} bridge_optimization[] __initdata = { - {"Cache L2", "write through", "write back"}, - {"CPU-PCI posted write", "off", "on"}, - {"CPU-Memory posted write", "off", "on"}, - {"PCI-Memory posted write", "off", "on"}, - {"PCI burst", "off", "on"} -}; - -#define NUM_OPTIMIZATIONS \ - (sizeof(bridge_optimization) / sizeof(bridge_optimization[0])) - -struct bridge_mapping_type { - unsigned char addr; /* config space address */ - unsigned char mask; - unsigned char value; -} bridge_mapping[] = { - /* - * Intel Neptune/Mercury/Saturn: - * If the internal cache is write back, - * the L2 cache must be write through! - * I've to check out how to control that - * for the moment, we won't touch the cache - */ - {0x0 ,0x02 ,0x02 }, - {0x53 ,0x02 ,0x02 }, - {0x53 ,0x01 ,0x01 }, - {0x54 ,0x01 ,0x01 }, - {0x54 ,0x02 ,0x02 }, - - /* - * UMC 8891A Pentium chipset: - * Why did you think UMC was cheaper ?? - */ - {0x50 ,0x10 ,0x00 }, - {0x51 ,0x40 ,0x40 }, - {0x0 ,0x0 ,0x0 }, - {0x0 ,0x0 ,0x0 }, - {0x0 ,0x0 ,0x0 }, -}; - -static void __init quirk_bridge(struct pci_dev *dev, int pos) -{ - struct bridge_mapping_type *bmap; - unsigned char val; - int i; - - pos *= NUM_OPTIMIZATIONS; - for (i = 0; i < NUM_OPTIMIZATIONS; i++) { - printk(" %s: ", bridge_optimization[i].type); - bmap = &bridge_mapping[pos + i]; - if (!bmap->addr) { - printk("Not supported.\n"); - } else { - pci_read_config_byte(dev, bmap->addr, &val); - if ((val & bmap->mask) == bmap->value) - printk("%s.\n", bridge_optimization[i].on); - else { - printk("%s", bridge_optimization[i].off); - pci_write_config_byte(dev, - bmap->addr, - (val & (0xff - bmap->mask)) + bmap->value); - printk(" -> %s.\n", bridge_optimization[i].on); - } - } - } -} - -#endif - - /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ -static void __init quirk_passive_release(struct pci_dev *dev, int arg) +static void __init quirk_passive_release(struct pci_dev *dev) { struct pci_dev *d = NULL; unsigned char dlc; @@ -118,7 +31,7 @@ while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk("PIIX3: Enabling Passive Release\n"); + printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->name); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } @@ -135,92 +48,48 @@ int isa_dma_bridge_buggy = 0; /* Exported */ -static void __init quirk_isa_dma_hangs(struct pci_dev *dev, int arg) +static void __init quirk_isa_dma_hangs(struct pci_dev *dev) { - if(!isa_dma_bridge_buggy) - { + if (!isa_dma_bridge_buggy) { isa_dma_bridge_buggy=1; printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); } } -typedef void (*quirk_handler)(struct pci_dev *, int); - /* - * Mapping from quirk handler functions to names. + * The main table of quirks. */ -struct quirk_name { - quirk_handler handler; - char *name; -}; - -static struct quirk_name quirk_names[] __initdata = { -#ifdef CONFIG_PCI_OPTIMIZE - { quirk_bridge, "Bridge optimization" }, -#endif - { quirk_passive_release,"Passive release enable" }, - { quirk_isa_dma_hangs, "Work around ISA DMA hangs" }, -}; - - -static inline char *get_quirk_name(quirk_handler handler) -{ - int i; - - for (i = 0; i < sizeof(quirk_names)/sizeof(quirk_names[0]); i++) - if (handler == quirk_names[i].handler) - return quirk_names[i].name; - - return NULL; -} - - -/* - * Mapping from PCI vendor/device ID pairs to quirk function types and arguments - */ - -struct quirk_info { - unsigned short vendor, device; - quirk_handler handler; - unsigned short arg; -}; - -static struct quirk_info quirk_list[] __initdata = { -#ifdef CONFIG_PCI_OPTIMIZE - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_BRD, quirk_bridge, 0x00 }, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8891A, quirk_bridge, 0x01 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, quirk_bridge, 0x00 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82434, quirk_bridge, 0x00 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82430, quirk_bridge, 0x00 }, -#endif - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release, 0x00 }, +static struct pci_fixup pci_fixups[] __initdata = { + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release }, /* * Its not totally clear which chipsets are the problematic ones * This is the 82C586 variants. At the moment the 596 is an unknown - * quantity + * quantity. */ - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs, 0x00 }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, + { 0 } }; -void __init pci_quirks_init(void) -{ - struct pci_dev *d; - int i; +static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f) +{ + while (f->pass) { + if (f->pass == pass && + (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && + (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - printk("PCI: pci_quirks_init\n"); + printk("PCI: Calling quirk %p for %s\n", f->hook, dev->name); #endif - for(d=pci_devices; d; d=d->next) { - for(i=0; ivendor == d->vendor && q->device == d->device) { - printk("PCI: %02x:%02x [%04x/%04x]: %s (%02x)\n", - d->bus->number, d->devfn, d->vendor, d->device, - get_quirk_name(q->handler), q->arg); - q->handler(d, q->arg); - } + f->hook(dev); } + f++; } +} + +void pci_fixup_device(int pass, struct pci_dev *dev) +{ + pci_do_fixups(dev, pass, pcibios_fixups); + pci_do_fixups(dev, pass, pci_fixups); } diff -u --recursive --new-file v2.3.14/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.14/linux/drivers/pnp/isapnp.c Wed Aug 18 09:59:26 1999 +++ linux/drivers/pnp/isapnp.c Mon Aug 23 10:52:02 1999 @@ -506,7 +506,7 @@ if (size > 2) irq->flags = tmp[2]; else - irq->flags = DEVICE_IRQ_FLAG_HIGHEDGE; + irq->flags = IORESOURCE_IRQ_HIGHEDGE; irq->res = *res; ptr = (*res)->irq; while (ptr && ptr->next) @@ -540,9 +540,7 @@ } } dma->map = tmp[0]; - dma->type = tmp[1] & 3; - dma->flags = (tmp[1] >> 2) & 7; - dma->speed = (tmp[1] >> 6) & 3; + dma->flags = tmp[1]; dma->res = *res; ptr = (*res)->dma; while (ptr && ptr->next) @@ -652,9 +650,7 @@ mem->max = ((tmp[4] << 8) | tmp[3]) << 8; mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; - mem->flags = tmp[0] & 7; - mem->flags |= (tmp[0] >> 2) & 0x18; - mem->type = (tmp[0] >> 3) & 3; + mem->flags = tmp[0]; mem->res = *res; ptr = (*res)->mem; while (ptr && ptr->next) @@ -1199,6 +1195,37 @@ return NULL; } +static unsigned int isapnp_dma_resource_flags(struct isapnp_dma *dma) +{ + return dma->flags | IORESOURCE_DMA | IORESOURCE_AUTO; +} + +static unsigned int isapnp_mem_resource_flags(struct isapnp_mem *mem) +{ + unsigned int result; + + result = mem->flags | IORESOURCE_MEM | IORESOURCE_AUTO; + if (!(mem->flags & IORESOURCE_MEM_WRITEABLE)) + result |= IORESOURCE_READONLY; + if (mem->flags & IORESOURCE_MEM_CACHEABLE) + result |= IORESOURCE_CACHEABLE; + if (mem->flags & IORESOURCE_MEM_RANGELENGTH) + result |= IORESOURCE_RANGELENGTH; + if (mem->flags & IORESOURCE_MEM_SHADOWABLE) + result |= IORESOURCE_SHADOWABLE; + return result; +} + +static unsigned int isapnp_irq_resource_flags(struct isapnp_irq *irq) +{ + return irq->flags | IORESOURCE_IRQ | IORESOURCE_AUTO; +} + +static unsigned int isapnp_port_resource_flags(struct isapnp_port *port) +{ + return port->flags | IORESOURCE_IO | IORESOURCE_AUTO; +} + static int isapnp_config_prepare(struct pci_dev *dev) { struct isapnp_resources *res, *resa; @@ -1216,47 +1243,41 @@ return -EINVAL; if (dev->active || dev->ro) return -EBUSY; - dev->irq = dev->irq2 = DEVICE_IRQ_NOTSET; - dev->irq_flags = dev->irq2_flags = 0; + for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) { + dev->irq_resource[idx].name = NULL; + dev->irq_resource[idx].start = 0; + dev->irq_resource[idx].end = 0; + dev->irq_resource[idx].flags = 0; + } for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) { - dev->dma[idx] = DEVICE_DMA_NOTSET; - dev->dma_type[idx] = DEVICE_DMA_TYPE_8AND16BIT; - dev->dma_flags[idx] = 0; - dev->dma_speed[idx] = DEVICE_DMA_SPEED_COMPATIBLE; + dev->dma_resource[idx].name = NULL; + dev->dma_resource[idx].start = 0; + dev->dma_resource[idx].end = 0; + dev->dma_resource[idx].flags = 0; } for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) { dev->resource[idx].name = NULL; - dev->resource[idx].start = DEVICE_IO_NOTSET; + dev->resource[idx].start = 0; dev->resource[idx].end = 0; - dev->resource[idx].fixed = 0; - dev->resource[idx].bits = 12; - dev->resource[idx].hw_flags = 0; - dev->resource[idx].type = DEVICE_IO_TYPE_8AND16BIT; + dev->resource[idx].flags = 0; } port_count = irq_count = dma_count = mem_count = 0; for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) { port_count1 = irq_count1 = dma_count1 = mem_count1 = 0; for (resa = res; resa; resa = resa->alt) { for (port = resa->port, idx = 0; port; port = port->next, idx++) { - if (dev->resource[port_count + idx].start == DEVICE_IO_NOTSET) { - dev->resource[port_count + idx].start = DEVICE_IO_AUTO; + if (dev->resource[port_count + idx].flags == 0) { + dev->resource[port_count + idx].flags = isapnp_port_resource_flags(port); dev->resource[port_count + idx].end = port->size; - dev->resource[port_count + idx].bits = port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 12; - dev->resource[port_count + idx].fixed = port->flags & ISAPNP_PORT_FLAG_FIXED ? 1 : 0; } } if (port_count1 < idx) port_count1 = idx; for (irq = resa->irq, idx = 0; irq; irq = irq->next, idx++) { - if (irq_count + idx == 0) { - if (dev->irq == DEVICE_IRQ_NOTSET) { - dev->irq = DEVICE_IRQ_AUTO; - dev->irq_flags = irq->flags; - } - } else if (irq_count + idx == 1) { - if (dev->irq2 == DEVICE_IRQ_NOTSET) { - dev->irq2 = DEVICE_IRQ_AUTO; - dev->irq2_flags = irq->flags; + int count = irq_count + idx; + if (count < DEVICE_COUNT_IRQ) { + if (dev->irq_resource[count].flags == 0) { + dev->irq_resource[count].flags = isapnp_irq_resource_flags(irq); } } @@ -1264,22 +1285,14 @@ if (irq_count1 < idx) irq_count1 = idx; for (dma = resa->dma, idx = 0; dma; dma = dma->next, idx++) - if (dev->dma[idx] == DEVICE_DMA_NOTSET) { - dev->dma[idx] = DEVICE_DMA_AUTO; - dev->dma_type[idx] = dma->type; - dev->dma_flags[idx] = dma->flags; - dev->dma_speed[idx] = dma->speed; + if (dev->dma_resource[idx].flags == 0) { + dev->dma_resource[idx].flags = isapnp_dma_resource_flags(dma); } if (dma_count1 < idx) dma_count1 = idx; for (mem = resa->mem, idx = 0; mem; mem = mem->next, idx++) - if (dev->resource[mem_count + idx + 8].start == DEVICE_IO_AUTO) { - dev->resource[mem_count + idx].start = DEVICE_IO_AUTO; - dev->resource[mem_count + idx].end = mem->size; - dev->resource[mem_count + idx].bits = 24; - dev->resource[mem_count + idx].fixed = 0; - dev->resource[mem_count + idx].hw_flags = mem->flags; - dev->resource[mem_count + idx].type = mem->type; + if (dev->resource[mem_count + idx + 8].flags == 0) { + dev->resource[mem_count + idx + 8].flags = isapnp_mem_resource_flags(mem); } if (mem_count1 < idx) mem_count1 = idx; @@ -1315,7 +1328,7 @@ return -EINVAL; /* process port settings */ for (tmp = 0; tmp < 8; tmp++) { - if (cfg->request->resource[tmp].start != DEVICE_IO_AUTO) + if (!(cfg->request->resource[tmp].flags & IORESOURCE_AUTO)) continue; /* don't touch */ port = cfg->port[tmp]; if (!port) { @@ -1331,21 +1344,16 @@ for (tmp1 = tmp; tmp1 > 0 && port; tmp1--) port = port->next; cfg->port[tmp] = port; - cfg->result.resource[tmp].start = DEVICE_IO_AUTO; if (!port) return -ENOENT; + cfg->result.resource[tmp].flags = isapnp_port_resource_flags(port); } } } /* process irq settings */ for (tmp = 0; tmp < 2; tmp++) { - if (tmp == 0) { - if (cfg->request->irq != DEVICE_IRQ_AUTO) - continue; /* don't touch */ - } else { - if (cfg->request->irq2 != DEVICE_IRQ_AUTO) - continue; /* don't touch */ - } + if (!(cfg->request->irq_resource[tmp].flags & IORESOURCE_AUTO)) + continue; /* don't touch */ irq = cfg->irq[tmp]; if (!irq) { cfg->irq[tmp] = irq = isapnp_find_irq(cfg->request, tmp); @@ -1360,19 +1368,15 @@ for (tmp1 = tmp; tmp1 > 0 && irq; tmp1--) irq = irq->next; cfg->irq[tmp] = irq; - if (tmp == 0) { - cfg->result.irq = DEVICE_IRQ_AUTO; - } else { - cfg->result.irq2 = DEVICE_IRQ_AUTO; - } if (!irq) return -ENOENT; + cfg->result.irq_resource[tmp].flags = isapnp_irq_resource_flags(irq); } } } /* process dma settings */ for (tmp = 0; tmp < 2; tmp++) { - if (cfg->request->dma[tmp] != DEVICE_DMA_AUTO) + if (!(cfg->request->dma_resource[tmp].flags & IORESOURCE_AUTO)) continue; /* don't touch */ dma = cfg->dma[tmp]; if (!dma) { @@ -1388,15 +1392,15 @@ for (tmp1 = tmp; tmp1 > 0 && dma; tmp1--) dma = dma->next; cfg->dma[tmp] = dma; - cfg->result.dma[tmp] = DEVICE_DMA_AUTO; if (!dma) return -ENOENT; + cfg->result.dma_resource[tmp].flags = isapnp_dma_resource_flags(dma); } } } /* process memory settings */ for (tmp = 0; tmp < 4; tmp++) { - if (cfg->request->resource[tmp + 8].start != DEVICE_IO_AUTO) + if (!(cfg->request->resource[tmp + 8].flags & IORESOURCE_AUTO)) continue; /* don't touch */ mem = cfg->mem[tmp]; if (!mem) { @@ -1412,9 +1416,9 @@ for (tmp1 = tmp; tmp1 > 0 && mem; tmp1--) mem = mem->next; cfg->mem[tmp] = mem; - cfg->result.resource[tmp + 8].start = DEVICE_IO_AUTO; if (!mem) return -ENOENT; + cfg->result.resource[tmp + 8].flags = isapnp_mem_resource_flags(mem); } } } @@ -1440,7 +1444,7 @@ for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { for (tmp = 0; tmp < 8; tmp++) { - if (dev->resource[tmp].start != DEVICE_IO_NOTSET) { + if (dev->resource[tmp].flags) { rport = dev->resource[tmp].start; rsize = (dev->resource[tmp].end - rport) + 1; if (port >= rport && port < rport + rsize) @@ -1452,18 +1456,20 @@ } } for (i = 0; i < 8; i++) { + unsigned int flags; if (i == idx) continue; - tmp = cfg->request->resource[i].start; - if (tmp == DEVICE_IO_NOTSET) + flags = cfg->request->resource[i].flags; + if (!flags) continue; - if (tmp == DEVICE_IO_AUTO) { /* auto */ + tmp = cfg->request->resource[i].start; + if (flags & IORESOURCE_AUTO) { /* auto */ xport = cfg->port[i]; if (!xport) return 1; - tmp = cfg->result.resource[i].start; - if (tmp == DEVICE_IO_AUTO) + if (cfg->result.resource[i].flags & IORESOURCE_AUTO) continue; + tmp = cfg->result.resource[i].start; if (tmp + xport->size >= port && tmp <= port + xport->size) return 1; continue; @@ -1482,25 +1488,30 @@ static int isapnp_valid_port(struct isapnp_cfgtmp *cfg, int idx) { int err; - unsigned long *value; + unsigned long *value1, *value2; struct isapnp_port *port; if (!cfg || idx < 0 || idx > 7) return -EINVAL; - if (cfg->result.resource[idx].start != DEVICE_IO_AUTO) /* don't touch */ + if (!(cfg->result.resource[idx].flags & IORESOURCE_AUTO)) /* don't touch */ return 0; __again: port = cfg->port[idx]; if (!port) return -EINVAL; - value = &cfg->result.resource[idx].start; - if (*value == DEVICE_IO_AUTO) { - if (!isapnp_check_port(cfg, *value = port->min, port->size, idx)) + value1 = &cfg->result.resource[idx].start; + value2 = &cfg->result.resource[idx].end; + if (cfg->result.resource[idx].flags & IORESOURCE_AUTO) { + cfg->result.resource[idx].flags &= ~IORESOURCE_AUTO; + *value1 = port->min; + *value2 = port->min + port->size - 1; + if (!isapnp_check_port(cfg, *value1, port->size, idx)) return 0; } do { - *value += port->align; - if (*value > port->max || !port->align) { + *value1 += port->align; + *value2 = *value1 + port->size - 1; + if (*value1 > port->max || !port->align) { if (port->res && port->res->alt) { if ((err = isapnp_alternative_switch(cfg, port->res, port->res->alt))<0) return err; @@ -1508,7 +1519,7 @@ } return -ENOENT; } - } while (isapnp_check_port(cfg, *value, port->size, idx)); + } while (isapnp_check_port(cfg, *value1, port->size, idx)); return 0; } @@ -1529,65 +1540,57 @@ } for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { - if (dev->irq == irq || dev->irq2 == irq) + if (dev->irq_resource[0].start == irq || + dev->irq_resource[1].start == irq) return 1; } } if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL)) return 1; free_irq(irq, NULL); - if (idx != 0) { - if (cfg->result.irq != DEVICE_IRQ_AUTO && - cfg->result.irq != DEVICE_IRQ_NOTSET) - if (cfg->result.irq == irq) - return 1; - } - if (idx != 1) { - if (cfg->result.irq2 != DEVICE_IRQ_AUTO && - cfg->result.irq2 != DEVICE_IRQ_NOTSET) - if (cfg->result.irq2 == irq) - return 1; + for (i = 0; i < DEVICE_COUNT_IRQ; i++) { + if (i == idx) + continue; + if (!cfg->result.irq_resource[i].flags) + continue; + if (cfg->result.irq_resource[i].flags & IORESOURCE_AUTO) + continue; + if (cfg->result.irq_resource[i].start == irq) + return 1; } return 0; } static int isapnp_valid_irq(struct isapnp_cfgtmp *cfg, int idx) { - /* IRQ priority: table is good for i386 */ + /* IRQ priority: this table is good for i386 */ static unsigned short xtab[16] = { 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 }; int err, i; - unsigned int *value; + unsigned long *value1, *value2; struct isapnp_irq *irq; if (!cfg || idx < 0 || idx > 1) return -EINVAL; - if (idx == 0) { - if (cfg->result.irq != DEVICE_IRQ_AUTO) /* don't touch */ - return 0; - } else { - if (cfg->result.irq2 != DEVICE_IRQ_AUTO) /* don't touch */ - return 0; - } + if (!(cfg->result.irq_resource[idx].flags & IORESOURCE_AUTO)) + return 0; __again: irq = cfg->irq[idx]; if (!irq) return -EINVAL; - if (idx == 0) { - value = &cfg->result.irq; - } else { - value = &cfg->result.irq2; - } - if (*value == DEVICE_IRQ_AUTO) { + value1 = &cfg->result.irq_resource[idx].start; + value2 = &cfg->result.irq_resource[idx].end; + if (cfg->result.irq_resource[idx].flags & IORESOURCE_AUTO) { for (i = 0; i < 16 && !(irq->map & (1<= 16) return -ENOENT; - if (!isapnp_check_interrupt(cfg, *value = xtab[i], idx)) + cfg->result.irq_resource[idx].flags &= ~IORESOURCE_AUTO; + if (!isapnp_check_interrupt(cfg, *value1 = *value2 = xtab[i], idx)) return 0; } do { - for (i = 0; i < 16 && xtab[i] != *value; i++); + for (i = 0; i < 16 && xtab[i] != *value1; i++); for (i++; i < 16 && !(irq->map & (1<= 16) { if (irq->res && irq->res->alt) { @@ -1597,9 +1600,9 @@ } return -ENOENT; } else { - *value = xtab[i]; + *value1 = *value2 = xtab[i]; } - } while (isapnp_check_interrupt(cfg, *value, idx)); + } while (isapnp_check_interrupt(cfg, *value1, idx)); return 0; } @@ -1616,7 +1619,7 @@ } for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { - if (dev->dma[0] == dma || dev->dma[1] == dma) + if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma) return 1; } } @@ -1626,10 +1629,10 @@ for (i = 0; i < 2; i++) { if (i == idx) continue; - if (cfg->result.dma[i] == DEVICE_DMA_NOTSET || - cfg->result.dma[i] == DEVICE_DMA_AUTO) + if (!cfg->result.dma_resource[i].flags || + (cfg->result.dma_resource[i].flags & IORESOURCE_AUTO)) continue; - if (cfg->result.dma[i] == dma) + if (cfg->result.dma_resource[i].start == dma) return 1; } return 0; @@ -1638,27 +1641,29 @@ static int isapnp_valid_dma(struct isapnp_cfgtmp *cfg, int idx) { int err, i; - unsigned char *value; + unsigned long *value1, *value2; struct isapnp_dma *dma; if (!cfg || idx < 0 || idx > 1) return -EINVAL; - if (cfg->result.dma[idx] != DEVICE_DMA_AUTO) /* don't touch */ + if (!(cfg->result.dma_resource[idx].flags & IORESOURCE_AUTO)) /* don't touch */ return 0; __again: dma = cfg->dma[idx]; if (!dma) return -EINVAL; - value = &cfg->result.dma[idx]; - if (*value == DEVICE_DMA_AUTO) { + value1 = &cfg->result.dma_resource[idx].start; + value2 = &cfg->result.dma_resource[idx].end; + if (cfg->result.dma_resource[idx].flags & IORESOURCE_AUTO) { for (i = 0; i < 8 && !(dma->map & (1<= 8) return -ENOENT; - if (!isapnp_check_dma(cfg, *value = i, idx)) + cfg->result.dma_resource[idx].flags &= ~IORESOURCE_AUTO; + if (!isapnp_check_dma(cfg, *value1 = *value2 = i, idx)) return 0; } do { - for (i = *value + 1; i < 8 && !(dma->map & (1<map & (1<= 8) { if (dma->res && dma->res->alt) { if ((err = isapnp_alternative_switch(cfg, dma->res, dma->res->alt))<0) @@ -1667,9 +1672,9 @@ } return -ENOENT; } else { - *value = i; + *value1 = *value2 = i; } - } while (isapnp_check_dma(cfg, *value, idx)); + } while (isapnp_check_dma(cfg, *value1, idx)); return 0; } @@ -1693,7 +1698,7 @@ for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { for (tmp = 0; tmp < 4; tmp++) { - if (dev->resource[tmp].start != DEVICE_IO_NOTSET) { + if (dev->resource[tmp].flags) { raddr = dev->resource[tmp + 8].start; rsize = (dev->resource[tmp + 8].end - raddr) + 1; if (addr >= raddr && addr < raddr + rsize) @@ -1705,17 +1710,17 @@ } } for (i = 0; i < 4; i++) { + unsigned int flags = cfg->request->resource[i + 8].flags; if (i == idx) continue; - tmp = cfg->request->resource[i + 8].start; - if (tmp == DEVICE_IO_NOTSET) + if (!flags) continue; - if (tmp == DEVICE_IO_AUTO) { /* auto */ + tmp = cfg->result.resource[i + 8].start; + if (flags & IORESOURCE_AUTO) { /* auto */ xmem = cfg->mem[i]; if (!xmem) return 1; - tmp = cfg->result.resource[i + 8].start; - if (tmp == DEVICE_IO_AUTO) + if (cfg->result.resource[i + 8].flags & IORESOURCE_AUTO) continue; if (tmp + xmem->size >= addr && tmp <= addr + xmem->size) return 1; @@ -1735,26 +1740,30 @@ static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx) { int err; - unsigned long *value; + unsigned long *value1, *value2; struct isapnp_mem *mem; if (!cfg || idx < 0 || idx > 3) return -EINVAL; - if (cfg->result.resource[idx + 8].start != DEVICE_IO_AUTO) /* don't touch */ + if (!(cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO)) /* don't touch */ return 0; __again: mem = cfg->mem[idx]; if (!mem) return -EINVAL; - value = &cfg->result.resource[idx].start; - if (*value == DEVICE_IO_AUTO) { - *value = mem->min; - if (!isapnp_check_mem(cfg, *value, mem->size, idx)) + value1 = &cfg->result.resource[idx].start; + value2 = &cfg->result.resource[idx].end; + if (cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO) { + cfg->result.resource[idx + 8].flags &= ~IORESOURCE_AUTO; + *value1 = mem->min; + *value2 = mem->min + mem->size - 1; + if (!isapnp_check_mem(cfg, *value1, mem->size, idx)) return 0; } do { - *value += mem->align; - if (*value >= 8 || !mem->align) { + *value1 += mem->align; + *value2 = *value1 + mem->size - 1; + if (*value1 >= 8 || !mem->align) { if (mem->res && mem->res->alt) { if ((err = isapnp_alternative_switch(cfg, mem->res, mem->res->alt))<0) return err; @@ -1762,7 +1771,7 @@ } return -ENOENT; } - } while (isapnp_check_mem(cfg, *value, mem->size, idx)); + } while (isapnp_check_mem(cfg, *value1, mem->size, idx)); return 0; } @@ -1771,17 +1780,16 @@ int tmp; for (tmp = 0; tmp < 8; tmp++) - if (cfg->result.resource[tmp].start == DEVICE_IO_AUTO) + if (cfg->result.resource[tmp].flags & IORESOURCE_AUTO) + return -EAGAIN; + for (tmp = 0; tmp < 2; tmp++) + if (cfg->result.irq_resource[tmp].flags & IORESOURCE_AUTO) return -EAGAIN; - if (cfg->result.irq == DEVICE_IRQ_AUTO) - return -EAGAIN; - if (cfg->result.irq2 == DEVICE_IRQ_AUTO) - return -EAGAIN; for (tmp = 0; tmp < 2; tmp++) - if (cfg->result.dma[tmp] == DEVICE_DMA_AUTO) + if (cfg->result.dma_resource[tmp].flags & IORESOURCE_AUTO) return -EAGAIN; for (tmp = 0; tmp < 4; tmp++) - if (cfg->result.resource[tmp + 1].start == DEVICE_IO_AUTO) + if (cfg->result.resource[tmp + 8].flags & IORESOURCE_AUTO) return -EAGAIN; return 0; } @@ -1800,19 +1808,19 @@ memcpy(&cfg.result, dev, sizeof(struct pci_dev)); /* check if all values are set, otherwise try auto-configuration */ for (tmp = fauto = 0; !fauto && tmp < 8; tmp++) { - if (dev->resource[tmp].start == DEVICE_IO_AUTO) + if (dev->resource[tmp].flags & IORESOURCE_AUTO) + fauto++; + } + for (tmp = 0; !fauto && tmp < 2; tmp++) { + if (dev->irq_resource[tmp].flags & IORESOURCE_AUTO) fauto++; } - if (dev->irq == DEVICE_IRQ_AUTO) - fauto++; - if (dev->irq2 == DEVICE_IRQ_AUTO) - fauto++; for (tmp = 0; !fauto && tmp < 2; tmp++) { - if (dev->dma[tmp] == DEVICE_DMA_AUTO) + if (dev->dma_resource[tmp].flags & IORESOURCE_AUTO) fauto++; } for (tmp = 0; !fauto && tmp < 4; tmp++) { - if (dev->resource[tmp + 8].start == DEVICE_IO_AUTO) + if (dev->resource[tmp + 8].flags & IORESOURCE_AUTO) fauto++; } if (!fauto) @@ -1823,19 +1831,16 @@ /* find first valid configuration */ fauto = 0; do { - for (tmp = 0; tmp < 8 && cfg.result.resource[tmp].start != DEVICE_IO_NOTSET; tmp++) + for (tmp = 0; tmp < 8 && cfg.result.resource[tmp].flags; tmp++) if ((err = isapnp_valid_port(&cfg, tmp))<0) return err; - if (cfg.result.irq != DEVICE_IRQ_NOTSET) - if ((err = isapnp_valid_irq(&cfg, 0))<0) - return err; - if (cfg.result.irq2 != DEVICE_IRQ_NOTSET) - if ((err = isapnp_valid_irq(&cfg, 1))<0) + for (tmp = 0; tmp < 2 && cfg.result.irq_resource[tmp].flags; tmp++) + if ((err = isapnp_valid_irq(&cfg, tmp))<0) return err; - for (tmp = 0; tmp < 2 && tmp < cfg.result.dma[tmp] != DEVICE_DMA_NOTSET; tmp++) + for (tmp = 0; tmp < 2 && cfg.result.dma_resource[tmp].flags; tmp++) if ((err = isapnp_valid_dma(&cfg, tmp))<0) return err; - for (tmp = 0; tmp < 4 && tmp < cfg.result.resource[tmp + 8].start != DEVICE_IO_NOTSET; tmp++) + for (tmp = 0; tmp < 4 && cfg.result.resource[tmp + 8].flags; tmp++) if ((err = isapnp_valid_mem(&cfg, tmp))<0) return err; } while (isapnp_check_valid(&cfg)<0 && fauto++ < 20); @@ -1845,31 +1850,24 @@ /* we have valid configuration, try configure hardware */ isapnp_cfg_begin(dev->bus->number, dev->devfn); dev->active = 1; - dev->irq = cfg.result.irq; - dev->irq2 = cfg.result.irq2; - dev->dma[0] = cfg.result.dma[0]; - dev->dma[1] = cfg.result.dma[1]; + dev->irq_resource[0] = cfg.result.irq_resource[0]; + dev->irq_resource[1] = cfg.result.irq_resource[1]; + dev->dma_resource[0] = cfg.result.dma_resource[0]; + dev->dma_resource[1] = cfg.result.dma_resource[1]; for (tmp = 0; tmp < 12; tmp++) { - dev->resource[tmp].start = cfg.result.resource[tmp].start; - if (cfg.result.resource[tmp].start != DEVICE_IO_NOTSET && - cfg.result.resource[tmp].end != DEVICE_IO_AUTO) - dev->resource[tmp].end += cfg.result.resource[tmp].start; + dev->resource[tmp] = cfg.result.resource[tmp]; } - for (tmp = 0; tmp < 8 && dev->resource[tmp].start != DEVICE_IO_NOTSET; tmp++) + for (tmp = 0; tmp < 8 && dev->resource[tmp].flags; tmp++) isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), dev->resource[tmp].start); - if (dev->irq != DEVICE_IRQ_NOTSET) { - if (dev->irq == 2) - dev->irq = 9; - isapnp_write_byte(ISAPNP_CFG_IRQ+(0<<1), dev->irq); - } - if (dev->irq2 != DEVICE_IRQ_NOTSET) { - if (dev->irq2 == 2) - dev->irq2 = 9; - isapnp_write_byte(ISAPNP_CFG_IRQ+(1<<1), dev->irq2); - } - for (tmp = 0; tmp < 2 && dev->dma[tmp] != DEVICE_DMA_NOTSET; tmp++) - isapnp_write_byte(ISAPNP_CFG_DMA+tmp, dev->dma[tmp]); - for (tmp = 0; tmp < 4 && dev->resource[tmp].start != DEVICE_IO_NOTSET; tmp++) + for (tmp = 0; tmp < 2 && dev->irq_resource[tmp].flags; tmp++) { + int irq = dev->irq_resource[tmp].start; + if (irq == 2) + irq = 9; + isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq); + } + for (tmp = 0; tmp < 2 && dev->dma_resource[tmp].flags; tmp++) + isapnp_write_byte(ISAPNP_CFG_DMA+tmp, dev->dma_resource[tmp].start); + for (tmp = 0; tmp < 4 && dev->resource[tmp+8].flags; tmp++) isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (dev->resource[tmp + 8].start >> 8) & 0xffff); isapnp_activate(dev->devfn); isapnp_cfg_end(); @@ -1882,11 +1880,22 @@ return -EINVAL; isapnp_cfg_begin(dev->bus->number, dev->devfn); isapnp_deactivate(dev->devfn); - dev->activate = 0; + dev->active = 0; isapnp_cfg_end(); return 0; } +void isapnp_resource_change(struct resource *resource, + unsigned long start, + unsigned long size) +{ + if (resource == NULL) + return; + resource->flags &= ~IORESOURCE_AUTO; + resource->start = start; + resource->end = start + size - 1; +} + /* * Inititialization. */ @@ -1971,7 +1980,7 @@ struct pci_dev *next; while (dev) { - next = dev->next; + next = dev->sibling; isapnp_free_resources((struct isapnp_resources *)dev->sysdata, 0); kfree(dev); dev = next; @@ -2067,6 +2076,7 @@ EXPORT_SYMBOL(isapnp_deactivate); EXPORT_SYMBOL(isapnp_find_card); EXPORT_SYMBOL(isapnp_find_dev); +EXPORT_SYMBOL(isapnp_resource_change); int __init isapnp_init(void) { diff -u --recursive --new-file v2.3.14/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c --- v2.3.14/linux/drivers/pnp/isapnp_proc.c Tue Aug 17 17:19:58 1999 +++ linux/drivers/pnp/isapnp_proc.c Mon Aug 23 10:52:02 1999 @@ -312,13 +312,13 @@ } if (!irq->map) isapnp_printf(buffer, ""); - if (irq->flags & DEVICE_IRQ_FLAG_HIGHEDGE) + if (irq->flags & IORESOURCE_IRQ_HIGHEDGE) isapnp_printf(buffer, " High-Edge"); - if (irq->flags & DEVICE_IRQ_FLAG_LOWEDGE) + if (irq->flags & IORESOURCE_IRQ_LOWEDGE) isapnp_printf(buffer, " Low-Edge"); - if (irq->flags & DEVICE_IRQ_FLAG_HIGHLEVEL) + if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL) isapnp_printf(buffer, " High-Level"); - if (irq->flags & DEVICE_IRQ_FLAG_LOWLEVEL) + if (irq->flags & IORESOURCE_IRQ_LOWLEVEL) isapnp_printf(buffer, " Low-Level"); isapnp_printf(buffer, "\n"); } @@ -340,31 +340,31 @@ } if (!dma->map) isapnp_printf(buffer, ""); - switch (dma->type) { - case DEVICE_DMA_TYPE_8BIT: + switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) { + case IORESOURCE_DMA_8BIT: s = "8-bit"; break; - case DEVICE_DMA_TYPE_8AND16BIT: + case IORESOURCE_DMA_8AND16BIT: s = "8-bit&16-bit"; break; default: s = "16-bit"; } isapnp_printf(buffer, " %s", s); - if (dma->flags & DEVICE_DMA_FLAG_MASTER) + if (dma->flags & IORESOURCE_DMA_MASTER) isapnp_printf(buffer, " master"); - if (dma->flags & DEVICE_DMA_FLAG_BYTE) + if (dma->flags & IORESOURCE_DMA_BYTE) isapnp_printf(buffer, " byte-count"); - if (dma->flags & DEVICE_DMA_FLAG_WORD) + if (dma->flags & IORESOURCE_DMA_WORD) isapnp_printf(buffer, " word-count"); - switch (dma->speed) { - case DEVICE_DMA_SPEED_TYPEA: + switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) { + case IORESOURCE_DMA_TYPEA: s = "type-A"; break; - case DEVICE_DMA_SPEED_TYPEB: + case IORESOURCE_DMA_TYPEB: s = "type-B"; break; - case DEVICE_DMA_SPEED_TYPEF: + case IORESOURCE_DMA_TYPEF: s = "type-F"; break; default: @@ -380,21 +380,21 @@ isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x", space, mem->min, mem->max, mem->align, mem->size); - if (mem->flags & DEVICE_IO_FLAG_WRITEABLE) + if (mem->flags & IORESOURCE_MEM_WRITEABLE) isapnp_printf(buffer, ", writeable"); - if (mem->flags & DEVICE_IO_FLAG_CACHEABLE) + if (mem->flags & IORESOURCE_MEM_CACHEABLE) isapnp_printf(buffer, ", cacheable"); - if (mem->flags & DEVICE_IO_FLAG_RANGELENGTH) + if (mem->flags & IORESOURCE_MEM_RANGELENGTH) isapnp_printf(buffer, ", range-length"); - if (mem->flags & DEVICE_IO_FLAG_SHADOWABLE) + if (mem->flags & IORESOURCE_MEM_SHADOWABLE) isapnp_printf(buffer, ", shadowable"); - if (mem->flags & DEVICE_IO_FLAG_EXPANSIONROM) + if (mem->flags & IORESOURCE_MEM_EXPANSIONROM) isapnp_printf(buffer, ", expansion ROM"); - switch (mem->type) { - case DEVICE_IO_TYPE_8BIT: + switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_8BIT: s = "8-bit"; break; - case DEVICE_IO_TYPE_8AND16BIT: + case IORESOURCE_MEM_8AND16BIT: s = "8-bit&16-bit"; break; default: @@ -734,11 +734,12 @@ return 1; } isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port); - if (isapnp_info_device->resource[idx].start == DEVICE_IO_NOTSET) + if (!isapnp_info_device->resource[idx].flags) return 0; - if (isapnp_info_device->resource[idx].start == DEVICE_IO_AUTO) { + if (isapnp_info_device->resource[idx].flags & IORESOURCE_AUTO) { isapnp_info_device->resource[idx].start = port; isapnp_info_device->resource[idx].end += port - 1; + isapnp_info_device->resource[idx].flags &= ~IORESOURCE_AUTO; } else { isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start; isapnp_info_device->resource[idx].start = port; @@ -746,6 +747,12 @@ } return 0; } + +static void isapnp_set_irqresource(struct resource *res, int irq) +{ + res->start = res->end = irq; + res->flags = IORESOURCE_IRQ; +} static int isapnp_set_irq(char *line) { @@ -767,18 +774,16 @@ return 1; } isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq); - if (idx == 0) { - if (isapnp_info_device->irq == DEVICE_IRQ_NOTSET) - return 0; - isapnp_info_device->irq = irq; - } else { - if (isapnp_info_device->irq2 == DEVICE_IRQ_NOTSET) - return 0; - isapnp_info_device->irq2 = irq; - } + isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq); return 0; } +static void isapnp_set_dmaresource(struct resource *res, int dma) +{ + res->start = res->end = dma; + res->flags = IORESOURCE_DMA; +} + static int isapnp_set_dma(char *line) { int idx, dma; @@ -797,9 +802,7 @@ return 1; } isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma); - if (isapnp_info_device->dma[idx] == DEVICE_DMA_NOTSET) - return 0; - isapnp_info_device->dma[idx] = dma; + isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma); return 0; } @@ -819,11 +822,12 @@ } mem >>= 8; isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff); - if (isapnp_info_device->resource[idx + 8].start == DEVICE_IO_NOTSET) + if (!isapnp_info_device->resource[idx + 8].flags) return 0; - if (isapnp_info_device->resource[idx + 8].start == DEVICE_IO_AUTO) { + if (isapnp_info_device->resource[idx + 8].flags & IORESOURCE_AUTO) { isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00; isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1; + isapnp_info_device->resource[idx + 8].flags &= ~IORESOURCE_AUTO; } else { isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start; isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00; diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.3.14/linux/drivers/scsi/Config.in Wed Jun 9 16:59:15 1999 +++ linux/drivers/scsi/Config.in Mon Aug 23 10:12:38 1999 @@ -34,9 +34,6 @@ dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI -if [ "$CONFIG_SCSI_MEGARAID" != "n" ]; then - bool ' Concurrent IO commands on MegaRAID' CONFIG_MEGARAID_MULTI_IO -fi dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.3.14/linux/drivers/scsi/aha152x.c Tue Jul 6 19:08:33 1999 +++ linux/drivers/scsi/aha152x.c Mon Aug 23 10:14:44 1999 @@ -1394,9 +1394,7 @@ if (ptr && !ptr->device->soft_reset) { ptr->host_scribble = NULL; ptr->result = DID_RESET << 16; - spin_lock_irqsave(&io_request_lock, flags); ptr->scsi_done(CURRENT_SC); - spin_unlock_irqrestore(&io_request_lock, flags); CURRENT_SC = NULL; } save_flags(flags); diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.3.14/linux/drivers/scsi/aha1542.c Wed Oct 7 15:52:55 1998 +++ linux/drivers/scsi/aha1542.c Mon Aug 23 10:14:44 1999 @@ -18,6 +18,9 @@ * 1-Jan-97 * Modified by Bjorn L. Thordarson and Einar Thor Einarsson * Recognize that DMA0 is valid DMA channel -- 13-Jul-98 + * Modified by Chris Faulhaber + * Added module command-line options + * 18-Jul-99 */ #include @@ -84,7 +87,7 @@ static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL}; /* - * LILO params: aha1542=[,,[,]] + * LILO/Module params: aha1542=[,,[,]] * * Where: is any of the valid AHA addresses: * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 @@ -100,6 +103,11 @@ * Factory default is 5 MB/s. */ +#if defined(MODULE) +int aha1542[] = { 0x330, 11, 4, -1 }; +MODULE_PARM(aha1542, "1-4i"); +#endif + #define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ #define BIOS_TRANSLATION_6432 1 /* Default case these days */ #define BIOS_TRANSLATION_25563 2 /* Big disk case */ @@ -823,7 +831,8 @@ mbenable_cmd[1]=0; mbenable_cmd[2]=mbenable_result[1]; - if(mbenable_result[1] & 0x03) retval = BIOS_TRANSLATION_25563; + if((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) + retval = BIOS_TRANSLATION_25563; aha1542_out(base,mbenable_cmd,3); WAIT(INTRFLAGS(base),INTRMASK,HACC,0); @@ -877,7 +886,7 @@ } /* called from init/main.c */ -__initfunc(void aha1542_setup( char *str, int *ints)) +void __init aha1542_setup( char *str, int *ints) { const char *ahausage = "aha1542: usage: aha1542=[,,[,]]\n"; static int setup_idx = 0; @@ -953,6 +962,14 @@ DEB(printk("aha1542_detect: \n")); tpnt->proc_dir = &proc_scsi_aha1542; + +#ifdef MODULE + bases[0] = 4; + bases[1] = aha1542[0]; + bases[2] = aha1542[1]; + bases[3] = aha1542[2]; + bases[4] = aha1542[3]; +#endif for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++) if(bases[indx] != 0 && !check_region(bases[indx], 4)) { diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c --- v2.3.14/linux/drivers/scsi/dtc.c Sat Apr 11 11:13:25 1998 +++ linux/drivers/scsi/dtc.c Mon Aug 23 10:14:44 1999 @@ -177,7 +177,7 @@ * */ -__initfunc(void dtc_setup(char *str, int *ints)) { +void __init dtc_setup(char *str, int *ints){ static int commandline_current = 0; int i; if (ints[0] != 2) @@ -208,8 +208,7 @@ * */ - -__initfunc(int dtc_detect(Scsi_Host_Template * tpnt)) { +int __init dtc_detect(Scsi_Host_Template * tpnt){ static int current_override = 0, current_base = 0; struct Scsi_Host *instance; unsigned int base; diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.3.14/linux/drivers/scsi/gdth.c Mon Aug 9 10:25:01 1999 +++ linux/drivers/scsi/gdth.c Mon Aug 23 11:15:53 1999 @@ -266,7 +266,7 @@ #ifdef DEBUG_GDTH static unchar DebugState = DEBUG_GDTH; -extern int sys_syslog(int,char*,int); +extern long sys_syslog(int,char*,int); #define LOGEN sys_syslog(7,NULL,0) #ifdef __SERIAL__ diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.14/linux/drivers/scsi/hosts.c Wed Aug 18 10:00:52 1999 +++ linux/drivers/scsi/hosts.c Mon Aug 23 10:14:44 1999 @@ -335,6 +335,10 @@ #include "sun3x_esp.h" #endif +#ifdef CONFIG_IPHASE5526 +#include "../net/fc/iph5526_scsi.h" +#endif + /* * Moved ppa driver to the end of the probe list * since it is a removable host adapter. @@ -599,6 +603,9 @@ #ifdef CONFIG_SCSI_POWERTECSCSI POWERTECSCSI, #endif +#endif +#ifdef CONFIG_IPHASE5526 + IPH5526_SCSI_FC, #endif /* "Removable host adapters" below this line (Parallel Port/USB/other) */ #ifdef CONFIG_SCSI_PPA diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/i91uscsi.c linux/drivers/scsi/i91uscsi.c --- v2.3.14/linux/drivers/scsi/i91uscsi.c Thu Jan 14 10:31:41 1999 +++ linux/drivers/scsi/i91uscsi.c Mon Aug 23 10:23:23 1999 @@ -218,8 +218,8 @@ static void tul_do_pause(unsigned amount) -{ /* Pause for amount*10 milliseconds */ - unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ +{ /* Pause for amount jiffies */ + unsigned long the_time = jiffies + amount; #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) while (time_before_eq(jiffies, the_time)); @@ -579,7 +579,7 @@ /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */ /* SONY 5200 tape drive won't work if only stall for 1 sec */ - tul_do_pause(seconds * 100); + tul_do_pause(seconds * HZ); TUL_RD(pCurHcb->HCS_Base, TUL_SInt); diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c --- v2.3.14/linux/drivers/scsi/ini9100u.c Mon Aug 9 10:25:01 1999 +++ linux/drivers/scsi/ini9100u.c Mon Aug 23 10:14:44 1999 @@ -95,6 +95,15 @@ * pSRB_tail members of the HCS structure. * 09/01/99 bv - v1.03d * - Fixed a deadlock problem in SMP. + * 21/01/99 bv - v1.03e + * - Add support for the Domex 3192U PCI SCSI + * This is a slightly modified patch by + * Brian Macy + * 22/02/99 bv - v1.03f + * - Didn't detect the INIC-950 in 2.0.x correctly. + * Now fixed. + * 05/07/99 bv - v1.03g + * - Changed the assumption that HZ = 100 **************************************************************************/ #define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) @@ -158,7 +167,7 @@ char *i91uCopyright = "Copyright (C) 1996-98"; char *i91uInitioName = "by Initio Corporation"; char *i91uProductName = "INI-9X00U/UW"; -char *i91uVersion = "v1.03d"; +char *i91uVersion = "v1.03g"; #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) struct proc_dir_entry proc_scsi_ini9100u = @@ -230,17 +239,12 @@ /* ---- EXTERNAL VARIABLES ---- */ extern HCS tul_hcs[]; -struct id { - int vendor_id; - int device_id; -}; - -const struct id id_table[] = { - { INI_VENDOR_ID, I950_DEVICE_ID }, - { INI_VENDOR_ID, I940_DEVICE_ID }, - { INI_VENDOR_ID, I935_DEVICE_ID }, - { INI_VENDOR_ID, 0x0002 }, - { DMX_VENDOR_ID, 0x0002 }, +const PCI_ID i91u_pci_devices[] = { + { INI_VENDOR_ID, I950_DEVICE_ID }, + { INI_VENDOR_ID, I940_DEVICE_ID }, + { INI_VENDOR_ID, I935_DEVICE_ID }, + { INI_VENDOR_ID, I920_DEVICE_ID }, + { DMX_VENDOR_ID, I920_DEVICE_ID }, }; /* @@ -334,14 +338,13 @@ int iAdapters = 0; long dRegValue; WORD wBIOS; - const int iNumIdEntries = sizeof(id_table)/sizeof(id_table[0]); int i = 0; init_i91uAdapter_table(); - for (i=0; i < iNumIdEntries; i++) { - struct id curId = id_table[i]; - while ((pDev = pci_find_device(curId.vendor_id, curId.device_id, pDev)) != NULL) { + for (i = 0; i < TULSZ(i91u_pci_devices); i++) + { + while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) { pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue); wBIOS = (UWORD) (dRegValue & 0xFF); if (((dRegValue & 0xFF00) >> 8) == 0xFF) @@ -377,17 +380,6 @@ unsigned short command; WORD wBIOS, wBASE; BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum; - struct { - unsigned short vendor_id; - unsigned short device_id; - } const i91u_pci_devices[] = - { - {INI_VENDOR_ID, I935_DEVICE_ID}, - {INI_VENDOR_ID, I940_DEVICE_ID}, - {INI_VENDOR_ID, I950_DEVICE_ID}, - {INI_VENDOR_ID, I920_DEVICE_ID} - }; - iAdapters = 0; /* @@ -398,57 +390,25 @@ unsigned long page_offset, base; #endif -#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) - struct pci_dev *pdev = NULL; -#else int index; unsigned char pci_bus, pci_devfn; -#endif bPCIBusNum = 0; bPCIDeviceNum = 0; init_i91uAdapter_table(); for (i = 0; i < TULSZ(i91u_pci_devices); i++) { -#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) - pdev = NULL; - while ((pdev = pci_find_device(i91u_pci_devices[i].vendor_id, - i91u_pci_devices[i].device_id, - pdev))) -#else index = 0; while (!(pcibios_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, index++, &pci_bus, &pci_devfn))) -#endif { - if (i == 0) { - /* + if (i == 2) { printk("i91u: The RAID controller is not supported by\n"); printk("i91u: this driver, we are ignoring it.\n"); - */ } else { /* * Read sundry information from PCI BIOS. */ -#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) - bPCIBusNum = pdev->bus->number; - bPCIDeviceNum = pdev->devfn; - dRegValue = pdev->base_address[0]; - if (dRegValue == -1) { /* Check return code */ - printk("\n\ri91u: tulip read configuration error.\n"); - return (0); /* Read configuration space error */ - } - /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ - wBASE = (WORD) dRegValue; - - /* Now read the interrupt line */ - dRegValue = pdev->irq; - bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - pci_write_config_word(pdev, PCI_COMMAND, - command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); - -#else bPCIBusNum = pci_bus; bPCIDeviceNum = pci_devfn; pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0, @@ -467,7 +427,6 @@ pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command); pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); -#endif wBASE &= PCI_BASE_ADDRESS_IO_MASK; wBIOS = TUL_RDWORD(wBASE, 0x50); diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h --- v2.3.14/linux/drivers/scsi/ini9100u.h Wed Aug 18 16:44:56 1999 +++ linux/drivers/scsi/ini9100u.h Tue Aug 24 17:10:34 1999 @@ -63,7 +63,9 @@ * - Removed unused code * 12/13/98 bv - v1.03b * - Add spinlocks to HCS structure. -*******************************************************************************/ + * 21/01/99 bv - v1.03e + * - Added PCI_ID structure + **************************************************************************/ #ifndef CVT_LINUX_VERSION #define CVT_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S)) @@ -88,7 +90,7 @@ extern int i91u_biosparam(Disk *, int, int *); /*for linux v1.13 */ #endif -#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03d" +#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g" #if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0) #define INI9100U { \ @@ -207,11 +209,19 @@ #define SENSE_SIZE 14 #define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */ -#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */ +#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */ #define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */ #define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */ #define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */ #define I920_DEVICE_ID 0x0002 /* Initio's other product ID */ + +/************************************************************************/ +/* Vendor ID/Device ID Pair Structure */ +/************************************************************************/ +typedef struct PCI_ID_Struc { + unsigned short vendor_id; + unsigned short device_id; +} PCI_ID; /************************************************************************/ /* Scatter-Gather Element Structure */ diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/mca_53c9x.c linux/drivers/scsi/mca_53c9x.c --- v2.3.14/linux/drivers/scsi/mca_53c9x.c Wed Aug 18 10:00:52 1999 +++ linux/drivers/scsi/mca_53c9x.c Mon Aug 23 10:14:44 1999 @@ -275,7 +275,7 @@ free_irq(esp->irq, esp_intr); free_dma(esp->dma); - mca_mark_as_unused(esp->eregs->slot); + mca_mark_as_unused(esp->slot); return 0; } diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.3.14/linux/drivers/scsi/megaraid.c Mon Aug 9 10:25:01 1999 +++ linux/drivers/scsi/megaraid.c Mon Aug 23 13:44:03 1999 @@ -9,14 +9,12 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version : 1.00 + * Version : 1.04 * * Description: Linux device driver for AMI MegaRAID controller * - * Supported controllers: MegaRAID 418, 428, 438, 466, 762 + * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490 * - * Maintainer: Jeff L Jones - * * History: * * Version 0.90: @@ -38,10 +36,10 @@ * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: - * Small changes to the comments/formatting. Plus a couple of + * Small changes to the comments/formatting. Plus a couple of * added notes. Returned to the authors. No actual code changes * save printk levels. - * 8 Oct 98 Alan Cox + * 8 Oct 98 Alan Cox * * Merged with 2.1.131 source tree. * 12 Dec 98 K. Baranowski @@ -73,14 +71,15 @@ * * Version 0.96: * 762 fully supported. + * * Version 0.97: * Changed megaraid_command to use wait_queue. * Fixed bug of undesirably detecting HP onboard controllers which - * are disabled. + * are disabled. * * Version 1.00: * Checks to see if an irq ocurred while in isr, and runs through - * routine again. + * routine again. * Copies mailbox to temp area before processing in isr * Added barrier() in busy wait to fix volatility bug * Uses separate list for freed Scbs, keeps track of cmd state @@ -88,17 +87,45 @@ * Full multi-io commands working stablely without previous problems * Added skipXX LILO option for Madrona motherboard support * + * Version 1.01: + * Fixed bug in mega_cmd_done() for megamgr control commands, + * the host_byte in the result code from the scsi request to + * scsi midlayer is set to DID_BAD_TARGET when adapter's + * returned codes are 0xF0 and 0xF4. + * + * Version 1.02: + * Fixed the tape drive bug by extending the adapter timeout value + * for passthrough command to 60 seconds in mega_build_cmd(). + * + * Version 1.03: + * Fixed Madrona support. + * Changed the adapter timeout value from 60 sec in 1.02 to 10 min + * for bigger and slower tape drive. + * Added driver version printout at driver loadup time + * + * Version 1.04 + * Added code for 40 ld FW support. + * Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with + * data area greater than 4 KB, which is the upper bound for data + * tranfer through scsi_ioctl interface. + * The addtional 32 bit field for 64bit address in the newly defined + * mailbox64 structure is set to 0 at this point. * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that * fails to detect the controller as a pci device on the system. * - * Timeout period for mid scsi layer is too short for - * this controller. Must be increased or Aborts will occur. + * Timeout period for upper scsi layer, i.e. SD_TIMEOUT in + * /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT + * value must be increased to (30 * HZ) otherwise false timeouts + * will occur in the upper layer. * *===================================================================*/ #define CRLFSTR "\n" +#define IOCTL_CMD_NEW 0x81 + +#define MEGARAID_VERSION "v1.04 (August 16, 1999)" #include @@ -138,6 +165,7 @@ #include #include +#include #include "sd.h" #include "scsi.h" @@ -203,22 +231,22 @@ spin_unlock_irqrestore(&mega_lock,cpuflag);\ }; -u_long RDINDOOR (mega_host_config * megaCfg) +u32 RDINDOOR (mega_host_config * megaCfg) { return readl (megaCfg->base + 0x20); } -void WRINDOOR (mega_host_config * megaCfg, u_long value) +void WRINDOOR (mega_host_config * megaCfg, u32 value) { writel (value, megaCfg->base + 0x20); } -u_long RDOUTDOOR (mega_host_config * megaCfg) +u32 RDOUTDOOR (mega_host_config * megaCfg) { return readl (megaCfg->base + 0x2C); } -void WROUTDOOR (mega_host_config * megaCfg, u_long value) +void WROUTDOOR (mega_host_config * megaCfg, u32 value) { writel (value, megaCfg->base + 0x2C); } @@ -234,7 +262,7 @@ mega_scb * scb, int intr); static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, - u_long * buffer, u_long * length); + u32 * buffer, u32 * length); static int mega_busyWaitMbox(mega_host_config *); static void mega_runpendq (mega_host_config *); @@ -242,6 +270,9 @@ static void mega_cmd_done (mega_host_config *, mega_scb *, int); static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); static inline void freeSgList(mega_host_config *megaCfg); +static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry, + mega_Enquiry3 *enquiry3, + megaRaidProductInfo *productInfo ); /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 @@ -259,9 +290,9 @@ *================================================================ */ -/* Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id - on each channel. Used for Madrona motherboard, where SAF_TE - processor id cannot be scanned */ +/* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning + XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE + processor id cannot be scanned */ static char *megaraid; #if LINUX_VERSION_CODE > 0x20100 #ifdef MODULE @@ -271,10 +302,10 @@ static int skip_id; static int numCtlrs = 0; -static mega_host_config *megaCtlrs[12] = {0}; +static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0}; #if DEBUG -static u_long maxCmdTime = 0; +static u32 maxCmdTime = 0; #endif static mega_scb *pLastScb = NULL; @@ -480,6 +511,8 @@ { int islogical; Scsi_Cmnd *SCpnt; + mega_passthru *pthru; + mega_mailbox *mbox; if (pScb == NULL) { TRACE(("NULL pScb in mega_cmd_done!")); @@ -487,7 +520,9 @@ } SCpnt = pScb->SCpnt; - freeSCB(megaCfg, pScb); + /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/ + pthru = &pScb->pthru; + mbox = (mega_mailbox *) &pScb->mboxData; if (SCpnt == NULL) { TRACE(("NULL SCpnt in mega_cmd_done!")); @@ -498,30 +533,58 @@ while(1); } - islogical = (SCpnt->channel == megaCfg->host->max_channel && - SCpnt->target == 0); + islogical = (SCpnt->channel == megaCfg->host->max_channel); + if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) { status = 0xF0; } - - SCpnt->result = 0; /* clear result; otherwise, success returns corrupt - value */ +/* clear result; otherwise, success returns corrupt value */ + SCpnt->result = 0; + +if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/ + switch (status) { + case 0xF0: + case 0xF4: + SCpnt->result=(DID_BAD_TARGET<<16)|status; + break; + default: + SCpnt->result|=status; + }/*end of switch*/ +} +else{ /* Convert MegaRAID status to Linux error code */ switch (status) { - case 0x00: /* SUCCESS */ - case 0x02: /* ERROR_ABORTED */ + case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/ SCpnt->result |= (DID_OK << 16); break; - case 0x8: /* ERR_DEST_DRIVE_FAILED */ - SCpnt->result |= (DID_BUS_BUSY << 16); + case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */ + /*set sense_buffer and result fields*/ + if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){ + memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14); + SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status; + } + else{ + SCpnt->sense_buffer[0]=0x70; + SCpnt->sense_buffer[2]=ABORTED_COMMAND; + SCpnt->result |= (CHECK_CONDITION << 1); + } break; - default: - SCpnt->result |= (DID_BAD_TARGET << 16); + case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */ + SCpnt->result |= (DID_BUS_BUSY << 16)|status; + break; + default: + SCpnt->result |= (DID_BAD_TARGET << 16)|status; break; } + } + if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW ) + /* not IOCTL_CMD_NEW SCB, freeSCB()*/ + /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue() + * after copy data back to user space*/ + freeSCB(megaCfg, pScb); /* Add Scsi_Command to end of completed queue */ ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); @@ -543,18 +606,14 @@ mega_passthru *pthru; long seg; char islogical; + char lun = SCpnt->lun; - if (SCpnt == NULL) { - printk("NULL SCpnt in mega_build_cmd!\n"); - while(1); - } - - if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */ + if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) ) /* ioctl */ return mega_ioctl (megaCfg, SCpnt); + + islogical = (SCpnt->channel == megaCfg->host->max_channel); - islogical = (SCpnt->channel == megaCfg->host->max_channel && SCpnt->target == 0); - - if (!islogical && SCpnt->lun != 0) { + if (!islogical && lun != 0) { SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; @@ -566,6 +625,16 @@ return NULL; } + if ( islogical ) { + lun = (SCpnt->target * 8) + lun; +#if 1 + if ( lun > FC_MAX_LOGICAL_DRIVES ){ + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } +#endif + } /*----------------------------------------------------- * * Logical drive commands @@ -602,7 +671,7 @@ pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 1; - pthru->logdrv = SCpnt->lun; + pthru->logdrv = lun; pthru->cdblen = SCpnt->cmd_len; pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer); pthru->dataxferlen = SCpnt->request_bufflen; @@ -627,37 +696,37 @@ mbox = (mega_mailbox *) & pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); - mbox->logdrv = SCpnt->lun; + mbox->logdrv = lun; mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; /* 6-byte */ if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { mbox->numsectors = - (u_long) SCpnt->cmnd[4]; + (u32) SCpnt->cmnd[4]; mbox->lba = - ((u_long) SCpnt->cmnd[1] << 16) | - ((u_long) SCpnt->cmnd[2] << 8) | - (u_long) SCpnt->cmnd[3]; + ((u32) SCpnt->cmnd[1] << 16) | + ((u32) SCpnt->cmnd[2] << 8) | + (u32) SCpnt->cmnd[3]; mbox->lba &= 0x1FFFFF; } /* 10-byte */ if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { mbox->numsectors = - (u_long) SCpnt->cmnd[8] | - ((u_long) SCpnt->cmnd[7] << 8); + (u32) SCpnt->cmnd[8] | + ((u32) SCpnt->cmnd[7] << 8); mbox->lba = - ((u_long) SCpnt->cmnd[2] << 24) | - ((u_long) SCpnt->cmnd[3] << 16) | - ((u_long) SCpnt->cmnd[4] << 8) | - (u_long) SCpnt->cmnd[5]; + ((u32) SCpnt->cmnd[2] << 24) | + ((u32) SCpnt->cmnd[3] << 16) | + ((u32) SCpnt->cmnd[4] << 8) | + (u32) SCpnt->cmnd[5]; } /* Calculate Scatter-Gather info */ mbox->numsgelements = build_sglist (megaCfg, pScb, - (u_long *) & mbox->xferaddr, - (u_long *) & seg); + (u32 *) & mbox->xferaddr, + (u32 *) & seg); return pScb; @@ -684,18 +753,20 @@ memset (mbox, 0, sizeof (pScb->mboxData)); memset (pthru, 0, sizeof (mega_passthru)); - pthru->timeout = 0; + pthru->timeout = 2; /*set adapter timeout value to 10 min. for tape drive*/ + /* 0=6sec/1=60sec/2=10min/3=3hrs */ pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 0; - pthru->channel = SCpnt->channel; - pthru->target = SCpnt->target; + pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel; + pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/ + (SCpnt->channel<<4)|SCpnt->target : SCpnt->target; pthru->cdblen = SCpnt->cmd_len; memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); pthru->numsgelements = build_sglist (megaCfg, pScb, - (u_long *) & pthru->dataxferaddr, - (u_long *) & pthru->dataxferlen); + (u32 *) & pthru->dataxferaddr, + (u32 *) & pthru->dataxferlen); /* Initialize mailbox */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU; @@ -715,6 +786,7 @@ mega_ioctl_mbox *mbox; mega_mailbox *mailbox; mega_passthru *pthru; + u8 *mboxdata; long seg; unsigned char *data = (unsigned char *)SCpnt->request_buffer; int i; @@ -733,13 +805,13 @@ printk("......\n"); #endif + mboxdata = (u8 *) & pScb->mboxData; mbox = (mega_ioctl_mbox *) & pScb->mboxData; mailbox = (mega_mailbox *) & pScb->mboxData; memset (mailbox, 0, sizeof (pScb->mboxData)); if (data[0] == 0x03) { /* passthrough command */ unsigned char cdblen = data[2]; - pthru = &pScb->pthru; memset (pthru, 0, sizeof (mega_passthru)); pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0; @@ -755,10 +827,9 @@ mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; mailbox->xferaddr = virt_to_bus (pthru); - pthru->numsgelements = build_sglist (megaCfg, pScb, - (u_long *) & pthru->dataxferaddr, - (u_long *) & pthru->dataxferlen); + (u32 *) & pthru->dataxferaddr, + (u32 *) & pthru->dataxferlen); for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { data[i] = data[i+cdblen+7]; @@ -768,18 +839,60 @@ } /* else normal (nonpassthru) command */ + if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { + /* use external data area for large xfers */ + /* If cmnd[0] is set to IOCTL_CMD_NEW then * + * cmnd[4..7] = external user buffer * + * cmnd[8..11] = length of buffer * + * */ + char *kern_area; + char *user_area = *((char **)&SCpnt->cmnd[4]); + u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]); + if (verify_area(VERIFY_READ, user_area, xfer_size)) { + printk("megaraid: Got bad user address.\n"); + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA); + if (kern_area == NULL) { + printk("megaraid: Couldn't allocate kernel mem.\n"); + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + copy_from_user(kern_area,user_area,xfer_size); + pScb->kern_area = kern_area; + } + mbox->cmd = data[0]; mbox->channel = data[1]; mbox->param = data[2]; mbox->pad[0] = data[3]; mbox->logdrv = data[4]; - mbox->numsgelements = build_sglist (megaCfg, pScb, - (u_long *) & mbox->xferaddr, - (u_long *) & seg); + if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) { + if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */ + *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/ + *(mboxdata+2) = data[2]; /*sub command*/ + *(mboxdata+3) = 0; /*number of elements in SG list*/ + mbox->xferaddr /*i.e. mboxdata byte 0x8 to 0xb*/ + = virt_to_bus(pScb->kern_area); + } + else{ + mbox->xferaddr = virt_to_bus(pScb->kern_area); + mbox->numsgelements = 0; + } + } + else { - for (i=0;i<(SCpnt->request_bufflen-6);i++) { - data[i] = data[i+6]; + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u32 *) & mbox->xferaddr, + (u32 *) & seg); + + for (i=0;i<(SCpnt->request_bufflen-6);i++) { + data[i] = data[i+6]; + } } return (pScb); @@ -808,7 +921,7 @@ { mega_host_config *megaCfg; u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; - u_long dword; + u32 dword; mega_mailbox *mbox; mega_scb *pScb; long flags; @@ -892,8 +1005,13 @@ printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount)); } + if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) + { /* external user buffer */ + up(&pScb->sem); + } /* Mark command as completed */ mega_cmd_done(megaCfg, pScb, qStatus); + } } @@ -907,6 +1025,7 @@ spin_lock_irqsave(&mega_lock, flags); mega_runpendq(megaCfg); spin_unlock_irqrestore(&mega_lock,flags); + } #if LINUX_VERSION_CODE >= 0x20100 @@ -940,6 +1059,11 @@ * u_char *mboxData - Mailbox area, 16 bytes * mega_scb *pScb - SCB posting (or NULL if N/A) * int intr - if 1, interrupt, 0 is blocking + * Return Value: (added on 7/26 for 40ld/64bit) + * -1: the command was not actually issued out + * othercases: + * intr==0, return ScsiStatus, i.e. mbox->status + * intr==1, return 0 *===================================================== */ static int megaIssueCmd (mega_host_config * megaCfg, @@ -949,21 +1073,29 @@ { mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; u_char byte; - u_long cmdDone; + u32 cmdDone; Scsi_Cmnd *SCpnt; - + u32 phys_mbox; + u8 retval=-1; + mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ mboxData[0xF] = 1; /* Set busy */ + phys_mbox = virt_to_bus (megaCfg->mbox); + #if 0 if (intr && mbox->busy) { return 0; } #endif +#if DEBUG + showMbox(pScb); +#endif + /* Wait until mailbox is free */ while (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox!!\n"); + printk("Blocked mailbox......!!\n"); udelay(1000); #if DEBUG @@ -980,12 +1112,13 @@ SCpnt->result = (DID_ABORT << 16); callDone(SCpnt); - return 0; + return -1; } + pLastScb = pScb; - /* Copy mailbox data into host structure */ + megaCfg->mbox64->xferSegment = 0; memcpy (mbox, mboxData, 16); /* Kick IO */ @@ -993,22 +1126,24 @@ /* Issue interrupt (non-blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; + mbox->mraid_poll = 0; mbox->mraid_ack = 0; - WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); + WRINDOOR (megaCfg, phys_mbox | 0x1); } else { ENABLE_INTR (megaCfg->host->io_port); ISSUE_COMMAND (megaCfg->host->io_port); } pScb->state = SCB_ISSUED; + + retval=0; } else { /* Issue non-ISR (blocking) command */ disable_irq(megaCfg->host->irq); if (megaCfg->flag & BOARD_QUARTZ) { mbox->mraid_poll = 0; mbox->mraid_ack = 0; - WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); + WRINDOOR (megaCfg, phys_mbox | 0x1); while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); WROUTDOOR (megaCfg, cmdDone); @@ -1018,7 +1153,7 @@ mega_rundoneq (); } - WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + WRINDOOR (megaCfg, phys_mbox | 0x2); while (RDINDOOR (megaCfg) & 0x2); } @@ -1043,20 +1178,21 @@ } enable_irq(megaCfg->host->irq); + retval=mbox->status; } while (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox on exit!\n"); + printk("Blocked mailbox on exit......!\n"); udelay(1000); } - return 0; + return retval; } /*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*/ static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, - u_long * buffer, u_long * length) + u32 * buffer, u32 * length) { struct scatterlist *sgList; int idx; @@ -1064,21 +1200,21 @@ /* Scatter-gather not used */ if (scb->SCpnt->use_sg == 0) { *buffer = virt_to_bus (scb->SCpnt->request_buffer); - *length = (u_long) scb->SCpnt->request_bufflen; + *length = (u32) scb->SCpnt->request_bufflen; return 0; } sgList = (struct scatterlist *) scb->SCpnt->request_buffer; if (scb->SCpnt->use_sg == 1) { *buffer = virt_to_bus (sgList[0].address); - *length = (u_long) sgList[0].length; + *length = (u32) sgList[0].length; return 0; } /* Copy Scatter-Gather list info into controller structure */ for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { scb->sgList[idx].address = virt_to_bus (sgList[idx].address); - scb->sgList[idx].length = (u_long) sgList[idx].length; + scb->sgList[idx].length = (u32) sgList[idx].length; } /* Reset pointer and length fields */ @@ -1105,12 +1241,13 @@ * 10 01 numstatus byte * 11 01 status byte *--------------------------------------------------------------------*/ -static int mega_register_mailbox (mega_host_config * megaCfg, u_long paddr) +static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr) { /* align on 16-byte boundry */ - megaCfg->mbox = &megaCfg->mailbox; - megaCfg->mbox = (mega_mailbox *) ((((ulong) megaCfg->mbox) + 16) & 0xfffffff0); - paddr = (paddr + 16) & 0xfffffff0; + megaCfg->mbox = &megaCfg->mailbox64.mailbox; + megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0); + megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4); + paddr = (paddr + 4 + 16) & 0xfffffff0; /* Register mailbox area with the firmware */ if (megaCfg->flag & BOARD_QUARTZ) { @@ -1128,84 +1265,162 @@ return 0; } + +/*--------------------------------------------------------------------------- + * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and + * puts it into ProductInfo and Enquiry3 structures for later use + *---------------------------------------------------------------------------*/ +static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry, + mega_Enquiry3 *enquiry3, + megaRaidProductInfo *productInfo ) +{ + int i; + + productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds; + enquiry3->rbldRate = inquiry->AdpInfo.RbldRate; + productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent; + for (i=0;i<4;i++) { + productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i]; + productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i]; + } + enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval; + productInfo->DramSize = inquiry->AdpInfo.DramSize; + + enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv; + for (i=0;ilDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i]; + enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i]; + enquiry3->lDrvState[i] = inquiry->LogdrvInfo.LDrvState[i]; + } + + for (i=0;i<(MAX_PHYSICAL_DRIVES);i++) { + enquiry3->pDrvState[i] = inquiry->PhysdrvInfo.PDrvState[i]; + } +} + + /*------------------------------------------------------------------- * Issue an adapter info query to the controller *-------------------------------------------------------------------*/ static int mega_i_query_adapter (mega_host_config * megaCfg) { - mega_RAIDINQ *adapterInfo; + mega_Enquiry3 *enquiry3Pnt; mega_mailbox *mbox; u_char mboxData[16]; - u_long paddr; + u32 paddr; + u8 retval; spin_lock_init (&mega_lock); - /* Initialize adapter inquiry */ + /* Initialize adapter inquiry mailbox*/ paddr = virt_to_bus (megaCfg->mega_buffer); mbox = (mega_mailbox *) mboxData; memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); memset (mbox, 0, 16); - /* Initialize mailbox registers */ - mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; - mbox->xferaddr = paddr; +/* + * Try to issue Enquiry3 command + * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and + * update enquiry3 structure + */ + mbox->xferaddr = virt_to_bus ( (void*) megaCfg->mega_buffer); + /* Initialize mailbox databuffer addr */ + enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; + /* point mega_Enguiry3 to the data buf */ + + mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */ + mboxData[2]=NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */ + mboxData[3]=ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ /* Issue a blocking command to the card */ - megaIssueCmd (megaCfg, mboxData, NULL, 0); + if ( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 ) + { /* the adapter does not support 40ld*/ - /* Initialize host/local structures with Adapter info */ - adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; - megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent; -/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */ - megaCfg->host->max_id = 16; /* max targets/chan */ - megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; + mega_RAIDINQ adapterInquiryData; + mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData; -#if 0 - printk ("KERN_DEBUG ---- Logical drive info ----\n"); + mbox->xferaddr = virt_to_bus ( (void*) adapterInquiryPnt); + + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter*/ + /* Issue a blocking command to the card */; + retval=megaIssueCmd (megaCfg, mboxData, NULL, 0); + + /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/ + mega_Convert8ldTo40ld( adapterInquiryPnt, + enquiry3Pnt, + (megaRaidProductInfo * ) &megaCfg->productInfo ); + + } + else{ /* adapter supports 40ld */ + megaCfg->flag |= BOARD_40LD; + + /*get productInfo, which is static information and will be unchanged*/ + mbox->xferaddr = virt_to_bus ( (void*) &megaCfg->productInfo ); + + mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */ + mboxData[2]=NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ + + if( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 ) + printk("ami:Product_info (0x0E) cmd failed with error: %d\n", retval); + + } + + megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent; + megaCfg->host->max_id = 16; /* max targets per channel */ + /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/ + megaCfg->host->max_lun = /* max lun */ + (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; + + megaCfg->numldrv = enquiry3Pnt->numLDrv; + megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds; + +#if 0 + int i; + printk (KERN_DEBUG "---- Logical drive info from enquiry3 struct----\n"); for (i = 0; i < megaCfg->numldrv; i++) { - printk ("%d: size: %ld prop: %x state: %x\n", i, - adapterInfo->LogdrvInfo.LDrvSize[i], - adapterInfo->LogdrvInfo.LDrvProp[i], - adapterInfo->LogdrvInfo.LDrvState[i]); + printk ("%d: size: %d prop: %x state: %x\n", i, + enquiry3Pnt->lDrvSize[i], + enquiry3Pnt->lDrvProp[i], + enquiry3Pnt->lDrvState[i]); } + printk (KERN_DEBUG "---- Physical drive info ----\n"); - for (i = 0; i < MAX_PHYSICAL_DRIVES; i++) { + for (i = 0; i < FC_MAX_PHYSICAL_DEVICES; i++) { if (i && !(i % 8)) printk ("\n"); - printk ("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]); + printk ("%d: %x ", i, enquiry3Pnt->pDrvState[i]); } printk ("\n"); #endif - megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds; - #ifdef HP /* use HP firmware and bios version encoding */ sprintf (megaCfg->fwVer, "%c%d%d.%d%d", - adapterInfo->AdpInfo.FwVer[2], - adapterInfo->AdpInfo.FwVer[1] >> 8, - adapterInfo->AdpInfo.FwVer[1] & 0x0f, - adapterInfo->AdpInfo.FwVer[2] >> 8, - adapterInfo->AdpInfo.FwVer[2] & 0x0f); + megaCfg->productInfo.FwVer[2], + megaCfg->productInfo.FwVer[1] >> 8, + megaCfg->productInfo.FwVer[1] & 0x0f, + megaCfg->productInfo.FwVer[2] >> 8, + megaCfg->productInfo.FwVer[2] & 0x0f); sprintf (megaCfg->biosVer, "%c%d%d.%d%d", - adapterInfo->AdpInfo.BiosVer[2], - adapterInfo->AdpInfo.BiosVer[1] >> 8, - adapterInfo->AdpInfo.BiosVer[1] & 0x0f, - adapterInfo->AdpInfo.BiosVer[2] >> 8, - adapterInfo->AdpInfo.BiosVer[2] & 0x0f); + megaCfg->productInfo.BiosVer[2], + megaCfg->productInfo.BiosVer[1] >> 8, + megaCfg->productInfo.BiosVer[1] & 0x0f, + megaCfg->productInfo.BiosVer[2] >> 8, + megaCfg->productInfo.BiosVer[2] & 0x0f); #else - memcpy (megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); - megaCfg->fwVer[4] = 0; + memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4); + megaCfg->fwVer[4] = 0; - memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); - megaCfg->biosVer[4] = 0; + memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4); + megaCfg->biosVer[4] = 0; #endif - printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, - megaCfg->fwVer, - megaCfg->biosVer, - megaCfg->numldrv); - return 0; + printk ("megaraid: [%s:%s] detected %d logical drives" CRLFSTR, + megaCfg->fwVer, + megaCfg->biosVer, + megaCfg->numldrv); + + return 0; } /*------------------------------------------------------------------------- @@ -1225,15 +1440,15 @@ } int findCard (Scsi_Host_Template * pHostTmpl, - u_short pciVendor, u_short pciDev, + u16 pciVendor, u16 pciDev, long flag) { mega_host_config *megaCfg; struct Scsi_Host *host; u_char pciBus, pciDevFun, megaIrq; - u_long megaBase; - u_short jdx,pciIdx = 0; - u_short numFound = 0; + u32 megaBase; + u16 pciIdx = 0; + u16 numFound = 0; #if LINUX_VERSION_CODE < 0x20100 while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { @@ -1249,8 +1464,8 @@ pciBus = pdev->bus->number; pciDevFun = pdev->devfn; #endif - if (flag & BOARD_QUARTZ) { - u_short magic; + if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { + u16 magic; pcibios_read_config_word (pciBus, pciDevFun, PCI_CONF_AMISIG, &magic); @@ -1259,7 +1474,7 @@ continue; /* not an AMI board */ } } - printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", + printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n", pciVendor, pciDev, pciIdx, pciBus, @@ -1272,6 +1487,7 @@ pciIdx++; if (flag & BOARD_QUARTZ) { + megaBase &= PCI_BASE_ADDRESS_MEM_MASK; megaBase = (long) ioremap (megaBase, 128); } @@ -1285,7 +1501,7 @@ megaCfg = (mega_host_config *) host->hostdata; memset (megaCfg, 0, sizeof (mega_host_config)); - printk (" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, + printk ("scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, host->host_no, (u_int) megaBase, megaIrq); /* Copy resource info into structure */ @@ -1298,8 +1514,7 @@ megaCfg->host->io_port = megaBase; megaCfg->host->n_io_port = 16; megaCfg->host->unique_id = (pciBus << 8) | pciDevFun; - megaCtlrs[numCtlrs++] = megaCfg; - + megaCtlrs[numCtlrs++] = megaCfg; if (flag != BOARD_QUARTZ) { /* Request our IO Range */ if (check_region (megaBase, 16)) { @@ -1319,14 +1534,9 @@ continue; } - mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox)); + mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64)); mega_i_query_adapter (megaCfg); - for(jdx=0; jdxnReads[jdx] = 0; - megaCfg->nWrites[jdx] = 0; - } - /* Initialize SCBs */ if (initSCB (megaCfg)) { scsi_unregister (host); @@ -1364,6 +1574,8 @@ skip_id = (skip_id > 15) ? -1 : skip_id; } + printk ("megaraid: " MEGARAID_VERSION CRLFSTR); + count += findCard (pHostTmpl, 0x101E, 0x9010, 0); count += findCard (pHostTmpl, 0x101E, 0x9060, 0); count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); @@ -1424,16 +1636,15 @@ { static char buffer[512]; mega_host_config *megaCfg; - mega_RAIDINQ *adapterInfo; megaCfg = (mega_host_config *) pSHost->hostdata; - adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; - sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans", + sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans %d luns", megaCfg->fwVer, - adapterInfo->AdpInfo.MaxConcCmds, + megaCfg->productInfo.MaxConcCmds, megaCfg->host->max_id, - megaCfg->host->max_channel); + megaCfg->host->max_channel, + megaCfg->host->max_lun); return buffer; } @@ -1463,9 +1674,13 @@ megaCfg = (mega_host_config *) SCpnt->host->hostdata; if (!(megaCfg->flag & (1L << SCpnt->channel))) { - printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n", + if (SCpnt->channel < SCpnt->host->max_channel) + printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n", megaCfg->host->host_no, - SCpnt->channel + 'A'); + SCpnt->channel + '1'); + else + printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no); + megaCfg->flag |= (1L << SCpnt->channel); } @@ -1489,6 +1704,7 @@ /* Allocate and build a SCB request */ if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { + /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/ /* Add SCB to the head of the pending queue */ ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next); @@ -1499,6 +1715,25 @@ else { printk("IRQ pend...\n"); } + + if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW ) + { /* user data from external user buffer */ + char *user_area; + u32 xfer_size; + + init_MUTEX_LOCKED(&pScb->sem); + down(&pScb->sem); + + user_area = *((char **)&pScb->SCpnt->cmnd[4]); + xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]); + + copy_to_user(user_area,pScb->kern_area,xfer_size); + + kfree(pScb->kern_area); + + freeSCB(megaCfg, pScb); + } + } spin_unlock_irqrestore(&mega_lock,flags); @@ -1699,3 +1934,4 @@ #include "scsi_module.c" #endif + diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h --- v2.3.14/linux/drivers/scsi/megaraid.h Wed Aug 18 16:44:24 1999 +++ linux/drivers/scsi/megaraid.h Mon Aug 23 14:49:42 1999 @@ -9,6 +9,7 @@ #define IN_ABORT 0x40000000L #define IN_RESET 0x20000000L #define BOARD_QUARTZ 0x08000000L +#define BOARD_40LD 0x04000000L #define SCB_FREE 0x0 #define SCB_ACTIVE 0x1 @@ -147,32 +148,333 @@ } #endif + +/*********************************************************************** + * Structure Declarations for the Firmware supporting 40 Logical Drives + * and 256 Physical Drives. + ***********************************************************************/ + +#define FC_MAX_LOGICAL_DRIVES 40 +#define FC_MAX_LOG_DEVICES FC_MAX_LOGICAL_DRIVES +#define FC_MAX_SPAN_DEPTH 8 +#define FC_MAX_ROW_SIZE 32 + +#define FC_MAX_CHANNELS 16 +#define FC_MAX_TARGETS_PER_CHANNEL 16 +#define FC_MAX_PHYSICAL_DEVICES 256 + +#define FC_NEW_CONFIG 0xA1 +#define DCMD_FC_CMD 0xA1 + #define NC_SUBOP_PRODUCT_INFO 0x0E + #define NC_SUBOP_ENQUIRY3 0x0F + #define ENQ3_GET_SOLICITED_NOTIFY_ONLY 0x01 + #define ENQ3_GET_SOLICITED_FULL 0x02 + #define ENQ3_GET_UNSOLICITED 0x03 + + +/******************************************** + * PRODUCT_INFO Strucure + ********************************************/ + +#define SIG_40LOG_32STR_8SPN 0x00282008 + +/* + * Utilities declare this strcture size as 1024 bytes. So more fields can + * be added in future. + */ + +struct MRaidProductInfo +{ + u32 DataSize; /* current size in bytes (not including resvd) */ + u32 ConfigSignature; + /* Current value is 0x00282008 + * 0x28=MAX_LOGICAL_DRIVES, + * 0x20=Number of stripes and + * 0x08=Number of spans */ + u8 FwVer[16]; /* printable ASCI string */ + u8 BiosVer[16]; /* printable ASCI string */ + u8 ProductName[80]; /* printable ASCI string */ + + u8 MaxConcCmds; /* Max. concurrent commands supported */ + u8 SCSIChanPresent; /* Number of SCSI Channels detected */ + u8 FCLoopPresent; /* Number of Fibre Loops detected */ + u8 memType; /* EDO, FPM, SDRAM etc */ + + u32 signature; + u16 DramSize; /* In terms of MB */ + u16 subSystemID; + + u16 subSystemVendorID; + u8 numNotifyCounters; + u8 pad1k[889]; /* 135 + 889 resvd = 1024 total size */ +}__attribute__((packed)); +typedef struct MRaidProductInfo megaRaidProductInfo; + +/******************************************** + * Standard ENQUIRY Strucure + ********************************************/ +struct FC_ADP_INFO +{ + u8 MaxConcCmds; /* Max. concurrent commands supported. */ + u8 RbldRate; /* Rebuild Rate. Varies from 0%-100% */ + u8 MaxTargPerChan; /* Max. Targets supported per chan. */ + u8 ChanPresent; /* No. of Chans present on this adapter. */ + u8 FwVer[4]; /* Firmware version. */ + u16 AgeOfFlash; /* No. of times FW has been downloaded. */ + u8 ChipSetValue; /* Contents of 0xC0000832 */ + u8 DramSize; /* In terms of MB */ + u8 CacheFlushInterval; /* In terms of Seconds */ + u8 BiosVersion[4]; + u8 BoardType; + u8 sense_alert; + u8 write_config_count; /* Increase with evry configuration change */ + u8 drive_inserted_count; /* Increase with every drive inserted */ + u8 inserted_drive; /* Channel: Id of inserted drive */ + u8 battery_status; + /* + BIT 0 : battery module missing + BIT 1 : VBAD + BIT 2 : temp high + BIT 3 : battery pack missing + BIT 4,5 : 00 - charge complete + 01 - fast charge in prog + 10 - fast charge fail + 11 - undefined + BIt 6 : counter > 1000 + Bit 7 : undefined + */ + u8 dec_fault_bus_info; /* was resvd */ +}__attribute__((packed)); + +struct FC_LDRV_INFO +{ + u8 NumLDrv; /* No. of Log. Drvs configured. */ + u8 recon_state[FC_MAX_LOGICAL_DRIVES/8]; + /* bit field for State of reconstruct */ + u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8]; + /* bit field Status of Long Operations. */ + + u32 LDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv. */ + u8 LDrvProp[FC_MAX_LOGICAL_DRIVES]; + u8 LDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives. */ +}__attribute__((packed)); + +#define PREVSTAT_MASK 0xf0 +#define CURRSTAT_MASK 0x0f + +struct FC_PDRV_INFO +{ + u8 PDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys Drvs. */ +}__attribute__((packed)); + + +struct FC_AdapterInq +{ + struct FC_ADP_INFO AdpInfo; + struct FC_LDRV_INFO LogdrvInfo; + struct FC_PDRV_INFO PhysdrvInfo; +}__attribute__((packed)); + + +typedef struct FC_AdapterInq mega_RAIDINQ_FC; + +/******************************************** + * NOTIFICATION Strucure + ********************************************/ + +#define MAX_NOTIFY_SIZE 0x80 +#define CUR_NOTIFY_SIZE sizeof(struct MegaRAID_Notify) + +/* + * Utilities declare this strcture size as ?? bytes. So more fields can + * be added in future. + */ +struct MegaRAID_Notify +{ + u32 globalCounter; /* Any change increments this counter */ + + u8 paramCounter; /* Indicates any params changed */ + u8 paramId; /* Param modified - defined below */ + u16 paramVal; /* New val of last param modified */ + + u8 writeConfigCounter; /* write config occurred */ + u8 writeConfigRsvd[3]; + + u8 ldrvOpCounter; /* Indicates ldrv op started/completed */ + u8 ldrvOpId; /* ldrv num */ + u8 ldrvOpCmd; /* ldrv operation - defined below */ + u8 ldrvOpStatus; /* status of the operation */ + + u8 ldrvStateCounter; /* Indicates change of ldrv state */ + u8 ldrvStateId; /* ldrv num */ + u8 ldrvStateNew; /* New state */ + u8 ldrvStateOld; /* old state */ + + u8 pdrvStateCounter; /* Indicates change of ldrv state */ + u8 pdrvStateId; /* pdrv id */ + u8 pdrvStateNew; /* New state */ + u8 pdrvStateOld; /* old state */ + + u8 pdrvFmtCounter; /* Indicates pdrv format started/over */ + u8 pdrvFmtId; /* pdrv id */ + u8 pdrvFmtVal; /* format started/over */ + u8 pdrvFmtRsvd; + + u8 targXferCounter; /* Indicates SCSI-2 Xfer rate change */ + u8 targXferId; /* pdrv Id */ + u8 targXferVal; /* new Xfer params of last pdrv */ + u8 targXferRsvd; + + u8 fcLoopIdChgCounter; /* Indicates loopid changed */ + u8 fcLoopIdPdrvId; /* pdrv id */ + u8 fcLoopId0; /* loopid on fc loop 0 */ + u8 fcLoopId1; /* loopid on fc loop 1 */ + + u8 fcLoopStateCounter; /* Indicates loop state changed */ + u8 fcLoopState0; /* state of fc loop 0 */ + u8 fcLoopState1; /* state of fc loop 1 */ + u8 fcLoopStateRsvd; +}__attribute__((packed)); + + +/******************************************** + * PARAM IDs in Notify struct + ********************************************/ +#define PARAM_RBLD_RATE 0x01 + /*-------------------------------------- + * Param val = + * byte 0: new rbld rate + *--------------------------------------*/ +#define PARAM_CACHE_FLUSH_INTERVAL 0x02 + /*-------------------------------------- + * Param val = + * byte 0: new cache flush interval + *--------------------------------------*/ +#define PARAM_SENSE_ALERT 0x03 + /*-------------------------------------- + * Param val = + * byte 0: last pdrv id causing chkcond + *--------------------------------------*/ +#define PARAM_DRIVE_INSERTED 0x04 + /*-------------------------------------- + * Param val = + * byte 0: last pdrv id inserted + *--------------------------------------*/ +#define PARAM_BATTERY_STATUS 0x05 + /*-------------------------------------- + * Param val = + * byte 0: battery status + *--------------------------------------*/ + +/******************************************** + * Ldrv operation cmd in Notify struct + ********************************************/ +#define LDRV_CMD_CHKCONSISTANCY 0x01 +#define LDRV_CMD_INITIALIZE 0x02 +#define LDRV_CMD_RECONSTRUCTION 0x03 + +/******************************************** + * Ldrv operation status in Notify struct + ********************************************/ +#define LDRV_OP_SUCCESS 0x00 +#define LDRV_OP_FAILED 0x01 +#define LDRV_OP_ABORTED 0x02 +#define LDRV_OP_CORRECTED 0x03 +#define LDRV_OP_STARTED 0x04 + + +/******************************************** + * Raid Logical drive states. + ********************************************/ +#define RDRV_OFFLINE 0 +#define RDRV_DEGRADED 1 +#define RDRV_OPTIMAL 2 +#define RDRV_DELETED 3 + +/******************************************* + * Physical drive states. + *******************************************/ +#define PDRV_UNCNF 0 +#define PDRV_ONLINE 3 +#define PDRV_FAILED 4 +#define PDRV_RBLD 5 +/* #define PDRV_HOTSPARE 6 */ + +/******************************************* + * Formal val in Notify struct + *******************************************/ +#define PDRV_FMT_START 0x01 +#define PDRV_FMT_OVER 0x02 + +/******************************************** + * FC Loop State in Notify Struct + ********************************************/ +#define ENQ_FCLOOP_FAILED 0 +#define ENQ_FCLOOP_ACTIVE 1 +#define ENQ_FCLOOP_TRANSIENT 2 + +/******************************************** + * ENQUIRY3 Strucure + ********************************************/ +/* + * Utilities declare this strcture size as 1024 bytes. So more fields can + * be added in future. + */ +struct MegaRAID_Enquiry3 +{ + u32 dataSize; /* current size in bytes (not including resvd) */ + + struct MegaRAID_Notify notify; + + u8 notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; + + u8 rbldRate; /* Rebuild rate (0% - 100%) */ + u8 cacheFlushInterval; /* In terms of Seconds */ + u8 senseAlert; + u8 driveInsertedCount; /* drive insertion count */ + + u8 batteryStatus; + u8 numLDrv; /* No. of Log Drives configured */ + u8 reconState[FC_MAX_LOGICAL_DRIVES/8]; /* State of reconstruct */ + u16 lDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8]; /* log. Drv Status */ + + u32 lDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv */ + u8 lDrvProp[FC_MAX_LOGICAL_DRIVES]; + u8 lDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives */ + u8 pDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys. Drvs. */ + u16 physDrvFormat[FC_MAX_PHYSICAL_DEVICES/16]; + + u8 targXfer[80]; /* phys device transfer rate */ + u8 pad1k[263]; /* 761 + 263reserved = 1024 bytes total size */ +}__attribute__((packed)); +typedef struct MegaRAID_Enquiry3 mega_Enquiry3; + /* Structures */ typedef struct _mega_ADP_INFO { - u_char MaxConcCmds; - u_char RbldRate; - u_char MaxTargPerChan; - u_char ChanPresent; - u_char FwVer[4]; - u_short AgeOfFlash; - u_char ChipSet; - u_char DRAMSize; - u_char CacheFlushInterval; - u_char BiosVer[4]; - u_char resvd[7]; + u8 MaxConcCmds; + u8 RbldRate; + u8 MaxTargPerChan; + u8 ChanPresent; + u8 FwVer[4]; + u16 AgeOfFlash; + u8 ChipSetValue; + u8 DramSize; + u8 CacheFlushInterval; + u8 BiosVer[4]; + u8 resvd[7]; } mega_ADP_INFO; typedef struct _mega_LDRV_INFO { - u_char NumLDrv; - u_char resvd[3]; - u_long LDrvSize[MAX_LOGICAL_DRIVES]; - u_char LDrvProp[MAX_LOGICAL_DRIVES]; - u_char LDrvState[MAX_LOGICAL_DRIVES]; + u8 NumLDrv; + u8 resvd[3]; + u32 LDrvSize[MAX_LOGICAL_DRIVES]; + u8 LDrvProp[MAX_LOGICAL_DRIVES]; + u8 LDrvState[MAX_LOGICAL_DRIVES]; } mega_LDRV_INFO; typedef struct _mega_PDRV_INFO { - u_char PDrvState[MAX_PHYSICAL_DRIVES]; - u_char resvd; + u8 PDrvState[MAX_PHYSICAL_DRIVES]; + u8 resvd; } mega_PDRV_INFO; // RAID inquiry: Mailbox command 0x5 @@ -184,65 +486,70 @@ // Passthrough command: Mailbox command 0x3 typedef struct mega_passthru { - u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u_char ars:1; - u_char reserved:3; - u_char islogical:1; - u_char logdrv; /* if islogical == 1 */ - u_char channel; /* if islogical == 0 */ - u_char target; /* if islogical == 0 */ - u_char queuetag; /* unused */ - u_char queueaction; /* unused */ - u_char cdb[MAX_CDB_LEN]; - u_char cdblen; - u_char reqsenselen; - u_char reqsensearea[MAX_REQ_SENSE_LEN]; - u_char numsgelements; - u_char scsistatus; - u_long dataxferaddr; - u_long dataxferlen; + u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ + u8 ars:1; + u8 reserved:3; + u8 islogical:1; + u8 logdrv; /* if islogical == 1 */ + u8 channel; /* if islogical == 0 */ + u8 target; /* if islogical == 0 */ + u8 queuetag; /* unused */ + u8 queueaction; /* unused */ + u8 cdb[MAX_CDB_LEN]; + u8 cdblen; + u8 reqsenselen; + u8 reqsensearea[MAX_REQ_SENSE_LEN]; + u8 numsgelements; + u8 scsistatus; + u32 dataxferaddr; + u32 dataxferlen; } mega_passthru; typedef struct _mega_mailbox { - /* 0x0 */ u_char cmd; - /* 0x1 */ u_char cmdid; - /* 0x2 */ u_short numsectors; - /* 0x4 */ u_long lba; - /* 0x8 */ u_long xferaddr; - /* 0xC */ u_char logdrv; - /* 0xD */ u_char numsgelements; - /* 0xE */ u_char resvd; - /* 0xF */ u_char busy; - /* 0x10 */ u_char numstatus; - /* 0x11 */ u_char status; - /* 0x12 */ u_char completed[46]; - u_char mraid_poll; - u_char mraid_ack; - u_char pad[16]; + /* 0x0 */ u8 cmd; + /* 0x1 */ u8 cmdid; + /* 0x2 */ u16 numsectors; + /* 0x4 */ u32 lba; + /* 0x8 */ u32 xferaddr; + /* 0xC */ u8 logdrv; + /* 0xD */ u8 numsgelements; + /* 0xE */ u8 resvd; + /* 0xF */ u8 busy; + /* 0x10 */ u8 numstatus; + /* 0x11 */ u8 status; + /* 0x12 */ u8 completed[46]; + u8 mraid_poll; + u8 mraid_ack; + u8 pad[16]; } mega_mailbox; +typedef struct { + u32 xferSegment; /* for 64-bit controllers */ + mega_mailbox mailbox; +} mega_mailbox64; + typedef struct _mega_ioctl_mbox { - /* 0x0 */ u_char cmd; - /* 0x1 */ u_char cmdid; - /* 0x2 */ u_char channel; - /* 0x3 */ u_char param; - /* 0x4 */ u_char pad[4]; - /* 0x8 */ u_long xferaddr; - /* 0xC */ u_char logdrv; - /* 0xD */ u_char numsgelements; - /* 0xE */ u_char resvd; - /* 0xF */ u_char busy; - /* 0x10 */ u_char numstatus; - /* 0x11 */ u_char status; - /* 0x12 */ u_char completed[46]; - u_char mraid_poll; - u_char mraid_ack; - u_char malign[16]; + /* 0x0 */ u8 cmd; + /* 0x1 */ u8 cmdid; + /* 0x2 */ u8 channel; + /* 0x3 */ u8 param; + /* 0x4 */ u8 pad[4]; + /* 0x8 */ u32 xferaddr; + /* 0xC */ u8 logdrv; + /* 0xD */ u8 numsgelements; + /* 0xE */ u8 resvd; + /* 0xF */ u8 busy; + /* 0x10 */ u8 numstatus; + /* 0x11 */ u8 status; + /* 0x12 */ u8 completed[46]; + u8 mraid_poll; + u8 mraid_ack; + u8 malign[16]; } mega_ioctl_mbox; typedef struct _mega_sglist { - u_long address; - u_long length; + u32 address; + u32 length; } mega_sglist; /* Queued command data */ @@ -250,39 +557,51 @@ struct _mega_scb { int idx; - u_long state; - u_long isrcount; - u_char mboxData[16]; + u32 state; + u32 isrcount; + u8 mboxData[16]; mega_passthru pthru; Scsi_Cmnd *SCpnt; mega_sglist *sgList; + char *kern_area; /* Only used for large ioctl xfers */ + struct wait_queue *ioctl_wait; + struct semaphore sem; mega_scb *next; }; /* Per-controller data */ typedef struct _mega_host_config { - u_char numldrv; - u_long flag; - u_long base; + u8 numldrv; + u32 flag; + u32 base; mega_scb *qFree; mega_scb *qPending; - u_long nReads[MAX_LOGICAL_DRIVES]; - u_long nWrites[MAX_LOGICAL_DRIVES]; + u32 nReads[FC_MAX_LOGICAL_DRIVES]; + u32 nWrites[FC_MAX_LOGICAL_DRIVES]; /* Host adapter parameters */ - u_char fwVer[7]; - u_char biosVer[7]; + u8 fwVer[7]; + u8 biosVer[7]; struct Scsi_Host *host; - /* The following must be DMA-able!! */ - volatile mega_mailbox *mbox; - volatile mega_mailbox mailbox; - volatile u_char mega_buffer[2 * 1024L]; + volatile mega_mailbox64 *mbox64; /* ptr to beginning of 64-bit mailbox */ + volatile mega_mailbox *mbox; /* ptr to beginning of standard mailbox */ + volatile mega_mailbox64 mailbox64; +#if 0 + volatile union { + u8 generic_buffer[2 * 1024L]; + mega_RAIDINQ adapterInfoData; + mega_Enquiry3 enquiry3Data; + }mega_buffer; +#else + volatile u8 mega_buffer[2*1024L]; +#endif + volatile megaRaidProductInfo productInfo; - u_char max_cmds; + u8 max_cmds; mega_scb scbList[MAX_COMMANDS]; } mega_host_config; diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.3.14/linux/drivers/scsi/qlogicfc.c Thu Aug 5 15:11:52 1999 +++ linux/drivers/scsi/qlogicfc.c Mon Aug 23 10:14:44 1999 @@ -1,5 +1,5 @@ /* - * QLogic ISP2100 SCSI-FCP + * QLogic ISP2x00 SCSI-FCP * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe * @@ -17,7 +17,7 @@ /* Renamed and updated to 1.3.x by Michael Griffith */ /* This is a version of the isp1020 driver which was modified by - * Chris Loveland to support the isp2100 + * Chris Loveland to support the isp2100 and isp2200 */ /* @@ -63,28 +63,30 @@ /* Configuration section **************************************************** */ -/* Set the following macro to 1 to reload the ISP2100's firmware. This is - version 1.15.19 of the firmware. */ +/* Set the following macro to 1 to reload the ISP2x00's firmware. This is + version 1.15.37 of the isp2100's firmware and version 2.00.16 of the + isp2200's firmware. +*/ #define RELOAD_FIRMWARE 1 #define USE_NVRAM_DEFAULTS 1 -#define ISP2100_PORTDB 1 +#define ISP2x00_PORTDB 1 /* Set the following to 1 to include fabric support, fabric support is * currently not as well tested as the other aspects of the driver */ -#define ISP2100_FABRIC 0 +#define ISP2x00_FABRIC 0 /* Macros used for debugging */ /* -#define DEBUG_ISP2100 1 -#define DEBUG_ISP2100_INT 1 -#define DEBUG_ISP2100_INTR 1 -#define DEBUG_ISP2100_SETUP 1 +#define DEBUG_ISP2x00 1 +#define DEBUG_ISP2x00_INT 1 +#define DEBUG_ISP2x00_INTR 1 +#define DEBUG_ISP2x00_SETUP 1 -#define DEBUG_ISP2100_FABRIC 1 +#define DEBUG_ISP2x00_FABRIC 1 */ /* #define TRACE_ISP 1 */ @@ -127,32 +129,32 @@ #define TRACE(w, i, a) #endif -#if DEBUG_ISP2100_FABRIC +#if DEBUG_ISP2x00_FABRIC #define DEBUG_FABRIC(x) x #else #define DEBUG_FABRIC(x) -#endif /* DEBUG_ISP2100_FABRIC */ +#endif /* DEBUG_ISP2x00_FABRIC */ -#if DEBUG_ISP2100 -#define ENTER(x) printk("isp2100 : entering %s()\n", x); -#define LEAVE(x) printk("isp2100 : leaving %s()\n", x); +#if DEBUG_ISP2x00 +#define ENTER(x) printk("isp2x00 : entering %s()\n", x); +#define LEAVE(x) printk("isp2x00 : leaving %s()\n", x); #define DEBUG(x) x #else #define ENTER(x) #define LEAVE(x) #define DEBUG(x) -#endif /* DEBUG_ISP2100 */ +#endif /* DEBUG_ISP2x00 */ -#if DEBUG_ISP2100_INTR -#define ENTER_INTR(x) printk("isp2100 : entering %s()\n", x); -#define LEAVE_INTR(x) printk("isp2100 : leaving %s()\n", x); +#if DEBUG_ISP2x00_INTR +#define ENTER_INTR(x) printk("isp2x00 : entering %s()\n", x); +#define LEAVE_INTR(x) printk("isp2x00 : leaving %s()\n", x); #define DEBUG_INTR(x) x #else #define ENTER_INTR(x) #define LEAVE_INTR(x) #define DEBUG_INTR(x) -#endif /* DEBUG ISP2100_INTR */ +#endif /* DEBUG ISP2x00_INTR */ #if BITS_PER_LONG > 32 @@ -167,11 +169,9 @@ #define bus_to_virt_high32(x) 0x0 #endif -#define ISP2100_REV_ID 1 +#define ISP2100_REV_ID1 1 #define ISP2100_REV_ID3 3 - -#define MAX_TARGETS 16 -#define MAX_LUNS 8 +#define ISP2200_REV_ID5 5 /* host configuration and control registers */ #define HOST_HCCR 0xc0 /* host command and control */ @@ -219,6 +219,8 @@ #define PORT_DB_CHANGED 0x8014 #define CHANGE_NOTIFICATION 0x8015 #define SCSI_COMMAND_COMPLETE 0x8020 +#define POINT_TO_POINT_UP 0x8030 +#define CONNECTION_MODE 0x8036 struct Entry_header { u_char entry_type; @@ -235,6 +237,7 @@ #define ENTRY_COMMAND 0x11 #define ENTRY_CONTINUATION 0x02 #endif + #define ENTRY_STATUS 0x03 #define ENTRY_MARKER 0x04 @@ -256,7 +259,7 @@ u_int handle; u_char target_lun; u_char target_id; - u_short rsvd1; + u_short expanded_lun; u_short control_flags; u_short rsvd2; u_short time_out; @@ -277,7 +280,7 @@ u_int handle; u_char target_lun; u_char target_id; - u_short rsvd1; + u_short expanded_lun; u_short control_flags; u_short rsvd2; u_short time_out; @@ -299,19 +302,6 @@ #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -struct Ext_Command_Entry { - struct Entry_header hdr; - u_int 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]; -}; - #if BITS_PER_LONG > 32 struct Continuation_Entry { struct Entry_header hdr; @@ -331,7 +321,7 @@ u_char target_lun; u_char target_id; u_char modifier; - u_char rsvd; + u_char expanded_lun; u_char rsvds[52]; }; @@ -613,6 +603,17 @@ u_int req_queue_addr_high; u_int res_queue_addr_lo; u_int res_queue_addr_high; + /* the rest of this structure only applies to the isp2200 */ + u_short lun_enables; + u_char cmd_resource_cnt; + u_char notify_resource_cnt; + u_short timeout; + u_short reserved3; + u_short add_firm_opts; + u_char res_accum_timer; + u_char irq_delay_timer; + u_short special_options; + u_short reserved4[13]; }; /* @@ -622,7 +623,7 @@ #define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) #define QUEUE_ENTRY_LEN 64 -#if ISP2100_FABRIC +#if ISP2x00_FABRIC #define QLOGICFC_MAX_ID 0xff #else #define QLOGICFC_MAX_ID 0x7d @@ -636,10 +637,10 @@ #define AS_LOOP_GOOD 1 #define AS_REDO_PORTDB 2 -struct isp2100_hostdata { +struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; - /* result and request queues (shared with isp2100): */ + /* result and request queues (shared with isp2x00): */ u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ @@ -668,176 +669,187 @@ QLOGICFC_REQ_QUEUE_LEN) #define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) -static void isp2100_enable_irqs(struct Scsi_Host *); -static void isp2100_disable_irqs(struct Scsi_Host *); -static int isp2100_init(struct Scsi_Host *); -static int isp2100_reset_hardware(struct Scsi_Host *); -static int isp2100_mbox_command(struct Scsi_Host *, u_short[]); -static int isp2100_return_status(struct Status_Entry *); -static void isp2100_intr_handler(int, void *, struct pt_regs *); -static void do_isp2100_intr_handler(int, void *, struct pt_regs *); -static int isp2100_make_portdb(struct Scsi_Host *); +static void isp2x00_enable_irqs(struct Scsi_Host *); +static void isp2x00_disable_irqs(struct Scsi_Host *); +static int isp2x00_init(struct Scsi_Host *); +static int isp2x00_reset_hardware(struct Scsi_Host *); +static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]); +static int isp2x00_return_status(struct Status_Entry *); +static void isp2x00_intr_handler(int, void *, struct pt_regs *); +static void do_isp2x00_intr_handler(int, void *, struct pt_regs *); +static int isp2x00_make_portdb(struct Scsi_Host *); -#if ISP2100_FABRIC -static int isp2100_init_fabric(struct Scsi_Host *, struct id_name_map *, int); +#if ISP2x00_FABRIC +static int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int); #endif #if USE_NVRAM_DEFAULTS -static int isp2100_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); -static u_short isp2100_read_nvram_word(struct Scsi_Host *, u_short); +static int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); +static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short); #endif -#if DEBUG_ISP2100 -static void isp2100_print_scsi_cmd(Scsi_Cmnd *); +#if DEBUG_ISP2x00 +static void isp2x00_print_scsi_cmd(Scsi_Cmnd *); #endif -#if DEBUG_ISP2100_INTR -static void isp2100_print_status_entry(struct Status_Entry *); +#if DEBUG_ISP2x00_INTR +static void isp2x00_print_status_entry(struct Status_Entry *); #endif -static struct proc_dir_entry proc_scsi_isp2100 = +static struct proc_dir_entry proc_scsi_isp2x00 = { - PROC_SCSI_QLOGICFC, 7, "isp2100", + PROC_SCSI_QLOGICFC, 7, "isp2x00", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -static inline void isp2100_enable_irqs(struct Scsi_Host *host) +static inline void isp2x00_enable_irqs(struct Scsi_Host *host) { outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); } -static inline void isp2100_disable_irqs(struct Scsi_Host *host) +static inline void isp2x00_disable_irqs(struct Scsi_Host *host) { outw(0x0, host->io_port + PCI_INTER_CTL); } -int isp2100_detect(Scsi_Host_Template * tmpt) +int isp2x00_detect(Scsi_Host_Template * tmpt) { int hosts = 0; int wait_time; struct Scsi_Host *host = NULL; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; + unsigned short device_ids[2]; + int i; + + + ENTER("isp2x00_detect"); - ENTER("isp2100_detect"); + device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100; + device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200; - tmpt->proc_dir = &proc_scsi_isp2100; + tmpt->proc_dir = &proc_scsi_isp2x00; if (pci_present() == 0) { printk("qlogicfc : PCI not present\n"); return 0; } - while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, pdev))) { - host = scsi_register(tmpt, sizeof(struct isp2100_hostdata)); - host->max_id = QLOGICFC_MAX_ID + 1; - host->hostt->use_new_eh_code = 1; - hostdata = (struct isp2100_hostdata *) host->hostdata; - - memset(hostdata, 0, sizeof(struct isp2100_hostdata)); - hostdata->pci_dev = pdev; - - hostdata->queued = 0; - /* set up the control block */ - hostdata->control_block.version = 0x0f; - hostdata->control_block.firm_opts = 0x0108; - hostdata->control_block.max_frame_len = 2048; - hostdata->control_block.max_iocb = 256; - hostdata->control_block.exec_throttle = 8; - hostdata->control_block.retry_delay = 5; - hostdata->control_block.retry_cnt = 0; - hostdata->control_block.node_name[0] = 0x0020; - hostdata->control_block.node_name[1] = 0xE000; - hostdata->control_block.node_name[2] = 0x008B; - hostdata->control_block.node_name[3] = 0x0000; - hostdata->control_block.hard_addr = 0x0003; - hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; - hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; - hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(&hostdata->res); - hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(&hostdata->res); - hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); - hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); + for (i=0; i<2; i++){ + while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { - hostdata->adapter_state = AS_LOOP_DOWN; - hostdata->host_id = hosts; + host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); + host->max_id = QLOGICFC_MAX_ID + 1; + host->hostt->use_new_eh_code = 1; + hostdata = (struct isp2x00_hostdata *) host->hostdata; + + memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); + hostdata->pci_dev = pdev; + + hostdata->queued = 0; + /* set up the control block */ + hostdata->control_block.version = 0x1; + hostdata->control_block.firm_opts = 0x0108; + hostdata->control_block.max_frame_len = 2048; + hostdata->control_block.max_iocb = 256; + hostdata->control_block.exec_throttle = 8; + hostdata->control_block.retry_delay = 5; + hostdata->control_block.retry_cnt = 1; + hostdata->control_block.node_name[0] = 0x0020; + hostdata->control_block.node_name[1] = 0xE000; + hostdata->control_block.node_name[2] = 0x008B; + hostdata->control_block.node_name[3] = 0x0000; + hostdata->control_block.hard_addr = 0x0003; + hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; + hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; + hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(&hostdata->res); + hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(&hostdata->res); + hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); + hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); + + + hostdata->adapter_state = AS_LOOP_DOWN; + hostdata->host_id = hosts; - if (isp2100_init(host) || isp2100_reset_hardware(host)) { - scsi_unregister(host); - continue; - } - host->this_id = 0; + if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { + scsi_unregister(host); + continue; + } + host->this_id = 0; - if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { - printk("qlogicfc%d : interrupt %d already in use\n", - hostdata->host_id, host->irq); - scsi_unregister(host); - continue; - } - if (check_region(host->io_port, 0xff)) { - printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " - "in use\n", - hostdata->host_id, host->io_port, host->io_port + 0xff); - free_irq(host->irq, host); - scsi_unregister(host); - continue; - } - request_region(host->io_port, 0xff, "qlogicfc"); + if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { + printk("qlogicfc%d : interrupt %d already in use\n", + hostdata->host_id, host->irq); + scsi_unregister(host); + continue; + } + if (check_region(host->io_port, 0xff)) { + printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " + "in use\n", + hostdata->host_id, host->io_port, host->io_port + 0xff); + free_irq(host->irq, host); + scsi_unregister(host); + continue; + } + request_region(host->io_port, 0xff, "qlogicfc"); - outw(0x0, host->io_port + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - isp2100_enable_irqs(host); - /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) - barrier(); + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + isp2x00_enable_irqs(host); + /* wait for the loop to come up */ + for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) + barrier(); - if (hostdata->adapter_state == AS_LOOP_DOWN) { - printk("qlogicfc%d : loop is not up\n", hostdata->host_id); + if (hostdata->adapter_state == AS_LOOP_DOWN) { + printk("qlogicfc%d : link is not up\n", hostdata->host_id); + } + hosts++; } - hosts++; } - /* this busy loop should not be needed but the isp2100 seems to need + /* this busy loop should not be needed but the isp2x00 seems to need some time before recognizing it is attached to a fabric */ -#if ISP2100_FABRIC +#if ISP2x00_FABRIC for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) barrier(); #endif - LEAVE("isp2100_detect"); + LEAVE("isp2x00_detect"); return hosts; } -static int isp2100_make_portdb(struct Scsi_Host *host) +static int isp2x00_make_portdb(struct Scsi_Host *host) { short param[8]; int i, j; struct id_name_map temp[QLOGICFC_MAX_ID + 1]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); memset(temp, 0, sizeof(temp)); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; -#if ISP2100_FABRIC +#if ISP2x00_FABRIC for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { param[0] = MBOX_PORT_LOGOUT; param[1] = i << 8; param[2] = 0; param[3] = 0; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0]); + + DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0])); } } #endif @@ -845,7 +857,7 @@ param[0] = MBOX_GET_INIT_SCSI_ID; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { hostdata->port_id = ((u_int) param[3]) << 16; @@ -864,7 +876,7 @@ param[0] = MBOX_GET_PORT_NAME; param[1] = (i << 8) & 0xff00; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { temp[j].loop_id = i; @@ -883,8 +895,8 @@ } -#if ISP2100_FABRIC - isp2100_init_fabric(host, temp, j); +#if ISP2x00_FABRIC + isp2x00_init_fabric(host, temp, j); #endif for (i = 0; i <= QLOGICFC_MAX_ID; i++) { @@ -914,19 +926,19 @@ } - isp2100_enable_irqs(host); + isp2x00_enable_irqs(host); return 0; } -#if ISP2100_FABRIC +#if ISP2x00_FABRIC #define FABRIC_PORT 0x7e #define FABRIC_CONTROLLER 0x7f #define FABRIC_SNS 0x80 -int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) +int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) { u_short param[8]; @@ -937,15 +949,15 @@ u_int port_id; struct sns_cb req; u_char sns_response[608]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; param[1] = (u16)FABRIC_PORT << 8; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0])); @@ -973,7 +985,7 @@ param[6] = virt_to_bus_high32(&req) >> 16; param[7] = virt_to_bus_high32(&req); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); @@ -999,7 +1011,7 @@ param[6] = virt_to_bus_high32(&req) >> 16; param[7] = virt_to_bus_high32(&req); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); @@ -1022,7 +1034,7 @@ param[2] = (u_short) (port_id >> 16); param[3] = (u_short) (port_id); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { port_db[scsi_id].wwn = wwn; @@ -1032,6 +1044,13 @@ } else { printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]); DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id)); + param[0] = MBOX_PORT_LOGOUT; + param[1] = loop_id << 8; + param[2] = 0; + param[3] = 0; + + isp2x00_mbox_command(host, param); + } } @@ -1046,42 +1065,42 @@ return 1; } -#endif /* ISP2100_FABRIC */ +#endif /* ISP2x00_FABRIC */ -int isp2100_release(struct Scsi_Host *host) +int isp2x00_release(struct Scsi_Host *host) { - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - ENTER("isp2100_release"); + ENTER("isp2x00_release"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; outw(0x0, host->io_port + PCI_INTER_CTL); free_irq(host->irq, host); release_region(host->io_port, 0xff); - LEAVE("isp2100_release"); + LEAVE("isp2x00_release"); return 0; } -const char *isp2100_info(struct Scsi_Host *host) +const char *isp2x00_info(struct Scsi_Host *host) { static char buf[80]; - struct isp2100_hostdata *hostdata; - ENTER("isp2100_info"); + struct isp2x00_hostdata *hostdata; + ENTER("isp2x00_info"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; sprintf(buf, - "QLogic ISP2100 SCSI on PCI bus %02x device %02x irq %d base 0x%lx", - hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, + "QLogic ISP%04x SCSI on PCI bus %02x device %02x irq %d base 0x%lx", + hostdata->pci_dev->device, hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, host->io_port); - LEAVE("isp2100_info"); + LEAVE("isp2x00_info"); return buf; } @@ -1093,7 +1112,7 @@ * interrupt handler may call this routine as part of * request-completion handling). */ -int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) +int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) { int i, sg_count, n, num_free; u_int in_ptr, out_ptr; @@ -1102,19 +1121,19 @@ struct Command_Entry *cmd; struct Continuation_Entry *cont; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - ENTER("isp2100_queuecommand"); + ENTER("isp2x00_queuecommand"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; Cmnd->scsi_done = done; - DEBUG(isp2100_print_scsi_cmd(Cmnd)); + DEBUG(isp2x00_print_scsi_cmd(Cmnd)); if (hostdata->adapter_state == AS_REDO_PORTDB) { hostdata->adapter_state = AS_LOOP_GOOD; - isp2100_make_portdb(host); + isp2x00_make_portdb(host); printk("qlogicfc%d : Port Database\n", hostdata->host_id); for (i = 0; hostdata->port_db[i].wwn != 0; i++) { printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id); @@ -1186,7 +1205,8 @@ cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; -#if ISP2100_PORTDB + cmd->expanded_lun = Cmnd->lun; +#if ISP2x00_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; #else cmd->target_id = Cmnd->target; @@ -1307,7 +1327,7 @@ host->can_queue = host->host_busy + 1; } - LEAVE("isp2100_queuecommand"); + LEAVE("isp2x00_queuecommand"); return 0; } @@ -1316,27 +1336,27 @@ #define ASYNC_EVENT_INTERRUPT 0x01 -void do_isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +void do_isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); - isp2100_intr_handler(irq, dev_id, regs); + isp2x00_intr_handler(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags); } -void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd *Cmnd; struct Status_Entry *sts; struct Scsi_Host *host = dev_id; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; u_int in_ptr, out_ptr, handle, num_free; u_short status; - ENTER_INTR("isp2100_intr_handler"); + ENTER_INTR("isp2x00_intr_handler"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq)); @@ -1356,13 +1376,17 @@ switch (status) { case LOOP_UP: - printk("qlogicfc%d : loop is up\n", hostdata->host_id); + case POINT_TO_POINT_UP: + printk("qlogicfc%d : link is up\n", hostdata->host_id); hostdata->adapter_state = AS_REDO_PORTDB; break; case LOOP_DOWN: - printk("qlogicfc%d : loop is down\n", hostdata->host_id); + printk("qlogicfc%d : link is down\n", hostdata->host_id); hostdata->adapter_state = AS_LOOP_DOWN; break; + case CONNECTION_MODE: + printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1)); + break; case LIP_OCCURED: case CHANGE_NOTIFICATION: case PORT_DB_CHANGED: @@ -1411,9 +1435,9 @@ out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; TRACE("done", out_ptr, Cmnd); - DEBUG_INTR(isp2100_print_status_entry(sts)); + DEBUG_INTR(isp2x00_print_status_entry(sts)); if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { - Cmnd->result = isp2100_return_status(sts); + Cmnd->result = isp2x00_return_status(sts); hostdata->handle_ptrs[sts->handle] = NULL; hostdata->queued--; @@ -1431,7 +1455,7 @@ } /* * if we get back an error indicating the port - * is not there or if the loop is down and + * is not there or if the link is down and * this is a device that used to be there * allow the command to timeout. * the device may well be back in a couple of @@ -1483,14 +1507,14 @@ } outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - LEAVE_INTR("isp2100_intr_handler"); + LEAVE_INTR("isp2x00_intr_handler"); } -static int isp2100_return_status(struct Status_Entry *sts) +static int isp2x00_return_status(struct Status_Entry *sts) { int host_status = DID_ERROR; -#if DEBUG_ISP2100_INTR +#if DEBUG_ISP2x00_INTR static char *reason[] = { "DID_OK", @@ -1504,9 +1528,9 @@ "DID_RESET", "DID_BAD_INTR" }; -#endif /* DEBUG_ISP2100_INTR */ +#endif /* DEBUG_ISP2x00_INTR */ - ENTER("isp2100_return_status"); + ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", sts->completion_status)); @@ -1551,24 +1575,24 @@ DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", reason[host_status], sts->scsi_status)); - LEAVE("isp2100_return_status"); + LEAVE("isp2x00_return_status"); return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -int isp2100_abort(Scsi_Cmnd * Cmnd) +int isp2x00_abort(Scsi_Cmnd * Cmnd) { u_short param[8]; int i; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; int return_status = SUCCESS; - ENTER("isp2100_abort"); + ENTER("isp2x00_abort"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++) if (hostdata->handle_ptrs[i] == Cmnd) @@ -1578,10 +1602,10 @@ return SUCCESS; } - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); param[0] = MBOX_ABORT_IOCB; -#if ISP2100_PORTDB +#if ISP2x00_PORTDB param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun; #else param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; @@ -1589,7 +1613,7 @@ param[2] = i & 0xffff; param[3] = i >> 16; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]); @@ -1602,54 +1626,54 @@ if (return_status != SUCCESS){ param[0] = MBOX_GET_FIRMWARE_STATE; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); printk("qlogicfc%d : abort failed\n", hostdata->host_id); printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]); } - isp2100_enable_irqs(host); + isp2x00_enable_irqs(host); - LEAVE("isp2100_abort"); + LEAVE("isp2x00_abort"); return return_status; } -int isp2100_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) +int isp2x00_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) { u_short param[8]; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; int return_status = SCSI_RESET_SUCCESS; - ENTER("isp2100_reset"); + ENTER("isp2x00_reset"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; param[0] = MBOX_BUS_RESET; param[1] = 3; - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]); return_status = SCSI_RESET_ERROR; } - isp2100_enable_irqs(host); + isp2x00_enable_irqs(host); - LEAVE("isp2100_reset"); + LEAVE("isp2x00_reset"); return return_status;; } -int isp2100_biosparam(Disk * disk, kdev_t n, int ip[]) +int isp2x00_biosparam(Disk * disk, kdev_t n, int ip[]) { int size = disk->capacity; - ENTER("isp2100_biosparam"); + ENTER("isp2x00_biosparam"); ip[0] = 64; ip[1] = 32; @@ -1659,21 +1683,21 @@ ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); } - LEAVE("isp2100_biosparam"); + LEAVE("isp2x00_biosparam"); return 0; } -static int isp2100_reset_hardware(struct Scsi_Host *host) +static int isp2x00_reset_hardware(struct Scsi_Host *host) { u_short param[8]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; int loop_count; - ENTER("isp2100_reset_hardware"); + ENTER("isp2x00_reset_hardware"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; outw(0x01, host->io_port + ISP_CTRL_STATUS); outw(HCCR_RESET, host->io_port + HOST_HCCR); @@ -1688,7 +1712,7 @@ -#if DEBUG_ISP2100 +#if DEBUG_ISP2x00 printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX0)); printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX1)); printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX2)); @@ -1697,19 +1721,30 @@ printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX5)); printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX6)); printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX7)); -#endif /* DEBUG_ISP2100 */ +#endif /* DEBUG_ISP2x00 */ DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id)); #if RELOAD_FIRMWARE { int i; - for (i = 0; i < risc_code_length01; i++) { + unsigned short * risc_code = NULL; + unsigned short risc_code_len = 0; + if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2100){ + risc_code = risc_code2100; + risc_code_len = risc_code_length2100; + } + else if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2200){ + risc_code = risc_code2200; + risc_code_len = risc_code_length2200; + } + + for (i = 0; i < risc_code_len; i++) { param[0] = MBOX_WRITE_RAM_WORD; param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; + param[2] = risc_code[i]; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : firmware load failure\n", hostdata->host_id); @@ -1722,7 +1757,7 @@ param[0] = MBOX_VERIFY_CHECKSUM; param[1] = risc_code_addr01; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id); @@ -1733,11 +1768,11 @@ param[0] = MBOX_EXEC_FIRMWARE; param[1] = risc_code_addr01; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); param[0] = MBOX_ABOUT_FIRMWARE; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : about firmware failure\n", hostdata->host_id); @@ -1748,7 +1783,7 @@ #ifdef USE_NVRAM_DEFAULTS - if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) { + if (isp2x00_get_nvram_defaults(host, &hostdata->control_block) != 0) { printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id); } #endif @@ -1769,38 +1804,38 @@ param[5] = 0; param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); return 1; } - LEAVE("isp2100_reset_hardware"); + LEAVE("isp2x00_reset_hardware"); return 0; } #ifdef USE_NVRAM_DEFAULTS -static int isp2100_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) +static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) { u_short value; - if (isp2100_read_nvram_word(host, 0) != 0x5349) + if (isp2x00_read_nvram_word(host, 0) != 0x5349) return 1; - value = isp2100_read_nvram_word(host, 8); - control_block->node_name[0] = isp2100_read_nvram_word(host, 9); - control_block->node_name[1] = isp2100_read_nvram_word(host, 10); - control_block->node_name[2] = isp2100_read_nvram_word(host, 11); - control_block->node_name[3] = isp2100_read_nvram_word(host, 12); - control_block->hard_addr = isp2100_read_nvram_word(host, 13); + value = isp2x00_read_nvram_word(host, 8); + control_block->node_name[0] = isp2x00_read_nvram_word(host, 9); + control_block->node_name[1] = isp2x00_read_nvram_word(host, 10); + control_block->node_name[2] = isp2x00_read_nvram_word(host, 11); + control_block->node_name[3] = isp2x00_read_nvram_word(host, 12); + control_block->hard_addr = isp2x00_read_nvram_word(host, 13); return 0; @@ -1808,19 +1843,19 @@ #endif -static int isp2100_init(struct Scsi_Host *sh) +static int isp2x00_init(struct Scsi_Host *sh) { u_int io_base; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; u_char revision; u_int irq; u_short command; struct pci_dev *pdev; - ENTER("isp2100_init"); + ENTER("isp2x00_init"); - hostdata = (struct isp2100_hostdata *) sh->hostdata; + hostdata = (struct isp2x00_hostdata *) sh->hostdata; pdev = hostdata->pci_dev; if (pci_read_config_word(pdev, PCI_COMMAND, &command) @@ -1832,14 +1867,13 @@ irq = pdev->irq; - if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, pdev->vendor); return 1; } - if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) { - printk("qlogicfc%d : 0x%04x does not match ISP2100 device id\n", hostdata->host_id, + if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100 && pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2200) { + printk("qlogicfc%d : 0x%04x does not match ISP2100 or ISP2200 device id\n", hostdata->host_id, pdev->device); return 1; } @@ -1854,8 +1888,8 @@ printk("qlogicfc%d : bus mastering is disabled\n", hostdata->host_id); return 1; } - if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3) - printk("qlogicfc%d : new isp2100 revision ID (%d)\n", hostdata->host_id, revision); + if (revision != ISP2100_REV_ID1 && revision != ISP2100_REV_ID3 && revision != ISP2200_REV_ID5) + printk("qlogicfc%d : new isp2x00 revision ID (%d)\n", hostdata->host_id, revision); hostdata->revision = revision; @@ -1863,7 +1897,7 @@ sh->irq = irq; sh->io_port = io_base; - LEAVE("isp2100_init"); + LEAVE("isp2x00_init"); return 0; } @@ -1873,7 +1907,7 @@ #define NVRAM_DELAY() udelay(10) /* 10 microsecond delay */ -u_short isp2100_read_nvram_word(struct Scsi_Host * host, u_short byte) +u_short isp2x00_read_nvram_word(struct Scsi_Host * host, u_short byte) { int i; u_short value, output, input; @@ -1922,10 +1956,10 @@ * currently, this is only called during initialization or abort/reset, * at which times interrupts are disabled, so polling is OK, I guess... */ -static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[]) +static int isp2x00_mbox_command(struct Scsi_Host *host, u_short param[]) { int loop_count; - struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata; + struct isp2x00_hostdata *hostdata = (struct isp2x00_hostdata *) host->hostdata; if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD) return 1; @@ -1975,7 +2009,7 @@ printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id); break; } - isp2100_intr_handler(host->irq, host, NULL); + isp2x00_intr_handler(host->irq, host, NULL); if (hostdata->mbox_done == 1) break; @@ -2008,9 +2042,9 @@ return 0; } -#if DEBUG_ISP2100_INTR +#if DEBUG_ISP2x00_INTR -void isp2100_print_status_entry(struct Status_Entry *status) +void isp2x00_print_status_entry(struct Status_Entry *status) { printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); @@ -2024,12 +2058,12 @@ } -#endif /* DEBUG_ISP2100_INTR */ +#endif /* DEBUG_ISP2x00_INTR */ -#if DEBUG_ISP2100 +#if DEBUG_ISP2x00 -void isp2100_print_scsi_cmd(Scsi_Cmnd * cmd) +void isp2x00_print_scsi_cmd(Scsi_Cmnd * cmd) { int i; @@ -2041,7 +2075,7 @@ printk("\n"); } -#endif /* DEBUG_ISP2100 */ +#endif /* DEBUG_ISP2x00 */ #ifdef MODULE diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h --- v2.3.14/linux/drivers/scsi/qlogicfc.h Mon Jul 5 19:58:24 1999 +++ linux/drivers/scsi/qlogicfc.h Mon Aug 23 10:14:44 1999 @@ -1,5 +1,5 @@ /* - * QLogic ISP2100 SCSI-FCP + * QLogic ISP2x00 SCSI-FCP * * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe @@ -18,7 +18,7 @@ /* Renamed and updated to 1.3.x by Michael Griffith */ /* This is a version of the isp1020 driver which was modified by - * Chris Loveland to support the isp2100 + * Chris Loveland to support the isp2x00 */ @@ -74,28 +74,28 @@ #define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0)) #define QLOGICFC_CMD_PER_LUN 8 -int isp2100_detect(Scsi_Host_Template *); -int isp2100_release(struct Scsi_Host *); -const char * isp2100_info(struct Scsi_Host *); -int isp2100_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int isp2100_abort(Scsi_Cmnd *); -int isp2100_reset(Scsi_Cmnd *, unsigned int); -int isp2100_biosparam(Disk *, kdev_t, int[]); +int isp2x00_detect(Scsi_Host_Template *); +int isp2x00_release(struct Scsi_Host *); +const char * isp2x00_info(struct Scsi_Host *); +int isp2x00_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int isp2x00_abort(Scsi_Cmnd *); +int isp2x00_reset(Scsi_Cmnd *, unsigned int); +int isp2x00_biosparam(Disk *, kdev_t, int[]); #ifndef NULL #define NULL (0) #endif -extern struct proc_dir_entry proc_scsi_isp2100; +extern struct proc_dir_entry proc_scsi_isp2x00; #define QLOGICFC { \ - detect: isp2100_detect, \ - release: isp2100_release, \ - info: isp2100_info, \ - queuecommand: isp2100_queuecommand, \ - eh_abort_handler: isp2100_abort, \ - reset: isp2100_reset, \ - bios_param: isp2100_biosparam, \ + detect: isp2x00_detect, \ + release: isp2x00_release, \ + info: isp2x00_info, \ + queuecommand: isp2x00_queuecommand, \ + eh_abort_handler: isp2x00_abort, \ + reset: isp2x00_reset, \ + bios_param: isp2x00_biosparam, \ can_queue: QLOGICFC_REQ_QUEUE_LEN, \ this_id: -1, \ sg_tablesize: QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN), \ diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/qlogicfc_asm.c linux/drivers/scsi/qlogicfc_asm.c --- v2.3.14/linux/drivers/scsi/qlogicfc_asm.c Thu Apr 15 05:42:43 1999 +++ linux/drivers/scsi/qlogicfc_asm.c Mon Aug 23 10:14:44 1999 @@ -1,160 +1,141 @@ -/************************************************************************ - * * - * --- ISP2100 Fabric Initiator/Target Firmware --- * - * * - * * - ************************************************************************ - * * - * NOTICE * - * * - * COPYRIGHT 1998 QLOGIC CORPORATION * - * ALL RIGHTS RESERVED * - * * - ************************************************************************ - */ /* - * Firmware Version 1.15.19 (14:58 Jan 19, 1999) + * Firmware Version 1.15.37 (15:37 May 03, 1999) */ -unsigned short risc_code_version = 1*1024+15; - -unsigned char firmware_version[] = {1,15,19}; - -#define FW_VERSION_STRING "1.15.19" - unsigned short risc_code_addr01 = 0x1000 ; +unsigned short risc_code_length2100 = 0x65db; +unsigned short risc_code_length2200 = 0x81bd; -unsigned short risc_code01[] = { - 0x0078, 0x1029, 0x0000, 0x65e6, 0x0000, 0x2043, 0x4f50, 0x5952, +unsigned short risc_code2100[] = { + 0x0078, 0x1029, 0x0000, 0x65db, 0x0000, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x3620, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3135, 0x2020, 0x2020, - 0x2400, 0x20c1, 0x0021, 0x20a1, 0x75e6, 0x2009, 0x0000, 0x20a9, - 0x071a, 0x41a4, 0x3400, 0x20c9, 0x7aff, 0x2091, 0x2000, 0x2059, - 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x20a0, 0x2051, 0x7600, + 0x2400, 0x20c1, 0x0021, 0x20a1, 0x75db, 0x2009, 0x0000, 0x20a9, + 0x0725, 0x41a4, 0x3400, 0x20c9, 0x7aff, 0x2091, 0x2000, 0x2059, + 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x209a, 0x2051, 0x7600, 0x2a70, 0x705b, 0x9500, 0x705f, 0xffff, 0x7057, 0x94f9, 0x7063, - 0x0300, 0x1078, 0x1282, 0x20a1, 0x7d00, 0x715c, 0x810d, 0x810d, + 0x0300, 0x1078, 0x127a, 0x20a1, 0x7d00, 0x715c, 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0007, 0xa112, 0xa00e, 0x21a8, 0x41a4, 0x3400, 0x8211, 0x00c0, 0x1058, 0x715c, 0x3400, 0xa102, 0x0040, 0x1068, 0x0048, 0x1068, 0x20a8, 0xa00e, 0x41a4, - 0x1078, 0x1249, 0x1078, 0x136e, 0x1078, 0x14f3, 0x1078, 0x19c8, - 0x1078, 0x3615, 0x1078, 0x5b94, 0x1078, 0x12f9, 0x1078, 0x242f, - 0x1078, 0x3c56, 0x1078, 0x3a2e, 0x1078, 0x4494, 0x1078, 0x1e5b, - 0x1078, 0x46d3, 0x1078, 0x4174, 0x1078, 0x1d7a, 0x1078, 0x1e3a, + 0x1078, 0x1241, 0x1078, 0x1366, 0x1078, 0x14eb, 0x1078, 0x19c0, + 0x1078, 0x360d, 0x1078, 0x5b8c, 0x1078, 0x12f1, 0x1078, 0x2429, + 0x1078, 0x3c4e, 0x1078, 0x3a26, 0x1078, 0x448c, 0x1078, 0x1e55, + 0x1078, 0x46cb, 0x1078, 0x416c, 0x1078, 0x1d74, 0x1078, 0x1e34, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x109d, 0x7820, 0xa086, 0x0002, 0x00c0, 0x109d, 0x7823, 0x4000, 0x0068, 0x1095, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, 0xa08e, 0x0003, - 0x00c0, 0x10bd, 0x1078, 0x2d8d, 0x1078, 0x2457, 0x1078, 0x3ca6, - 0x1078, 0x3b19, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, - 0x10c1, 0x1078, 0x44ac, 0x0078, 0x10a4, 0x1079, 0x10c5, 0x0078, - 0x10aa, 0x1078, 0x5866, 0x0078, 0x10b9, 0x10cf, 0x10d0, 0x114b, - 0x10cd, 0x11c6, 0x1246, 0x1247, 0x1248, 0x1078, 0x12d5, 0x007c, - 0x127e, 0x0f7e, 0x2091, 0x8000, 0x1078, 0x2eb2, 0x2079, 0x0100, - 0x7844, 0xa005, 0x00c0, 0x113c, 0x2011, 0x3542, 0x1078, 0x456e, + 0x00c0, 0x10bd, 0x1078, 0x2d7e, 0x1078, 0x2451, 0x1078, 0x3c9e, + 0x1078, 0x3b11, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, + 0x10c1, 0x1078, 0x44a4, 0x0078, 0x10a4, 0x1079, 0x10c5, 0x0078, + 0x10aa, 0x1078, 0x585e, 0x0078, 0x10b9, 0x10cf, 0x10d0, 0x1143, + 0x10cd, 0x11be, 0x123e, 0x123f, 0x1240, 0x1078, 0x12cd, 0x007c, + 0x127e, 0x0f7e, 0x2091, 0x8000, 0x1078, 0x2ea3, 0x2079, 0x0100, + 0x7844, 0xa005, 0x00c0, 0x1134, 0x2011, 0x353a, 0x1078, 0x4566, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, - 0x73b8, 0x1078, 0x2d4a, 0x1078, 0x56b1, 0x2011, 0x0004, 0x1078, - 0x6953, 0x1078, 0x39c8, 0x70c7, 0x0000, 0x70bf, 0x0000, 0x70c3, - 0x0000, 0x1078, 0x113f, 0x2011, 0x0000, 0x2079, 0x7651, 0x7804, - 0xd0ac, 0x0040, 0x1104, 0xc295, 0x70a4, 0xa005, 0x0040, 0x1109, - 0xc29d, 0x72be, 0xa296, 0x0004, 0x0040, 0x112a, 0x2011, 0x0001, - 0x1078, 0x6953, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, - 0x0f7f, 0x1078, 0x2150, 0x2011, 0x0005, 0x1078, 0x57c0, 0x1078, - 0x4c7a, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x127f, - 0x0078, 0x113e, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, - 0x2011, 0x0005, 0x1078, 0x57c0, 0x1078, 0x4c7a, 0x0c7e, 0x2061, + 0x73b8, 0x1078, 0x2d3b, 0x1078, 0x56a9, 0x2011, 0x0004, 0x1078, + 0x694d, 0x1078, 0x39c0, 0x70c7, 0x0000, 0x70c3, 0x0000, 0x1078, + 0x1137, 0x72bc, 0x2079, 0x7651, 0x7804, 0xd0ac, 0x0040, 0x1101, + 0xc295, 0x72be, 0xa296, 0x0004, 0x0040, 0x1122, 0x2011, 0x0001, + 0x1078, 0x694d, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, + 0x0f7f, 0x1078, 0x214a, 0x2011, 0x0005, 0x1078, 0x57b8, 0x1078, + 0x4c72, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x127f, + 0x0078, 0x1136, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, + 0x2011, 0x0005, 0x1078, 0x57b8, 0x1078, 0x4c72, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x0f7f, 0x127f, 0x007c, 0x0c7e, - 0x20a9, 0x0082, 0x2009, 0x007e, 0x1078, 0x380d, 0x8108, 0x00f0, - 0x1144, 0x0c7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x708c, 0xa086, - 0xffff, 0x0040, 0x1159, 0x1078, 0x2150, 0x1078, 0x4c7a, 0x0078, - 0x11c4, 0x70bc, 0xd09c, 0x0040, 0x1181, 0xd084, 0x0040, 0x1181, + 0x20a9, 0x0082, 0x2009, 0x007e, 0x1078, 0x3805, 0x8108, 0x00f0, + 0x113c, 0x0c7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x708c, 0xa086, + 0xffff, 0x0040, 0x1151, 0x1078, 0x214a, 0x1078, 0x4c72, 0x0078, + 0x11bc, 0x70bc, 0xd09c, 0x0040, 0x1179, 0xd084, 0x0040, 0x1179, 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, - 0x0040, 0x1181, 0x70c0, 0xa086, 0xffff, 0x0040, 0x117d, 0x1078, - 0x2245, 0x1078, 0x4c7a, 0x2011, 0x0001, 0x2019, 0x0000, 0x1078, - 0x227d, 0x1078, 0x4c7a, 0x0078, 0x11c4, 0x70c4, 0xa005, 0x00c0, - 0x11c4, 0x7088, 0xa005, 0x00c0, 0x11c4, 0x2001, 0x7652, 0x2004, - 0xd0ac, 0x0040, 0x11a7, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x017e, 0x1078, 0x3825, 0x00c0, 0x119a, 0x6000, 0xd0ec, - 0x00c0, 0x11a2, 0x017f, 0x8108, 0x00f0, 0x1191, 0x0c7f, 0x157f, - 0x0078, 0x11a7, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x11c4, 0x7003, - 0x0003, 0x708f, 0xffff, 0x2001, 0x0000, 0x1078, 0x202b, 0x1078, - 0x2dc8, 0x2001, 0x7837, 0x2004, 0xa086, 0x0005, 0x00c0, 0x11bc, - 0x2011, 0x0000, 0x1078, 0x57c0, 0x2011, 0x0000, 0x1078, 0x57ca, - 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x127f, 0x007c, 0x017e, 0x0f7e, + 0x0040, 0x1179, 0x70c0, 0xa086, 0xffff, 0x0040, 0x1175, 0x1078, + 0x223f, 0x1078, 0x4c72, 0x2011, 0x0001, 0x2019, 0x0000, 0x1078, + 0x2277, 0x1078, 0x4c72, 0x0078, 0x11bc, 0x70c4, 0xa005, 0x00c0, + 0x11bc, 0x7088, 0xa005, 0x00c0, 0x11bc, 0x2001, 0x7652, 0x2004, + 0xd0ac, 0x0040, 0x119f, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x017e, 0x1078, 0x381d, 0x00c0, 0x1192, 0x6000, 0xd0ec, + 0x00c0, 0x119a, 0x017f, 0x8108, 0x00f0, 0x1189, 0x0c7f, 0x157f, + 0x0078, 0x119f, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x11bc, 0x7003, + 0x0003, 0x708f, 0xffff, 0x2001, 0x0000, 0x1078, 0x2025, 0x1078, + 0x2db9, 0x2001, 0x7837, 0x2004, 0xa086, 0x0005, 0x00c0, 0x11b4, + 0x2011, 0x0000, 0x1078, 0x57b8, 0x2011, 0x0000, 0x1078, 0x57c2, + 0x1078, 0x4c72, 0x1078, 0x4d32, 0x127f, 0x007c, 0x017e, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x7940, 0xa18c, 0x0010, - 0x7942, 0x7924, 0xd1b4, 0x0040, 0x11d7, 0x7827, 0x0040, 0xd19c, - 0x0040, 0x11dc, 0x7827, 0x0008, 0x007e, 0x037e, 0x157e, 0x7900, - 0xa18a, 0x0003, 0x0050, 0x1202, 0x7954, 0xd1ac, 0x00c0, 0x1202, - 0x2009, 0x00f8, 0x1078, 0x35e4, 0x7843, 0x0090, 0x7843, 0x0010, - 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x11fa, 0x7824, 0xd0ac, - 0x00c0, 0x1236, 0x00f0, 0x11f2, 0x2001, 0x0001, 0x1078, 0x202b, - 0x0078, 0x123f, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0008, - 0x00e0, 0x1208, 0x2091, 0x6000, 0x00f0, 0x1208, 0x7853, 0x0400, - 0x782f, 0x0000, 0x2009, 0x00f8, 0x1078, 0x35e4, 0x20a9, 0x000e, - 0x0005, 0x00f0, 0x1218, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, + 0x7942, 0x7924, 0xd1b4, 0x0040, 0x11cf, 0x7827, 0x0040, 0xd19c, + 0x0040, 0x11d4, 0x7827, 0x0008, 0x007e, 0x037e, 0x157e, 0x7900, + 0xa18a, 0x0003, 0x0050, 0x11fa, 0x7954, 0xd1ac, 0x00c0, 0x11fa, + 0x2009, 0x00f8, 0x1078, 0x35dc, 0x7843, 0x0090, 0x7843, 0x0010, + 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x11f2, 0x7824, 0xd0ac, + 0x00c0, 0x122e, 0x00f0, 0x11ea, 0x2001, 0x0001, 0x1078, 0x2025, + 0x0078, 0x1237, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0008, + 0x00e0, 0x1200, 0x2091, 0x6000, 0x00f0, 0x1200, 0x7853, 0x0400, + 0x782f, 0x0000, 0x2009, 0x00f8, 0x1078, 0x35dc, 0x20a9, 0x000e, + 0x0005, 0x00f0, 0x1210, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, - 0x122d, 0x7824, 0xd0ac, 0x00c0, 0x1236, 0x8319, 0x00c0, 0x1223, - 0x2001, 0x0001, 0x1078, 0x202b, 0x0078, 0x123d, 0x7828, 0xc09d, + 0x1225, 0x7824, 0xd0ac, 0x00c0, 0x122e, 0x8319, 0x00c0, 0x121b, + 0x2001, 0x0001, 0x1078, 0x2025, 0x0078, 0x1235, 0x7828, 0xc09d, 0x782a, 0x7827, 0x0008, 0x7827, 0x0040, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, - 0x1255, 0x704f, 0xffff, 0x0078, 0x1257, 0x704f, 0x0000, 0x7053, + 0x124d, 0x704f, 0xffff, 0x0078, 0x124f, 0x704f, 0x0000, 0x7053, 0xffff, 0x7067, 0x0000, 0x706b, 0x0000, 0x2061, 0x7820, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0x7828, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, - 0x0000, 0x007c, 0x1078, 0x12a8, 0x2011, 0x0000, 0x81ff, 0x0040, - 0x12a7, 0xa186, 0x0001, 0x00c0, 0x1297, 0x705f, 0x8fff, 0x7057, - 0x8501, 0x7063, 0x0100, 0x705b, 0x8500, 0x0078, 0x12a5, 0xa186, - 0x0002, 0x00c0, 0x129f, 0x2011, 0x0000, 0x0078, 0x12a5, 0xa186, - 0x0005, 0x00c0, 0x12a5, 0x2011, 0x0001, 0x1078, 0x12cf, 0x007c, - 0x2009, 0x0000, 0x2011, 0x0000, 0x1078, 0x12cf, 0x2019, 0xaaaa, + 0x0000, 0x007c, 0x1078, 0x12a0, 0x2011, 0x0000, 0x81ff, 0x0040, + 0x129f, 0xa186, 0x0001, 0x00c0, 0x128f, 0x705f, 0x8fff, 0x7057, + 0x8501, 0x7063, 0x0100, 0x705b, 0x8500, 0x0078, 0x129d, 0xa186, + 0x0002, 0x00c0, 0x1297, 0x2011, 0x0000, 0x0078, 0x129d, 0xa186, + 0x0005, 0x00c0, 0x129d, 0x2011, 0x0001, 0x1078, 0x12c7, 0x007c, + 0x2009, 0x0000, 0x2011, 0x0000, 0x1078, 0x12c7, 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2362, 0x2c24, 0x2061, 0x7fff, 0x2c04, 0xa406, - 0x0040, 0x12bd, 0xc18d, 0x0078, 0x12ca, 0xc185, 0x2011, 0x0001, - 0x1078, 0x12cf, 0x2061, 0xffff, 0x2362, 0x2c04, 0xa306, 0x00c0, - 0x12ca, 0xc195, 0x2011, 0x0001, 0x1078, 0x12cf, 0x007c, 0x3800, + 0x0040, 0x12b5, 0xc18d, 0x0078, 0x12c2, 0xc185, 0x2011, 0x0001, + 0x1078, 0x12c7, 0x2061, 0xffff, 0x2362, 0x2c04, 0xa306, 0x00c0, + 0x12c2, 0xc195, 0x2011, 0x0001, 0x1078, 0x12c7, 0x007c, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x007c, 0x2091, 0x8000, 0x0068, - 0x12d7, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, - 0x00c0, 0x12dd, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, + 0x12cf, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, + 0x00c0, 0x12d5, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12f6, + 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12ee, 0x007c, 0x2071, 0x7600, 0x7158, 0x712e, 0x2021, 0x0001, 0xa190, - 0x002d, 0xa298, 0x002d, 0x0048, 0x130f, 0x705c, 0xa302, 0x00c8, - 0x130f, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x1301, 0x200b, + 0x002d, 0xa298, 0x002d, 0x0048, 0x1307, 0x705c, 0xa302, 0x00c8, + 0x1307, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x12f9, 0x200b, 0x0000, 0x749e, 0x74a2, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, - 0x2071, 0x7600, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x1322, 0xa06e, - 0x0078, 0x132c, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, + 0x2071, 0x7600, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x131a, 0xa06e, + 0x0078, 0x1324, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x127e, 0x2091, 0x8000, 0x70a0, 0x8001, 0x00c8, - 0x133c, 0xa06e, 0x0078, 0x1345, 0x70a2, 0x702c, 0x2068, 0x2d04, + 0x1334, 0xa06e, 0x0078, 0x133d, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, 0x8000, 0x70a2, 0x127f, 0x0e7f, 0x007c, - 0x8dff, 0x0040, 0x1364, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, - 0x1348, 0x0d7f, 0x0078, 0x1358, 0x007c, 0x0e7e, 0x2071, 0x7600, + 0x8dff, 0x0040, 0x135c, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, + 0x1340, 0x0d7f, 0x0078, 0x1350, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x70a0, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, 0x007c, 0x0e7e, 0x2270, 0x700b, 0x0000, 0x2071, 0x7859, 0x7018, 0xa088, 0x7862, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, - 0x1397, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a8, 0x0f7f, 0x0e7f, - 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7004, 0xa005, 0x00c0, 0x13a6, - 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a8, 0x0f7f, 0x0e7f, 0x007c, - 0x7000, 0x0079, 0x13ab, 0x13af, 0x1419, 0x1436, 0x1436, 0x7018, - 0x711c, 0xa106, 0x00c0, 0x13b7, 0x7007, 0x0000, 0x007c, 0x0d7e, + 0x138f, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a0, 0x0f7f, 0x0e7f, + 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7004, 0xa005, 0x00c0, 0x139e, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a0, 0x0f7f, 0x0e7f, 0x007c, + 0x7000, 0x0079, 0x13a3, 0x13a7, 0x1411, 0x142e, 0x142e, 0x7018, + 0x711c, 0xa106, 0x00c0, 0x13af, 0x7007, 0x0000, 0x007c, 0x0d7e, 0xa180, 0x7862, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, - 0x0d7f, 0xd084, 0x0040, 0x13d9, 0x7007, 0x0001, 0x1078, 0x13de, - 0x007c, 0x7007, 0x0002, 0x1078, 0x13f4, 0x007c, 0x017e, 0x027e, - 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13e9, 0x2110, + 0x0d7f, 0xd084, 0x0040, 0x13d1, 0x7007, 0x0001, 0x1078, 0x13d6, + 0x007c, 0x7007, 0x0002, 0x1078, 0x13ec, 0x007c, 0x017e, 0x027e, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13e1, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, 0x137e, 0x147e, 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, - 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1408, 0x2110, 0xa006, + 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1400, 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0001, 0x3300, 0x7016, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x76e5, 0x20a1, 0x0018, @@ -167,1088 +148,1088 @@ 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0x7711, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e, 0x2071, 0x7859, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, - 0xd1fc, 0x0040, 0x1479, 0xa18c, 0x0700, 0x0040, 0x1476, 0x7008, - 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, 0x1479, 0x7004, 0x1079, - 0x147d, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13a8, 0x1485, 0x14a7, - 0x14c1, 0x14ea, 0x1483, 0x0078, 0x1483, 0x137e, 0x147e, 0x157e, + 0xd1fc, 0x0040, 0x1471, 0xa18c, 0x0700, 0x0040, 0x146e, 0x7008, + 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, 0x1471, 0x7004, 0x1079, + 0x1475, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13a0, 0x147d, 0x149f, + 0x14b9, 0x14e2, 0x147b, 0x0078, 0x147b, 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f, 0x137f, 0x700c, 0xa005, - 0x0040, 0x14ae, 0x1078, 0x13de, 0x007c, 0x7008, 0xa080, 0x0002, - 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x13a8, 0x007c, 0x700c, - 0xa005, 0x0040, 0x14ae, 0x1078, 0x13f4, 0x007c, 0x0d7e, 0x7008, + 0x0040, 0x14a6, 0x1078, 0x13d6, 0x007c, 0x7008, 0xa080, 0x0002, + 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x13a0, 0x007c, 0x700c, + 0xa005, 0x0040, 0x14a6, 0x1078, 0x13ec, 0x007c, 0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, - 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a8, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a0, 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x76e3, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, - 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14e0, 0x2001, + 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14d8, 0x2001, 0x76ee, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, - 0x157f, 0x147f, 0x137f, 0x7007, 0x0000, 0x1078, 0x3d4f, 0x1078, - 0x13a8, 0x007c, 0x2001, 0x7713, 0x2003, 0x0100, 0x7007, 0x0000, - 0x1078, 0x13a8, 0x007c, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, + 0x157f, 0x147f, 0x137f, 0x7007, 0x0000, 0x1078, 0x3d47, 0x1078, + 0x13a0, 0x007c, 0x2001, 0x7713, 0x2003, 0x0100, 0x7007, 0x0000, + 0x1078, 0x13a0, 0x007c, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0x786a, 0x7003, 0x0000, 0x700f, 0x7870, 0x7013, 0x7870, 0x780f, 0x0070, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079, - 0x1509, 0x1511, 0x1557, 0x1511, 0x1511, 0x1511, 0x153c, 0x1520, - 0x1515, 0xa085, 0x0001, 0x0078, 0x1571, 0x684c, 0xd0bc, 0x0040, - 0x1511, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x155f, - 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1511, 0x684c, 0xd0bc, - 0x0040, 0x1511, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, - 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, - 0x6832, 0x6858, 0x0078, 0x1567, 0xa18c, 0x00ff, 0xa186, 0x0015, - 0x00c0, 0x1511, 0x684c, 0xd0ac, 0x0040, 0x1511, 0x6804, 0x681a, - 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, - 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x1567, 0x684c, - 0xd0ac, 0x0040, 0x1511, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, - 0x000f, 0xa188, 0x1c84, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, + 0x1501, 0x1509, 0x154f, 0x1509, 0x1509, 0x1509, 0x1534, 0x1518, + 0x150d, 0xa085, 0x0001, 0x0078, 0x1569, 0x684c, 0xd0bc, 0x0040, + 0x1509, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x1557, + 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1509, 0x684c, 0xd0bc, + 0x0040, 0x1509, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, + 0x6832, 0x6858, 0x0078, 0x155f, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x00c0, 0x1509, 0x684c, 0xd0ac, 0x0040, 0x1509, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, + 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x155f, 0x684c, + 0xd0ac, 0x0040, 0x1509, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, + 0x000f, 0xa188, 0x1c7e, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a, - 0x2004, 0x82ff, 0x0040, 0x158c, 0xa280, 0x0004, 0x0d7e, 0x206c, - 0x684c, 0xd0dc, 0x00c0, 0x1588, 0x1078, 0x1504, 0x10c0, 0x12d5, + 0x2004, 0x82ff, 0x0040, 0x1584, 0xa280, 0x0004, 0x0d7e, 0x206c, + 0x684c, 0xd0dc, 0x00c0, 0x1580, 0x1078, 0x14fc, 0x10c0, 0x12cd, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, - 0x15a0, 0x7206, 0x2001, 0x15b4, 0x007e, 0x2260, 0x0078, 0x16cc, + 0x1598, 0x7206, 0x2001, 0x15ac, 0x007e, 0x2260, 0x0078, 0x16c4, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, - 0x788b, 0x0048, 0x15ad, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, - 0x00c0, 0x15b4, 0x1078, 0x16b5, 0x127f, 0x007c, 0x127e, 0x027e, + 0x788b, 0x0048, 0x15a5, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, + 0x00c0, 0x15ac, 0x1078, 0x16ad, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, 0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, 0x0d7e, 0x0c7e, 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, - 0xa005, 0x0040, 0x1608, 0x6808, 0xa005, 0x0040, 0x166e, 0x7000, - 0xa005, 0x00c0, 0x15d5, 0x0078, 0x1602, 0x700c, 0x7110, 0xa106, - 0x00c0, 0x1672, 0x7004, 0xa406, 0x00c0, 0x1602, 0x2001, 0x0005, - 0x2004, 0xd08c, 0x0040, 0x15eb, 0x047e, 0x1078, 0x178d, 0x047f, - 0x2460, 0x0078, 0x15cb, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, - 0x15de, 0x7804, 0xa084, 0x6000, 0x0040, 0x15fc, 0xa086, 0x6000, - 0x0040, 0x15fc, 0x0078, 0x15de, 0x7803, 0x0004, 0x7003, 0x0000, - 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5c29, 0x0078, 0x1672, - 0x6808, 0xa005, 0x0040, 0x166e, 0x7000, 0xa005, 0x00c0, 0x1612, - 0x0078, 0x166e, 0x700c, 0x7110, 0xa106, 0x00c0, 0x161b, 0x7004, - 0xa406, 0x00c0, 0x166e, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, - 0x1628, 0x047e, 0x1078, 0x178d, 0x047f, 0x2460, 0x0078, 0x1608, - 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x161b, 0x2001, 0x0005, - 0x2004, 0xd08c, 0x00c0, 0x1621, 0x7804, 0xa084, 0x6000, 0x0040, - 0x163f, 0xa086, 0x6000, 0x0040, 0x163f, 0x0078, 0x161b, 0x7007, - 0x0000, 0xa016, 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x1660, - 0xa08e, 0x0002, 0x00c0, 0x166e, 0x0c7e, 0x0e7e, 0x6818, 0x2060, - 0x1078, 0x1c59, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x165c, - 0x7308, 0x720c, 0x0078, 0x165e, 0x7310, 0x7214, 0x0e7f, 0x0c7f, + 0xa005, 0x0040, 0x1600, 0x6808, 0xa005, 0x0040, 0x1666, 0x7000, + 0xa005, 0x00c0, 0x15cd, 0x0078, 0x15fa, 0x700c, 0x7110, 0xa106, + 0x00c0, 0x166a, 0x7004, 0xa406, 0x00c0, 0x15fa, 0x2001, 0x0005, + 0x2004, 0xd08c, 0x0040, 0x15e3, 0x047e, 0x1078, 0x1785, 0x047f, + 0x2460, 0x0078, 0x15c3, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, + 0x15d6, 0x7804, 0xa084, 0x6000, 0x0040, 0x15f4, 0xa086, 0x6000, + 0x0040, 0x15f4, 0x0078, 0x15d6, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5c21, 0x0078, 0x166a, + 0x6808, 0xa005, 0x0040, 0x1666, 0x7000, 0xa005, 0x00c0, 0x160a, + 0x0078, 0x1666, 0x700c, 0x7110, 0xa106, 0x00c0, 0x1613, 0x7004, + 0xa406, 0x00c0, 0x1666, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, + 0x1620, 0x047e, 0x1078, 0x1785, 0x047f, 0x2460, 0x0078, 0x1600, + 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1613, 0x2001, 0x0005, + 0x2004, 0xd08c, 0x00c0, 0x1619, 0x7804, 0xa084, 0x6000, 0x0040, + 0x1637, 0xa086, 0x6000, 0x0040, 0x1637, 0x0078, 0x1613, 0x7007, + 0x0000, 0xa016, 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x1658, + 0xa08e, 0x0002, 0x00c0, 0x1666, 0x0c7e, 0x0e7e, 0x6818, 0x2060, + 0x1078, 0x1c53, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x1654, + 0x7308, 0x720c, 0x0078, 0x1656, 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, 0x7824, 0xa211, 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, - 0x2071, 0x786a, 0x7000, 0xa086, 0x0000, 0x0040, 0x16b2, 0x7004, - 0xac06, 0x00c0, 0x16a3, 0x2079, 0x0030, 0x7804, 0xd0fc, 0x00c0, - 0x169f, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1685, 0x7803, - 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1691, 0x7803, 0x0002, 0x7803, - 0x0009, 0x7003, 0x0003, 0x7007, 0x0000, 0x0078, 0x16a3, 0x1078, - 0x178d, 0x0078, 0x167a, 0x157e, 0x20a9, 0x0009, 0x2009, 0x7870, - 0x2104, 0xac06, 0x00c0, 0x16ad, 0x200a, 0xa188, 0x0003, 0x00f0, - 0x16a8, 0x157f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, 0x7110, 0xa106, - 0x00c0, 0x16bd, 0x7003, 0x0000, 0x007c, 0x2104, 0x7006, 0x2060, + 0x1078, 0x5c21, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0x786a, 0x7000, 0xa086, 0x0000, 0x0040, 0x16aa, 0x7004, + 0xac06, 0x00c0, 0x169b, 0x2079, 0x0030, 0x7804, 0xd0fc, 0x00c0, + 0x1697, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x167d, 0x7803, + 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1689, 0x7803, 0x0002, 0x7803, + 0x0009, 0x7003, 0x0003, 0x7007, 0x0000, 0x0078, 0x169b, 0x1078, + 0x1785, 0x0078, 0x1672, 0x157e, 0x20a9, 0x0009, 0x2009, 0x7870, + 0x2104, 0xac06, 0x00c0, 0x16a5, 0x200a, 0xa188, 0x0003, 0x00f0, + 0x16a0, 0x157f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, 0x7110, 0xa106, + 0x00c0, 0x16b5, 0x7003, 0x0000, 0x007c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, 0x788b, 0x0048, - 0x16cb, 0x2009, 0x7870, 0x7112, 0x8cff, 0x00c0, 0x16d3, 0x1078, - 0x1958, 0x0078, 0x16fa, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, - 0x00c0, 0x16de, 0x682c, 0xa306, 0x0040, 0x16e2, 0x1078, 0x1ca4, - 0x00c0, 0x16cf, 0x684c, 0xd0f4, 0x00c0, 0x16cf, 0x6824, 0x2050, + 0x16c3, 0x2009, 0x7870, 0x7112, 0x8cff, 0x00c0, 0x16cb, 0x1078, + 0x1950, 0x0078, 0x16f2, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, + 0x00c0, 0x16d6, 0x682c, 0xa306, 0x0040, 0x16da, 0x1078, 0x1c9e, + 0x00c0, 0x16c7, 0x684c, 0xd0f4, 0x00c0, 0x16c7, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009, - 0x0011, 0x1078, 0x16fb, 0x0040, 0x16f9, 0x2009, 0x0001, 0x1078, - 0x16fb, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x1788, 0xa03e, 0x2730, - 0x6850, 0xd0fc, 0x00c0, 0x171a, 0x0d7e, 0x2804, 0xac68, 0x2900, - 0x0079, 0x170a, 0x176a, 0x172a, 0x172a, 0x176a, 0x176a, 0x1762, - 0x176a, 0x172a, 0x176a, 0x1730, 0x1730, 0x176a, 0x176a, 0x176a, - 0x1759, 0x1730, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, - 0x0d7e, 0xd99c, 0x0040, 0x176d, 0x2804, 0xac68, 0x6f08, 0x6e0c, - 0x0078, 0x176d, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x176d, - 0x7b0c, 0xd3bc, 0x0040, 0x1751, 0x7004, 0x0e7e, 0x2070, 0x701c, - 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1751, 0x7b08, 0xa39c, 0x0fff, - 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, 0x00c0, 0x174c, 0x6810, - 0xa302, 0x0048, 0x174c, 0x6b10, 0x2011, 0x0000, 0x2468, 0x0078, - 0x1753, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, - 0x176d, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, - 0x00c0, 0x176a, 0x0d7f, 0x1078, 0x1c40, 0x00c0, 0x16fb, 0xa00e, - 0x0078, 0x1788, 0x0d7f, 0x1078, 0x12d5, 0x7b22, 0x7a26, 0x7d32, + 0x0011, 0x1078, 0x16f3, 0x0040, 0x16f1, 0x2009, 0x0001, 0x1078, + 0x16f3, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x1780, 0xa03e, 0x2730, + 0x6850, 0xd0fc, 0x00c0, 0x1712, 0x0d7e, 0x2804, 0xac68, 0x2900, + 0x0079, 0x1702, 0x1762, 0x1722, 0x1722, 0x1762, 0x1762, 0x175a, + 0x1762, 0x1722, 0x1762, 0x1728, 0x1728, 0x1762, 0x1762, 0x1762, + 0x1751, 0x1728, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, + 0x0d7e, 0xd99c, 0x0040, 0x1765, 0x2804, 0xac68, 0x6f08, 0x6e0c, + 0x0078, 0x1765, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1765, + 0x7b0c, 0xd3bc, 0x0040, 0x1749, 0x7004, 0x0e7e, 0x2070, 0x701c, + 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1749, 0x7b08, 0xa39c, 0x0fff, + 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, 0x00c0, 0x1744, 0x6810, + 0xa302, 0x0048, 0x1744, 0x6b10, 0x2011, 0x0000, 0x2468, 0x0078, + 0x174b, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, + 0x1765, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, + 0x00c0, 0x1762, 0x0d7f, 0x1078, 0x1c3a, 0x00c0, 0x16f3, 0xa00e, + 0x0078, 0x1780, 0x0d7f, 0x1078, 0x12cd, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x2300, 0x6b10, - 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, 0x6816, 0x1078, 0x1c40, - 0x007c, 0x1078, 0x12d5, 0x1078, 0x12d5, 0x127e, 0x2091, 0x2100, + 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, 0x6816, 0x1078, 0x1c3a, + 0x007c, 0x1078, 0x12cd, 0x1078, 0x12cd, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, - 0xa184, 0x0700, 0x00c0, 0x178b, 0xa184, 0x0003, 0xa086, 0x0003, - 0x0040, 0x178b, 0x7000, 0x0079, 0x17a5, 0x17ad, 0x17af, 0x1887, - 0x18ef, 0x1906, 0x17ad, 0x17ad, 0x17ad, 0x1078, 0x12d5, 0x8001, - 0x7002, 0xa184, 0x0880, 0x00c0, 0x17c4, 0x8aff, 0x0040, 0x1827, - 0x2009, 0x0001, 0x1078, 0x16fb, 0x0040, 0x1918, 0x2009, 0x0001, - 0x1078, 0x16fb, 0x0078, 0x1918, 0x7803, 0x0004, 0x7003, 0x0000, - 0xd1bc, 0x00c0, 0x180f, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x7820, + 0xa184, 0x0700, 0x00c0, 0x1783, 0xa184, 0x0003, 0xa086, 0x0003, + 0x0040, 0x1783, 0x7000, 0x0079, 0x179d, 0x17a5, 0x17a7, 0x187f, + 0x18e7, 0x18fe, 0x17a5, 0x17a5, 0x17a5, 0x1078, 0x12cd, 0x8001, + 0x7002, 0xa184, 0x0880, 0x00c0, 0x17bc, 0x8aff, 0x0040, 0x181f, + 0x2009, 0x0001, 0x1078, 0x16f3, 0x0040, 0x1910, 0x2009, 0x0001, + 0x1078, 0x16f3, 0x0078, 0x1910, 0x7803, 0x0004, 0x7003, 0x0000, + 0xd1bc, 0x00c0, 0x1807, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x7820, 0x6910, 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x037f, - 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c59, 0x2a00, + 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c53, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x6850, - 0xc0fd, 0x6852, 0x6808, 0x8001, 0x680a, 0x00c0, 0x1801, 0x684c, - 0xd0e4, 0x0040, 0x1801, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, - 0x5c29, 0x7808, 0xd0ec, 0x00c0, 0x180b, 0x7803, 0x0009, 0x7003, - 0x0004, 0x0078, 0x1918, 0x1078, 0x16b5, 0x0078, 0x1918, 0x057e, - 0x7d0c, 0xd5bc, 0x00c0, 0x1816, 0x1078, 0x7592, 0x057f, 0x1078, - 0x191c, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, - 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x684c, - 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x183f, 0x7003, 0x0000, - 0x6808, 0x8001, 0x680a, 0x00c0, 0x183b, 0x7004, 0x2060, 0x2009, - 0x0048, 0x1078, 0x5c29, 0x1078, 0x16b5, 0x0078, 0x1918, 0x7814, + 0xc0fd, 0x6852, 0x6808, 0x8001, 0x680a, 0x00c0, 0x17f9, 0x684c, + 0xd0e4, 0x0040, 0x17f9, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, + 0x5c21, 0x7808, 0xd0ec, 0x00c0, 0x1803, 0x7803, 0x0009, 0x7003, + 0x0004, 0x0078, 0x1910, 0x1078, 0x16ad, 0x0078, 0x1910, 0x057e, + 0x7d0c, 0xd5bc, 0x00c0, 0x180e, 0x1078, 0x7587, 0x057f, 0x1078, + 0x1914, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, + 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x684c, + 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x1837, 0x7003, 0x0000, + 0x6808, 0x8001, 0x680a, 0x00c0, 0x1833, 0x7004, 0x2060, 0x2009, + 0x0048, 0x1078, 0x5c21, 0x1078, 0x16ad, 0x0078, 0x1910, 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, - 0x1078, 0x1983, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, - 0x7804, 0xd0fc, 0x0040, 0x1860, 0x7803, 0x0002, 0x7803, 0x0004, + 0x1078, 0x197b, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, + 0x7804, 0xd0fc, 0x0040, 0x1858, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x0070, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x1078, 0x19a6, 0x0040, 0x183b, 0x7908, 0xd1ec, - 0x00c0, 0x187e, 0x2009, 0x0009, 0x0078, 0x1880, 0x2009, 0x0019, - 0x7902, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x8001, - 0x7002, 0xd194, 0x0040, 0x1899, 0x7804, 0xd0fc, 0x00c0, 0x1795, - 0x8aff, 0x0040, 0x1918, 0x2009, 0x0001, 0x1078, 0x16fb, 0x0078, - 0x1918, 0xa184, 0x0880, 0x00c0, 0x18a6, 0x8aff, 0x0040, 0x1918, - 0x2009, 0x0001, 0x1078, 0x16fb, 0x0078, 0x1918, 0x7803, 0x0004, - 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x18da, 0x027e, 0x037e, 0x6b28, - 0x6a2c, 0x1078, 0x1c59, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, 0xac68, - 0x6034, 0xd09c, 0x00c0, 0x18ca, 0x6808, 0x2008, 0xa31a, 0x680c, + 0x1078, 0x5c21, 0x1078, 0x199e, 0x0040, 0x1833, 0x7908, 0xd1ec, + 0x00c0, 0x1876, 0x2009, 0x0009, 0x0078, 0x1878, 0x2009, 0x0019, + 0x7902, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x8001, + 0x7002, 0xd194, 0x0040, 0x1891, 0x7804, 0xd0fc, 0x00c0, 0x178d, + 0x8aff, 0x0040, 0x1910, 0x2009, 0x0001, 0x1078, 0x16f3, 0x0078, + 0x1910, 0xa184, 0x0880, 0x00c0, 0x189e, 0x8aff, 0x0040, 0x1910, + 0x2009, 0x0001, 0x1078, 0x16f3, 0x0078, 0x1910, 0x7803, 0x0004, + 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x18d2, 0x027e, 0x037e, 0x6b28, + 0x6a2c, 0x1078, 0x1c53, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, 0xac68, + 0x6034, 0xd09c, 0x00c0, 0x18c2, 0x6808, 0x2008, 0xa31a, 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, 0x7816, - 0x0078, 0x18d6, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, 0x7810, + 0x0078, 0x18ce, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, 0x7816, 0x0f7f, 0x0d7f, - 0x0078, 0x17cf, 0x057e, 0x7d0c, 0x1078, 0x7592, 0x057f, 0x1078, - 0x191c, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, - 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x7803, - 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0040, 0x1902, 0x6808, - 0x8001, 0x680a, 0x00c0, 0x1902, 0x7004, 0x2060, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x1078, 0x16b5, 0x0078, 0x1918, 0x7803, 0x0004, - 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0040, 0x1902, - 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x16cc, - 0x017f, 0x007f, 0x127f, 0x007c, 0x1078, 0x192d, 0x20e1, 0x9028, + 0x0078, 0x17c7, 0x057e, 0x7d0c, 0x1078, 0x7587, 0x057f, 0x1078, + 0x1914, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, + 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x7803, + 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0040, 0x18fa, 0x6808, + 0x8001, 0x680a, 0x00c0, 0x18fa, 0x7004, 0x2060, 0x2009, 0x0048, + 0x1078, 0x5c21, 0x1078, 0x16ad, 0x0078, 0x1910, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0040, 0x18fa, + 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x16c4, + 0x017f, 0x007f, 0x127f, 0x007c, 0x1078, 0x1925, 0x20e1, 0x9028, 0x700f, 0x7870, 0x7013, 0x7870, 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x2001, 0x0138, 0x2202, 0x007c, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, - 0x00c0, 0x194a, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, - 0x194a, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, 0x194a, 0x8421, - 0x00c0, 0x1934, 0x007c, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, - 0xa005, 0x00c0, 0x1957, 0x8109, 0x00c0, 0x194f, 0x007c, 0x007c, - 0x1078, 0x194b, 0x0040, 0x1980, 0x7908, 0xd1ec, 0x00c0, 0x1970, - 0x1078, 0x19a6, 0x0040, 0x1970, 0x7803, 0x0009, 0x7904, 0xd1fc, - 0x0040, 0x1966, 0x7803, 0x0006, 0x1078, 0x194b, 0x0040, 0x1980, - 0x780c, 0xd0a4, 0x00c0, 0x1980, 0x7007, 0x0000, 0x1078, 0x19a6, - 0x0040, 0x1982, 0x7803, 0x0019, 0x7003, 0x0003, 0x0078, 0x1982, - 0x1078, 0x191c, 0x007c, 0x3c00, 0x007e, 0x0e7e, 0x2071, 0x0200, - 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x192d, 0x20e1, 0x7000, + 0x00c0, 0x1942, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, + 0x1942, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, 0x1942, 0x8421, + 0x00c0, 0x192c, 0x007c, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, + 0xa005, 0x00c0, 0x194f, 0x8109, 0x00c0, 0x1947, 0x007c, 0x007c, + 0x1078, 0x1943, 0x0040, 0x1978, 0x7908, 0xd1ec, 0x00c0, 0x1968, + 0x1078, 0x199e, 0x0040, 0x1968, 0x7803, 0x0009, 0x7904, 0xd1fc, + 0x0040, 0x195e, 0x7803, 0x0006, 0x1078, 0x1943, 0x0040, 0x1978, + 0x780c, 0xd0a4, 0x00c0, 0x1978, 0x7007, 0x0000, 0x1078, 0x199e, + 0x0040, 0x197a, 0x7803, 0x0019, 0x7003, 0x0003, 0x0078, 0x197a, + 0x1078, 0x1914, 0x007c, 0x3c00, 0x007e, 0x0e7e, 0x2071, 0x0200, + 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1925, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x0e7f, 0x007f, 0x20e0, 0x007c, 0x3c00, 0x007e, - 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x19b3, 0xa085, - 0x0001, 0x0078, 0x19c5, 0x2001, 0x020a, 0x81ff, 0x0040, 0x19be, + 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x19ab, 0xa085, + 0x0001, 0x0078, 0x19bd, 0x2001, 0x020a, 0x81ff, 0x0040, 0x19b6, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x007f, 0x20e0, 0x007c, 0x0e7e, 0x2071, 0x788b, 0x7003, 0x0000, 0x0e7f, 0x007c, 0x0d7e, - 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1a4a, 0x6934, - 0xa184, 0x0007, 0x0079, 0x19dc, 0x19e4, 0x1a35, 0x19e4, 0x19e4, - 0x19e4, 0x1a1a, 0x19f7, 0x19e6, 0x1078, 0x12d5, 0x684c, 0xd0b4, - 0x0040, 0x1b4c, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, - 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1a3d, 0x6834, - 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x19e4, 0x684c, 0xd0b4, - 0x0040, 0x1b4c, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, + 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1a42, 0x6934, + 0xa184, 0x0007, 0x0079, 0x19d4, 0x19dc, 0x1a2d, 0x19dc, 0x19dc, + 0x19dc, 0x1a12, 0x19ef, 0x19de, 0x1078, 0x12cd, 0x684c, 0xd0b4, + 0x0040, 0x1b46, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, + 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1a35, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x19dc, 0x684c, 0xd0b4, + 0x0040, 0x1b46, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, - 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6958, - 0x0078, 0x1a46, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, 0x1a4a, - 0x684c, 0xd0b4, 0x0040, 0x1b4c, 0x6804, 0x681a, 0xa080, 0x000d, - 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6958, - 0xa006, 0x682e, 0x682a, 0x0078, 0x1a46, 0x684c, 0xd0b4, 0x0040, - 0x1789, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, - 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6926, 0x684c, + 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6958, + 0x0078, 0x1a3e, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, 0x1a42, + 0x684c, 0xd0b4, 0x0040, 0x1b46, 0x6804, 0x681a, 0xa080, 0x000d, + 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6958, + 0xa006, 0x682e, 0x682a, 0x0078, 0x1a3e, 0x684c, 0xd0b4, 0x0040, + 0x1781, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, + 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, 0x0f7e, 0x2079, 0x0020, 0x7804, - 0xd0fc, 0x10c0, 0x1b50, 0x0e7e, 0x0d7e, 0x2071, 0x788b, 0x7000, - 0xa005, 0x00c0, 0x1ac6, 0x0c7e, 0x7206, 0xa280, 0x0004, 0x205c, - 0x7004, 0x2068, 0x6818, 0x0d7e, 0x2068, 0x686c, 0x7812, 0x6890, - 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, - 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, 0x6824, 0x2050, 0x6818, - 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0xa184, - 0x0007, 0x0040, 0x1a88, 0x017e, 0x2009, 0x0008, 0xa102, 0x017f, - 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, 0x0000, 0x781e, - 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, - 0x00c0, 0x1a9f, 0x6928, 0x6810, 0xa106, 0x0040, 0x1aac, 0x037e, - 0x047e, 0x6b14, 0x6c10, 0x1078, 0x1ca4, 0x047f, 0x037f, 0x0040, - 0x1aac, 0x0c7f, 0x0078, 0x1ac6, 0x8aff, 0x00c0, 0x1ab4, 0x0c7f, - 0xa085, 0x0001, 0x0078, 0x1ac6, 0x127e, 0x2091, 0x8000, 0x2079, - 0x0020, 0x2009, 0x0001, 0x1078, 0x1aca, 0x0040, 0x1ac3, 0x2009, - 0x0001, 0x1078, 0x1aca, 0x127f, 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, - 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, 0x037e, 0x027e, - 0x8aff, 0x0040, 0x1b45, 0x700c, 0x7214, 0xa202, 0x7010, 0x7218, - 0xa203, 0x0048, 0x1b44, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, - 0x1af7, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1ae7, 0x1b26, - 0x1b07, 0x1b07, 0x1b26, 0x1b26, 0x1b1e, 0x1b26, 0x1b07, 0x1b26, - 0x1b0d, 0x1b0d, 0x1b26, 0x1b26, 0x1b26, 0x1b15, 0x1b0d, 0xc0fc, - 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1b2a, - 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x1b29, 0x6b08, - 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1b29, 0x6b10, 0x6a14, 0x6d00, - 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1b29, 0x0d7f, 0x0d7e, 0x6834, - 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1b26, 0x0d7f, 0x1078, - 0x1c40, 0x00c0, 0x1ad0, 0xa00e, 0x0078, 0x1b45, 0x0d7f, 0x1078, - 0x12d5, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, - 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, - 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, - 0x1078, 0x1c40, 0x0078, 0x1b45, 0xa006, 0x027f, 0x037f, 0x047f, - 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x12d5, 0x1078, 0x12d5, - 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, 0x0e7e, 0x0d7e, - 0x0c7e, 0x2079, 0x0020, 0x2071, 0x788b, 0x2b68, 0x6818, 0x2060, - 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, 0x1b4e, 0x7000, - 0x0079, 0x1b6a, 0x1c11, 0x1b6e, 0x1bde, 0x1c0f, 0x8001, 0x7002, - 0xd19c, 0x00c0, 0x1b82, 0x8aff, 0x0040, 0x1ba1, 0x2009, 0x0001, - 0x1078, 0x1aca, 0x0040, 0x1c11, 0x2009, 0x0001, 0x1078, 0x1aca, - 0x0078, 0x1c11, 0x7803, 0x0004, 0xd194, 0x0040, 0x1b92, 0x6850, - 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1b97, 0x684c, 0xc0f5, 0x684e, - 0x0078, 0x1b97, 0x1078, 0x1c59, 0x6850, 0xc0fd, 0x6852, 0x2a00, - 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0078, - 0x1c11, 0x711c, 0x81ff, 0x0040, 0x1bb7, 0x7918, 0x7922, 0x7827, - 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, 0x700c, 0xa100, - 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, 0x1c11, 0x0f7e, - 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, - 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x7820, 0xd0bc, 0x00c0, - 0x1bc5, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, 0x007f, 0xa102, - 0x78c6, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, - 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1c11, 0x8001, 0x7002, - 0xd194, 0x0040, 0x1bf3, 0x7804, 0xd0fc, 0x00c0, 0x1b60, 0xd19c, - 0x00c0, 0x1c0d, 0x8aff, 0x0040, 0x1c11, 0x2009, 0x0001, 0x1078, - 0x1aca, 0x0078, 0x1c11, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, - 0x1c59, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1c06, - 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1c0a, 0x6810, 0xa31a, - 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1b92, 0x0078, 0x1b92, 0x1078, - 0x12d5, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, - 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x788b, 0x7000, 0xa086, 0x0000, - 0x0040, 0x1c3d, 0x2079, 0x0020, 0x20e1, 0x9040, 0x7804, 0xd0fc, - 0x0040, 0x1c24, 0x1078, 0x1b50, 0x7000, 0xa086, 0x0000, 0x00c0, - 0x1c24, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1c33, 0x20e1, - 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, - 0x8840, 0x2804, 0xa005, 0x00c0, 0x1c54, 0x6004, 0xa005, 0x0040, - 0x1c56, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x1c84, - 0x2044, 0x88ff, 0x1040, 0x12d5, 0x8a51, 0x007c, 0x2051, 0x0000, - 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x1c73, 0x2c00, - 0xad06, 0x0040, 0x1c68, 0x6000, 0xa005, 0x00c0, 0x1c68, 0x2d00, - 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x1c94, 0x2044, - 0x88ff, 0x1040, 0x12d5, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, - 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, - 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x1c79, 0x1c75, 0x0000, - 0x0000, 0x1c83, 0x0000, 0x1c79, 0x0000, 0x1c80, 0x1c7d, 0x0000, - 0x0000, 0x0000, 0x1c83, 0x1c80, 0x0000, 0x1c7b, 0x1c7b, 0x0000, - 0x0000, 0x1c83, 0x0000, 0x1c7b, 0x0000, 0x1c81, 0x1c81, 0x0000, - 0x0000, 0x0000, 0x1c83, 0x1c81, 0x0a7e, 0x097e, 0x087e, 0x6858, - 0xa055, 0x0040, 0x1d45, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, - 0x1c84, 0xa986, 0x0007, 0x0040, 0x1cbd, 0xa986, 0x000e, 0x0040, - 0x1cbd, 0xa986, 0x000f, 0x00c0, 0x1cc1, 0x605c, 0xa422, 0x6060, - 0xa31a, 0x2804, 0xa045, 0x00c0, 0x1ccf, 0x0050, 0x1cc9, 0x0078, - 0x1d45, 0x6004, 0xa065, 0x0040, 0x1d45, 0x0078, 0x1cac, 0x2804, - 0xa005, 0x0040, 0x1ced, 0xac68, 0xd99c, 0x00c0, 0x1cdd, 0x6808, - 0xa422, 0x680c, 0xa31b, 0x0078, 0x1ce1, 0x6810, 0xa422, 0x6814, - 0xa31b, 0x0048, 0x1d0c, 0x2300, 0xa405, 0x0040, 0x1cf3, 0x8a51, - 0x0040, 0x1d45, 0x8840, 0x0078, 0x1ccf, 0x6004, 0xa065, 0x0040, - 0x1d45, 0x0078, 0x1cac, 0x8a51, 0x0040, 0x1d45, 0x8840, 0x2804, - 0xa005, 0x00c0, 0x1d06, 0x6004, 0xa065, 0x0040, 0x1d45, 0x6034, - 0xa0cc, 0x000f, 0xa9c0, 0x1c84, 0x2804, 0x2040, 0x2b68, 0x6850, - 0xc0fc, 0x6852, 0x0078, 0x1d39, 0x8422, 0x8420, 0x831a, 0xa399, - 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, 0x00c0, - 0x1d27, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1048, - 0x12d5, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x1d33, 0x6910, - 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x12d5, 0x6800, - 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd, - 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x007f, - 0x007f, 0x007f, 0xa006, 0x0078, 0x1d4a, 0x087f, 0x097f, 0x0a7f, - 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, 0xa084, 0x0007, - 0x0079, 0x1d52, 0x1d5a, 0x1d5b, 0x1d5e, 0x1d61, 0x1d66, 0x1d69, - 0x1d6e, 0x1d73, 0x007c, 0x1078, 0x1b50, 0x007c, 0x1078, 0x178d, - 0x007c, 0x1078, 0x178d, 0x1078, 0x1b50, 0x007c, 0x1078, 0x145e, - 0x007c, 0x1078, 0x1b50, 0x1078, 0x145e, 0x007c, 0x1078, 0x178d, - 0x1078, 0x145e, 0x007c, 0x1078, 0x178d, 0x1078, 0x1b50, 0x1078, - 0x145e, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, 0x0200, 0x2071, - 0x7b80, 0x2069, 0x7600, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, - 0x1078, 0x2058, 0x781b, 0x0002, 0x20e1, 0x8700, 0x127f, 0x007c, - 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, 0x0079, 0x1d98, - 0x1dbc, 0x1da0, 0x1da4, 0x1da8, 0x1dae, 0x1db2, 0x1db6, 0x1dba, - 0x1078, 0x417d, 0x0078, 0x1dbc, 0x1078, 0x41ac, 0x0078, 0x1dbc, - 0x1078, 0x417d, 0x1078, 0x41ac, 0x0078, 0x1dbc, 0x1078, 0x1dbe, - 0x0078, 0x1dbc, 0x1078, 0x1dbe, 0x0078, 0x1dbc, 0x1078, 0x1dbe, - 0x0078, 0x1dbc, 0x1078, 0x1dbe, 0x127f, 0x007c, 0x007e, 0x017e, - 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, 0x1dc8, 0x1078, 0x12d5, - 0xa184, 0x0030, 0x0040, 0x1dd9, 0x6a00, 0xa286, 0x0003, 0x00c0, - 0x1dd3, 0x1078, 0x12d5, 0x1078, 0x357b, 0x20e1, 0x9010, 0x0078, - 0x1de5, 0xa184, 0x00c0, 0x0040, 0x1ddf, 0x1078, 0x12d5, 0xa184, - 0x0300, 0x0040, 0x1de5, 0x20e1, 0x9020, 0x7932, 0x027f, 0x017f, - 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, 0x7600, 0x7128, - 0x2001, 0x7823, 0x2102, 0x2001, 0x782b, 0x2102, 0xa182, 0x0211, - 0x00c8, 0x1dfe, 0x2009, 0x0008, 0x0078, 0x1e28, 0xa182, 0x0259, - 0x00c8, 0x1e06, 0x2009, 0x0007, 0x0078, 0x1e28, 0xa182, 0x02c1, - 0x00c8, 0x1e0e, 0x2009, 0x0006, 0x0078, 0x1e28, 0xa182, 0x0349, - 0x00c8, 0x1e16, 0x2009, 0x0005, 0x0078, 0x1e28, 0xa182, 0x0421, - 0x00c8, 0x1e1e, 0x2009, 0x0004, 0x0078, 0x1e28, 0xa182, 0x0581, - 0x00c8, 0x1e26, 0x2009, 0x0003, 0x0078, 0x1e28, 0x2009, 0x0002, - 0x2079, 0x0200, 0x7912, 0xa182, 0x0005, 0x00c8, 0x1e32, 0x7916, - 0x0078, 0x1e34, 0x7817, 0x0004, 0x1078, 0x2058, 0x0f7f, 0x0e7f, - 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, 0x0100, 0x2071, - 0x7600, 0x6024, 0x6026, 0x6033, 0x00ef, 0x60e7, 0x0000, 0x60eb, - 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, - 0x0080, 0x602f, 0x0000, 0x6007, 0x0caf, 0x600f, 0x00ff, 0x602b, - 0x002f, 0x127f, 0x007c, 0x2001, 0x762d, 0x2003, 0x0000, 0x2001, - 0x762c, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x007e, - 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, 0x1e73, 0xa184, - 0x0007, 0x0079, 0x1e79, 0xa195, 0x0004, 0xa284, 0x0007, 0x0079, - 0x1e79, 0x1ea5, 0x1e81, 0x1e85, 0x1e89, 0x1e8f, 0x1e93, 0x1e99, - 0x1e9f, 0x1078, 0x46e6, 0x0078, 0x1ea5, 0x1078, 0x47d5, 0x0078, - 0x1ea5, 0x1078, 0x47d5, 0x1078, 0x46e6, 0x0078, 0x1ea5, 0x1078, - 0x1eaa, 0x0078, 0x1ea5, 0x1078, 0x46e6, 0x1078, 0x1eaa, 0x0078, - 0x1ea5, 0x1078, 0x47d5, 0x1078, 0x1eaa, 0x0078, 0x1ea5, 0x1078, - 0x47d5, 0x1078, 0x46e6, 0x1078, 0x1eaa, 0x027f, 0x017f, 0x007f, - 0x127f, 0x007c, 0xd1ac, 0x0040, 0x1f5e, 0x017e, 0x047e, 0x0c7e, - 0x644c, 0x74ba, 0xa48c, 0xff00, 0xa196, 0xff00, 0x0040, 0x1ed9, - 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, 0x1ed9, 0x7130, - 0xd18c, 0x00c0, 0x1ed9, 0x2011, 0x7652, 0x2214, 0xd2ec, 0x0040, - 0x1ecd, 0xc18d, 0x7132, 0x0078, 0x1ed9, 0x6240, 0xa294, 0x0010, - 0x0040, 0x1f1b, 0x6248, 0xa294, 0xff00, 0xa296, 0xff00, 0x00c0, - 0x1f1b, 0x037e, 0x73b8, 0x2011, 0x8013, 0x1078, 0x2d4a, 0x037f, - 0x7130, 0xc185, 0x7132, 0x2011, 0x7652, 0x220c, 0xd1a4, 0x0040, - 0x1f03, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x46b4, - 0x2019, 0x000e, 0x1078, 0x74d9, 0xa484, 0x00ff, 0xa080, 0x232f, - 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, - 0x1078, 0x7541, 0x017f, 0xd1ac, 0x00c0, 0x1f0c, 0x2019, 0x0004, - 0x1078, 0x2299, 0x0078, 0x1f1b, 0x157e, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x1078, 0x3825, 0x00c0, 0x1f17, 0x1078, 0x3621, 0x8108, - 0x00f0, 0x1f11, 0x157f, 0x0c7f, 0x047f, 0x6043, 0x0000, 0x2009, - 0x00f7, 0x1078, 0x35e4, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, - 0x0000, 0x0040, 0x1f33, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, - 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, 0x1078, 0x57c0, - 0x2011, 0x0002, 0x1078, 0x57ca, 0x1078, 0x56d6, 0x1078, 0x45eb, - 0x037e, 0x2019, 0x0000, 0x1078, 0x5768, 0x037f, 0x60e3, 0x0000, - 0x017f, 0x2001, 0x7600, 0x2014, 0xa296, 0x0004, 0x00c0, 0x1f56, - 0xd19c, 0x00c0, 0x1f56, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, - 0x2001, 0x7620, 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, - 0x1fff, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, 0x0001, 0x00c0, - 0x1f82, 0x017e, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, - 0x7803, 0x1000, 0x7803, 0x0000, 0x2079, 0x7836, 0x7807, 0x0000, - 0x7833, 0x0000, 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x017f, 0x0f7f, - 0x0078, 0x1fff, 0x0f7f, 0x017e, 0x6220, 0xd2b4, 0x0040, 0x1fb7, - 0x1078, 0x45eb, 0x1078, 0x5582, 0x6027, 0x0004, 0x0d7e, 0x2069, - 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1f9a, 0x6803, 0x1000, - 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0x7836, 0x6028, 0xa09a, - 0x0002, 0x00c8, 0x1faa, 0x8000, 0x602a, 0x0c7f, 0x1078, 0x5574, - 0x0078, 0x1ffe, 0x2019, 0x783f, 0x2304, 0xa065, 0x0040, 0x1fb4, - 0x2009, 0x0027, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x1ffe, 0xd2bc, - 0x0040, 0x1ffe, 0x1078, 0x45f9, 0x6017, 0x0010, 0x6027, 0x0004, - 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1fcc, + 0xd0fc, 0x10c0, 0x1b4a, 0x0e7e, 0x0d7e, 0x2071, 0x788b, 0x7000, + 0xa005, 0x00c0, 0x1ac0, 0x0c7e, 0x7206, 0xa280, 0x0004, 0x205c, + 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x0d7e, 0x2068, 0x686c, + 0x7812, 0x6890, 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, + 0x2079, 0x0100, 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x6908, 0xa184, 0x0007, 0x0040, 0x1a82, 0x017e, 0x2009, 0x0008, + 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, + 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, + 0x6814, 0xa106, 0x00c0, 0x1a99, 0x6928, 0x6810, 0xa106, 0x0040, + 0x1aa6, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, 0x1c9e, 0x047f, + 0x037f, 0x0040, 0x1aa6, 0x0c7f, 0x0078, 0x1ac0, 0x8aff, 0x00c0, + 0x1aae, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x1ac0, 0x127e, 0x2091, + 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, 0x1ac4, 0x0040, + 0x1abd, 0x2009, 0x0001, 0x1078, 0x1ac4, 0x127f, 0x0c7f, 0xa006, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, + 0x037e, 0x027e, 0x8aff, 0x0040, 0x1b3f, 0x700c, 0x7214, 0xa202, + 0x7010, 0x7218, 0xa203, 0x0048, 0x1b3e, 0xa03e, 0x2730, 0x6850, + 0xd0fc, 0x00c0, 0x1af1, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, + 0x1ae1, 0x1b20, 0x1b01, 0x1b01, 0x1b20, 0x1b20, 0x1b18, 0x1b20, + 0x1b01, 0x1b20, 0x1b07, 0x1b07, 0x1b20, 0x1b20, 0x1b20, 0x1b0f, + 0x1b07, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, + 0x0040, 0x1b24, 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, + 0x1b23, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1b23, 0x6b10, + 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1b23, 0x0d7f, + 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1b20, + 0x0d7f, 0x1078, 0x1c3a, 0x00c0, 0x1aca, 0xa00e, 0x0078, 0x1b3f, + 0x0d7f, 0x1078, 0x12cd, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, + 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, + 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, + 0xa201, 0x7012, 0x1078, 0x1c3a, 0x0078, 0x1b3f, 0xa006, 0x027f, + 0x037f, 0x047f, 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x12cd, + 0x1078, 0x12cd, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, + 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0x788b, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, + 0x1b48, 0x7000, 0x0079, 0x1b64, 0x1c0b, 0x1b68, 0x1bd8, 0x1c09, + 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1b7c, 0x8aff, 0x0040, 0x1b9b, + 0x2009, 0x0001, 0x1078, 0x1ac4, 0x0040, 0x1c0b, 0x2009, 0x0001, + 0x1078, 0x1ac4, 0x0078, 0x1c0b, 0x7803, 0x0004, 0xd194, 0x0040, + 0x1b8c, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1b91, 0x684c, + 0xc0f5, 0x684e, 0x0078, 0x1b91, 0x1078, 0x1c53, 0x6850, 0xc0fd, + 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, + 0x0000, 0x0078, 0x1c0b, 0x711c, 0x81ff, 0x0040, 0x1bb1, 0x7918, + 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, + 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, + 0x1c0b, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, + 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x7820, + 0xd0bc, 0x00c0, 0x1bbf, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, + 0x007f, 0xa102, 0x78c6, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, + 0x027f, 0x0f7f, 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1c0b, + 0x8001, 0x7002, 0xd194, 0x0040, 0x1bed, 0x7804, 0xd0fc, 0x00c0, + 0x1b5a, 0xd19c, 0x00c0, 0x1c07, 0x8aff, 0x0040, 0x1c0b, 0x2009, + 0x0001, 0x1078, 0x1ac4, 0x0078, 0x1c0b, 0x027e, 0x037e, 0x6b28, + 0x6a2c, 0x1078, 0x1c53, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, + 0x00c0, 0x1c00, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1c04, + 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1b8c, 0x0078, + 0x1b8c, 0x1078, 0x12cd, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, + 0x007f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x788b, 0x7000, + 0xa086, 0x0000, 0x0040, 0x1c37, 0x2079, 0x0020, 0x20e1, 0x9040, + 0x7804, 0xd0fc, 0x0040, 0x1c1e, 0x1078, 0x1b4a, 0x7000, 0xa086, + 0x0000, 0x00c0, 0x1c1e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x1c2d, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, + 0x0f7f, 0x007c, 0x8840, 0x2804, 0xa005, 0x00c0, 0x1c4e, 0x6004, + 0xa005, 0x0040, 0x1c50, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, + 0xa080, 0x1c7e, 0x2044, 0x88ff, 0x1040, 0x12cd, 0x8a51, 0x007c, + 0x2051, 0x0000, 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, + 0x1c6d, 0x2c00, 0xad06, 0x0040, 0x1c62, 0x6000, 0xa005, 0x00c0, + 0x1c62, 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, + 0x1c8e, 0x2044, 0x88ff, 0x1040, 0x12cd, 0x007c, 0x0000, 0x0011, + 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, + 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x1c73, + 0x1c6f, 0x0000, 0x0000, 0x1c7d, 0x0000, 0x1c73, 0x0000, 0x1c7a, + 0x1c77, 0x0000, 0x0000, 0x0000, 0x1c7d, 0x1c7a, 0x0000, 0x1c75, + 0x1c75, 0x0000, 0x0000, 0x1c7d, 0x0000, 0x1c75, 0x0000, 0x1c7b, + 0x1c7b, 0x0000, 0x0000, 0x0000, 0x1c7d, 0x1c7b, 0x0a7e, 0x097e, + 0x087e, 0x6858, 0xa055, 0x0040, 0x1d3f, 0x2d60, 0x6034, 0xa0cc, + 0x000f, 0xa9c0, 0x1c7e, 0xa986, 0x0007, 0x0040, 0x1cb7, 0xa986, + 0x000e, 0x0040, 0x1cb7, 0xa986, 0x000f, 0x00c0, 0x1cbb, 0x605c, + 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x1cc9, 0x0050, + 0x1cc3, 0x0078, 0x1d3f, 0x6004, 0xa065, 0x0040, 0x1d3f, 0x0078, + 0x1ca6, 0x2804, 0xa005, 0x0040, 0x1ce7, 0xac68, 0xd99c, 0x00c0, + 0x1cd7, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x1cdb, 0x6810, + 0xa422, 0x6814, 0xa31b, 0x0048, 0x1d06, 0x2300, 0xa405, 0x0040, + 0x1ced, 0x8a51, 0x0040, 0x1d3f, 0x8840, 0x0078, 0x1cc9, 0x6004, + 0xa065, 0x0040, 0x1d3f, 0x0078, 0x1ca6, 0x8a51, 0x0040, 0x1d3f, + 0x8840, 0x2804, 0xa005, 0x00c0, 0x1d00, 0x6004, 0xa065, 0x0040, + 0x1d3f, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x1c7e, 0x2804, 0x2040, + 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0078, 0x1d33, 0x8422, 0x8420, + 0x831a, 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, + 0xd99c, 0x00c0, 0x1d21, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, + 0xa11b, 0x1048, 0x12cd, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, + 0x1d2d, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, + 0x12cd, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, + 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, + 0x6826, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x1d44, 0x087f, + 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, + 0xa084, 0x0007, 0x0079, 0x1d4c, 0x1d54, 0x1d55, 0x1d58, 0x1d5b, + 0x1d60, 0x1d63, 0x1d68, 0x1d6d, 0x007c, 0x1078, 0x1b4a, 0x007c, + 0x1078, 0x1785, 0x007c, 0x1078, 0x1785, 0x1078, 0x1b4a, 0x007c, + 0x1078, 0x1456, 0x007c, 0x1078, 0x1b4a, 0x1078, 0x1456, 0x007c, + 0x1078, 0x1785, 0x1078, 0x1456, 0x007c, 0x1078, 0x1785, 0x1078, + 0x1b4a, 0x1078, 0x1456, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, + 0x0200, 0x2071, 0x7b80, 0x2069, 0x7600, 0x2009, 0x0004, 0x7912, + 0x7817, 0x0004, 0x1078, 0x2052, 0x781b, 0x0002, 0x20e1, 0x8700, + 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, + 0x0079, 0x1d92, 0x1db6, 0x1d9a, 0x1d9e, 0x1da2, 0x1da8, 0x1dac, + 0x1db0, 0x1db4, 0x1078, 0x4175, 0x0078, 0x1db6, 0x1078, 0x41a4, + 0x0078, 0x1db6, 0x1078, 0x4175, 0x1078, 0x41a4, 0x0078, 0x1db6, + 0x1078, 0x1db8, 0x0078, 0x1db6, 0x1078, 0x1db8, 0x0078, 0x1db6, + 0x1078, 0x1db8, 0x0078, 0x1db6, 0x1078, 0x1db8, 0x127f, 0x007c, + 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, 0x1dc2, + 0x1078, 0x12cd, 0xa184, 0x0030, 0x0040, 0x1dd3, 0x6a00, 0xa286, + 0x0003, 0x00c0, 0x1dcd, 0x1078, 0x12cd, 0x1078, 0x3573, 0x20e1, + 0x9010, 0x0078, 0x1ddf, 0xa184, 0x00c0, 0x0040, 0x1dd9, 0x1078, + 0x12cd, 0xa184, 0x0300, 0x0040, 0x1ddf, 0x20e1, 0x9020, 0x7932, + 0x027f, 0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, + 0x7600, 0x7128, 0x2001, 0x7823, 0x2102, 0x2001, 0x782b, 0x2102, + 0xa182, 0x0211, 0x00c8, 0x1df8, 0x2009, 0x0008, 0x0078, 0x1e22, + 0xa182, 0x0259, 0x00c8, 0x1e00, 0x2009, 0x0007, 0x0078, 0x1e22, + 0xa182, 0x02c1, 0x00c8, 0x1e08, 0x2009, 0x0006, 0x0078, 0x1e22, + 0xa182, 0x0349, 0x00c8, 0x1e10, 0x2009, 0x0005, 0x0078, 0x1e22, + 0xa182, 0x0421, 0x00c8, 0x1e18, 0x2009, 0x0004, 0x0078, 0x1e22, + 0xa182, 0x0581, 0x00c8, 0x1e20, 0x2009, 0x0003, 0x0078, 0x1e22, + 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0xa182, 0x0005, 0x00c8, + 0x1e2c, 0x7916, 0x0078, 0x1e2e, 0x7817, 0x0004, 0x1078, 0x2052, + 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, + 0x0100, 0x2071, 0x7600, 0x6024, 0x6026, 0x6033, 0x00ef, 0x60e7, + 0x0000, 0x60eb, 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, + 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x0caf, 0x600f, + 0x00ff, 0x602b, 0x002f, 0x127f, 0x007c, 0x2001, 0x762d, 0x2003, + 0x0000, 0x2001, 0x762c, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, + 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, + 0x1e6d, 0xa184, 0x0007, 0x0079, 0x1e73, 0xa195, 0x0004, 0xa284, + 0x0007, 0x0079, 0x1e73, 0x1e9f, 0x1e7b, 0x1e7f, 0x1e83, 0x1e89, + 0x1e8d, 0x1e93, 0x1e99, 0x1078, 0x46de, 0x0078, 0x1e9f, 0x1078, + 0x47cd, 0x0078, 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x46de, 0x0078, + 0x1e9f, 0x1078, 0x1ea4, 0x0078, 0x1e9f, 0x1078, 0x46de, 0x1078, + 0x1ea4, 0x0078, 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x1ea4, 0x0078, + 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x46de, 0x1078, 0x1ea4, 0x027f, + 0x017f, 0x007f, 0x127f, 0x007c, 0xd1ac, 0x0040, 0x1f58, 0x017e, + 0x047e, 0x0c7e, 0x644c, 0x74ba, 0xa48c, 0xff00, 0xa196, 0xff00, + 0x0040, 0x1ed3, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, + 0x1ed3, 0x7130, 0xd18c, 0x00c0, 0x1ed3, 0x2011, 0x7652, 0x2214, + 0xd2ec, 0x0040, 0x1ec7, 0xc18d, 0x7132, 0x0078, 0x1ed3, 0x6240, + 0xa294, 0x0010, 0x0040, 0x1f15, 0x6248, 0xa294, 0xff00, 0xa296, + 0xff00, 0x00c0, 0x1f15, 0x037e, 0x73b8, 0x2011, 0x8013, 0x1078, + 0x2d3b, 0x037f, 0x7130, 0xc185, 0x7132, 0x2011, 0x7652, 0x220c, + 0xd1a4, 0x0040, 0x1efd, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, + 0x1078, 0x46ac, 0x2019, 0x000e, 0x1078, 0x74ce, 0xa484, 0x00ff, + 0xa080, 0x2329, 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, + 0x2009, 0x000e, 0x1078, 0x7536, 0x017f, 0xd1ac, 0x00c0, 0x1f06, + 0x2019, 0x0004, 0x1078, 0x2293, 0x0078, 0x1f15, 0x157e, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x1078, 0x381d, 0x00c0, 0x1f11, 0x1078, + 0x3619, 0x8108, 0x00f0, 0x1f0b, 0x157f, 0x0c7f, 0x047f, 0x6043, + 0x0000, 0x2009, 0x00f7, 0x1078, 0x35dc, 0x0f7e, 0x2079, 0x7849, + 0x783c, 0xa086, 0x0000, 0x0040, 0x1f2d, 0x6027, 0x0004, 0x783f, + 0x0000, 0x2079, 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, + 0x1078, 0x57b8, 0x2011, 0x0002, 0x1078, 0x57c2, 0x1078, 0x56ce, + 0x1078, 0x45e3, 0x037e, 0x2019, 0x0000, 0x1078, 0x5760, 0x037f, + 0x60e3, 0x0000, 0x017f, 0x2001, 0x7600, 0x2014, 0xa296, 0x0004, + 0x00c0, 0x1f50, 0xd19c, 0x00c0, 0x1f50, 0x6228, 0xc29d, 0x622a, + 0x2003, 0x0001, 0x2001, 0x7620, 0x2003, 0x0000, 0x6027, 0x0020, + 0xd194, 0x0040, 0x1ff9, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, + 0x0001, 0x00c0, 0x1f7c, 0x017e, 0x6027, 0x0004, 0x783f, 0x0000, + 0x2079, 0x0140, 0x7803, 0x1000, 0x7803, 0x0000, 0x2079, 0x7836, + 0x7807, 0x0000, 0x7833, 0x0000, 0x1078, 0x4c72, 0x1078, 0x4d32, + 0x017f, 0x0f7f, 0x0078, 0x1ff9, 0x0f7f, 0x017e, 0x6220, 0xd2b4, + 0x0040, 0x1fb1, 0x1078, 0x45e3, 0x1078, 0x557a, 0x6027, 0x0004, + 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1f94, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0x7836, - 0x6044, 0xa09a, 0x0002, 0x00c8, 0x1fed, 0x8000, 0x6046, 0x603c, - 0x0c7f, 0xa005, 0x0040, 0x1ffe, 0x1078, 0x45f0, 0xa080, 0x0007, - 0x2004, 0xa086, 0x0006, 0x00c0, 0x1fe9, 0x6017, 0x0012, 0x0078, - 0x1ffe, 0x6017, 0x0016, 0x0078, 0x1ffe, 0x037e, 0x2019, 0x0001, - 0x1078, 0x5768, 0x037f, 0x2019, 0x7845, 0x2304, 0xa065, 0x0040, - 0x1ffd, 0x2009, 0x004f, 0x1078, 0x5c29, 0x0c7f, 0x017f, 0xd19c, - 0x0040, 0x2027, 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, - 0x1078, 0x57c0, 0x2011, 0x0002, 0x1078, 0x57ca, 0x1078, 0x56d6, - 0x1078, 0x45eb, 0x037e, 0x2019, 0x0000, 0x1078, 0x5768, 0x037f, - 0x60e3, 0x0000, 0x1078, 0x75b0, 0x1078, 0x75ce, 0x2001, 0x7600, - 0x2003, 0x0004, 0x6027, 0x0008, 0x1078, 0x11c6, 0x017f, 0xa18c, - 0xffd0, 0x6126, 0x007c, 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, - 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x71b0, 0x70b2, 0xa116, - 0x0040, 0x2051, 0x81ff, 0x0040, 0x2043, 0x2011, 0x8011, 0x1078, - 0x2d4a, 0x0078, 0x2051, 0x2011, 0x8012, 0x1078, 0x2d4a, 0x037e, - 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, 0x1078, 0x2299, 0x0c7f, - 0x037f, 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, - 0x0c7e, 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x2073, - 0x2204, 0x60f2, 0xa192, 0x0005, 0x00c8, 0x206a, 0xa190, 0x207c, - 0x0078, 0x206c, 0x2011, 0x2080, 0x2204, 0x60ee, 0x027f, 0x007f, - 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, - 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, - 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0x2130, 0xa094, - 0xff00, 0x00c0, 0x208e, 0x81ff, 0x0040, 0x2092, 0x1078, 0x4330, - 0x0078, 0x2099, 0xa080, 0x232f, 0x200c, 0xa18c, 0xff00, 0x810f, - 0xa006, 0x007c, 0xa080, 0x232f, 0x200c, 0xa18c, 0x00ff, 0x007c, - 0x20c0, 0x20c4, 0x20c8, 0x20ce, 0x20d4, 0x20da, 0x20e0, 0x20e8, - 0x20f0, 0x20f6, 0x20fc, 0x2104, 0x210c, 0x2114, 0x211c, 0x2126, - 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, - 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, - 0x107e, 0x007e, 0x0078, 0x2149, 0x107e, 0x007e, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1e64, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d4b, 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x1078, 0x1d90, 0x0078, 0x2149, - 0x0005, 0x0078, 0x2130, 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, - 0x2139, 0x2149, 0x20c6, 0x20ca, 0x20d0, 0x20d6, 0x20dc, 0x20e2, - 0x20ea, 0x20f2, 0x20f8, 0x20fe, 0x2106, 0x210e, 0x2116, 0x211e, - 0x2128, 0x0008, 0x2133, 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, - 0x0c7e, 0x027e, 0x2041, 0x007e, 0x70bc, 0xd09c, 0x0040, 0x215a, - 0x2041, 0x007f, 0x2001, 0x010c, 0x203c, 0x727c, 0x82ff, 0x0040, - 0x21a5, 0x037e, 0x738c, 0xa38e, 0xffff, 0x00c0, 0x2169, 0x2019, - 0x0001, 0x8314, 0xa2e0, 0x7cc0, 0x2c04, 0xa38c, 0x0001, 0x0040, - 0x2176, 0xa084, 0xff00, 0x8007, 0x0078, 0x2178, 0xa084, 0x00ff, - 0xa70e, 0x0040, 0x219a, 0xa08e, 0x00ff, 0x0040, 0x21a0, 0x2009, - 0x0000, 0x1078, 0x2085, 0x1078, 0x37ee, 0x00c0, 0x219d, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2194, 0x1078, 0x21f7, - 0x0040, 0x219d, 0x0078, 0x219a, 0x1078, 0x22fb, 0x1078, 0x221e, - 0x0040, 0x219d, 0x8318, 0x0078, 0x2169, 0x738e, 0x0078, 0x21a2, - 0x708f, 0xffff, 0x037f, 0x0078, 0x21f4, 0xa780, 0x232f, 0x203c, - 0xa7bc, 0xff00, 0x873f, 0x708c, 0xa096, 0xffff, 0x0040, 0x21b7, - 0xa812, 0x00c8, 0x21c7, 0x708f, 0xffff, 0x0078, 0x21f1, 0x2009, - 0x0000, 0x70bc, 0xd09c, 0x0040, 0x21c2, 0xd094, 0x0040, 0x21c2, - 0x2009, 0x007e, 0x2100, 0xa802, 0x20a8, 0x0078, 0x21cb, 0x2008, - 0x2810, 0xa202, 0x20a8, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, - 0x21e8, 0x1078, 0x37ee, 0x00c0, 0x21f1, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x00c0, 0x21e2, 0x1078, 0x21f7, 0x0040, 0x21f1, - 0x0078, 0x21e8, 0x1078, 0x22fb, 0x1078, 0x221e, 0x0040, 0x21f1, - 0x017f, 0x8108, 0x157f, 0x00f0, 0x21cb, 0x708f, 0xffff, 0x0078, - 0x21f4, 0x017f, 0x157f, 0x718e, 0x027f, 0x0c7f, 0x007c, 0x017e, - 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2219, - 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x2001, 0x0000, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, - 0x8000, 0x708a, 0x127f, 0x2009, 0x0004, 0x1078, 0x5c29, 0xa085, - 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, - 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2240, 0x2d00, - 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, - 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, - 0x0080, 0x1078, 0x37ee, 0x00c0, 0x2253, 0x1078, 0x2256, 0x0040, - 0x2253, 0x70c3, 0xffff, 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, - 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2278, 0x2d00, - 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x70c4, 0x8000, - 0x70c6, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x2009, - 0x007f, 0x1078, 0x37ee, 0x00c0, 0x2296, 0x2c68, 0x1078, 0x5b9c, - 0x0040, 0x2296, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, - 0x2009, 0x0022, 0x1078, 0x5c29, 0xa085, 0x0001, 0x0d7f, 0x0c7f, - 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, 0x4969, - 0x1078, 0x4919, 0x1078, 0x6103, 0x20a9, 0x007f, 0x2009, 0x0000, - 0x017e, 0x1078, 0x3825, 0x00c0, 0x22b1, 0x1078, 0x39a6, 0x1078, - 0x3621, 0x017f, 0x8108, 0x00f0, 0x22a8, 0x027f, 0x037f, 0x067f, - 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, - 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x017f, 0x2e60, 0x1078, - 0x39a6, 0x6210, 0x6314, 0x1078, 0x3621, 0x6212, 0x6316, 0x017f, - 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x6018, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x22f1, 0x2071, 0x7600, - 0x7088, 0xa005, 0x0040, 0x22ee, 0x8001, 0x708a, 0x007f, 0x0e7f, - 0x007c, 0x2071, 0x7600, 0x70c4, 0xa005, 0x0040, 0x22ee, 0x8001, - 0x70c6, 0x0078, 0x22ee, 0x6000, 0xc08c, 0x6002, 0x007c, 0x0e7e, - 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x81ff, 0x00c0, 0x230c, - 0x20a9, 0x0001, 0x0078, 0x2310, 0x20a9, 0x007f, 0x2011, 0x0000, - 0x027e, 0xa2e0, 0x7720, 0x2c64, 0x8cff, 0x0040, 0x2322, 0x2019, - 0x0029, 0x1078, 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, - 0x1078, 0x39a6, 0x027f, 0x8210, 0x00f0, 0x2310, 0x027e, 0x027f, - 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x7eef, - 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, - 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, - 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, - 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, - 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, - 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, - 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, - 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, - 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, - 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, - 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, - 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, - 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, - 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, - 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, - 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, - 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, - 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, - 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, - 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, - 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, - 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, - 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, - 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, - 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, - 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, + 0x6028, 0xa09a, 0x0002, 0x00c8, 0x1fa4, 0x8000, 0x602a, 0x0c7f, + 0x1078, 0x556c, 0x0078, 0x1ff8, 0x2019, 0x783f, 0x2304, 0xa065, + 0x0040, 0x1fae, 0x2009, 0x0027, 0x1078, 0x5c21, 0x0c7f, 0x0078, + 0x1ff8, 0xd2bc, 0x0040, 0x1ff8, 0x1078, 0x45f1, 0x6017, 0x0010, + 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, + 0x0040, 0x1fc6, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, + 0x2061, 0x7836, 0x6044, 0xa09a, 0x0002, 0x00c8, 0x1fe7, 0x8000, + 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040, 0x1ff8, 0x1078, 0x45e8, + 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, 0x1fe3, 0x6017, + 0x0012, 0x0078, 0x1ff8, 0x6017, 0x0016, 0x0078, 0x1ff8, 0x037e, + 0x2019, 0x0001, 0x1078, 0x5760, 0x037f, 0x2019, 0x7845, 0x2304, + 0xa065, 0x0040, 0x1ff7, 0x2009, 0x004f, 0x1078, 0x5c21, 0x0c7f, + 0x017f, 0xd19c, 0x0040, 0x2021, 0x017e, 0x6028, 0xc09c, 0x602a, + 0x2011, 0x0003, 0x1078, 0x57b8, 0x2011, 0x0002, 0x1078, 0x57c2, + 0x1078, 0x56ce, 0x1078, 0x45e3, 0x037e, 0x2019, 0x0000, 0x1078, + 0x5760, 0x037f, 0x60e3, 0x0000, 0x1078, 0x75a5, 0x1078, 0x75c3, + 0x2001, 0x7600, 0x2003, 0x0004, 0x6027, 0x0008, 0x1078, 0x11be, + 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, 0x007e, 0x017e, 0x027e, + 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x71b0, + 0x70b2, 0xa116, 0x0040, 0x204b, 0x81ff, 0x0040, 0x203d, 0x2011, + 0x8011, 0x1078, 0x2d3b, 0x0078, 0x204b, 0x2011, 0x8012, 0x1078, + 0x2d3b, 0x037e, 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, 0x1078, + 0x2293, 0x0c7f, 0x037f, 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, + 0x007f, 0x007c, 0x0c7e, 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, + 0xa190, 0x206d, 0x2204, 0x60f2, 0xa192, 0x0005, 0x00c8, 0x2064, + 0xa190, 0x2076, 0x0078, 0x2066, 0x2011, 0x207a, 0x2204, 0x60ee, + 0x027f, 0x007f, 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, + 0x0580, 0x0420, 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, + 0x01a8, 0x01a8, 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, + 0x2130, 0xa094, 0xff00, 0x00c0, 0x2088, 0x81ff, 0x0040, 0x208c, + 0x1078, 0x4328, 0x0078, 0x2093, 0xa080, 0x2329, 0x200c, 0xa18c, + 0xff00, 0x810f, 0xa006, 0x007c, 0xa080, 0x2329, 0x200c, 0xa18c, + 0x00ff, 0x007c, 0x20ba, 0x20be, 0x20c2, 0x20c8, 0x20ce, 0x20d4, + 0x20da, 0x20e2, 0x20ea, 0x20f0, 0x20f6, 0x20fe, 0x2106, 0x210e, + 0x2116, 0x2120, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, + 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, + 0x212a, 0x212a, 0x107e, 0x007e, 0x0078, 0x2143, 0x107e, 0x007e, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1e5e, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1d8a, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, 0x1078, 0x1d8a, + 0x0078, 0x2143, 0x0005, 0x0078, 0x212a, 0xb084, 0x003c, 0x8004, + 0x8004, 0x0079, 0x2133, 0x2143, 0x20c0, 0x20c4, 0x20ca, 0x20d0, + 0x20d6, 0x20dc, 0x20e4, 0x20ec, 0x20f2, 0x20f8, 0x2100, 0x2108, + 0x2110, 0x2118, 0x2122, 0x0008, 0x212d, 0x007f, 0x107f, 0x2091, + 0x8001, 0x007c, 0x0c7e, 0x027e, 0x2041, 0x007e, 0x70bc, 0xd09c, + 0x0040, 0x2154, 0x2041, 0x007f, 0x2001, 0x010c, 0x203c, 0x727c, + 0x82ff, 0x0040, 0x219f, 0x037e, 0x738c, 0xa38e, 0xffff, 0x00c0, + 0x2163, 0x2019, 0x0001, 0x8314, 0xa2e0, 0x7cc0, 0x2c04, 0xa38c, + 0x0001, 0x0040, 0x2170, 0xa084, 0xff00, 0x8007, 0x0078, 0x2172, + 0xa084, 0x00ff, 0xa70e, 0x0040, 0x2194, 0xa08e, 0x00ff, 0x0040, + 0x219a, 0x2009, 0x0000, 0x1078, 0x207f, 0x1078, 0x37e6, 0x00c0, + 0x2197, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x218e, + 0x1078, 0x21f1, 0x0040, 0x2197, 0x0078, 0x2194, 0x1078, 0x22f5, + 0x1078, 0x2218, 0x0040, 0x2197, 0x8318, 0x0078, 0x2163, 0x738e, + 0x0078, 0x219c, 0x708f, 0xffff, 0x037f, 0x0078, 0x21ee, 0xa780, + 0x2329, 0x203c, 0xa7bc, 0xff00, 0x873f, 0x708c, 0xa096, 0xffff, + 0x0040, 0x21b1, 0xa812, 0x00c8, 0x21c1, 0x708f, 0xffff, 0x0078, + 0x21eb, 0x2009, 0x0000, 0x70bc, 0xd09c, 0x0040, 0x21bc, 0xd094, + 0x0040, 0x21bc, 0x2009, 0x007e, 0x2100, 0xa802, 0x20a8, 0x0078, + 0x21c5, 0x2008, 0x2810, 0xa202, 0x20a8, 0x2700, 0x157e, 0x017e, + 0xa106, 0x0040, 0x21e2, 0x1078, 0x37e6, 0x00c0, 0x21eb, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x21dc, 0x1078, 0x21f1, + 0x0040, 0x21eb, 0x0078, 0x21e2, 0x1078, 0x22f5, 0x1078, 0x2218, + 0x0040, 0x21eb, 0x017f, 0x8108, 0x157f, 0x00f0, 0x21c5, 0x708f, + 0xffff, 0x0078, 0x21ee, 0x017f, 0x157f, 0x718e, 0x027f, 0x0c7f, + 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, + 0x0040, 0x2213, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, + 0x1078, 0x37b5, 0x2001, 0x0000, 0x1078, 0x37c9, 0x127e, 0x2091, + 0x8000, 0x7088, 0x8000, 0x708a, 0x127f, 0x2009, 0x0004, 0x1078, + 0x5c21, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, + 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, 0x0040, + 0x223a, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, + 0x7088, 0x8000, 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x027e, 0x2009, 0x0080, 0x1078, 0x37e6, 0x00c0, 0x224d, 0x1078, + 0x2250, 0x0040, 0x224d, 0x70c3, 0xffff, 0x027f, 0x0c7f, 0x007c, + 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, 0x0040, + 0x2272, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, + 0x70c4, 0x8000, 0x70c6, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x0d7e, 0x2009, 0x007f, 0x1078, 0x37e6, 0x00c0, 0x2290, 0x2c68, + 0x1078, 0x5b94, 0x0040, 0x2290, 0x2d00, 0x601a, 0x6312, 0x601f, + 0x0001, 0x620a, 0x2009, 0x0022, 0x1078, 0x5c21, 0xa085, 0x0001, + 0x0d7f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, + 0x1078, 0x4961, 0x1078, 0x4911, 0x1078, 0x60f9, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, 0x00c0, 0x22ab, 0x1078, + 0x399e, 0x1078, 0x3619, 0x017f, 0x8108, 0x00f0, 0x22a2, 0x027f, + 0x037f, 0x067f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, + 0x027e, 0x017e, 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, + 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x017f, + 0x2e60, 0x1078, 0x399e, 0x6210, 0x6314, 0x1078, 0x3619, 0x6212, + 0x6316, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, + 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x22eb, + 0x2071, 0x7600, 0x7088, 0xa005, 0x0040, 0x22e8, 0x8001, 0x708a, + 0x007f, 0x0e7f, 0x007c, 0x2071, 0x7600, 0x70c4, 0xa005, 0x0040, + 0x22e8, 0x8001, 0x70c6, 0x0078, 0x22e8, 0x6000, 0xc08c, 0x6002, + 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x81ff, + 0x00c0, 0x2306, 0x20a9, 0x0001, 0x0078, 0x230a, 0x20a9, 0x007f, + 0x2011, 0x0000, 0x027e, 0xa2e0, 0x7720, 0x2c64, 0x8cff, 0x0040, + 0x231c, 0x2019, 0x0029, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, + 0x1078, 0x7370, 0x1078, 0x399e, 0x027f, 0x8210, 0x00f0, 0x230a, + 0x027e, 0x027f, 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, + 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, + 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, + 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, + 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, + 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, + 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, + 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, + 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, + 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, + 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, + 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, + 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, + 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, + 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, + 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, + 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, + 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, + 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, + 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, + 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, + 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, + 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, + 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, + 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, + 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, + 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, - 0x766d, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, - 0x7033, 0x767d, 0x7037, 0x767d, 0x7007, 0x0001, 0x2061, 0x76bd, - 0x6003, 0x0002, 0x007c, 0x0090, 0x2456, 0x0068, 0x2456, 0x2071, - 0x766d, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2456, 0x2a60, 0x7820, - 0xa08e, 0x0069, 0x00c0, 0x253d, 0x0079, 0x24da, 0x007c, 0x2071, - 0x766d, 0x7004, 0x0079, 0x245c, 0x2460, 0x2461, 0x246b, 0x247d, - 0x007c, 0x0090, 0x246a, 0x0068, 0x246a, 0x2b78, 0x7818, 0xd084, - 0x0040, 0x2489, 0x007c, 0x2b78, 0x2061, 0x76bd, 0x6008, 0xa08e, - 0x0100, 0x0040, 0x2478, 0xa086, 0x0200, 0x0040, 0x2535, 0x007c, - 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, 0x6834, - 0xa086, 0x0103, 0x0040, 0x2485, 0x007c, 0x2a60, 0x2b78, 0x7018, - 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2492, 0x61b0, - 0x0079, 0x249a, 0x2100, 0xa08a, 0x0036, 0x00c8, 0x2531, 0x61b0, - 0x0079, 0x24da, 0x2513, 0x2545, 0x254d, 0x2551, 0x2559, 0x255f, - 0x2563, 0x256c, 0x2570, 0x2578, 0x257c, 0x2531, 0x2531, 0x2531, - 0x2580, 0x2531, 0x2590, 0x25a7, 0x25be, 0x263a, 0x263f, 0x266c, - 0x26b9, 0x26c8, 0x26e9, 0x271f, 0x2729, 0x2736, 0x2749, 0x2761, - 0x276a, 0x27a7, 0x27ad, 0x2531, 0x27bd, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x27c1, 0x27c7, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x27cf, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x27dc, 0x27e2, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2578, 0x257c, 0x2531, 0x2531, 0x27f4, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2841, 0x290e, 0x2922, 0x2929, 0x298c, 0x29e7, - 0x29f2, 0x2a34, 0x2a41, 0x2a4e, 0x2a51, 0x27f8, 0x2a7a, 0x2ac1, - 0x2ace, 0x2bc8, 0x2cb6, 0x2cdd, 0x2dd5, 0x2de3, 0x2df0, 0x2e2a, - 0x713c, 0x0078, 0x2513, 0x2021, 0x4000, 0x1078, 0x2d24, 0x127e, - 0x2091, 0x8000, 0x0068, 0x2520, 0x7818, 0xd084, 0x0040, 0x2523, - 0x127f, 0x0078, 0x2517, 0x781b, 0x0001, 0x7c22, 0x7926, 0x7a2a, - 0x7b2e, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, 0x127f, - 0x007c, 0x2021, 0x4001, 0x0078, 0x2515, 0x2021, 0x4002, 0x0078, - 0x2515, 0x2021, 0x4003, 0x0078, 0x2515, 0x2021, 0x4005, 0x0078, - 0x2515, 0x2021, 0x4006, 0x0078, 0x2515, 0xa02e, 0x2520, 0x7b28, - 0x7a2c, 0x7824, 0x7930, 0x0078, 0x2d33, 0x7823, 0x0004, 0x7824, - 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, - 0x2d37, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2513, 0x7924, - 0x2114, 0x0078, 0x2513, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, - 0x0007, 0x53a3, 0x0078, 0x2513, 0x7824, 0x2060, 0x0078, 0x2582, - 0x2009, 0x0001, 0x2011, 0x000f, 0x2019, 0x0013, 0x0078, 0x2513, - 0x7d38, 0x7c3c, 0x0078, 0x2547, 0x7d38, 0x7c3c, 0x0078, 0x2553, - 0x2061, 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, - 0x00c0, 0x2584, 0x2010, 0xa005, 0x0040, 0x2513, 0x0078, 0x2539, - 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2541, 0x8019, - 0x0040, 0x2541, 0x604a, 0x6142, 0x782c, 0x6052, 0x7828, 0x6056, - 0xa006, 0x605a, 0x605e, 0x1078, 0x3c71, 0x0078, 0x2513, 0x2061, - 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2541, 0x8019, 0x0040, - 0x2541, 0x604e, 0x6146, 0x782c, 0x6062, 0x7828, 0x6066, 0xa006, - 0x606a, 0x606e, 0x1078, 0x3a47, 0x0078, 0x2513, 0xa02e, 0x2520, - 0x81ff, 0x00c0, 0x253d, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, - 0x20a1, 0x7674, 0x41a1, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x2009, - 0x0020, 0x1078, 0x2d33, 0x701b, 0x25d6, 0x007c, 0x6834, 0x2008, - 0xa084, 0x00ff, 0xa096, 0x0011, 0x0040, 0x25e2, 0xa096, 0x0019, - 0x00c0, 0x253d, 0x810f, 0xa18c, 0x00ff, 0x0040, 0x253d, 0x710e, - 0x700c, 0x8001, 0x0040, 0x2613, 0x700e, 0x1078, 0x2cfb, 0x0040, - 0x253d, 0x2009, 0x0020, 0x2061, 0x76bd, 0x6224, 0x6328, 0x642c, - 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0x1078, 0x2d33, 0x701b, 0x2606, 0x007c, 0x6834, 0xa084, - 0x00ff, 0xa096, 0x0002, 0x0040, 0x2611, 0xa096, 0x000a, 0x00c0, - 0x253d, 0x0078, 0x25e8, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, - 0x1078, 0x3722, 0x00c0, 0x2621, 0x7007, 0x0003, 0x701b, 0x2623, - 0x007c, 0x1078, 0x3b0a, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, - 0x2099, 0x7674, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, - 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, - 0x0078, 0x2d37, 0x6198, 0x7824, 0x609a, 0x0078, 0x2513, 0x2091, - 0x8000, 0x7823, 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, - 0x2020, 0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, - 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, - 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, 0xa08a, 0x0003, - 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff, 0x00c0, 0x253d, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x7c28, 0x7d2c, 0x1078, 0x3969, 0xd28c, - 0x00c0, 0x267e, 0x1078, 0x38f9, 0x0078, 0x2680, 0x1078, 0x3935, - 0x00c0, 0x26aa, 0x2061, 0x7d00, 0x127e, 0x2091, 0x8000, 0x6000, - 0xa086, 0x0000, 0x0040, 0x2698, 0x6010, 0xa06d, 0x0040, 0x2698, - 0x683c, 0xa406, 0x00c0, 0x2698, 0x6840, 0xa506, 0x0040, 0x26a3, - 0x127f, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, - 0x253d, 0x0078, 0x2684, 0x1078, 0x6738, 0x127f, 0x0040, 0x253d, - 0x0078, 0x2513, 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b0a, 0x127e, - 0x2091, 0x8000, 0x1078, 0x6b47, 0x1078, 0x3a7a, 0x127f, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38ae, 0x1078, 0x397a, 0x0040, 0x253d, 0x0078, 0x2513, - 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x2031, - 0x000f, 0x1078, 0x38ae, 0x8631, 0x00c8, 0x26d1, 0x2019, 0x0005, - 0x1078, 0x399b, 0x0040, 0x253d, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x2541, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x457b, 0x0078, - 0x2513, 0x127e, 0x2091, 0x8000, 0x81ff, 0x00c0, 0x2719, 0x2029, - 0x00ff, 0x644c, 0x2400, 0xa506, 0x0040, 0x2713, 0x2508, 0x1078, - 0x3825, 0x00c0, 0x2713, 0x2031, 0x000f, 0x1078, 0x38ae, 0x8631, - 0x00c8, 0x26fd, 0x2019, 0x0004, 0x1078, 0x399b, 0x0040, 0x2719, - 0x7824, 0xa08a, 0x1000, 0x00c8, 0x271c, 0x8003, 0x800b, 0x810b, - 0xa108, 0x1078, 0x457b, 0x8529, 0x00c8, 0x26f2, 0x127f, 0x0078, - 0x2513, 0x127f, 0x0078, 0x253d, 0x127f, 0x0078, 0x2541, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x1078, 0x38de, 0x1078, 0x3969, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38c7, 0x1078, 0x3969, 0x0078, 0x2513, 0x81ff, 0x00c0, - 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3938, 0x0040, - 0x253d, 0x1078, 0x376a, 0x1078, 0x38f2, 0x1078, 0x3969, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x38ae, 0x62a0, - 0x2019, 0x0005, 0x0c7e, 0x1078, 0x39a6, 0x0c7f, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x1078, 0x3969, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3969, 0x2208, - 0x0078, 0x2513, 0x157e, 0x0d7e, 0x0e7e, 0x2069, 0x76ff, 0x6810, - 0x6914, 0xa10a, 0x00c8, 0x2776, 0x2009, 0x0000, 0x6816, 0x2011, - 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, 0x7720, 0x2d04, - 0xa075, 0x0040, 0x278b, 0x704c, 0x1078, 0x2795, 0xa210, 0x7080, - 0x1078, 0x2795, 0xa318, 0x8d68, 0x00f0, 0x277f, 0x2300, 0xa218, - 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x2513, 0x0f7e, 0x017e, 0xa07d, - 0x0040, 0x27a4, 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0040, - 0x27a4, 0x2178, 0x0078, 0x279c, 0x017f, 0x0f7f, 0x007c, 0x2069, - 0x76ff, 0x6910, 0x629c, 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, - 0x614c, 0xa190, 0x232f, 0x2214, 0xa294, 0x00ff, 0x6068, 0xa084, - 0xff00, 0xa215, 0x6364, 0x0078, 0x2513, 0x613c, 0x6240, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x0078, 0x2513, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x6244, 0x6338, 0x0078, 0x2513, 0x613c, - 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0x7651, 0x831f, - 0xa305, 0x6816, 0x0078, 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x0078, 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x7828, 0xa00d, - 0x0040, 0x2541, 0x782c, 0xa005, 0x0040, 0x2541, 0x6244, 0x6146, - 0x6338, 0x603a, 0x0078, 0x2513, 0x7d38, 0x7c3c, 0x0078, 0x25c0, - 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x253d, 0x624c, - 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x2810, 0x2001, 0x7640, - 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d37, - 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x253d, 0x0c7e, 0x1078, - 0x2cfb, 0x0c7f, 0x0040, 0x253d, 0x6837, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x1078, 0x6a41, 0x0040, 0x253d, 0x7007, 0x0003, 0x701b, - 0x2832, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x253d, 0xad80, - 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, - 0x2d37, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x2009, 0x001c, 0x7a2c, - 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2d33, 0x701b, 0x2850, 0x007c, - 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x2541, 0x6804, 0xd0ac, - 0x0040, 0x285d, 0xd0a4, 0x0040, 0x2541, 0xd094, 0x0040, 0x2868, - 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, 0x6106, 0x0c7f, - 0xd08c, 0x0040, 0x2873, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18d, - 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0002, - 0x0048, 0x2888, 0xd084, 0x0040, 0x2888, 0x6a28, 0xa28a, 0x007f, - 0x00c8, 0x2541, 0xa288, 0x232f, 0x210c, 0xa18c, 0x00ff, 0x6152, - 0xd0dc, 0x0040, 0x2891, 0x6828, 0xa08a, 0x007f, 0x00c8, 0x2541, - 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x2541, 0xa08a, 0x0841, - 0x00c8, 0x2541, 0xa084, 0x0007, 0x00c0, 0x2541, 0x680c, 0xa005, - 0x0040, 0x2541, 0x6810, 0xa005, 0x0040, 0x2541, 0x6848, 0x6940, - 0xa10a, 0x00c8, 0x2541, 0x8001, 0x0040, 0x2541, 0x684c, 0x6944, - 0xa10a, 0x00c8, 0x2541, 0x8001, 0x0040, 0x2541, 0x20a9, 0x001c, - 0x2d98, 0x2069, 0x7651, 0x2da0, 0x53a3, 0x6814, 0xa08c, 0x00ff, - 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, 0x3c71, 0x1078, - 0x3a47, 0x6000, 0xa086, 0x0000, 0x00c0, 0x290c, 0x6808, 0x602a, - 0x1078, 0x1dea, 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, - 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, - 0x0040, 0x28ec, 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, - 0x8217, 0x831f, 0x0078, 0x28ee, 0xa084, 0xf0ff, 0x6006, 0x610a, - 0x620e, 0x6312, 0x1078, 0x4607, 0x0c7e, 0x2061, 0x0100, 0x602f, - 0x0040, 0x602f, 0x0000, 0x0c7f, 0x60b4, 0xa005, 0x0040, 0x2908, - 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x357b, 0x0078, 0x290c, - 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x2513, 0x6000, 0xa086, - 0x0000, 0x0040, 0x253d, 0x2069, 0x7651, 0x7830, 0x6842, 0x7834, - 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x0078, 0x2d37, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x357b, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x617c, 0x81ff, 0x0040, 0x2943, - 0x703f, 0x0000, 0x2001, 0x7cc0, 0x2009, 0x0040, 0x7a2c, 0x7b28, - 0x7c3c, 0x7d38, 0x127e, 0x2091, 0x8000, 0x1078, 0x2d37, 0x701b, - 0x2510, 0x127f, 0x007c, 0x703f, 0x0001, 0x0d7e, 0x2069, 0x7cc0, - 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2019, 0xffff, 0x43a4, 0x654c, - 0xa588, 0x232f, 0x210c, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, - 0x0002, 0x2100, 0xa506, 0x0040, 0x2975, 0x1078, 0x3825, 0x00c0, - 0x2975, 0x6014, 0x821c, 0x0048, 0x296d, 0xa398, 0x7cc0, 0xa085, - 0xff00, 0x8007, 0x201a, 0x0078, 0x2974, 0xa398, 0x7cc0, 0x2324, - 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, 0xa182, 0x0080, - 0x00c8, 0x297c, 0x0078, 0x2959, 0x8201, 0x8007, 0x2d0c, 0xa105, - 0x206a, 0x0d7f, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2099, 0x7cc0, - 0x1078, 0x35c4, 0x0078, 0x2932, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x0c7e, 0x1078, 0x2cfb, 0x0c7f, 0x0040, 0x253d, 0x2001, 0x7652, - 0x2004, 0xd0b4, 0x0040, 0x29b9, 0x6000, 0xd08c, 0x00c0, 0x29b9, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x29b9, 0x6837, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a79, 0x0040, 0x253d, - 0x7007, 0x0003, 0x701b, 0x29b5, 0x007c, 0x1078, 0x2d13, 0x0040, - 0x2541, 0x20a9, 0x0029, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, - 0x20a9, 0x0002, 0xac80, 0x0004, 0x2098, 0xad80, 0x0004, 0x20a0, - 0x1078, 0x35c4, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, - 0x0006, 0x20a0, 0x1078, 0x35c4, 0x20a9, 0x0004, 0xac80, 0x000a, - 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x35c4, 0x2d00, 0x2009, - 0x0029, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d37, 0x81ff, - 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3985, - 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, 0x7828, 0xa08a, 0x1000, - 0x00c8, 0x2541, 0x1078, 0x2d13, 0x0040, 0x2541, 0x2031, 0x000f, - 0x1078, 0x38ae, 0x8631, 0x00c8, 0x2a00, 0x2019, 0x0004, 0x1078, - 0x399b, 0x7924, 0x810f, 0x7a28, 0x1078, 0x2a10, 0x0078, 0x2513, - 0xa186, 0x00ff, 0x0040, 0x2a18, 0x1078, 0x2a28, 0x0078, 0x2a27, + 0x8000, 0x2071, 0x766d, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, + 0x703a, 0x703e, 0x7033, 0x767d, 0x7037, 0x767d, 0x7007, 0x0001, + 0x2061, 0x76bd, 0x6003, 0x0002, 0x007c, 0x0090, 0x2450, 0x0068, + 0x2450, 0x2071, 0x766d, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2450, + 0x2a60, 0x7820, 0xa08e, 0x0069, 0x00c0, 0x2537, 0x0079, 0x24d4, + 0x007c, 0x2071, 0x766d, 0x7004, 0x0079, 0x2456, 0x245a, 0x245b, + 0x2465, 0x2477, 0x007c, 0x0090, 0x2464, 0x0068, 0x2464, 0x2b78, + 0x7818, 0xd084, 0x0040, 0x2483, 0x007c, 0x2b78, 0x2061, 0x76bd, + 0x6008, 0xa08e, 0x0100, 0x0040, 0x2472, 0xa086, 0x0200, 0x0040, + 0x252f, 0x007c, 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, + 0x2068, 0x6834, 0xa086, 0x0103, 0x0040, 0x247f, 0x007c, 0x2a60, + 0x2b78, 0x7018, 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, + 0x248c, 0x61b0, 0x0079, 0x2494, 0x2100, 0xa08a, 0x0036, 0x00c8, + 0x252b, 0x61b0, 0x0079, 0x24d4, 0x250d, 0x253f, 0x2547, 0x254b, + 0x2553, 0x2559, 0x255d, 0x2566, 0x256a, 0x2572, 0x2576, 0x252b, + 0x252b, 0x252b, 0x257a, 0x252b, 0x258a, 0x25a1, 0x25b8, 0x2634, + 0x2639, 0x2666, 0x26b3, 0x26c2, 0x26e3, 0x2719, 0x2723, 0x2730, + 0x2743, 0x275b, 0x2764, 0x27a1, 0x27a7, 0x252b, 0x27b7, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x27bb, 0x27c1, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x27c9, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x27d6, 0x27dc, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x2572, 0x2576, 0x252b, 0x252b, + 0x27ee, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x283b, 0x2908, 0x291c, 0x2923, + 0x2986, 0x29d7, 0x29e2, 0x2a24, 0x2a31, 0x2a3e, 0x2a41, 0x27f2, + 0x2a6a, 0x2ab1, 0x2abe, 0x2bb9, 0x2ca7, 0x2cce, 0x2dc6, 0x2dd4, + 0x2de1, 0x2e1b, 0x713c, 0x0078, 0x250d, 0x2021, 0x4000, 0x1078, + 0x2d15, 0x127e, 0x2091, 0x8000, 0x0068, 0x251a, 0x7818, 0xd084, + 0x0040, 0x251d, 0x127f, 0x0078, 0x2511, 0x781b, 0x0001, 0x7c22, + 0x7926, 0x7a2a, 0x7b2e, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x250f, 0x2021, + 0x4002, 0x0078, 0x250f, 0x2021, 0x4003, 0x0078, 0x250f, 0x2021, + 0x4005, 0x0078, 0x250f, 0x2021, 0x4006, 0x0078, 0x250f, 0xa02e, + 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x2d24, 0x7823, + 0x0004, 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, + 0x7930, 0x0078, 0x2d28, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, + 0x250d, 0x7924, 0x2114, 0x0078, 0x250d, 0x2099, 0x0009, 0x20a1, + 0x0009, 0x20a9, 0x0007, 0x53a3, 0x0078, 0x250d, 0x7824, 0x2060, + 0x0078, 0x257c, 0x2009, 0x0001, 0x2011, 0x000f, 0x2019, 0x0025, + 0x0078, 0x250d, 0x7d38, 0x7c3c, 0x0078, 0x2541, 0x7d38, 0x7c3c, + 0x0078, 0x254d, 0x2061, 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, + 0x8c60, 0x8109, 0x00c0, 0x257e, 0x2010, 0xa005, 0x0040, 0x250d, + 0x0078, 0x2533, 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, + 0x253b, 0x8019, 0x0040, 0x253b, 0x604a, 0x6142, 0x782c, 0x6052, + 0x7828, 0x6056, 0xa006, 0x605a, 0x605e, 0x1078, 0x3c69, 0x0078, + 0x250d, 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x253b, + 0x8019, 0x0040, 0x253b, 0x604e, 0x6146, 0x782c, 0x6062, 0x7828, + 0x6066, 0xa006, 0x606a, 0x606e, 0x1078, 0x3a3f, 0x0078, 0x250d, + 0xa02e, 0x2520, 0x81ff, 0x00c0, 0x2537, 0x7924, 0x7b28, 0x7a2c, + 0x20a9, 0x0005, 0x20a1, 0x7674, 0x41a1, 0x1078, 0x2cec, 0x0040, + 0x2537, 0x2009, 0x0020, 0x1078, 0x2d24, 0x701b, 0x25d0, 0x007c, + 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0040, 0x25dc, + 0xa096, 0x0019, 0x00c0, 0x2537, 0x810f, 0xa18c, 0x00ff, 0x0040, + 0x2537, 0x710e, 0x700c, 0x8001, 0x0040, 0x260d, 0x700e, 0x1078, + 0x2cec, 0x0040, 0x2537, 0x2009, 0x0020, 0x2061, 0x76bd, 0x6224, + 0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x1078, 0x2d24, 0x701b, 0x2600, 0x007c, + 0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0040, 0x260b, 0xa096, + 0x000a, 0x00c0, 0x2537, 0x0078, 0x25e2, 0x7010, 0x2068, 0x6838, + 0xc0fd, 0x683a, 0x1078, 0x371a, 0x00c0, 0x261b, 0x7007, 0x0003, + 0x701b, 0x261d, 0x007c, 0x1078, 0x3b02, 0x127e, 0x2091, 0x8000, + 0x20a9, 0x0005, 0x2099, 0x7674, 0x530a, 0x2100, 0xa210, 0xa399, + 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, + 0x0020, 0x127f, 0x0078, 0x2d28, 0x6198, 0x7824, 0x609a, 0x0078, + 0x250d, 0x2091, 0x8000, 0x7823, 0x4000, 0x7827, 0x4953, 0x782b, + 0x5020, 0x782f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, + 0x7836, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, + 0xa205, 0x783a, 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, + 0x2091, 0x5000, 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, + 0xa08a, 0x0003, 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff, 0x00c0, + 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x7c28, 0x7d2c, 0x1078, + 0x3961, 0xd28c, 0x00c0, 0x2678, 0x1078, 0x38f1, 0x0078, 0x267a, + 0x1078, 0x392d, 0x00c0, 0x26a4, 0x2061, 0x7d00, 0x127e, 0x2091, + 0x8000, 0x6000, 0xa086, 0x0000, 0x0040, 0x2692, 0x6010, 0xa06d, + 0x0040, 0x2692, 0x683c, 0xa406, 0x00c0, 0x2692, 0x6840, 0xa506, + 0x0040, 0x269d, 0x127f, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x2537, 0x0078, 0x267e, 0x1078, 0x6732, 0x127f, + 0x0040, 0x2537, 0x0078, 0x250d, 0xa00e, 0x2001, 0x0005, 0x1078, + 0x3b02, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b3c, 0x1078, 0x3a72, + 0x127f, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x1078, 0x38a6, 0x1078, 0x3972, 0x0040, 0x2537, + 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, + 0x253b, 0x2031, 0x000f, 0x1078, 0x38a6, 0x8631, 0x00c8, 0x26cb, + 0x2019, 0x0005, 0x1078, 0x3993, 0x0040, 0x2537, 0x7828, 0xa08a, + 0x1000, 0x00c8, 0x253b, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, + 0x4573, 0x0078, 0x250d, 0x127e, 0x2091, 0x8000, 0x81ff, 0x00c0, + 0x2713, 0x2029, 0x00ff, 0x644c, 0x2400, 0xa506, 0x0040, 0x270d, + 0x2508, 0x1078, 0x381d, 0x00c0, 0x270d, 0x2031, 0x000f, 0x1078, + 0x38a6, 0x8631, 0x00c8, 0x26f7, 0x2019, 0x0004, 0x1078, 0x3993, + 0x0040, 0x2713, 0x7824, 0xa08a, 0x1000, 0x00c8, 0x2716, 0x8003, + 0x800b, 0x810b, 0xa108, 0x1078, 0x4573, 0x8529, 0x00c8, 0x26ec, + 0x127f, 0x0078, 0x250d, 0x127f, 0x0078, 0x2537, 0x127f, 0x0078, + 0x253b, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, 0x38d6, 0x1078, + 0x3961, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x1078, 0x38bf, 0x1078, 0x3961, 0x0078, 0x250d, + 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x3930, 0x0040, 0x2537, 0x1078, 0x3762, 0x1078, 0x38ea, 0x1078, + 0x3961, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x38a6, 0x62a0, 0x2019, 0x0005, 0x0c7e, 0x1078, 0x399e, 0x0c7f, + 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x1078, + 0x3961, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x3961, 0x2208, 0x0078, 0x250d, 0x157e, 0x0d7e, 0x0e7e, 0x2069, + 0x76ff, 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2770, 0x2009, 0x0000, + 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, + 0x7720, 0x2d04, 0xa075, 0x0040, 0x2785, 0x704c, 0x1078, 0x278f, + 0xa210, 0x7080, 0x1078, 0x278f, 0xa318, 0x8d68, 0x00f0, 0x2779, + 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x250d, 0x0f7e, + 0x017e, 0xa07d, 0x0040, 0x279e, 0x2001, 0x0000, 0x8000, 0x2f0c, + 0x81ff, 0x0040, 0x279e, 0x2178, 0x0078, 0x2796, 0x017f, 0x0f7f, + 0x007c, 0x2069, 0x76ff, 0x6910, 0x629c, 0x0078, 0x250d, 0x81ff, + 0x00c0, 0x2537, 0x614c, 0xa190, 0x2329, 0x2214, 0xa294, 0x00ff, + 0x6068, 0xa084, 0xff00, 0xa215, 0x6364, 0x0078, 0x250d, 0x613c, + 0x6240, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x0078, + 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x6244, 0x6338, 0x0078, + 0x250d, 0x613c, 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, + 0x7651, 0x831f, 0xa305, 0x6816, 0x0078, 0x250d, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, + 0x7828, 0xa00d, 0x0040, 0x253b, 0x782c, 0xa005, 0x0040, 0x253b, + 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, 0x250d, 0x7d38, 0x7c3c, + 0x0078, 0x25ba, 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, + 0x2537, 0x624c, 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x280a, + 0x2001, 0x7640, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x0078, 0x2d28, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, + 0x253b, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2537, + 0x0c7e, 0x1078, 0x2cec, 0x0c7f, 0x0040, 0x2537, 0x6837, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a36, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x282c, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, + 0x2537, 0xad80, 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0078, 0x2d28, 0x1078, 0x2cec, 0x0040, 0x2537, 0x2009, + 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2d24, 0x701b, + 0x284a, 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x253b, + 0x6804, 0xd0ac, 0x0040, 0x2857, 0xd0a4, 0x0040, 0x253b, 0xd094, + 0x0040, 0x2862, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, + 0x6106, 0x0c7f, 0xd08c, 0x0040, 0x286d, 0x0c7e, 0x2061, 0x0100, + 0x6104, 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, + 0xa18a, 0x0002, 0x0048, 0x2882, 0xd084, 0x0040, 0x2882, 0x6a28, + 0xa28a, 0x007f, 0x00c8, 0x253b, 0xa288, 0x2329, 0x210c, 0xa18c, + 0x00ff, 0x6152, 0xd0dc, 0x0040, 0x288b, 0x6828, 0xa08a, 0x007f, + 0x00c8, 0x253b, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x253b, + 0xa08a, 0x0841, 0x00c8, 0x253b, 0xa084, 0x0007, 0x00c0, 0x253b, + 0x680c, 0xa005, 0x0040, 0x253b, 0x6810, 0xa005, 0x0040, 0x253b, + 0x6848, 0x6940, 0xa10a, 0x00c8, 0x253b, 0x8001, 0x0040, 0x253b, + 0x684c, 0x6944, 0xa10a, 0x00c8, 0x253b, 0x8001, 0x0040, 0x253b, + 0x20a9, 0x001c, 0x2d98, 0x2069, 0x7651, 0x2da0, 0x53a3, 0x6814, + 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, + 0x3c69, 0x1078, 0x3a3f, 0x6000, 0xa086, 0x0000, 0x00c0, 0x2906, + 0x6808, 0x602a, 0x1078, 0x1de4, 0x6818, 0x691c, 0x6a20, 0x6b24, + 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, + 0x6c04, 0xd4f4, 0x0040, 0x28e6, 0x6830, 0x6934, 0x6a38, 0x6b3c, + 0x8007, 0x810f, 0x8217, 0x831f, 0x0078, 0x28e8, 0xa084, 0xf0ff, + 0x6006, 0x610a, 0x620e, 0x6312, 0x1078, 0x45ff, 0x0c7e, 0x2061, + 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x60b4, 0xa005, + 0x0040, 0x2902, 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x3573, + 0x0078, 0x2906, 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x250d, + 0x6000, 0xa086, 0x0000, 0x0040, 0x2537, 0x2069, 0x7651, 0x7830, + 0x6842, 0x7834, 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0078, 0x2d28, 0x81ff, 0x00c0, 0x2537, 0x1078, + 0x3573, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x617c, 0x81ff, + 0x0040, 0x293d, 0x703f, 0x0000, 0x2001, 0x7cc0, 0x2009, 0x0040, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x127e, 0x2091, 0x8000, 0x1078, + 0x2d28, 0x701b, 0x250a, 0x127f, 0x007c, 0x703f, 0x0001, 0x0d7e, + 0x2069, 0x7cc0, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2019, 0xffff, + 0x43a4, 0x654c, 0xa588, 0x2329, 0x210c, 0xa18c, 0x00ff, 0x216a, + 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, 0x0040, 0x296f, 0x1078, + 0x381d, 0x00c0, 0x296f, 0x6014, 0x821c, 0x0048, 0x2967, 0xa398, + 0x7cc0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0078, 0x296e, 0xa398, + 0x7cc0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, + 0xa182, 0x0080, 0x00c8, 0x2976, 0x0078, 0x2953, 0x8201, 0x8007, + 0x2d0c, 0xa105, 0x206a, 0x0d7f, 0x20a9, 0x0040, 0x20a1, 0x7cc0, + 0x2099, 0x7cc0, 0x1078, 0x35bc, 0x0078, 0x292c, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x0c7e, 0x1078, 0x2cec, 0x0c7f, 0x0040, 0x2537, + 0x2001, 0x7652, 0x2004, 0xd0b4, 0x0040, 0x29b3, 0x6000, 0xd08c, + 0x00c0, 0x29b3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x29b3, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a6e, + 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, 0x29af, 0x007c, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x20a9, 0x0029, 0x2c98, 0xade8, 0x0002, + 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, + 0x0006, 0x20a0, 0x1078, 0x35bc, 0x20a9, 0x0004, 0xac80, 0x000a, + 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x35bc, 0x2d00, 0x2009, + 0x0029, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d28, 0x81ff, + 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, 0x397d, + 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x7828, 0xa08a, 0x1000, + 0x00c8, 0x253b, 0x1078, 0x2d04, 0x0040, 0x253b, 0x2031, 0x000f, + 0x1078, 0x38a6, 0x8631, 0x00c8, 0x29f0, 0x2019, 0x0004, 0x1078, + 0x3993, 0x7924, 0x810f, 0x7a28, 0x1078, 0x2a00, 0x0078, 0x250d, + 0xa186, 0x00ff, 0x0040, 0x2a08, 0x1078, 0x2a18, 0x0078, 0x2a17, 0x2029, 0x007e, 0x2061, 0x7600, 0x644c, 0x2400, 0xa506, 0x0040, - 0x2a24, 0x2508, 0x1078, 0x2a28, 0x8529, 0x00c8, 0x2a1d, 0x007c, - 0x1078, 0x3825, 0x00c0, 0x2a33, 0x2200, 0x8003, 0x800b, 0x810b, - 0xa108, 0x1078, 0x457b, 0x007c, 0x81ff, 0x00c0, 0x253d, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x1078, 0x38ae, 0x1078, 0x3990, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38ae, 0x1078, 0x397a, 0x0078, 0x2513, 0x6100, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x6004, 0xa086, 0x0707, - 0x0040, 0x2541, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x253d, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x2a6a, + 0x2a14, 0x2508, 0x1078, 0x2a18, 0x8529, 0x00c8, 0x2a0d, 0x007c, + 0x1078, 0x381d, 0x00c0, 0x2a23, 0x2200, 0x8003, 0x800b, 0x810b, + 0xa108, 0x1078, 0x4573, 0x007c, 0x81ff, 0x00c0, 0x2537, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x1078, 0x38a6, 0x1078, 0x3988, 0x0078, + 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, + 0x1078, 0x38a6, 0x1078, 0x3972, 0x0078, 0x250d, 0x6100, 0x0078, + 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x6004, 0xa086, 0x0707, + 0x0040, 0x253b, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x2537, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x2a5a, 0xace8, 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, - 0x0078, 0x2513, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0040, - 0x2a84, 0x81ff, 0x00c0, 0x253d, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x2541, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, - 0x2a98, 0xa182, 0x007f, 0x00c8, 0x2541, 0x2100, 0x1078, 0x209a, + 0x0078, 0x250d, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0040, + 0x2a74, 0x81ff, 0x00c0, 0x2537, 0x7828, 0xa08a, 0x1000, 0x00c8, + 0x253b, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, + 0x2a88, 0xa182, 0x007f, 0x00c8, 0x253b, 0x2100, 0x1078, 0x2094, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x2061, 0x7849, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x0100, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, - 0x001e, 0x2011, 0x35a0, 0x1078, 0x45fe, 0x7924, 0xa18c, 0xff00, - 0x810f, 0x7a28, 0x1078, 0x2a10, 0x127f, 0x0c7f, 0x027f, 0x0078, - 0x2513, 0x7924, 0xa18c, 0xff00, 0x810f, 0x0c7e, 0x1078, 0x37ee, - 0x2c08, 0x0c7f, 0x00c0, 0x2541, 0x0078, 0x2513, 0x81ff, 0x00c0, - 0x253d, 0x60bc, 0xd09c, 0x0040, 0x253d, 0x1078, 0x2cfb, 0x0040, - 0x253d, 0x6823, 0x0000, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x1078, 0x2d33, 0x701b, 0x2ae5, 0x007c, 0x2009, 0x0080, 0x1078, - 0x3825, 0x00c0, 0x2af2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x0040, 0x2af6, 0x2021, 0x400a, 0x0078, 0x2515, 0x0d7e, 0xade8, + 0x001e, 0x2011, 0x3598, 0x1078, 0x45f6, 0x7924, 0xa18c, 0xff00, + 0x810f, 0x7a28, 0x1078, 0x2a00, 0x127f, 0x0c7f, 0x027f, 0x0078, + 0x250d, 0x7924, 0xa18c, 0xff00, 0x810f, 0x0c7e, 0x1078, 0x37e6, + 0x2c08, 0x0c7f, 0x00c0, 0x253b, 0x0078, 0x250d, 0x81ff, 0x00c0, + 0x2537, 0x60bc, 0xd09c, 0x0040, 0x2537, 0x1078, 0x2cec, 0x0040, + 0x2537, 0x6823, 0x0000, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x1078, 0x2d24, 0x701b, 0x2ad5, 0x007c, 0x2009, 0x0080, 0x1078, + 0x381d, 0x00c0, 0x2ae2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0040, 0x2ae6, 0x2021, 0x400a, 0x0078, 0x250f, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, - 0xa0be, 0x0100, 0x0040, 0x2b68, 0xa0be, 0x0112, 0x0040, 0x2b68, - 0xa0be, 0x0113, 0x0040, 0x2b68, 0xa0be, 0x0114, 0x0040, 0x2b68, - 0xa0be, 0x0117, 0x0040, 0x2b68, 0xa0be, 0x011a, 0x0040, 0x2b68, - 0xa0be, 0x0121, 0x0040, 0x2b5e, 0xa0be, 0x0131, 0x0040, 0x2b5e, - 0xa0be, 0x0171, 0x0040, 0x2b68, 0xa0be, 0x0173, 0x0040, 0x2b68, - 0xa0be, 0x01a1, 0x00c0, 0x2b31, 0x6830, 0x8007, 0x6832, 0x0078, - 0x2b6e, 0xa0be, 0x0212, 0x0040, 0x2b64, 0xa0be, 0x0213, 0x0040, - 0x2b64, 0xa0be, 0x0214, 0x0040, 0x2b56, 0xa0be, 0x0217, 0x0040, - 0x2b50, 0xa0be, 0x021a, 0x00c0, 0x2b4a, 0x6838, 0x8007, 0x683a, - 0x0078, 0x2b68, 0xa0be, 0x0300, 0x0040, 0x2b68, 0x0078, 0x2541, - 0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x2ba4, 0xad80, 0x000e, - 0x20a9, 0x0001, 0x1078, 0x2ba4, 0x0078, 0x2b68, 0xad80, 0x000c, - 0x1078, 0x2bb2, 0x0078, 0x2b6e, 0xad80, 0x000e, 0x1078, 0x2bb2, - 0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x2ba4, 0x0c7e, 0x1078, - 0x2cfb, 0x0040, 0x2b99, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, - 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, 0x0000, - 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, 0x0c7f, - 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, - 0x1078, 0x6a5d, 0x0040, 0x253d, 0x7007, 0x0003, 0x701b, 0x2b9d, - 0x007c, 0x0c7f, 0x0d7f, 0x0078, 0x253d, 0x6820, 0xa086, 0x8001, - 0x0040, 0x253d, 0x0078, 0x2513, 0x017e, 0x2008, 0x2044, 0x8000, - 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x00f0, 0x2ba6, - 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, 0x2044, 0x8000, - 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, 0x2a0a, - 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, 0x017f, 0x007c, - 0x81ff, 0x00c0, 0x253d, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, - 0xa182, 0x0080, 0x0048, 0x2541, 0xa182, 0x00ff, 0x00c8, 0x2541, - 0x7a2c, 0x7b28, 0x6064, 0xa306, 0x00c0, 0x2be6, 0x6068, 0xa24e, - 0x0040, 0x2541, 0xa9cc, 0xff00, 0x0040, 0x2541, 0x0c7e, 0x1078, - 0x2c5a, 0x2c68, 0x0c7f, 0x0040, 0x2c0d, 0xa0c6, 0x4000, 0x00c0, - 0x2bf3, 0x0078, 0x2c0a, 0xa0c6, 0x4007, 0x00c0, 0x2bfa, 0x2408, - 0x0078, 0x2c0a, 0xa0c6, 0x4008, 0x00c0, 0x2c02, 0x2708, 0x2610, - 0x0078, 0x2c0a, 0xa0c6, 0x4009, 0x00c0, 0x2c08, 0x0078, 0x2c0a, - 0x2001, 0x4006, 0x2020, 0x0078, 0x2515, 0x017e, 0x0b7e, 0x0c7e, - 0x0e7e, 0x2c70, 0x1078, 0x5b9c, 0x0040, 0x2c48, 0x2d00, 0x601a, - 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x2cfb, 0x0c7f, 0x2b70, - 0x0040, 0x253d, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, - 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x22bb, - 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, - 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x0040, 0x253d, 0x7007, 0x0003, - 0x701b, 0x2c53, 0x007c, 0x6830, 0xa086, 0x0100, 0x00c0, 0x2513, - 0x0078, 0x253d, 0x0e7e, 0x0d7e, 0x2029, 0x0000, 0x2021, 0x0080, - 0x20a9, 0x007f, 0x2071, 0x77a0, 0x2e04, 0xa005, 0x00c0, 0x2c6e, - 0x2100, 0xa406, 0x0040, 0x2cab, 0x0078, 0x2c9f, 0x2068, 0x6f10, - 0x2700, 0xa306, 0x00c0, 0x2c90, 0x6e14, 0x2600, 0xa206, 0x00c0, - 0x2c90, 0x2400, 0xa106, 0x00c0, 0x2c8c, 0x2d60, 0xd884, 0x0040, - 0x2cb1, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2cb1, - 0x2001, 0x4000, 0x0078, 0x2cb2, 0x2001, 0x4007, 0x0078, 0x2cb2, - 0x2400, 0xa106, 0x00c0, 0x2c9f, 0x6e14, 0x87ff, 0x00c0, 0x2c9b, - 0x86ff, 0x0040, 0x2cab, 0x2001, 0x4008, 0x0078, 0x2cb2, 0x8420, - 0x8e70, 0x00f0, 0x2c64, 0x2001, 0x4009, 0x0078, 0x2cb2, 0x2001, - 0x0001, 0x0078, 0x2cb2, 0x1078, 0x37ee, 0x00c0, 0x2ca7, 0x6312, - 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, - 0x253d, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x6837, 0x0000, 0x7824, - 0xa005, 0x0040, 0x2541, 0xa096, 0x00ff, 0x0040, 0x2ccb, 0xa092, - 0x0004, 0x00c8, 0x2541, 0x2010, 0x2d18, 0x1078, 0x227d, 0x0040, - 0x253d, 0x7007, 0x0003, 0x701b, 0x2cd6, 0x007c, 0x6830, 0xa086, - 0x0100, 0x0040, 0x253d, 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, - 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, 0x2541, - 0xa182, 0x00ff, 0x00c8, 0x2541, 0x127e, 0x2091, 0x8000, 0x1078, - 0x697f, 0x00c0, 0x2cf8, 0x1078, 0x380d, 0x127f, 0x0078, 0x2513, - 0x127f, 0x0078, 0x253d, 0x1078, 0x132f, 0x0040, 0x2d12, 0xa006, - 0x6802, 0x7010, 0xa005, 0x00c0, 0x2d0a, 0x2d00, 0x7012, 0x7016, - 0x0078, 0x2d10, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, - 0xad80, 0x000d, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x1078, - 0x3825, 0x00c0, 0x2d21, 0xa6b4, 0x00ff, 0xa682, 0x0010, 0x0048, - 0x2d22, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, 0x0040, - 0x2d2f, 0x2168, 0x6904, 0x1078, 0x1348, 0x0078, 0x2d26, 0x7112, - 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x2d39, 0x2031, - 0x0000, 0x2061, 0x76bd, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, - 0x642e, 0x6532, 0x2c10, 0x1078, 0x137f, 0x7007, 0x0002, 0x701b, - 0x2513, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0000, - 0x2001, 0x767b, 0x2004, 0xa005, 0x00c0, 0x2d65, 0x0068, 0x2d65, - 0x7818, 0xd084, 0x00c0, 0x2d65, 0x781b, 0x0001, 0x7a22, 0x7b26, - 0x7c2a, 0x2091, 0x4080, 0x0078, 0x2d8a, 0x017e, 0x0c7e, 0x0e7e, - 0x2071, 0x766d, 0x7138, 0xa182, 0x0008, 0x0048, 0x2d73, 0x7030, - 0x2060, 0x0078, 0x2d84, 0x7030, 0xa0e0, 0x0008, 0xac82, 0x76bd, - 0x0048, 0x2d7c, 0x2061, 0x767d, 0x2c00, 0x7032, 0x81ff, 0x00c0, - 0x2d82, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x0e7f, - 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, 0x766d, - 0x7038, 0xa005, 0x0040, 0x2dc6, 0x127e, 0x2091, 0x8000, 0x0068, - 0x2dc5, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x2dc4, - 0x0c7e, 0x781b, 0x0001, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, - 0x7826, 0x6008, 0x782a, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, - 0xa005, 0x00c0, 0x2dba, 0x7033, 0x767d, 0x7037, 0x767d, 0x0c7f, - 0x0078, 0x2dc4, 0xac80, 0x0008, 0xa0fa, 0x76bd, 0x0048, 0x2dc2, - 0x2001, 0x767d, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, 0x007c, - 0x027e, 0x2001, 0x7652, 0x2004, 0xd0c4, 0x0040, 0x2dd3, 0x2011, - 0x8014, 0x1078, 0x2d4a, 0x027f, 0x007c, 0x81ff, 0x00c0, 0x253d, - 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x1078, 0x357b, - 0x127f, 0x0078, 0x2513, 0x7824, 0x2008, 0xa18c, 0xfffd, 0x00c0, - 0x2dee, 0x61c8, 0xa10d, 0x61ca, 0x0078, 0x2513, 0x0078, 0x2541, - 0x81ff, 0x00c0, 0x253d, 0x6000, 0xa086, 0x0003, 0x00c0, 0x253d, - 0x2001, 0x7652, 0x2004, 0xd0a4, 0x00c0, 0x253d, 0x1078, 0x2d13, - 0x0040, 0x2541, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, - 0x2e0d, 0x7828, 0xa005, 0x0040, 0x2513, 0x0c7e, 0x1078, 0x2cfb, - 0x0c7f, 0x0040, 0x253d, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, - 0xc0fd, 0x683a, 0x1078, 0x6ae6, 0x0040, 0x253d, 0x7007, 0x0003, - 0x701b, 0x2e23, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x253d, - 0x0078, 0x2513, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x253d, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2cfb, - 0x0040, 0x253d, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, - 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, 0x3825, - 0x00c0, 0x2e70, 0x6004, 0xa0c6, 0x0707, 0x0040, 0x2e70, 0xa084, - 0x00ff, 0xa0c6, 0x0006, 0x00c0, 0x2e70, 0x87ff, 0x0040, 0x2e63, - 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, - 0x2bb2, 0x0078, 0x2e6c, 0xac80, 0x000a, 0x2098, 0x3400, 0x20a9, - 0x0004, 0x53a3, 0x1078, 0x2bb2, 0x21a2, 0x94a0, 0xa6b0, 0x0005, - 0x8108, 0xa186, 0x007e, 0x0040, 0x2e7b, 0xa686, 0x0028, 0x0040, - 0x2e84, 0x0078, 0x2e46, 0x86ff, 0x00c0, 0x2e82, 0x7120, 0x810b, - 0x0078, 0x2513, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, - 0x772a, 0x2061, 0x76bd, 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, - 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x137f, 0x7007, - 0x0002, 0x701b, 0x2e9c, 0x007c, 0x702c, 0xa005, 0x00c0, 0x2eae, - 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0x76bd, - 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x2e46, 0x7120, 0x810b, - 0x0078, 0x2513, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, 0x2071, - 0x7600, 0x6044, 0xd0a4, 0x00c0, 0x2edb, 0xd084, 0x0040, 0x2ec4, - 0x1078, 0x3004, 0x0078, 0x2ed7, 0xd08c, 0x0040, 0x2ecb, 0x1078, - 0x2f1b, 0x0078, 0x2ed7, 0xd094, 0x0040, 0x2ed2, 0x1078, 0x2efe, - 0x0078, 0x2ed7, 0xd09c, 0x0040, 0x2ed7, 0x1078, 0x2ee5, 0x0e7f, - 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, 0x2ee2, - 0xc19d, 0x612a, 0x017f, 0x0078, 0x2ed7, 0x6043, 0x0040, 0x6043, - 0x0000, 0x706f, 0x0000, 0x7087, 0x0001, 0x70a7, 0x0000, 0x2009, - 0x7cc0, 0x200b, 0x0000, 0x707f, 0x0000, 0x7073, 0x000f, 0x2009, - 0x000f, 0x2011, 0x353b, 0x1078, 0x45fe, 0x007c, 0x7070, 0xa005, - 0x00c0, 0x2f1a, 0x2011, 0x353b, 0x1078, 0x456e, 0x6043, 0x0020, - 0x6043, 0x0000, 0x6044, 0xd08c, 0x00c0, 0x2f16, 0x7083, 0x0000, - 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x2f1a, 0x7077, 0x0000, - 0x0078, 0x2f1a, 0x007c, 0x7074, 0xa08a, 0x0003, 0x00c8, 0x2f24, - 0x1079, 0x2f27, 0x0078, 0x2f26, 0x1078, 0x12d5, 0x007c, 0x2f2a, - 0x2f79, 0x3003, 0x0f7e, 0x7077, 0x0001, 0x20e1, 0xa000, 0x20e1, - 0x8700, 0x1078, 0x1dea, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, - 0x7b00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, - 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f, - 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f, - 0x0000, 0x2079, 0x7b0c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, - 0x7605, 0x20a1, 0x7b0e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0x7b12, - 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0x7b00, 0x20a1, 0x020b, - 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x1078, - 0x3562, 0x0f7f, 0x707b, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, - 0x007c, 0x0d7e, 0x7078, 0x707b, 0x0000, 0xa025, 0x0040, 0x2fed, - 0x6020, 0xd0b4, 0x00c0, 0x2feb, 0x7184, 0x81ff, 0x0040, 0x2fd4, - 0xa486, 0x000c, 0x00c0, 0x2fdf, 0xa480, 0x0018, 0x8004, 0x20a8, - 0x2011, 0x7b80, 0x2019, 0x7b00, 0x220c, 0x2304, 0xa106, 0x00c0, - 0x2fab, 0x8210, 0x8318, 0x00f0, 0x2f94, 0x6043, 0x0004, 0x608b, - 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x7077, 0x0002, 0x7083, - 0x0002, 0x0078, 0x2feb, 0x2069, 0x7b80, 0x6930, 0xa18e, 0x1101, - 0x00c0, 0x2fdf, 0x6834, 0xa005, 0x00c0, 0x2fdf, 0x6900, 0xa18c, - 0x00ff, 0x00c0, 0x2fbf, 0x6804, 0xa005, 0x0040, 0x2fd4, 0x2011, - 0x7b8e, 0x2019, 0x7605, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, - 0x0048, 0x2fd2, 0x00c0, 0x2fdf, 0x8210, 0x8318, 0x00f0, 0x2fc5, - 0x0078, 0x2fdf, 0x7087, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, - 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x2feb, 0x60c3, - 0x000c, 0x1078, 0x3562, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0, - 0x2feb, 0x60c3, 0x000c, 0x2011, 0x7840, 0x2013, 0x0000, 0x707b, - 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, - 0x5579, 0x0078, 0x2feb, 0x007c, 0x7080, 0xa08a, 0x001d, 0x00c8, - 0x300d, 0x1079, 0x3010, 0x0078, 0x300f, 0x1078, 0x12d5, 0x007c, - 0x3034, 0x3043, 0x3074, 0x3089, 0x30b9, 0x30e1, 0x3111, 0x313b, - 0x316b, 0x3191, 0x31da, 0x31fc, 0x3220, 0x3236, 0x325e, 0x3271, - 0x327a, 0x3293, 0x32c1, 0x32e9, 0x3317, 0x3341, 0x3384, 0x33b5, - 0x33d7, 0x3415, 0x343b, 0x3454, 0x3461, 0x7003, 0x0007, 0x6004, - 0xa084, 0xfff9, 0x6006, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, - 0x6043, 0x0002, 0x7083, 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, - 0x1078, 0x4561, 0x007c, 0x0f7e, 0x7078, 0xa086, 0x0014, 0x00c0, - 0x3072, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3072, 0x2079, - 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3070, 0x7834, 0xa005, - 0x00c0, 0x3070, 0x7a38, 0xd2fc, 0x0040, 0x3066, 0x70a4, 0xa005, - 0x00c0, 0x3066, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x2011, 0x3542, - 0x1078, 0x456e, 0x7083, 0x0010, 0x1078, 0x327a, 0x0078, 0x3072, - 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0003, 0x6043, 0x0004, - 0x1078, 0x35cc, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, - 0x20a3, 0x0000, 0x00f0, 0x3080, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x30b7, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x30b3, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1102, 0x00c0, 0x30b3, 0x7834, 0xa005, 0x00c0, - 0x30b3, 0x7a38, 0xd2fc, 0x0040, 0x30ad, 0x70a4, 0xa005, 0x00c0, - 0x30ad, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0004, 0x1078, - 0x30b9, 0x0078, 0x30b7, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0005, 0x1078, 0x35cc, 0x20a3, 0x1103, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x30d3, - 0x714c, 0xa186, 0xffff, 0x0040, 0x30d3, 0x1078, 0x3506, 0x0040, - 0x30d3, 0x1078, 0x35fb, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x310f, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x310b, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1103, 0x00c0, 0x310b, 0x7834, 0xa005, 0x00c0, - 0x310b, 0x7a38, 0xd2fc, 0x0040, 0x3105, 0x70a4, 0xa005, 0x00c0, - 0x3105, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0006, 0x1078, - 0x3111, 0x0078, 0x310f, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0007, 0x1078, 0x35cc, 0x20a3, 0x1104, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x312d, - 0x7150, 0xa186, 0xffff, 0x0040, 0x312d, 0xa180, 0x232f, 0x200c, - 0xa18c, 0xff00, 0x810f, 0x1078, 0x3506, 0x20a9, 0x0008, 0x2298, - 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3169, - 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3165, - 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3165, 0x7834, - 0xa005, 0x00c0, 0x3165, 0x7a38, 0xd2fc, 0x0040, 0x315f, 0x70a4, - 0xa005, 0x00c0, 0x315f, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x0008, 0x1078, 0x316b, 0x0078, 0x3169, 0x7083, 0x0002, 0x707b, - 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0009, 0x1078, 0x35cc, 0x20a3, - 0x1105, 0x20a3, 0x0100, 0x3430, 0x706c, 0xa005, 0x00c0, 0x317e, - 0x1078, 0x3470, 0x0040, 0x318e, 0x0078, 0x3188, 0x20a9, 0x0008, - 0x2099, 0x7b8e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x1078, 0x3562, 0x0078, 0x3190, 0x1078, 0x302d, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x31d8, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x31d4, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1105, 0x00c0, 0x31d4, 0x7834, 0x2011, 0x0100, - 0xa21e, 0x00c0, 0x31bd, 0x7a38, 0xd2fc, 0x0040, 0x31b7, 0x70a4, - 0xa005, 0x00c0, 0x31b7, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x000a, 0x1078, 0x31da, 0x0078, 0x31d8, 0xa005, 0x00c0, 0x31d4, - 0x7a38, 0xd2fc, 0x0040, 0x31cc, 0x70a4, 0xa005, 0x00c0, 0x31cc, - 0x1078, 0x35fb, 0x70a7, 0x0001, 0x707f, 0x0000, 0x7083, 0x000e, - 0x1078, 0x325e, 0x0078, 0x31d8, 0x7083, 0x0002, 0x707b, 0x0000, - 0x0f7f, 0x007c, 0x7083, 0x000b, 0x2011, 0x7b0e, 0x22a0, 0x20a9, - 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, - 0x41a4, 0x1078, 0x35cc, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x6030, - 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, - 0x321e, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, 0x00c0, - 0x321a, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x321a, - 0x7834, 0xa005, 0x00c0, 0x321a, 0x7083, 0x000c, 0x1078, 0x3220, - 0x0078, 0x321e, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, - 0x7083, 0x000d, 0x1078, 0x35cc, 0x20a3, 0x1107, 0x20a3, 0x0000, - 0x2099, 0x7b8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, - 0xa005, 0x0040, 0x325c, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, - 0x0084, 0x00c0, 0x3258, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, - 0x00c0, 0x3258, 0x7834, 0xa005, 0x00c0, 0x3258, 0x707f, 0x0001, - 0x1078, 0x35be, 0x7083, 0x000e, 0x1078, 0x325e, 0x0078, 0x325c, - 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000f, - 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, - 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, - 0x007c, 0x7078, 0xa005, 0x0040, 0x3279, 0x2011, 0x3542, 0x1078, - 0x456e, 0x007c, 0x7083, 0x0011, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, - 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, - 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x32bf, - 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x32bd, - 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x32bd, 0x7834, - 0xa005, 0x00c0, 0x32bd, 0x7a38, 0xd2fc, 0x0040, 0x32b7, 0x70a4, - 0xa005, 0x00c0, 0x32b7, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x0012, 0x1078, 0x32c1, 0x0078, 0x32bf, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0013, 0x1078, 0x35d8, 0x20a3, 0x1103, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x32db, - 0x714c, 0xa186, 0xffff, 0x0040, 0x32db, 0x1078, 0x3506, 0x0040, - 0x32db, 0x1078, 0x35fb, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3315, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3313, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3313, 0x7834, 0xa005, 0x00c0, - 0x3313, 0x7a38, 0xd2fc, 0x0040, 0x330d, 0x70a4, 0xa005, 0x00c0, - 0x330d, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0014, 0x1078, - 0x3317, 0x0078, 0x3315, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, - 0x0015, 0x1078, 0x35d8, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, - 0x2011, 0x7b8e, 0x706c, 0xa006, 0x00c0, 0x3333, 0x7150, 0xa186, - 0xffff, 0x0040, 0x3333, 0xa180, 0x232f, 0x200c, 0xa18c, 0xff00, - 0x810f, 0x1078, 0x3506, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3382, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3380, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1105, 0x00c0, 0x3380, 0x7834, 0x2011, 0x0100, - 0xa21e, 0x00c0, 0x3369, 0x7a38, 0xd2fc, 0x0040, 0x3367, 0x70a4, - 0xa005, 0x00c0, 0x3367, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x0078, - 0x337a, 0xa005, 0x00c0, 0x3380, 0x7a38, 0xd2fc, 0x0040, 0x3378, - 0x70a4, 0xa005, 0x00c0, 0x3378, 0x1078, 0x35fb, 0x70a7, 0x0001, - 0x707f, 0x0000, 0x7083, 0x0016, 0x1078, 0x3384, 0x0078, 0x3382, + 0xa0be, 0x0100, 0x0040, 0x2b59, 0xa0be, 0x0112, 0x0040, 0x2b59, + 0xa0be, 0x0113, 0x0040, 0x2b59, 0xa0be, 0x0114, 0x0040, 0x2b59, + 0xa0be, 0x0117, 0x0040, 0x2b59, 0xa0be, 0x011a, 0x0040, 0x2b59, + 0xa0be, 0x0121, 0x0040, 0x2b4f, 0xa0be, 0x0131, 0x0040, 0x2b4f, + 0xa0be, 0x0171, 0x0040, 0x2b59, 0xa0be, 0x0173, 0x0040, 0x2b59, + 0xa0be, 0x01a1, 0x00c0, 0x2b21, 0x6830, 0x8007, 0x6832, 0x0078, + 0x2b5f, 0xa0be, 0x0212, 0x0040, 0x2b55, 0xa0be, 0x0213, 0x0040, + 0x2b55, 0xa0be, 0x0214, 0x0040, 0x2b47, 0xa0be, 0x0217, 0x0040, + 0x2b41, 0xa0be, 0x021a, 0x00c0, 0x2b3a, 0x6838, 0x8007, 0x683a, + 0x0078, 0x2b59, 0xa0be, 0x0300, 0x0040, 0x2b59, 0x0d7f, 0x0078, + 0x253b, 0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x2b95, 0xad80, + 0x000e, 0x20a9, 0x0001, 0x1078, 0x2b95, 0x0078, 0x2b59, 0xad80, + 0x000c, 0x1078, 0x2ba3, 0x0078, 0x2b5f, 0xad80, 0x000e, 0x1078, + 0x2ba3, 0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x2b95, 0x0c7e, + 0x1078, 0x2cec, 0x0040, 0x2b8a, 0x6838, 0xc0fd, 0x683a, 0x6837, + 0x0119, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, + 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, + 0x0c7f, 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, + 0x0000, 0x1078, 0x6a52, 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, + 0x2b8e, 0x007c, 0x0c7f, 0x0d7f, 0x0078, 0x2537, 0x6820, 0xa086, + 0x8001, 0x0040, 0x2537, 0x0078, 0x250d, 0x017e, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x00f0, + 0x2b97, 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, + 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, 0x017f, + 0x007c, 0x81ff, 0x00c0, 0x2537, 0x7924, 0x2140, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x0080, 0x0048, 0x253b, 0xa182, 0x00ff, 0x00c8, + 0x253b, 0x7a2c, 0x7b28, 0x6064, 0xa306, 0x00c0, 0x2bd7, 0x6068, + 0xa24e, 0x0040, 0x253b, 0xa9cc, 0xff00, 0x0040, 0x253b, 0x0c7e, + 0x1078, 0x2c4b, 0x2c68, 0x0c7f, 0x0040, 0x2bfe, 0xa0c6, 0x4000, + 0x00c0, 0x2be4, 0x0078, 0x2bfb, 0xa0c6, 0x4007, 0x00c0, 0x2beb, + 0x2408, 0x0078, 0x2bfb, 0xa0c6, 0x4008, 0x00c0, 0x2bf3, 0x2708, + 0x2610, 0x0078, 0x2bfb, 0xa0c6, 0x4009, 0x00c0, 0x2bf9, 0x0078, + 0x2bfb, 0x2001, 0x4006, 0x2020, 0x0078, 0x250f, 0x017e, 0x0b7e, + 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x5b94, 0x0040, 0x2c39, 0x2d00, + 0x601a, 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x2cec, 0x0c7f, + 0x2b70, 0x0040, 0x2537, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, + 0x22b5, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37b5, + 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, 0x7088, + 0x8000, 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, 0xa085, + 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x2c44, 0x007c, 0x6830, 0xa086, 0x0100, 0x00c0, + 0x250d, 0x0078, 0x2537, 0x0e7e, 0x0d7e, 0x2029, 0x0000, 0x2021, + 0x0080, 0x20a9, 0x007f, 0x2071, 0x77a0, 0x2e04, 0xa005, 0x00c0, + 0x2c5f, 0x2100, 0xa406, 0x0040, 0x2c9c, 0x0078, 0x2c90, 0x2068, + 0x6f10, 0x2700, 0xa306, 0x00c0, 0x2c81, 0x6e14, 0x2600, 0xa206, + 0x00c0, 0x2c81, 0x2400, 0xa106, 0x00c0, 0x2c7d, 0x2d60, 0xd884, + 0x0040, 0x2ca2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x2ca2, 0x2001, 0x4000, 0x0078, 0x2ca3, 0x2001, 0x4007, 0x0078, + 0x2ca3, 0x2400, 0xa106, 0x00c0, 0x2c90, 0x6e14, 0x87ff, 0x00c0, + 0x2c8c, 0x86ff, 0x0040, 0x2c9c, 0x2001, 0x4008, 0x0078, 0x2ca3, + 0x8420, 0x8e70, 0x00f0, 0x2c55, 0x2001, 0x4009, 0x0078, 0x2ca3, + 0x2001, 0x0001, 0x0078, 0x2ca3, 0x1078, 0x37e6, 0x00c0, 0x2c98, + 0x6312, 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, + 0x00c0, 0x2537, 0x1078, 0x2cec, 0x0040, 0x2537, 0x6837, 0x0000, + 0x7824, 0xa005, 0x0040, 0x253b, 0xa096, 0x00ff, 0x0040, 0x2cbc, + 0xa092, 0x0004, 0x00c8, 0x253b, 0x2010, 0x2d18, 0x1078, 0x2277, + 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, 0x2cc7, 0x007c, 0x6830, + 0xa086, 0x0100, 0x0040, 0x2537, 0x0078, 0x250d, 0x81ff, 0x00c0, + 0x2537, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, + 0x253b, 0xa182, 0x00ff, 0x00c8, 0x253b, 0x127e, 0x2091, 0x8000, + 0x1078, 0x6979, 0x00c0, 0x2ce9, 0x1078, 0x3805, 0x127f, 0x0078, + 0x250d, 0x127f, 0x0078, 0x2537, 0x1078, 0x1327, 0x0040, 0x2d03, + 0xa006, 0x6802, 0x7010, 0xa005, 0x00c0, 0x2cfb, 0x2d00, 0x7012, + 0x7016, 0x0078, 0x2d01, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, + 0x7016, 0xad80, 0x000d, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, + 0x1078, 0x381d, 0x00c0, 0x2d12, 0xa6b4, 0x00ff, 0xa682, 0x0010, + 0x0048, 0x2d13, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, + 0x0040, 0x2d20, 0x2168, 0x6904, 0x1078, 0x1340, 0x0078, 0x2d17, + 0x7112, 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x2d2a, + 0x2031, 0x0000, 0x2061, 0x76bd, 0x6606, 0x6112, 0x600e, 0x6226, + 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x1377, 0x7007, 0x0002, + 0x701b, 0x250d, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, + 0x0000, 0x2001, 0x767b, 0x2004, 0xa005, 0x00c0, 0x2d56, 0x0068, + 0x2d56, 0x7818, 0xd084, 0x00c0, 0x2d56, 0x781b, 0x0001, 0x7a22, + 0x7b26, 0x7c2a, 0x2091, 0x4080, 0x0078, 0x2d7b, 0x017e, 0x0c7e, + 0x0e7e, 0x2071, 0x766d, 0x7138, 0xa182, 0x0008, 0x0048, 0x2d64, + 0x7030, 0x2060, 0x0078, 0x2d75, 0x7030, 0xa0e0, 0x0008, 0xac82, + 0x76bd, 0x0048, 0x2d6d, 0x2061, 0x767d, 0x2c00, 0x7032, 0x81ff, + 0x00c0, 0x2d73, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, + 0x0e7f, 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, + 0x766d, 0x7038, 0xa005, 0x0040, 0x2db7, 0x127e, 0x2091, 0x8000, + 0x0068, 0x2db6, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, + 0x2db5, 0x0c7e, 0x781b, 0x0001, 0x7034, 0x2060, 0x2c04, 0x7822, + 0x6004, 0x7826, 0x6008, 0x782a, 0x2091, 0x4080, 0x7038, 0x8001, + 0x703a, 0xa005, 0x00c0, 0x2dab, 0x7033, 0x767d, 0x7037, 0x767d, + 0x0c7f, 0x0078, 0x2db5, 0xac80, 0x0008, 0xa0fa, 0x76bd, 0x0048, + 0x2db3, 0x2001, 0x767d, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, + 0x007c, 0x027e, 0x2001, 0x7652, 0x2004, 0xd0c4, 0x0040, 0x2dc4, + 0x2011, 0x8014, 0x1078, 0x2d3b, 0x027f, 0x007c, 0x81ff, 0x00c0, + 0x2537, 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x1078, + 0x3573, 0x127f, 0x0078, 0x250d, 0x7824, 0x2008, 0xa18c, 0xfffd, + 0x00c0, 0x2ddf, 0x61c8, 0xa10d, 0x61ca, 0x0078, 0x250d, 0x0078, + 0x253b, 0x81ff, 0x00c0, 0x2537, 0x6000, 0xa086, 0x0003, 0x00c0, + 0x2537, 0x2001, 0x7652, 0x2004, 0xd0a4, 0x00c0, 0x2537, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x00c0, 0x2dfe, 0x7828, 0xa005, 0x0040, 0x250d, 0x0c7e, 0x1078, + 0x2cec, 0x0c7f, 0x0040, 0x2537, 0x6837, 0x0000, 0x6833, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6adb, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x2e14, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, + 0x2537, 0x0078, 0x250d, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, + 0x00c0, 0x2537, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, + 0x2cec, 0x0040, 0x2537, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, + 0x0000, 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, + 0x381d, 0x00c0, 0x2e61, 0x6004, 0xa0c6, 0x0707, 0x0040, 0x2e61, + 0xa084, 0x00ff, 0xa0c6, 0x0006, 0x00c0, 0x2e61, 0x87ff, 0x0040, + 0x2e54, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, + 0x1078, 0x2ba3, 0x0078, 0x2e5d, 0xac80, 0x000a, 0x2098, 0x3400, + 0x20a9, 0x0004, 0x53a3, 0x1078, 0x2ba3, 0x21a2, 0x94a0, 0xa6b0, + 0x0005, 0x8108, 0xa186, 0x007e, 0x0040, 0x2e6c, 0xa686, 0x0028, + 0x0040, 0x2e75, 0x0078, 0x2e37, 0x86ff, 0x00c0, 0x2e73, 0x7120, + 0x810b, 0x0078, 0x250d, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, + 0x7022, 0x772a, 0x2061, 0x76bd, 0x6007, 0x0000, 0x6612, 0x7024, + 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x1377, + 0x7007, 0x0002, 0x701b, 0x2e8d, 0x007c, 0x702c, 0xa005, 0x00c0, + 0x2e9f, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, + 0x76bd, 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x2e37, 0x7120, + 0x810b, 0x0078, 0x250d, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, + 0x2071, 0x7600, 0x6044, 0xd0a4, 0x00c0, 0x2ecc, 0xd084, 0x0040, + 0x2eb5, 0x1078, 0x2ff7, 0x0078, 0x2ec8, 0xd08c, 0x0040, 0x2ebc, + 0x1078, 0x2f0e, 0x0078, 0x2ec8, 0xd094, 0x0040, 0x2ec3, 0x1078, + 0x2ef1, 0x0078, 0x2ec8, 0xd09c, 0x0040, 0x2ec8, 0x1078, 0x2ed6, + 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, + 0x2ed3, 0xc19d, 0x612a, 0x017f, 0x0078, 0x2ec8, 0x6043, 0x0040, + 0x6043, 0x0000, 0x706f, 0x0000, 0x7087, 0x0001, 0x70a7, 0x0000, + 0x70bf, 0x0000, 0x2009, 0x7cc0, 0x200b, 0x0000, 0x707f, 0x0000, + 0x7073, 0x000f, 0x2009, 0x000f, 0x2011, 0x3533, 0x1078, 0x45f6, + 0x007c, 0x7070, 0xa005, 0x00c0, 0x2f0d, 0x2011, 0x3533, 0x1078, + 0x4566, 0x6043, 0x0020, 0x6043, 0x0000, 0x6044, 0xd08c, 0x00c0, + 0x2f09, 0x7083, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, + 0x2f0d, 0x7077, 0x0000, 0x0078, 0x2f0d, 0x007c, 0x7074, 0xa08a, + 0x0003, 0x00c8, 0x2f17, 0x1079, 0x2f1a, 0x0078, 0x2f19, 0x1078, + 0x12cd, 0x007c, 0x2f1d, 0x2f6c, 0x2ff6, 0x0f7e, 0x7077, 0x0001, + 0x20e1, 0xa000, 0x20e1, 0x8700, 0x1078, 0x1de4, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2079, 0x7b00, 0x207b, 0x2200, 0x7807, 0x00ef, + 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, + 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, + 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0x7b0c, 0x207b, 0x1101, + 0x7807, 0x0000, 0x2099, 0x7605, 0x20a1, 0x7b0e, 0x20a9, 0x0004, + 0x53a3, 0x2079, 0x7b12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, + 0x7b00, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, + 0x600f, 0x0000, 0x1078, 0x355a, 0x0f7f, 0x707b, 0x0000, 0x6043, + 0x0008, 0x6043, 0x0000, 0x007c, 0x0d7e, 0x7078, 0x707b, 0x0000, + 0xa025, 0x0040, 0x2fe0, 0x6020, 0xd0b4, 0x00c0, 0x2fde, 0x7184, + 0x81ff, 0x0040, 0x2fc7, 0xa486, 0x000c, 0x00c0, 0x2fd2, 0xa480, + 0x0018, 0x8004, 0x20a8, 0x2011, 0x7b80, 0x2019, 0x7b00, 0x220c, + 0x2304, 0xa106, 0x00c0, 0x2f9e, 0x8210, 0x8318, 0x00f0, 0x2f87, + 0x6043, 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, + 0x7077, 0x0002, 0x7083, 0x0002, 0x0078, 0x2fde, 0x2069, 0x7b80, + 0x6930, 0xa18e, 0x1101, 0x00c0, 0x2fd2, 0x6834, 0xa005, 0x00c0, + 0x2fd2, 0x6900, 0xa18c, 0x00ff, 0x00c0, 0x2fb2, 0x6804, 0xa005, + 0x0040, 0x2fc7, 0x2011, 0x7b8e, 0x2019, 0x7605, 0x20a9, 0x0004, + 0x220c, 0x2304, 0xa102, 0x0048, 0x2fc5, 0x00c0, 0x2fd2, 0x8210, + 0x8318, 0x00f0, 0x2fb8, 0x0078, 0x2fd2, 0x7087, 0x0000, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, + 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, + 0x00c0, 0x2fde, 0x60c3, 0x000c, 0x1078, 0x355a, 0x0d7f, 0x007c, + 0x6020, 0xd0b4, 0x00c0, 0x2fde, 0x60c3, 0x000c, 0x2011, 0x7840, + 0x2013, 0x0000, 0x707b, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, + 0x60a7, 0x9575, 0x1078, 0x5571, 0x0078, 0x2fde, 0x007c, 0x7080, + 0xa08a, 0x001d, 0x00c8, 0x3000, 0x1079, 0x3003, 0x0078, 0x3002, + 0x1078, 0x12cd, 0x007c, 0x3027, 0x3036, 0x3067, 0x307c, 0x30ac, + 0x30d4, 0x3104, 0x312e, 0x315e, 0x3184, 0x31cd, 0x31ef, 0x3213, + 0x3229, 0x3251, 0x3264, 0x326d, 0x3286, 0x32b4, 0x32dc, 0x330a, + 0x3334, 0x337c, 0x33ad, 0x33cf, 0x340d, 0x3433, 0x344c, 0x3459, + 0x7003, 0x0007, 0x6004, 0xa084, 0xfff9, 0x6006, 0x007c, 0x608b, + 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, 0x7083, 0x0001, 0x2009, + 0x07d0, 0x2011, 0x353a, 0x1078, 0x4559, 0x007c, 0x0f7e, 0x7078, + 0xa086, 0x0014, 0x00c0, 0x3065, 0x6043, 0x0000, 0x6020, 0xd0b4, + 0x00c0, 0x3065, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, + 0x3063, 0x7834, 0xa005, 0x00c0, 0x3063, 0x7a38, 0xd2fc, 0x0040, + 0x3059, 0x70a4, 0xa005, 0x00c0, 0x3059, 0x1078, 0x35f3, 0x70a7, + 0x0001, 0x2011, 0x353a, 0x1078, 0x4566, 0x7083, 0x0010, 0x1078, + 0x326d, 0x0078, 0x3065, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, + 0x0003, 0x6043, 0x0004, 0x1078, 0x35c4, 0x20a3, 0x1102, 0x20a3, + 0x0000, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x3073, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x30aa, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x30a6, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x30a6, + 0x7834, 0xa005, 0x00c0, 0x30a6, 0x7a38, 0xd2fc, 0x0040, 0x30a0, + 0x70a4, 0xa005, 0x00c0, 0x30a0, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0004, 0x1078, 0x30ac, 0x0078, 0x30aa, 0x7083, 0x0002, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0005, 0x1078, 0x35c4, + 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x30c6, 0x714c, 0xa186, 0xffff, 0x0040, 0x30c6, + 0x1078, 0x34fe, 0x0040, 0x30c6, 0x1078, 0x35f3, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x3102, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x30fe, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x30fe, + 0x7834, 0xa005, 0x00c0, 0x30fe, 0x7a38, 0xd2fc, 0x0040, 0x30f8, + 0x70a4, 0xa005, 0x00c0, 0x30f8, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0006, 0x1078, 0x3104, 0x0078, 0x3102, 0x7083, 0x0002, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0007, 0x1078, 0x35c4, + 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x3120, 0x7150, 0xa186, 0xffff, 0x0040, 0x3120, + 0xa180, 0x2329, 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x34fe, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, + 0xa005, 0x0040, 0x315c, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, + 0x0014, 0x00c0, 0x3158, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, + 0x00c0, 0x3158, 0x7834, 0xa005, 0x00c0, 0x3158, 0x7a38, 0xd2fc, + 0x0040, 0x3152, 0x70a4, 0xa005, 0x00c0, 0x3152, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x0008, 0x1078, 0x315e, 0x0078, 0x315c, + 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0009, + 0x1078, 0x35c4, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x706c, + 0xa005, 0x00c0, 0x3171, 0x1078, 0x3468, 0x0040, 0x3181, 0x0078, + 0x317b, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, 0x0078, + 0x3183, 0x1078, 0x3020, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x31cb, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x31c7, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1105, 0x00c0, 0x31c7, + 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x31b0, 0x7a38, 0xd2fc, + 0x0040, 0x31aa, 0x70a4, 0xa005, 0x00c0, 0x31aa, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x000a, 0x1078, 0x31cd, 0x0078, 0x31cb, + 0xa005, 0x00c0, 0x31c7, 0x7a38, 0xd2fc, 0x0040, 0x31bf, 0x70a4, + 0xa005, 0x00c0, 0x31bf, 0x1078, 0x35f3, 0x70a7, 0x0001, 0x707f, + 0x0000, 0x7083, 0x000e, 0x1078, 0x3251, 0x0078, 0x31cb, 0x7083, + 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000b, 0x2011, + 0x7b0e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, + 0x0002, 0x2009, 0x0000, 0x41a4, 0x1078, 0x35c4, 0x20a3, 0x1106, + 0x20a3, 0x0000, 0x6030, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, + 0x0042, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x355a, 0x007c, 0x0f7e, + 0x7078, 0xa005, 0x0040, 0x3211, 0x2011, 0x353a, 0x1078, 0x4566, + 0xa086, 0x0084, 0x00c0, 0x320d, 0x2079, 0x7b80, 0x7a30, 0xa296, + 0x1106, 0x00c0, 0x320d, 0x7834, 0xa005, 0x00c0, 0x320d, 0x7083, + 0x000c, 0x1078, 0x3213, 0x0078, 0x3211, 0x7083, 0x0002, 0x707b, + 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000d, 0x1078, 0x35c4, 0x20a3, + 0x1107, 0x20a3, 0x0000, 0x2099, 0x7b8e, 0x20a9, 0x0040, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x1078, 0x355a, + 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x324f, 0x2011, 0x353a, + 0x1078, 0x4566, 0xa086, 0x0084, 0x00c0, 0x324b, 0x2079, 0x7b80, + 0x7a30, 0xa296, 0x1107, 0x00c0, 0x324b, 0x7834, 0xa005, 0x00c0, + 0x324b, 0x707f, 0x0001, 0x1078, 0x35b6, 0x7083, 0x000e, 0x1078, + 0x3251, 0x0078, 0x324f, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, + 0x007c, 0x7083, 0x000f, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, + 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, + 0x353a, 0x1078, 0x4559, 0x007c, 0x7078, 0xa005, 0x0040, 0x326c, + 0x2011, 0x353a, 0x1078, 0x4566, 0x007c, 0x7083, 0x0011, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, + 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, + 0x53a6, 0x60c3, 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, + 0xa005, 0x0040, 0x32b2, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, + 0x0014, 0x00c0, 0x32b0, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, + 0x00c0, 0x32b0, 0x7834, 0xa005, 0x00c0, 0x32b0, 0x7a38, 0xd2fc, + 0x0040, 0x32aa, 0x70a4, 0xa005, 0x00c0, 0x32aa, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x0012, 0x1078, 0x32b4, 0x0078, 0x32b2, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0013, 0x1078, 0x35d0, + 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x32ce, 0x714c, 0xa186, 0xffff, 0x0040, 0x32ce, + 0x1078, 0x34fe, 0x0040, 0x32ce, 0x1078, 0x35f3, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x3308, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x3306, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3306, + 0x7834, 0xa005, 0x00c0, 0x3306, 0x7a38, 0xd2fc, 0x0040, 0x3300, + 0x70a4, 0xa005, 0x00c0, 0x3300, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0014, 0x1078, 0x330a, 0x0078, 0x3308, 0x707b, 0x0000, + 0x0f7f, 0x007c, 0x7083, 0x0015, 0x1078, 0x35d0, 0x20a3, 0x1104, + 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa006, 0x00c0, + 0x3326, 0x7150, 0xa186, 0xffff, 0x0040, 0x3326, 0xa180, 0x2329, + 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x34fe, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x337a, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x3378, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1105, 0x00c0, 0x3378, + 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x3361, 0x7a38, 0xd2f4, + 0x0040, 0x3354, 0x70bf, 0x0008, 0xd2fc, 0x0040, 0x335f, 0x70a4, + 0xa005, 0x00c0, 0x335f, 0x1078, 0x35f3, 0x70a7, 0x0001, 0x0078, + 0x3372, 0xa005, 0x00c0, 0x3378, 0x7a38, 0xd2fc, 0x0040, 0x3370, + 0x70a4, 0xa005, 0x00c0, 0x3370, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x707f, 0x0000, 0x7083, 0x0016, 0x1078, 0x337c, 0x0078, 0x337a, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, 0x3430, - 0x2011, 0x7b8e, 0x7083, 0x0017, 0x0078, 0x3398, 0x7083, 0x001b, - 0x706c, 0xa005, 0x00c0, 0x33a2, 0x1078, 0x3470, 0x0040, 0x33b2, - 0x0078, 0x33ac, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x0078, 0x33b4, 0x1078, 0x302d, 0x007c, 0x0f7e, 0x7078, 0xa005, - 0x0040, 0x33d5, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, - 0x00c0, 0x33d3, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, - 0x33d3, 0x7834, 0xa005, 0x00c0, 0x33d3, 0x7083, 0x0018, 0x1078, - 0x33d7, 0x0078, 0x33d5, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, - 0x0019, 0x1078, 0x35d8, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, + 0x2011, 0x7b8e, 0x7083, 0x0017, 0x0078, 0x3390, 0x7083, 0x001b, + 0x706c, 0xa005, 0x00c0, 0x339a, 0x1078, 0x3468, 0x0040, 0x33aa, + 0x0078, 0x33a4, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, + 0x0078, 0x33ac, 0x1078, 0x3020, 0x007c, 0x0f7e, 0x7078, 0xa005, + 0x0040, 0x33cd, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0084, + 0x00c0, 0x33cb, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, + 0x33cb, 0x7834, 0xa005, 0x00c0, 0x33cb, 0x7083, 0x0018, 0x1078, + 0x33cf, 0x0078, 0x33cd, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, + 0x0019, 0x1078, 0x35d0, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, 0x7b8e, 0x2039, 0x7b0e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x6030, 0x2310, 0x8214, 0xa2a0, - 0x7b0e, 0x2414, 0xa38c, 0x0001, 0x0040, 0x3402, 0xa294, 0xff00, - 0x0078, 0x3405, 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, + 0x7b0e, 0x2414, 0xa38c, 0x0001, 0x0040, 0x33fa, 0xa294, 0xff00, + 0x0078, 0x33fd, 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, - 0x0040, 0x3439, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, - 0x00c0, 0x3437, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, 0x00c0, - 0x3437, 0x7834, 0xa005, 0x00c0, 0x3437, 0x707f, 0x0001, 0x1078, - 0x35be, 0x7083, 0x001a, 0x1078, 0x343b, 0x0078, 0x3439, 0x707b, + 0x60c3, 0x0084, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, + 0x0040, 0x3431, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0084, + 0x00c0, 0x342f, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, 0x00c0, + 0x342f, 0x7834, 0xa005, 0x00c0, 0x342f, 0x707f, 0x0001, 0x1078, + 0x35b6, 0x7083, 0x001a, 0x1078, 0x3433, 0x0078, 0x3431, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x3562, 0x007c, 0x7078, 0xa005, 0x0040, 0x3460, - 0x2011, 0x3542, 0x1078, 0x456e, 0x7083, 0x001c, 0x1078, 0x3461, + 0x0084, 0x1078, 0x355a, 0x007c, 0x7078, 0xa005, 0x0040, 0x3458, + 0x2011, 0x353a, 0x1078, 0x4566, 0x7083, 0x001c, 0x1078, 0x3459, 0x007c, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, - 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, 0x007c, + 0x0001, 0x2009, 0x07d0, 0x2011, 0x353a, 0x1078, 0x4559, 0x007c, 0x087e, 0x097e, 0x2029, 0x7652, 0x252c, 0x20a9, 0x0008, 0x2041, 0x7b0e, 0x28a0, 0x2099, 0x7b8e, 0x53a3, 0x20a9, 0x0008, 0x2011, - 0x0007, 0xd5d4, 0x0040, 0x3486, 0x2011, 0x0000, 0x2800, 0xa200, - 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x3498, 0xd5d4, 0x0040, 0x3493, - 0x8210, 0x0078, 0x3494, 0x8211, 0x00f0, 0x3486, 0x0078, 0x34fd, - 0x82ff, 0x00c0, 0x34aa, 0xd5d4, 0x0040, 0x34a4, 0xa1a6, 0x3fff, - 0x0040, 0x3490, 0x0078, 0x34a8, 0xa1a6, 0x3fff, 0x0040, 0x34fd, + 0x0007, 0xd5d4, 0x0040, 0x347e, 0x2011, 0x0000, 0x2800, 0xa200, + 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x3490, 0xd5d4, 0x0040, 0x348b, + 0x8210, 0x0078, 0x348c, 0x8211, 0x00f0, 0x347e, 0x0078, 0x34f5, + 0x82ff, 0x00c0, 0x34a2, 0xd5d4, 0x0040, 0x349c, 0xa1a6, 0x3fff, + 0x0040, 0x3488, 0x0078, 0x34a0, 0xa1a6, 0x3fff, 0x0040, 0x34f5, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0040, - 0x34b3, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x34ba, 0x8423, - 0x0078, 0x34bb, 0x8424, 0x00c8, 0x34c8, 0xd5d4, 0x0040, 0x34c3, - 0x8319, 0x0078, 0x34c4, 0x8318, 0x00f0, 0x34b4, 0x0078, 0x34fd, - 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x34cc, 0x2328, - 0x8529, 0xa2be, 0x0007, 0x0040, 0x34e0, 0x007e, 0x2039, 0x0007, - 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, 0x34dc, - 0x754e, 0xa5c8, 0x232f, 0x292c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, + 0x34ab, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x34b2, 0x8423, + 0x0078, 0x34b3, 0x8424, 0x00c8, 0x34c0, 0xd5d4, 0x0040, 0x34bb, + 0x8319, 0x0078, 0x34bc, 0x8318, 0x00f0, 0x34ac, 0x0078, 0x34f5, + 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x34c4, 0x2328, + 0x8529, 0xa2be, 0x0007, 0x0040, 0x34d8, 0x007e, 0x2039, 0x0007, + 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, 0x34d4, + 0x754e, 0xa5c8, 0x2329, 0x292c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405, 0x201a, 0x706f, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0xa085, 0x0001, 0x0078, 0x3503, 0xa006, 0x0078, 0x3503, - 0xa006, 0x1078, 0x12d5, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, - 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x3513, 0x8420, - 0x8001, 0x0078, 0x350b, 0x2118, 0x84ff, 0x0040, 0x351c, 0xa39a, - 0x0010, 0x8421, 0x00c0, 0x3517, 0x2021, 0x0001, 0x83ff, 0x0040, - 0x3525, 0x8423, 0x8319, 0x00c0, 0x3521, 0xa238, 0x2704, 0xa42c, - 0x00c0, 0x353a, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x232f, 0x242c, + 0x0000, 0xa085, 0x0001, 0x0078, 0x34fb, 0xa006, 0x0078, 0x34fb, + 0xa006, 0x1078, 0x12cd, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, + 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x350b, 0x8420, + 0x8001, 0x0078, 0x3503, 0x2118, 0x84ff, 0x0040, 0x3514, 0xa39a, + 0x0010, 0x8421, 0x00c0, 0x350f, 0x2021, 0x0001, 0x83ff, 0x0040, + 0x351d, 0x8423, 0x8319, 0x00c0, 0x3519, 0xa238, 0x2704, 0xa42c, + 0x00c0, 0x3532, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x2329, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0001, 0xa084, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7073, 0x0000, 0x0e7f, 0x007c, 0x0e7e, 0x0f7e, 0x2079, 0x0100, 0x2071, 0x0140, - 0x1078, 0x5582, 0x7004, 0xa084, 0x4000, 0x0040, 0x3553, 0x7003, + 0x1078, 0x557a, 0x7004, 0xa084, 0x4000, 0x0040, 0x354b, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, 0x2091, 0x8000, 0x2071, 0x7620, 0x2073, 0x0000, 0x7843, 0x0090, 0x7843, 0x0010, 0x127f, 0x0f7f, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0x7840, 0x2013, 0x0000, 0x707b, 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, - 0x60a7, 0x9575, 0x1078, 0x5579, 0x2009, 0x07d0, 0x2011, 0x3542, - 0x1078, 0x45fe, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x2009, 0x00f7, 0x1078, 0x35e4, 0x2061, 0x7849, 0x601b, + 0x60a7, 0x9575, 0x1078, 0x5571, 0x2009, 0x07d0, 0x2011, 0x353a, + 0x1078, 0x45f6, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x2009, 0x00f7, 0x1078, 0x35dc, 0x2061, 0x7849, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x7600, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, - 0x35a0, 0x1078, 0x4561, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, + 0x3598, 0x1078, 0x4559, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x0100, 0x1078, - 0x5582, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0040, 0x35b4, - 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x202b, - 0x1078, 0x357b, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, + 0x557a, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0040, 0x35ac, + 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x2025, + 0x1078, 0x3573, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2099, 0x7b8e, 0x3304, 0x8007, 0x20a2, 0x9398, - 0x94a0, 0x00f0, 0x35c4, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x94a0, 0x00f0, 0x35bc, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b00, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e, 0x2061, 0x0100, - 0x810f, 0x2001, 0x762c, 0x2004, 0xa005, 0x00c0, 0x35f5, 0x6030, - 0xa084, 0x00ff, 0xa105, 0x0078, 0x35f7, 0xa185, 0x00f7, 0x604a, + 0x810f, 0x2001, 0x762c, 0x2004, 0xa005, 0x00c0, 0x35ed, 0x6030, + 0xa084, 0x00ff, 0xa105, 0x0078, 0x35ef, 0xa185, 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, 0x017e, 0x047e, 0x2001, 0x7652, 0x2004, - 0xd0a4, 0x0040, 0x360e, 0xa006, 0x2020, 0x2009, 0x002a, 0x1078, - 0x7541, 0x2001, 0x760c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, - 0x1078, 0x2299, 0x047f, 0x017f, 0x007c, 0x157e, 0x20a9, 0x00ff, - 0x2009, 0x7720, 0xa006, 0x200a, 0x8108, 0x00f0, 0x361b, 0x157f, + 0xd0a4, 0x0040, 0x3606, 0xa006, 0x2020, 0x2009, 0x002a, 0x1078, + 0x7536, 0x2001, 0x760c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, + 0x1078, 0x2293, 0x047f, 0x017f, 0x007c, 0x157e, 0x20a9, 0x00ff, + 0x2009, 0x7720, 0xa006, 0x200a, 0x8108, 0x00f0, 0x3613, 0x157f, 0x007c, 0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0x7651, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, - 0x232f, 0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, + 0x2329, 0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, @@ -1256,500 +1237,500 @@ 0x61a2, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x6944, 0xa1b4, 0x00ff, 0xa682, 0x0010, - 0x00c8, 0x3715, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, - 0x371b, 0x2001, 0x760c, 0x2004, 0xa084, 0x0003, 0x00c0, 0x36fe, - 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x36ec, 0x6004, 0xa084, - 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x36f2, 0x6078, 0xa00d, 0x0040, - 0x3697, 0xa680, 0x75d5, 0x2004, 0xa10c, 0x00c0, 0x36e6, 0x607c, - 0xa00d, 0x0040, 0x36b3, 0xa680, 0x75d5, 0x2004, 0xa10c, 0x0040, - 0x36b3, 0x694c, 0xd1fc, 0x00c0, 0x36a9, 0x1078, 0x37ae, 0x0078, - 0x36e1, 0x1078, 0x377f, 0x694c, 0xd1ec, 0x00c0, 0x36e1, 0x1078, - 0x38c7, 0x0078, 0x36e1, 0x694c, 0xa184, 0xa000, 0x0040, 0x36d1, - 0xd1ec, 0x0040, 0x36ca, 0xd1fc, 0x0040, 0x36c2, 0x1078, 0x38de, - 0x0078, 0x36cd, 0xa680, 0x75d5, 0x200c, 0x607c, 0xa105, 0x607e, - 0x0078, 0x36d1, 0xd1fc, 0x0040, 0x36d1, 0x1078, 0x377f, 0x0078, - 0x36e1, 0x6050, 0xa00d, 0x0040, 0x36dc, 0x2d00, 0x200a, 0x6803, - 0x0000, 0x6052, 0x0078, 0x36e1, 0x2d00, 0x6052, 0x604e, 0x6803, - 0x0000, 0x1078, 0x4844, 0xa006, 0x127f, 0x007c, 0x2001, 0x0005, - 0x2009, 0x0000, 0x0078, 0x371f, 0x2001, 0x0028, 0x2009, 0x0000, - 0x0078, 0x371f, 0xa082, 0x0006, 0x00c8, 0x36fe, 0x60a0, 0xd0bc, - 0x0040, 0x368d, 0x2001, 0x0028, 0x0078, 0x3711, 0x2009, 0x760c, - 0x210c, 0xd18c, 0x0040, 0x3708, 0x2001, 0x0004, 0x0078, 0x3711, - 0xd184, 0x0040, 0x370f, 0x2001, 0x0004, 0x0078, 0x3711, 0x2001, - 0x0029, 0x2009, 0x0000, 0x0078, 0x371f, 0x2001, 0x0029, 0x2009, - 0x0000, 0x0078, 0x371f, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, + 0x00c8, 0x370d, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, + 0x3713, 0x2001, 0x760c, 0x2004, 0xa084, 0x0003, 0x00c0, 0x36f6, + 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x36e4, 0x6004, 0xa084, + 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x36ea, 0x6078, 0xa00d, 0x0040, + 0x368f, 0xa680, 0x75ca, 0x2004, 0xa10c, 0x00c0, 0x36de, 0x607c, + 0xa00d, 0x0040, 0x36ab, 0xa680, 0x75ca, 0x2004, 0xa10c, 0x0040, + 0x36ab, 0x694c, 0xd1fc, 0x00c0, 0x36a1, 0x1078, 0x37a6, 0x0078, + 0x36d9, 0x1078, 0x3777, 0x694c, 0xd1ec, 0x00c0, 0x36d9, 0x1078, + 0x38bf, 0x0078, 0x36d9, 0x694c, 0xa184, 0xa000, 0x0040, 0x36c9, + 0xd1ec, 0x0040, 0x36c2, 0xd1fc, 0x0040, 0x36ba, 0x1078, 0x38d6, + 0x0078, 0x36c5, 0xa680, 0x75ca, 0x200c, 0x607c, 0xa105, 0x607e, + 0x0078, 0x36c9, 0xd1fc, 0x0040, 0x36c9, 0x1078, 0x3777, 0x0078, + 0x36d9, 0x6050, 0xa00d, 0x0040, 0x36d4, 0x2d00, 0x200a, 0x6803, + 0x0000, 0x6052, 0x0078, 0x36d9, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x1078, 0x483c, 0xa006, 0x127f, 0x007c, 0x2001, 0x0005, + 0x2009, 0x0000, 0x0078, 0x3717, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x3717, 0xa082, 0x0006, 0x00c8, 0x36f6, 0x60a0, 0xd0bc, + 0x0040, 0x3685, 0x2001, 0x0028, 0x0078, 0x3709, 0x2009, 0x760c, + 0x210c, 0xd18c, 0x0040, 0x3700, 0x2001, 0x0004, 0x0078, 0x3709, + 0xd184, 0x0040, 0x3707, 0x2001, 0x0004, 0x0078, 0x3709, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0078, 0x3717, 0x2001, 0x0029, 0x2009, + 0x0000, 0x0078, 0x3717, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0xa1b4, 0x00ff, 0xa682, 0x0010, 0x00c8, - 0x3764, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x3754, - 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x3754, 0x6004, 0xa084, - 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x375a, 0x684c, 0xd0ec, 0x0040, - 0x3747, 0x1078, 0x38de, 0x1078, 0x377f, 0x0078, 0x374f, 0x1078, - 0x377f, 0x684c, 0xd0fc, 0x0040, 0x374f, 0x1078, 0x38c7, 0x1078, - 0x38f2, 0xa006, 0x0078, 0x3768, 0x2001, 0x0028, 0x2009, 0x0000, - 0x0078, 0x3768, 0xa082, 0x0006, 0x0048, 0x373d, 0x2001, 0x0029, - 0x2009, 0x0000, 0x0078, 0x3768, 0x2001, 0x0029, 0x2009, 0x0000, + 0x375c, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x374c, + 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x374c, 0x6004, 0xa084, + 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x3752, 0x684c, 0xd0ec, 0x0040, + 0x373f, 0x1078, 0x38d6, 0x1078, 0x3777, 0x0078, 0x3747, 0x1078, + 0x3777, 0x684c, 0xd0fc, 0x0040, 0x3747, 0x1078, 0x38bf, 0x1078, + 0x38ea, 0xa006, 0x0078, 0x3760, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x3760, 0xa082, 0x0006, 0x0048, 0x3735, 0x2001, 0x0029, + 0x2009, 0x0000, 0x0078, 0x3760, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0040, - 0x3778, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, - 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x3776, 0x127e, - 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x378b, 0x6802, 0x2d00, + 0x3770, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, + 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x376e, 0x127e, + 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x3783, 0x6802, 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, - 0x0078, 0x3789, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, - 0x37a0, 0x6800, 0xa005, 0x00c0, 0x379e, 0x6052, 0x604e, 0xad05, - 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x37ad, 0x6800, 0xa005, - 0x00c0, 0x37ab, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, - 0x6084, 0xa00d, 0x0040, 0x37b8, 0x2d00, 0x200a, 0x6086, 0x007c, - 0x2d00, 0x6086, 0x6082, 0x0078, 0x37b7, 0x127e, 0x0c7e, 0x027e, - 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x37cb, - 0xc285, 0x0078, 0x37cc, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, + 0x0078, 0x3781, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, + 0x3798, 0x6800, 0xa005, 0x00c0, 0x3796, 0x6052, 0x604e, 0xad05, + 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x37a5, 0x6800, 0xa005, + 0x00c0, 0x37a3, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, + 0x6084, 0xa00d, 0x0040, 0x37b0, 0x2d00, 0x200a, 0x6086, 0x007c, + 0x2d00, 0x6086, 0x6082, 0x0078, 0x37af, 0x127e, 0x0c7e, 0x027e, + 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x37c3, + 0xc285, 0x0078, 0x37c4, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0xa294, 0xff00, 0xa215, 0x6206, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f, 0x007c, 0x027e, 0xa182, - 0x00ff, 0x0048, 0x37f7, 0xa085, 0x0001, 0x0078, 0x380b, 0xa190, - 0x7720, 0x2204, 0xa065, 0x00c0, 0x380a, 0x017e, 0x0d7e, 0x1078, - 0x1314, 0x2d60, 0x0d7f, 0x017f, 0x0040, 0x37f3, 0x2c00, 0x2012, - 0x1078, 0x3621, 0xa006, 0x027f, 0x007c, 0x027e, 0xa182, 0x00ff, - 0x0048, 0x3816, 0xa085, 0x0001, 0x0078, 0x3823, 0x0d7e, 0xa190, - 0x7720, 0x2204, 0xa06d, 0x0040, 0x3821, 0x2013, 0x0000, 0x1078, - 0x1348, 0x0d7f, 0xa006, 0x027f, 0x007c, 0x017e, 0xa182, 0x00ff, - 0x0048, 0x382e, 0xa085, 0x0001, 0x0078, 0x3835, 0xa188, 0x7720, - 0x2104, 0xa065, 0x0040, 0x382a, 0xa006, 0x017f, 0x007c, 0x0d7e, + 0x00ff, 0x0048, 0x37ef, 0xa085, 0x0001, 0x0078, 0x3803, 0xa190, + 0x7720, 0x2204, 0xa065, 0x00c0, 0x3802, 0x017e, 0x0d7e, 0x1078, + 0x130c, 0x2d60, 0x0d7f, 0x017f, 0x0040, 0x37eb, 0x2c00, 0x2012, + 0x1078, 0x3619, 0xa006, 0x027f, 0x007c, 0x027e, 0xa182, 0x00ff, + 0x0048, 0x380e, 0xa085, 0x0001, 0x0078, 0x381b, 0x0d7e, 0xa190, + 0x7720, 0x2204, 0xa06d, 0x0040, 0x3819, 0x2013, 0x0000, 0x1078, + 0x1340, 0x0d7f, 0xa006, 0x027f, 0x007c, 0x017e, 0xa182, 0x00ff, + 0x0048, 0x3826, 0xa085, 0x0001, 0x0078, 0x382d, 0xa188, 0x7720, + 0x2104, 0xa065, 0x0040, 0x3822, 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0x7b8e, 0x6808, 0x605e, 0x6810, 0x6062, - 0x6138, 0xa10a, 0x0048, 0x384d, 0x603a, 0x6814, 0x6066, 0x2099, + 0x6138, 0xa10a, 0x0048, 0x3845, 0x603a, 0x6814, 0x6066, 0x2099, 0x7b96, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0x7b9a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0x7bae, 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, - 0x6076, 0xa182, 0x0211, 0x00c8, 0x3871, 0x2009, 0x0008, 0x0078, - 0x389b, 0xa182, 0x0259, 0x00c8, 0x3879, 0x2009, 0x0007, 0x0078, - 0x389b, 0xa182, 0x02c1, 0x00c8, 0x3881, 0x2009, 0x0006, 0x0078, - 0x389b, 0xa182, 0x0349, 0x00c8, 0x3889, 0x2009, 0x0005, 0x0078, - 0x389b, 0xa182, 0x0421, 0x00c8, 0x3891, 0x2009, 0x0004, 0x0078, - 0x389b, 0xa182, 0x0581, 0x00c8, 0x3899, 0x2009, 0x0003, 0x0078, - 0x389b, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f, + 0x6076, 0xa182, 0x0211, 0x00c8, 0x3869, 0x2009, 0x0008, 0x0078, + 0x3893, 0xa182, 0x0259, 0x00c8, 0x3871, 0x2009, 0x0007, 0x0078, + 0x3893, 0xa182, 0x02c1, 0x00c8, 0x3879, 0x2009, 0x0006, 0x0078, + 0x3893, 0xa182, 0x0349, 0x00c8, 0x3881, 0x2009, 0x0005, 0x0078, + 0x3893, 0xa182, 0x0421, 0x00c8, 0x3889, 0x2009, 0x0004, 0x0078, + 0x3893, 0xa182, 0x0581, 0x00c8, 0x3891, 0x2009, 0x0003, 0x0078, + 0x3893, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x0e7e, 0x2071, 0x7b8d, 0x2e04, 0x6896, 0x2071, 0x7b8e, - 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75d5, + 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10d, 0x617a, - 0x127f, 0x007c, 0x2001, 0x75d5, 0xa600, 0x2004, 0x8002, 0x127e, + 0x127f, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10c, 0x617a, 0x127f, 0x007c, 0x2001, - 0x75d5, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x617c, - 0xa10c, 0x617e, 0x127f, 0x0078, 0x38d7, 0x1078, 0x376a, 0x1078, - 0x3938, 0x00c0, 0x38d5, 0x1078, 0x38f2, 0x007c, 0x2001, 0x75d5, + 0x75ca, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x617c, + 0xa10c, 0x617e, 0x127f, 0x0078, 0x38cf, 0x1078, 0x3762, 0x1078, + 0x3930, 0x00c0, 0x38cd, 0x1078, 0x38ea, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x617c, 0xa10d, 0x617e, - 0x127f, 0x0078, 0x38ed, 0x1078, 0x37ae, 0x1078, 0x38fc, 0x00c0, - 0x38eb, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4844, 0x127f, - 0x007c, 0xa01e, 0x0078, 0x38fe, 0x2019, 0x0001, 0xa00e, 0x127e, - 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, 0x391e, - 0x8dff, 0x0040, 0x3933, 0x83ff, 0x0040, 0x3916, 0x6844, 0xa084, - 0x00ff, 0xa606, 0x0040, 0x3923, 0x0078, 0x391e, 0x683c, 0xa406, - 0x00c0, 0x391e, 0x6840, 0xa506, 0x0040, 0x3923, 0x2d08, 0x6800, - 0x2068, 0x0078, 0x3908, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x392b, - 0x624e, 0x0078, 0x392e, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, - 0x3933, 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x393a, - 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x3968, - 0x83ff, 0x0040, 0x394b, 0x6844, 0xa084, 0x00ff, 0xa606, 0x0040, - 0x3958, 0x0078, 0x3953, 0x683c, 0xa406, 0x00c0, 0x3953, 0x6840, - 0xa506, 0x0040, 0x3958, 0x2d08, 0x6800, 0x2068, 0x0078, 0x393d, - 0x6a00, 0x6080, 0xad06, 0x00c0, 0x3960, 0x6282, 0x0078, 0x3963, - 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x3968, 0x6186, 0x8dff, - 0x007c, 0x2001, 0x75d5, 0xa600, 0x2004, 0x6178, 0xa10c, 0x0040, - 0x3973, 0x2011, 0x0001, 0x617c, 0xa10c, 0x0040, 0x3979, 0xa295, - 0x0002, 0x007c, 0x1078, 0x39c5, 0x0040, 0x3982, 0x1078, 0x6a16, - 0x0078, 0x3984, 0xa085, 0x0001, 0x007c, 0x1078, 0x39c5, 0x0040, - 0x398d, 0x1078, 0x69a5, 0x0078, 0x398f, 0xa085, 0x0001, 0x007c, - 0x1078, 0x39c5, 0x0040, 0x3998, 0x1078, 0x69eb, 0x0078, 0x399a, - 0xa085, 0x0001, 0x007c, 0x1078, 0x39c5, 0x0040, 0x39a3, 0x1078, - 0x69c1, 0x0078, 0x39a5, 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, - 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, 0x0040, 0x39bd, 0x6800, - 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x007f, 0x0078, 0x39ac, 0x6083, 0x0000, 0x6087, + 0x127f, 0x0078, 0x38e5, 0x1078, 0x37a6, 0x1078, 0x38f4, 0x00c0, + 0x38e3, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x483c, 0x127f, + 0x007c, 0xa01e, 0x0078, 0x38f6, 0x2019, 0x0001, 0xa00e, 0x127e, + 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, 0x3916, + 0x8dff, 0x0040, 0x392b, 0x83ff, 0x0040, 0x390e, 0x6844, 0xa084, + 0x00ff, 0xa606, 0x0040, 0x391b, 0x0078, 0x3916, 0x683c, 0xa406, + 0x00c0, 0x3916, 0x6840, 0xa506, 0x0040, 0x391b, 0x2d08, 0x6800, + 0x2068, 0x0078, 0x3900, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x3923, + 0x624e, 0x0078, 0x3926, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, + 0x392b, 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x3932, + 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x3960, + 0x83ff, 0x0040, 0x3943, 0x6844, 0xa084, 0x00ff, 0xa606, 0x0040, + 0x3950, 0x0078, 0x394b, 0x683c, 0xa406, 0x00c0, 0x394b, 0x6840, + 0xa506, 0x0040, 0x3950, 0x2d08, 0x6800, 0x2068, 0x0078, 0x3935, + 0x6a00, 0x6080, 0xad06, 0x00c0, 0x3958, 0x6282, 0x0078, 0x395b, + 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x3960, 0x6186, 0x8dff, + 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x6178, 0xa10c, 0x0040, + 0x396b, 0x2011, 0x0001, 0x617c, 0xa10c, 0x0040, 0x3971, 0xa295, + 0x0002, 0x007c, 0x1078, 0x39bd, 0x0040, 0x397a, 0x1078, 0x6a0b, + 0x0078, 0x397c, 0xa085, 0x0001, 0x007c, 0x1078, 0x39bd, 0x0040, + 0x3985, 0x1078, 0x699a, 0x0078, 0x3987, 0xa085, 0x0001, 0x007c, + 0x1078, 0x39bd, 0x0040, 0x3990, 0x1078, 0x69e0, 0x0078, 0x3992, + 0xa085, 0x0001, 0x007c, 0x1078, 0x39bd, 0x0040, 0x399b, 0x1078, + 0x69b6, 0x0078, 0x399d, 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, + 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, 0x0040, 0x39b5, 0x6800, + 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x007f, 0x0078, 0x39a4, 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, - 0x0f7e, 0x2079, 0x7651, 0x7804, 0xd0a4, 0x0040, 0x39f1, 0x157e, - 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3825, - 0x00c0, 0x39e5, 0x6004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, - 0x00c0, 0x39e5, 0x6000, 0xc0ed, 0x6002, 0x017f, 0x8108, 0x00f0, - 0x39d5, 0x0c7f, 0x157f, 0x2009, 0x07d0, 0x2011, 0x39f3, 0x1078, - 0x45fe, 0x0f7f, 0x007c, 0x2011, 0x39f3, 0x1078, 0x456e, 0x157e, - 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3825, - 0x00c0, 0x3a1f, 0x6000, 0xd0ec, 0x0040, 0x3a1f, 0x047e, 0x62a0, - 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x7541, - 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x2019, 0x0029, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2009, 0x0000, 0x1078, 0x737b, 0x047f, 0x017f, - 0x8108, 0x00f0, 0x39fd, 0x0c7f, 0x157f, 0x007c, 0x0c7e, 0x6018, + 0x0f7e, 0x2079, 0x7651, 0x7804, 0xd0a4, 0x0040, 0x39e9, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, + 0x00c0, 0x39dd, 0x6004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, + 0x00c0, 0x39dd, 0x6000, 0xc0ed, 0x6002, 0x017f, 0x8108, 0x00f0, + 0x39cd, 0x0c7f, 0x157f, 0x2009, 0x07d0, 0x2011, 0x39eb, 0x1078, + 0x45f6, 0x0f7f, 0x007c, 0x2011, 0x39eb, 0x1078, 0x4566, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, + 0x00c0, 0x3a17, 0x6000, 0xd0ec, 0x0040, 0x3a17, 0x047e, 0x62a0, + 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x7536, + 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x2019, 0x0029, 0x1078, 0x495a, + 0x1078, 0x489d, 0x2009, 0x0000, 0x1078, 0x7370, 0x047f, 0x017f, + 0x8108, 0x00f0, 0x39f5, 0x0c7f, 0x157f, 0x007c, 0x0c7e, 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x2071, 0x76ff, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0x76ff, 0x684c, 0xa005, 0x00c0, 0x3a55, 0x7028, 0xc085, - 0x702a, 0xa085, 0x0001, 0x0078, 0x3a78, 0x6a60, 0x7236, 0x6b64, + 0x2071, 0x76ff, 0x684c, 0xa005, 0x00c0, 0x3a4d, 0x7028, 0xc085, + 0x702a, 0xa085, 0x0001, 0x0078, 0x3a70, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, - 0x0e7f, 0x007c, 0x0e7e, 0x6838, 0xd0fc, 0x00c0, 0x3acb, 0x6804, - 0xa00d, 0x0040, 0x3a99, 0x0d7e, 0x0e7e, 0x2071, 0x7600, 0x027e, + 0x0e7f, 0x007c, 0x0e7e, 0x6838, 0xd0fc, 0x00c0, 0x3ac3, 0x6804, + 0xa00d, 0x0040, 0x3a91, 0x0d7e, 0x0e7e, 0x2071, 0x7600, 0x027e, 0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, - 0x00c0, 0x3a8a, 0x702e, 0x70a0, 0xa200, 0x70a2, 0x027f, 0x0e7f, - 0x0d7f, 0x2071, 0x76ff, 0x701c, 0xa005, 0x00c0, 0x3adc, 0x0068, - 0x3ada, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3ada, 0x6934, - 0xa186, 0x0103, 0x00c0, 0x3aed, 0x6948, 0x6844, 0xa105, 0x00c0, - 0x3acd, 0x2009, 0x8020, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, - 0x3ada, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, + 0x00c0, 0x3a82, 0x702e, 0x70a0, 0xa200, 0x70a2, 0x027f, 0x0e7f, + 0x0d7f, 0x2071, 0x76ff, 0x701c, 0xa005, 0x00c0, 0x3ad4, 0x0068, + 0x3ad2, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3ad2, 0x6934, + 0xa186, 0x0103, 0x00c0, 0x3ae5, 0x6948, 0x6844, 0xa105, 0x00c0, + 0x3ac5, 0x2009, 0x8020, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, + 0x3ad2, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x2071, 0x7600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, 0x8000, 0x70a2, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, - 0x00c0, 0x3ada, 0x6868, 0xa005, 0x00c0, 0x3ada, 0x2009, 0x8020, - 0x0078, 0x3ab3, 0x2071, 0x76ff, 0x2d08, 0x206b, 0x0000, 0x7010, - 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x3aea, 0x6902, - 0x0078, 0x3aeb, 0x711e, 0x0078, 0x3acb, 0xa18c, 0x00ff, 0xa186, - 0x0017, 0x0040, 0x3afb, 0xa186, 0x001e, 0x0040, 0x3afb, 0xa18e, - 0x001f, 0x00c0, 0x3ada, 0x684c, 0xd0cc, 0x0040, 0x3ada, 0x6850, - 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x3ada, 0x2009, 0x8021, - 0x0078, 0x3ab3, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, + 0x00c0, 0x3ad2, 0x6868, 0xa005, 0x00c0, 0x3ad2, 0x2009, 0x8020, + 0x0078, 0x3aab, 0x2071, 0x76ff, 0x2d08, 0x206b, 0x0000, 0x7010, + 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x3ae2, 0x6902, + 0x0078, 0x3ae3, 0x711e, 0x0078, 0x3ac3, 0xa18c, 0x00ff, 0xa186, + 0x0017, 0x0040, 0x3af3, 0xa186, 0x001e, 0x0040, 0x3af3, 0xa18e, + 0x001f, 0x00c0, 0x3ad2, 0x684c, 0xd0cc, 0x0040, 0x3ad2, 0x6850, + 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x3ad2, 0x2009, 0x8021, + 0x0078, 0x3aab, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0x684a, 0x6952, - 0x007c, 0x2071, 0x76ff, 0x7004, 0x0079, 0x3b1e, 0x3b26, 0x3b35, - 0x3bc5, 0x3bc6, 0x3bd6, 0x3bdc, 0x3b27, 0x3bb3, 0x007c, 0x127e, - 0x2091, 0x8000, 0x0068, 0x3b34, 0x2009, 0x000d, 0x7030, 0x200a, + 0x007c, 0x2071, 0x76ff, 0x7004, 0x0079, 0x3b16, 0x3b1e, 0x3b2d, + 0x3bbd, 0x3bbe, 0x3bce, 0x3bd4, 0x3b1f, 0x3bab, 0x007c, 0x127e, + 0x2091, 0x8000, 0x0068, 0x3b2c, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x127f, 0x701c, 0xa06d, 0x0040, - 0x3bb2, 0x0e7e, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3b94, - 0x6934, 0xa186, 0x0103, 0x00c0, 0x3b6a, 0x6948, 0x6844, 0xa105, - 0x00c0, 0x3b87, 0x2009, 0x8020, 0x127e, 0x2091, 0x8000, 0x0068, - 0x3b66, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x3b66, 0x7122, + 0x3baa, 0x0e7e, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3b8c, + 0x6934, 0xa186, 0x0103, 0x00c0, 0x3b62, 0x6948, 0x6844, 0xa105, + 0x00c0, 0x3b7f, 0x2009, 0x8020, 0x127e, 0x2091, 0x8000, 0x0068, + 0x3b5e, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x3b5e, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, - 0x127f, 0x0e7f, 0x1078, 0x3c0f, 0x0078, 0x3bb2, 0x127f, 0x0e7f, - 0x0078, 0x3bb2, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, 0x3b78, - 0xa186, 0x001e, 0x0040, 0x3b78, 0xa18e, 0x001f, 0x00c0, 0x3b94, - 0x684c, 0xd0cc, 0x0040, 0x3b94, 0x6850, 0xa084, 0x00ff, 0xa086, - 0x0001, 0x00c0, 0x3b94, 0x2009, 0x8021, 0x0078, 0x3b4c, 0x6844, - 0xa086, 0x0100, 0x00c0, 0x3b94, 0x6868, 0xa005, 0x00c0, 0x3b94, - 0x2009, 0x8020, 0x0078, 0x3b4c, 0x0e7f, 0x1078, 0x3c23, 0x0040, - 0x3bb2, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, - 0x00c0, 0x3ba9, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x3ba9, - 0x710e, 0x7007, 0x0003, 0x1078, 0x3c43, 0x7050, 0xa086, 0x0100, - 0x0040, 0x3bc6, 0x007c, 0x701c, 0xa06d, 0x0040, 0x3bc4, 0x1078, - 0x3c23, 0x0040, 0x3bc4, 0x7007, 0x0003, 0x1078, 0x3c43, 0x7050, - 0xa086, 0x0100, 0x0040, 0x3bc6, 0x007c, 0x007c, 0x7050, 0xa09e, - 0x0100, 0x00c0, 0x3bcf, 0x7007, 0x0004, 0x0078, 0x3bd6, 0xa086, - 0x0200, 0x00c0, 0x3bd5, 0x7007, 0x0005, 0x007c, 0x1078, 0x3bdd, - 0x7006, 0x1078, 0x3c0f, 0x007c, 0x007c, 0x702c, 0x7130, 0x8108, - 0xa102, 0x0048, 0x3bea, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, - 0x0078, 0x3bf4, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x3bf4, + 0x127f, 0x0e7f, 0x1078, 0x3c07, 0x0078, 0x3baa, 0x127f, 0x0e7f, + 0x0078, 0x3baa, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, 0x3b70, + 0xa186, 0x001e, 0x0040, 0x3b70, 0xa18e, 0x001f, 0x00c0, 0x3b8c, + 0x684c, 0xd0cc, 0x0040, 0x3b8c, 0x6850, 0xa084, 0x00ff, 0xa086, + 0x0001, 0x00c0, 0x3b8c, 0x2009, 0x8021, 0x0078, 0x3b44, 0x6844, + 0xa086, 0x0100, 0x00c0, 0x3b8c, 0x6868, 0xa005, 0x00c0, 0x3b8c, + 0x2009, 0x8020, 0x0078, 0x3b44, 0x0e7f, 0x1078, 0x3c1b, 0x0040, + 0x3baa, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, + 0x00c0, 0x3ba1, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x3ba1, + 0x710e, 0x7007, 0x0003, 0x1078, 0x3c3b, 0x7050, 0xa086, 0x0100, + 0x0040, 0x3bbe, 0x007c, 0x701c, 0xa06d, 0x0040, 0x3bbc, 0x1078, + 0x3c1b, 0x0040, 0x3bbc, 0x7007, 0x0003, 0x1078, 0x3c3b, 0x7050, + 0xa086, 0x0100, 0x0040, 0x3bbe, 0x007c, 0x007c, 0x7050, 0xa09e, + 0x0100, 0x00c0, 0x3bc7, 0x7007, 0x0004, 0x0078, 0x3bce, 0xa086, + 0x0200, 0x00c0, 0x3bcd, 0x7007, 0x0005, 0x007c, 0x1078, 0x3bd5, + 0x7006, 0x1078, 0x3c07, 0x007c, 0x007c, 0x702c, 0x7130, 0x8108, + 0xa102, 0x0048, 0x3be2, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, + 0x0078, 0x3bec, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x3bec, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, - 0x00c0, 0x3c08, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c0b, 0x2001, + 0x00c0, 0x3c00, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c03, 0x2001, 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, 0x127f, 0x007c, 0x701c, - 0xa06d, 0x0040, 0x3c22, 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, - 0x7012, 0x2d04, 0x701e, 0xa005, 0x00c0, 0x3c1f, 0x701a, 0x127f, - 0x1078, 0x1348, 0x007c, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, - 0x0040, 0x3c32, 0x2304, 0x230c, 0xa10e, 0x0040, 0x3c32, 0xa006, - 0x0078, 0x3c42, 0x732c, 0x8319, 0x7130, 0xa102, 0x00c0, 0x3c3c, - 0x2300, 0xa005, 0x0078, 0x3c42, 0x0048, 0x3c41, 0xa302, 0x0078, - 0x3c42, 0x8002, 0x007c, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, + 0xa06d, 0x0040, 0x3c1a, 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, + 0x7012, 0x2d04, 0x701e, 0xa005, 0x00c0, 0x3c17, 0x701a, 0x127f, + 0x1078, 0x1340, 0x007c, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, + 0x0040, 0x3c2a, 0x2304, 0x230c, 0xa10e, 0x0040, 0x3c2a, 0xa006, + 0x0078, 0x3c3a, 0x732c, 0x8319, 0x7130, 0xa102, 0x00c0, 0x3c34, + 0x2300, 0xa005, 0x0078, 0x3c3a, 0x0048, 0x3c39, 0xa302, 0x0078, + 0x3c3a, 0x8002, 0x007c, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, - 0xc08d, 0x200a, 0x127f, 0x1078, 0x1399, 0x007c, 0x2071, 0x76cd, + 0xc08d, 0x200a, 0x127f, 0x1078, 0x1391, 0x007c, 0x2071, 0x76cd, 0x7003, 0x0000, 0x7007, 0x0000, 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, 0x708f, 0x0001, 0x70bf, 0x0000, - 0x007c, 0x0e7e, 0x2071, 0x76cd, 0x6848, 0xa005, 0x00c0, 0x3c7f, - 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0078, 0x3ca4, 0x6a50, + 0x007c, 0x0e7e, 0x2071, 0x76cd, 0x6848, 0xa005, 0x00c0, 0x3c77, + 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0078, 0x3c9c, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x0e7f, 0x007c, 0x2b78, 0x2071, - 0x76cd, 0x7004, 0x1079, 0x3d04, 0x700c, 0x0079, 0x3caf, 0x3cb4, - 0x3ca9, 0x3ca9, 0x3ca9, 0x3ca9, 0x007c, 0x700c, 0x0079, 0x3cb8, - 0x3cbd, 0x3d02, 0x3d02, 0x3d03, 0x3d03, 0x7830, 0x7930, 0xa106, - 0x0040, 0x3cc7, 0x7830, 0x7930, 0xa106, 0x00c0, 0x3ced, 0x7030, - 0xa10a, 0x0040, 0x3ced, 0x00c8, 0x3ccf, 0x712c, 0xa10a, 0xa18a, - 0x0002, 0x00c8, 0x3cee, 0x1078, 0x1314, 0x0040, 0x3ced, 0x2d00, + 0x76cd, 0x7004, 0x1079, 0x3cfc, 0x700c, 0x0079, 0x3ca7, 0x3cac, + 0x3ca1, 0x3ca1, 0x3ca1, 0x3ca1, 0x007c, 0x700c, 0x0079, 0x3cb0, + 0x3cb5, 0x3cfa, 0x3cfa, 0x3cfb, 0x3cfb, 0x7830, 0x7930, 0xa106, + 0x0040, 0x3cbf, 0x7830, 0x7930, 0xa106, 0x00c0, 0x3ce5, 0x7030, + 0xa10a, 0x0040, 0x3ce5, 0x00c8, 0x3cc7, 0x712c, 0xa10a, 0xa18a, + 0x0002, 0x00c8, 0x3ce6, 0x1078, 0x130c, 0x0040, 0x3ce5, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, 0xc085, 0x200a, - 0x007f, 0x700e, 0x127f, 0x1078, 0x1399, 0x007c, 0x1078, 0x1314, - 0x0040, 0x3ced, 0x2d00, 0x705a, 0x1078, 0x1314, 0x00c0, 0x3cfa, - 0x0078, 0x3cd9, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, - 0x0078, 0x3cdd, 0x007c, 0x007c, 0x3d15, 0x3d16, 0x3d4d, 0x3d4e, - 0x3d02, 0x3d84, 0x3d89, 0x3dc0, 0x3dc1, 0x3ddc, 0x3ddd, 0x3dde, - 0x3ddf, 0x3de0, 0x3de1, 0x3e4a, 0x3e74, 0x007c, 0x700c, 0x0079, - 0x3d19, 0x3d1e, 0x3d21, 0x3d31, 0x3d4c, 0x3d4c, 0x1078, 0x3cb5, - 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x4153, - 0x0040, 0x3d2e, 0x2091, 0x8000, 0x1078, 0x3cb5, 0x0d7f, 0x0078, - 0x3d3a, 0x127e, 0x8001, 0x700e, 0x1078, 0x4153, 0x7058, 0x2068, + 0x007f, 0x700e, 0x127f, 0x1078, 0x1391, 0x007c, 0x1078, 0x130c, + 0x0040, 0x3ce5, 0x2d00, 0x705a, 0x1078, 0x130c, 0x00c0, 0x3cf2, + 0x0078, 0x3cd1, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, + 0x0078, 0x3cd5, 0x007c, 0x007c, 0x3d0d, 0x3d0e, 0x3d45, 0x3d46, + 0x3cfa, 0x3d7c, 0x3d81, 0x3db8, 0x3db9, 0x3dd4, 0x3dd5, 0x3dd6, + 0x3dd7, 0x3dd8, 0x3dd9, 0x3e42, 0x3e6c, 0x007c, 0x700c, 0x0079, + 0x3d11, 0x3d16, 0x3d19, 0x3d29, 0x3d44, 0x3d44, 0x1078, 0x3cad, + 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x414b, + 0x0040, 0x3d26, 0x2091, 0x8000, 0x1078, 0x3cad, 0x0d7f, 0x0078, + 0x3d32, 0x127e, 0x8001, 0x700e, 0x1078, 0x414b, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, - 0x00ff, 0xa08a, 0x0020, 0x00c8, 0x3d49, 0x1079, 0x3d64, 0x127f, - 0x007c, 0x127f, 0x1078, 0x3de2, 0x007c, 0x007c, 0x007c, 0x0e7e, - 0x2071, 0x76cd, 0x700c, 0x0079, 0x3d55, 0x3d5a, 0x3d5a, 0x3d5a, - 0x3d5c, 0x3d60, 0x0e7f, 0x007c, 0x700f, 0x0001, 0x0078, 0x3d62, - 0x700f, 0x0002, 0x0e7f, 0x007c, 0x3de2, 0x3de2, 0x3dfe, 0x3de2, - 0x3ee9, 0x3de2, 0x3de2, 0x3de2, 0x3de2, 0x3de2, 0x3dfe, 0x3f2e, - 0x3f77, 0x3fcf, 0x3fe2, 0x3de2, 0x3de2, 0x3e1a, 0x3dfe, 0x3de2, - 0x3de2, 0x3e30, 0x4069, 0x4086, 0x3de2, 0x3e1a, 0x3de2, 0x3de2, - 0x3de2, 0x3de2, 0x3e30, 0x4086, 0x7020, 0x2068, 0x1078, 0x1348, - 0x007c, 0x700c, 0x0079, 0x3d8c, 0x3d91, 0x3d94, 0x3da4, 0x3dbf, - 0x3dbf, 0x1078, 0x3cb5, 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, - 0x007e, 0x1078, 0x4153, 0x0040, 0x3da1, 0x2091, 0x8000, 0x1078, - 0x3cb5, 0x0d7f, 0x0078, 0x3dad, 0x127e, 0x8001, 0x700e, 0x1078, - 0x4153, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, - 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x3dbc, - 0x1079, 0x3dc2, 0x127f, 0x007c, 0x127f, 0x1078, 0x3de2, 0x007c, - 0x007c, 0x007c, 0x3de2, 0x3dfe, 0x3ed3, 0x3de2, 0x3dfe, 0x3de2, - 0x3dfe, 0x3dfe, 0x3de2, 0x3dfe, 0x3ed3, 0x3dfe, 0x3dfe, 0x3dfe, - 0x3dfe, 0x3dfe, 0x3de2, 0x3dfe, 0x3ed3, 0x3de2, 0x3de2, 0x3dfe, - 0x3de2, 0x3de2, 0x3de2, 0x3dfe, 0x007c, 0x007c, 0x007c, 0x007c, + 0x00ff, 0xa08a, 0x0020, 0x00c8, 0x3d41, 0x1079, 0x3d5c, 0x127f, + 0x007c, 0x127f, 0x1078, 0x3dda, 0x007c, 0x007c, 0x007c, 0x0e7e, + 0x2071, 0x76cd, 0x700c, 0x0079, 0x3d4d, 0x3d52, 0x3d52, 0x3d52, + 0x3d54, 0x3d58, 0x0e7f, 0x007c, 0x700f, 0x0001, 0x0078, 0x3d5a, + 0x700f, 0x0002, 0x0e7f, 0x007c, 0x3dda, 0x3dda, 0x3df6, 0x3dda, + 0x3ee1, 0x3dda, 0x3dda, 0x3dda, 0x3dda, 0x3dda, 0x3df6, 0x3f26, + 0x3f6f, 0x3fc7, 0x3fda, 0x3dda, 0x3dda, 0x3e12, 0x3df6, 0x3dda, + 0x3dda, 0x3e28, 0x4061, 0x407e, 0x3dda, 0x3e12, 0x3dda, 0x3dda, + 0x3dda, 0x3dda, 0x3e28, 0x407e, 0x7020, 0x2068, 0x1078, 0x1340, + 0x007c, 0x700c, 0x0079, 0x3d84, 0x3d89, 0x3d8c, 0x3d9c, 0x3db7, + 0x3db7, 0x1078, 0x3cad, 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, + 0x007e, 0x1078, 0x414b, 0x0040, 0x3d99, 0x2091, 0x8000, 0x1078, + 0x3cad, 0x0d7f, 0x0078, 0x3da5, 0x127e, 0x8001, 0x700e, 0x1078, + 0x414b, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, + 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x3db4, + 0x1079, 0x3dba, 0x127f, 0x007c, 0x127f, 0x1078, 0x3dda, 0x007c, + 0x007c, 0x007c, 0x3dda, 0x3df6, 0x3ecb, 0x3dda, 0x3df6, 0x3dda, + 0x3df6, 0x3df6, 0x3dda, 0x3df6, 0x3ecb, 0x3df6, 0x3df6, 0x3df6, + 0x3df6, 0x3df6, 0x3dda, 0x3df6, 0x3ecb, 0x3dda, 0x3dda, 0x3df6, + 0x3dda, 0x3dda, 0x3dda, 0x3df6, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, - 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, + 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, - 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, 0x7007, 0x0001, + 0x2091, 0x8000, 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x127e, 0x2091, 0x8000, - 0x1078, 0x3a7a, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, - 0x00ff, 0xc0dd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, - 0x127f, 0x007c, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3df0, - 0x8001, 0x00c0, 0x3e27, 0x7007, 0x0001, 0x0078, 0x3eb0, 0x7007, - 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x3eb0, 0x007c, + 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0dd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a72, + 0x127f, 0x007c, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3de8, + 0x8001, 0x00c0, 0x3e1f, 0x7007, 0x0001, 0x0078, 0x3ea8, 0x7007, + 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x3ea8, 0x007c, 0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0x76f8, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, - 0x3e0c, 0x6884, 0xa08a, 0x0003, 0x00c8, 0x3e0c, 0xa080, 0x3ea1, - 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, 0x3e94, 0x1078, 0x1314, - 0x00c0, 0x3e55, 0x7007, 0x000f, 0x007c, 0x2d00, 0x7022, 0x70c4, + 0x3e04, 0x6884, 0xa08a, 0x0003, 0x00c8, 0x3e04, 0xa080, 0x3e99, + 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, 0x3e8c, 0x1078, 0x130c, + 0x00c0, 0x3e4d, 0x7007, 0x000f, 0x007c, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, 0xad00, 0x7096, 0x6008, 0xa20a, - 0x00c8, 0x3e64, 0xa00e, 0x2200, 0x7112, 0x620c, 0x8003, 0x800b, - 0xa296, 0x0004, 0x0040, 0x3e6d, 0xa108, 0x719a, 0x810b, 0x719e, - 0xae90, 0x0022, 0x1078, 0x137f, 0x7090, 0xa08e, 0x0100, 0x0040, - 0x3e88, 0xa086, 0x0200, 0x0040, 0x3e80, 0x7007, 0x0010, 0x007c, - 0x7020, 0x2068, 0x1078, 0x1348, 0x7014, 0x2068, 0x0078, 0x3e0c, + 0x00c8, 0x3e5c, 0xa00e, 0x2200, 0x7112, 0x620c, 0x8003, 0x800b, + 0xa296, 0x0004, 0x0040, 0x3e65, 0xa108, 0x719a, 0x810b, 0x719e, + 0xae90, 0x0022, 0x1078, 0x1377, 0x7090, 0xa08e, 0x0100, 0x0040, + 0x3e80, 0xa086, 0x0200, 0x0040, 0x3e78, 0x7007, 0x0010, 0x007c, + 0x7020, 0x2068, 0x1078, 0x1340, 0x7014, 0x2068, 0x0078, 0x3e04, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, 0x2068, - 0x6906, 0x711a, 0x0078, 0x3e4a, 0x7014, 0x2068, 0x7007, 0x0001, - 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x40a3, 0x0078, - 0x3eb0, 0x3ea4, 0x3ea8, 0x3eac, 0x0002, 0x0011, 0x0007, 0x0004, + 0x6906, 0x711a, 0x0078, 0x3e42, 0x7014, 0x2068, 0x7007, 0x0001, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x409b, 0x0078, + 0x3ea8, 0x3e9c, 0x3ea0, 0x3ea4, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, 0x0006, 0x0012, 0x000f, 0x0005, 0x0006, - 0x2009, 0x762c, 0x210c, 0x81ff, 0x00c0, 0x3ecd, 0x6838, 0xa084, - 0x00ff, 0x683a, 0x6853, 0x0000, 0x1078, 0x3668, 0x00c0, 0x3ec1, - 0x007c, 0x1078, 0x3b0a, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x127f, 0x0078, 0x3ec0, 0x2001, 0x0028, 0x2009, - 0x0000, 0x0078, 0x3ec1, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, - 0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x3ee2, 0x7007, 0x0006, - 0x0078, 0x3ee8, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, + 0x2009, 0x762c, 0x210c, 0x81ff, 0x00c0, 0x3ec5, 0x6838, 0xa084, + 0x00ff, 0x683a, 0x6853, 0x0000, 0x1078, 0x3660, 0x00c0, 0x3eb9, + 0x007c, 0x1078, 0x3b02, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x127f, 0x0078, 0x3eb8, 0x2001, 0x0028, 0x2009, + 0x0000, 0x0078, 0x3eb9, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, + 0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x3eda, 0x7007, 0x0006, + 0x0078, 0x3ee0, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, - 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x3f14, - 0x2009, 0x0000, 0x20a9, 0x007e, 0xa096, 0x0002, 0x0040, 0x3f14, - 0xa005, 0x00c0, 0x3f2b, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, - 0x3825, 0x00c0, 0x3f2b, 0x067e, 0x6e44, 0xa6b4, 0x000f, 0x1078, - 0x38ba, 0x067f, 0x0078, 0x3f2b, 0x047e, 0x2011, 0x760c, 0x2224, - 0xc484, 0xc48c, 0x2412, 0x047f, 0x0c7e, 0x1078, 0x3825, 0x00c0, - 0x3f27, 0x2091, 0x8000, 0x607b, 0x0000, 0x2091, 0x8001, 0x8108, - 0x00f0, 0x3f1d, 0x0c7f, 0x1078, 0x1348, 0x007c, 0x127e, 0x2091, + 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x3f0c, + 0x2009, 0x0000, 0x20a9, 0x007e, 0xa096, 0x0002, 0x0040, 0x3f0c, + 0xa005, 0x00c0, 0x3f23, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, + 0x381d, 0x00c0, 0x3f23, 0x067e, 0x6e44, 0xa6b4, 0x000f, 0x1078, + 0x38b2, 0x067f, 0x0078, 0x3f23, 0x047e, 0x2011, 0x760c, 0x2224, + 0xc484, 0xc48c, 0x2412, 0x047f, 0x0c7e, 0x1078, 0x381d, 0x00c0, + 0x3f1f, 0x2091, 0x8000, 0x607b, 0x0000, 0x2091, 0x8001, 0x8108, + 0x00f0, 0x3f15, 0x0c7f, 0x1078, 0x1340, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x7652, 0x2004, 0xd0a4, 0x0040, - 0x3f6e, 0x6944, 0x1078, 0x416f, 0x6100, 0xd184, 0x0040, 0x3f53, - 0x6858, 0xa084, 0x00ff, 0x00c0, 0x3f71, 0x6000, 0xd084, 0x0040, - 0x3f6e, 0x6004, 0xa005, 0x00c0, 0x3f74, 0x6003, 0x0000, 0x600b, - 0x0000, 0x0078, 0x3f6b, 0x2011, 0x0001, 0x6860, 0xa005, 0x00c0, - 0x3f5b, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, - 0x0040, 0x3f6e, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0040, - 0x3f6e, 0x600a, 0x6202, 0x127f, 0x0078, 0x4142, 0x127f, 0x0078, - 0x413a, 0x127f, 0x0078, 0x4132, 0x127f, 0x0078, 0x4136, 0x127e, + 0x3f66, 0x6944, 0x1078, 0x4167, 0x6100, 0xd184, 0x0040, 0x3f4b, + 0x6858, 0xa084, 0x00ff, 0x00c0, 0x3f69, 0x6000, 0xd084, 0x0040, + 0x3f66, 0x6004, 0xa005, 0x00c0, 0x3f6c, 0x6003, 0x0000, 0x600b, + 0x0000, 0x0078, 0x3f63, 0x2011, 0x0001, 0x6860, 0xa005, 0x00c0, + 0x3f53, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, + 0x0040, 0x3f66, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0040, + 0x3f66, 0x600a, 0x6202, 0x127f, 0x0078, 0x413a, 0x127f, 0x0078, + 0x4132, 0x127f, 0x0078, 0x412a, 0x127f, 0x0078, 0x412e, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x7652, 0x2004, 0xd0a4, - 0x0040, 0x3fcc, 0x6944, 0x1078, 0x416f, 0x6000, 0xa084, 0x0001, - 0x0040, 0x3fcc, 0x6204, 0x6308, 0x6c48, 0xa484, 0x0003, 0x0040, - 0x3fa4, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x3f9d, 0x2100, - 0xa210, 0x0048, 0x3fc9, 0x0078, 0x3fa4, 0x8001, 0x00c0, 0x3fc9, - 0x2100, 0xa212, 0x0048, 0x3fc9, 0xa484, 0x000c, 0x0040, 0x3fbe, - 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, 0x3fb6, - 0x2100, 0xa318, 0x0048, 0x3fc9, 0x0078, 0x3fbe, 0xa082, 0x0004, - 0x00c0, 0x3fc9, 0x2100, 0xa31a, 0x0048, 0x3fc9, 0x6860, 0xa005, - 0x0040, 0x3fc4, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, 0x0078, - 0x4142, 0x127f, 0x0078, 0x413e, 0x127f, 0x0078, 0x413a, 0x127e, - 0x2091, 0x8000, 0x7007, 0x0001, 0x6944, 0x1078, 0x416f, 0x6308, - 0x8318, 0x0048, 0x3fdf, 0x630a, 0x127f, 0x0078, 0x4150, 0x127f, - 0x0078, 0x413e, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, - 0x684c, 0xd0ac, 0x0040, 0x3ff6, 0x027e, 0x2009, 0x0000, 0x2011, - 0xfcff, 0x1078, 0x46b4, 0x027f, 0x0078, 0x402c, 0x6858, 0xa005, - 0x0040, 0x4040, 0x685c, 0xa065, 0x0040, 0x403c, 0x2001, 0x762c, - 0x2004, 0xa005, 0x0040, 0x4008, 0x1078, 0x6aa1, 0x0078, 0x400e, - 0x6013, 0x0400, 0x2009, 0x0041, 0x1078, 0x5c29, 0x6958, 0xa18c, - 0xe600, 0xa186, 0x2000, 0x0040, 0x4024, 0xa186, 0x0400, 0x0040, - 0x4024, 0x6944, 0x0c7e, 0x1078, 0x460c, 0x6000, 0xa084, 0xfdff, - 0x6002, 0x0c7f, 0x0078, 0x402c, 0x027e, 0x2009, 0x0000, 0x2011, - 0xfdff, 0x1078, 0x46b4, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x4038, - 0x6944, 0x1078, 0x460c, 0x6008, 0x8000, 0x0048, 0x4038, 0x600a, - 0x0c7f, 0x127f, 0x0078, 0x4142, 0x0c7f, 0x127f, 0x0078, 0x413a, - 0x6954, 0xa186, 0x002a, 0x00c0, 0x404c, 0x2001, 0x760c, 0x200c, - 0xc194, 0x2102, 0x0078, 0x402c, 0xa186, 0x0020, 0x0040, 0x4061, - 0xa186, 0x0029, 0x00c0, 0x403c, 0x6944, 0xa18c, 0xff00, 0x810f, - 0x1078, 0x3825, 0x00c0, 0x402c, 0x6000, 0xc0e4, 0x6002, 0x0078, - 0x402c, 0x685c, 0xa065, 0x0040, 0x403c, 0x6017, 0x0014, 0x0078, - 0x402c, 0x6944, 0x1078, 0x416f, 0x6000, 0xa084, 0x0001, 0x0040, - 0x4082, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x407c, 0x6206, - 0x2091, 0x8001, 0x0078, 0x4150, 0x2091, 0x8001, 0x6853, 0x0016, - 0x0078, 0x4149, 0x6853, 0x0007, 0x0078, 0x4149, 0x6834, 0x8007, - 0xa084, 0x00ff, 0x00c0, 0x4090, 0x1078, 0x3df0, 0x0078, 0x40a2, - 0x2030, 0x8001, 0x00c0, 0x409a, 0x7007, 0x0001, 0x1078, 0x40a3, - 0x0078, 0x40a2, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, - 0x704b, 0x40a3, 0x007c, 0x0e7e, 0x2009, 0x762c, 0x210c, 0x81ff, - 0x00c0, 0x4124, 0x2009, 0x760c, 0x210c, 0xd194, 0x00c0, 0x412e, - 0x6848, 0x2070, 0xae82, 0x7d00, 0x0048, 0x4113, 0x2001, 0x7615, - 0x2004, 0xae02, 0x00c8, 0x4113, 0x6944, 0x1078, 0x416f, 0x6100, - 0xa184, 0x0001, 0x0040, 0x40f9, 0xa184, 0x0100, 0x00c0, 0x4117, - 0xa184, 0x0200, 0x00c0, 0x411b, 0x601c, 0xa005, 0x00c0, 0x411f, - 0x711c, 0xa186, 0x0006, 0x00c0, 0x40fe, 0x6853, 0x0000, 0x6803, + 0x0040, 0x3fc4, 0x6944, 0x1078, 0x4167, 0x6000, 0xa084, 0x0001, + 0x0040, 0x3fc4, 0x6204, 0x6308, 0x6c48, 0xa484, 0x0003, 0x0040, + 0x3f9c, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x3f95, 0x2100, + 0xa210, 0x0048, 0x3fc1, 0x0078, 0x3f9c, 0x8001, 0x00c0, 0x3fc1, + 0x2100, 0xa212, 0x0048, 0x3fc1, 0xa484, 0x000c, 0x0040, 0x3fb6, + 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, 0x3fae, + 0x2100, 0xa318, 0x0048, 0x3fc1, 0x0078, 0x3fb6, 0xa082, 0x0004, + 0x00c0, 0x3fc1, 0x2100, 0xa31a, 0x0048, 0x3fc1, 0x6860, 0xa005, + 0x0040, 0x3fbc, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, 0x0078, + 0x413a, 0x127f, 0x0078, 0x4136, 0x127f, 0x0078, 0x4132, 0x127e, + 0x2091, 0x8000, 0x7007, 0x0001, 0x6944, 0x1078, 0x4167, 0x6308, + 0x8318, 0x0048, 0x3fd7, 0x630a, 0x127f, 0x0078, 0x4148, 0x127f, + 0x0078, 0x4136, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, + 0x684c, 0xd0ac, 0x0040, 0x3fee, 0x027e, 0x2009, 0x0000, 0x2011, + 0xfcff, 0x1078, 0x46ac, 0x027f, 0x0078, 0x4024, 0x6858, 0xa005, + 0x0040, 0x4038, 0x685c, 0xa065, 0x0040, 0x4034, 0x2001, 0x762c, + 0x2004, 0xa005, 0x0040, 0x4000, 0x1078, 0x6a96, 0x0078, 0x4006, + 0x6013, 0x0400, 0x2009, 0x0041, 0x1078, 0x5c21, 0x6958, 0xa18c, + 0xe600, 0xa186, 0x2000, 0x0040, 0x401c, 0xa186, 0x0400, 0x0040, + 0x401c, 0x6944, 0x0c7e, 0x1078, 0x4604, 0x6000, 0xa084, 0xfdff, + 0x6002, 0x0c7f, 0x0078, 0x4024, 0x027e, 0x2009, 0x0000, 0x2011, + 0xfdff, 0x1078, 0x46ac, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x4030, + 0x6944, 0x1078, 0x4604, 0x6008, 0x8000, 0x0048, 0x4030, 0x600a, + 0x0c7f, 0x127f, 0x0078, 0x413a, 0x0c7f, 0x127f, 0x0078, 0x4132, + 0x6954, 0xa186, 0x002a, 0x00c0, 0x4044, 0x2001, 0x760c, 0x200c, + 0xc194, 0x2102, 0x0078, 0x4024, 0xa186, 0x0020, 0x0040, 0x4059, + 0xa186, 0x0029, 0x00c0, 0x4034, 0x6944, 0xa18c, 0xff00, 0x810f, + 0x1078, 0x381d, 0x00c0, 0x4024, 0x6000, 0xc0e4, 0x6002, 0x0078, + 0x4024, 0x685c, 0xa065, 0x0040, 0x4034, 0x6017, 0x0014, 0x0078, + 0x4024, 0x6944, 0x1078, 0x4167, 0x6000, 0xa084, 0x0001, 0x0040, + 0x407a, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x4074, 0x6206, + 0x2091, 0x8001, 0x0078, 0x4148, 0x2091, 0x8001, 0x6853, 0x0016, + 0x0078, 0x4141, 0x6853, 0x0007, 0x0078, 0x4141, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x00c0, 0x4088, 0x1078, 0x3de8, 0x0078, 0x409a, + 0x2030, 0x8001, 0x00c0, 0x4092, 0x7007, 0x0001, 0x1078, 0x409b, + 0x0078, 0x409a, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, + 0x704b, 0x409b, 0x007c, 0x0e7e, 0x2009, 0x762c, 0x210c, 0x81ff, + 0x00c0, 0x411c, 0x2009, 0x760c, 0x210c, 0xd194, 0x00c0, 0x4126, + 0x6848, 0x2070, 0xae82, 0x7d00, 0x0048, 0x410b, 0x2001, 0x7615, + 0x2004, 0xae02, 0x00c8, 0x410b, 0x6944, 0x1078, 0x4167, 0x6100, + 0xa184, 0x0001, 0x0040, 0x40f1, 0xa184, 0x0100, 0x00c0, 0x410f, + 0xa184, 0x0200, 0x00c0, 0x4113, 0x601c, 0xa005, 0x00c0, 0x4117, + 0x711c, 0xa186, 0x0006, 0x00c0, 0x40f6, 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x127e, 0x2091, 0x8000, 0x7010, 0xa005, 0x00c0, - 0x40f0, 0x7112, 0x7018, 0xa065, 0x0040, 0x4123, 0x6000, 0xd0e4, - 0x00c0, 0x4128, 0x2e60, 0x1078, 0x4615, 0x127f, 0x0e7f, 0x007c, - 0x2068, 0x6800, 0xa005, 0x00c0, 0x40f0, 0x6902, 0x127f, 0x0e7f, - 0x007c, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x4149, 0x6944, 0xa18c, - 0xff00, 0x810f, 0x1078, 0x3825, 0x00c0, 0x4129, 0x6000, 0xd0e4, - 0x00c0, 0x4129, 0x711c, 0xa186, 0x0007, 0x00c0, 0x4113, 0x6853, - 0x0002, 0x0078, 0x412b, 0x6853, 0x0008, 0x0078, 0x412b, 0x6853, - 0x000e, 0x0078, 0x412b, 0x6853, 0x0017, 0x0078, 0x412b, 0x6853, - 0x0035, 0x0078, 0x412b, 0x127f, 0x6853, 0x0028, 0x0078, 0x412b, - 0x127f, 0x6853, 0x0029, 0x0e7f, 0x0078, 0x4149, 0x6853, 0x002a, - 0x0078, 0x412b, 0x2009, 0x003e, 0x0078, 0x4144, 0x2009, 0x0004, - 0x0078, 0x4144, 0x2009, 0x0006, 0x0078, 0x4144, 0x2009, 0x0016, - 0x0078, 0x4144, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, - 0x6856, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x2091, 0x8001, 0x007c, - 0x1078, 0x1348, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, - 0x4160, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, 0x416c, - 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x416c, 0x7074, 0xa081, + 0x40e8, 0x7112, 0x7018, 0xa065, 0x0040, 0x411b, 0x6000, 0xd0e4, + 0x00c0, 0x4120, 0x2e60, 0x1078, 0x460d, 0x127f, 0x0e7f, 0x007c, + 0x2068, 0x6800, 0xa005, 0x00c0, 0x40e8, 0x6902, 0x127f, 0x0e7f, + 0x007c, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x4141, 0x6944, 0xa18c, + 0xff00, 0x810f, 0x1078, 0x381d, 0x00c0, 0x4121, 0x6000, 0xd0e4, + 0x00c0, 0x4121, 0x711c, 0xa186, 0x0007, 0x00c0, 0x410b, 0x6853, + 0x0002, 0x0078, 0x4123, 0x6853, 0x0008, 0x0078, 0x4123, 0x6853, + 0x000e, 0x0078, 0x4123, 0x6853, 0x0017, 0x0078, 0x4123, 0x6853, + 0x0035, 0x0078, 0x4123, 0x127f, 0x6853, 0x0028, 0x0078, 0x4123, + 0x127f, 0x6853, 0x0029, 0x0e7f, 0x0078, 0x4141, 0x6853, 0x002a, + 0x0078, 0x4123, 0x2009, 0x003e, 0x0078, 0x413c, 0x2009, 0x0004, + 0x0078, 0x413c, 0x2009, 0x0006, 0x0078, 0x413c, 0x2009, 0x0016, + 0x0078, 0x413c, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, + 0x6856, 0x2091, 0x8000, 0x1078, 0x3a72, 0x2091, 0x8001, 0x007c, + 0x1078, 0x1340, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, + 0x4158, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, 0x4164, + 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x4164, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, - 0x1078, 0x460c, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, + 0x1078, 0x4604, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, - 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x418b, 0xa086, - 0x1000, 0x00c0, 0x41a7, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, - 0x4192, 0x3e60, 0xac84, 0x0007, 0x00c0, 0x41a7, 0xac82, 0x7d00, - 0x0048, 0x41a7, 0x6854, 0xac02, 0x00c8, 0x41a7, 0x2009, 0x0047, - 0x1078, 0x5c29, 0x7a1c, 0xd284, 0x00c0, 0x417d, 0x007c, 0xa016, - 0x1078, 0x1572, 0x0078, 0x41a2, 0x157e, 0x137e, 0x147e, 0x20e1, - 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x00c0, 0x41d5, 0xa484, - 0x7000, 0xa086, 0x1000, 0x00c0, 0x41d5, 0x1078, 0x41e2, 0x0040, - 0x41d5, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078, 0x4200, 0x147f, - 0x137f, 0x157f, 0x2009, 0x783e, 0x2104, 0xa005, 0x00c0, 0x41d1, - 0x007c, 0x1078, 0x4c7a, 0x0078, 0x41d0, 0x1078, 0x7574, 0x1078, - 0x41e2, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, 0x137f, 0x157f, - 0x0078, 0x41d0, 0xa484, 0x01ff, 0x687a, 0xa005, 0x0040, 0x41f4, + 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x4183, 0xa086, + 0x1000, 0x00c0, 0x419f, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, + 0x418a, 0x3e60, 0xac84, 0x0007, 0x00c0, 0x419f, 0xac82, 0x7d00, + 0x0048, 0x419f, 0x6854, 0xac02, 0x00c8, 0x419f, 0x2009, 0x0047, + 0x1078, 0x5c21, 0x7a1c, 0xd284, 0x00c0, 0x4175, 0x007c, 0xa016, + 0x1078, 0x156a, 0x0078, 0x419a, 0x157e, 0x137e, 0x147e, 0x20e1, + 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x00c0, 0x41cd, 0xa484, + 0x7000, 0xa086, 0x1000, 0x00c0, 0x41cd, 0x1078, 0x41da, 0x0040, + 0x41cd, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078, 0x41f8, 0x147f, + 0x137f, 0x157f, 0x2009, 0x783e, 0x2104, 0xa005, 0x00c0, 0x41c9, + 0x007c, 0x1078, 0x4c72, 0x0078, 0x41c8, 0x1078, 0x7569, 0x1078, + 0x41da, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, 0x137f, 0x157f, + 0x0078, 0x41c8, 0xa484, 0x01ff, 0x687a, 0xa005, 0x0040, 0x41ec, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, 0x20e1, 0x1000, - 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41f3, + 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41eb, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, 0xa196, 0x0000, - 0x00c0, 0x420d, 0x0078, 0x4381, 0x007c, 0xa196, 0x2000, 0x00c0, - 0x421e, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x421a, 0x1078, 0x2eb2, - 0x0078, 0x420c, 0x1078, 0x4226, 0x0078, 0x420c, 0xa196, 0x8000, - 0x00c0, 0x420c, 0x1078, 0x4407, 0x0078, 0x420c, 0x0c7e, 0x7110, - 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, 0x4233, 0xa196, - 0x0023, 0x00c0, 0x4328, 0xa08e, 0x0023, 0x00c0, 0x4264, 0x1078, - 0x447e, 0x0040, 0x4328, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, - 0x00c0, 0x424c, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0015, - 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0210, 0x00c0, 0x4256, - 0x2009, 0x0015, 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0100, - 0x00c0, 0x4328, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0016, - 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0022, 0x00c0, 0x4328, - 0x7030, 0xa08e, 0x0300, 0x00c0, 0x4275, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x0017, 0x0078, 0x42f4, 0xa08e, 0x0500, 0x00c0, - 0x4281, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0018, 0x0078, - 0x42f4, 0xa08e, 0x2010, 0x00c0, 0x4289, 0x2009, 0x0019, 0x0078, - 0x42f4, 0xa08e, 0x2110, 0x00c0, 0x4291, 0x2009, 0x001a, 0x0078, - 0x42f4, 0xa08e, 0x5200, 0x00c0, 0x429d, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x001b, 0x0078, 0x42f4, 0xa08e, 0x5000, 0x00c0, - 0x42a9, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x001c, 0x0078, - 0x42f4, 0xa08e, 0x1200, 0x00c0, 0x42b5, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x0024, 0x0078, 0x42f4, 0xa08c, 0xff00, 0xa18e, - 0x2400, 0x00c0, 0x42bf, 0x2009, 0x002d, 0x0078, 0x42f4, 0xa08c, - 0xff00, 0xa18e, 0x5300, 0x00c0, 0x42c9, 0x2009, 0x002a, 0x0078, - 0x42f4, 0xa08e, 0x0f00, 0x00c0, 0x42d1, 0x2009, 0x0020, 0x0078, - 0x42f4, 0xa08e, 0x5300, 0x00c0, 0x42d7, 0x0078, 0x42f2, 0xa08e, - 0x6104, 0x00c0, 0x42f2, 0x2011, 0x7b8d, 0x8208, 0x2204, 0xa082, + 0x00c0, 0x4205, 0x0078, 0x4379, 0x007c, 0xa196, 0x2000, 0x00c0, + 0x4216, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x4212, 0x1078, 0x2ea3, + 0x0078, 0x4204, 0x1078, 0x421e, 0x0078, 0x4204, 0xa196, 0x8000, + 0x00c0, 0x4204, 0x1078, 0x43ff, 0x0078, 0x4204, 0x0c7e, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, 0x422b, 0xa196, + 0x0023, 0x00c0, 0x4320, 0xa08e, 0x0023, 0x00c0, 0x425c, 0x1078, + 0x4476, 0x0040, 0x4320, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, + 0x00c0, 0x4244, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0015, + 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0210, 0x00c0, 0x424e, + 0x2009, 0x0015, 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0100, + 0x00c0, 0x4320, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0016, + 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0022, 0x00c0, 0x4320, + 0x7030, 0xa08e, 0x0300, 0x00c0, 0x426d, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x0017, 0x0078, 0x42ec, 0xa08e, 0x0500, 0x00c0, + 0x4279, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0018, 0x0078, + 0x42ec, 0xa08e, 0x2010, 0x00c0, 0x4281, 0x2009, 0x0019, 0x0078, + 0x42ec, 0xa08e, 0x2110, 0x00c0, 0x4289, 0x2009, 0x001a, 0x0078, + 0x42ec, 0xa08e, 0x5200, 0x00c0, 0x4295, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x001b, 0x0078, 0x42ec, 0xa08e, 0x5000, 0x00c0, + 0x42a1, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x001c, 0x0078, + 0x42ec, 0xa08e, 0x1200, 0x00c0, 0x42ad, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x0024, 0x0078, 0x42ec, 0xa08c, 0xff00, 0xa18e, + 0x2400, 0x00c0, 0x42b7, 0x2009, 0x002d, 0x0078, 0x42ec, 0xa08c, + 0xff00, 0xa18e, 0x5300, 0x00c0, 0x42c1, 0x2009, 0x002a, 0x0078, + 0x42ec, 0xa08e, 0x0f00, 0x00c0, 0x42c9, 0x2009, 0x0020, 0x0078, + 0x42ec, 0xa08e, 0x5300, 0x00c0, 0x42cf, 0x0078, 0x42ea, 0xa08e, + 0x6104, 0x00c0, 0x42ea, 0x2011, 0x7b8d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, - 0x2124, 0x1078, 0x2d4a, 0x8108, 0x00f0, 0x42e4, 0x2009, 0x0023, - 0x0078, 0x42f4, 0x2009, 0x001d, 0x017e, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x432a, 0x1078, 0x37ee, - 0x00c0, 0x432a, 0x6612, 0x6516, 0x86ff, 0x0040, 0x431a, 0x017f, - 0x017e, 0xa186, 0x0017, 0x00c0, 0x431a, 0x6864, 0xa606, 0x00c0, - 0x431a, 0x6868, 0xa506, 0xa084, 0xff00, 0x00c0, 0x431a, 0x6000, - 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x5b9c, 0x0040, 0x432d, 0x017f, - 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x5c29, - 0x0c7f, 0x007c, 0x017f, 0x0078, 0x4328, 0x0c7f, 0x0078, 0x432a, - 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, 0x00c0, 0x4350, - 0xa596, 0xfffd, 0x00c0, 0x4340, 0x2009, 0x007f, 0x0078, 0x437d, - 0xa596, 0xfffe, 0x00c0, 0x4348, 0x2009, 0x007e, 0x0078, 0x437d, - 0xa596, 0xfffc, 0x00c0, 0x4350, 0x2009, 0x0080, 0x0078, 0x437d, + 0x2124, 0x1078, 0x2d3b, 0x8108, 0x00f0, 0x42dc, 0x2009, 0x0023, + 0x0078, 0x42ec, 0x2009, 0x001d, 0x017e, 0x2011, 0x7b83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x207f, 0x00c0, 0x4322, 0x1078, 0x37e6, + 0x00c0, 0x4322, 0x6612, 0x6516, 0x86ff, 0x0040, 0x4312, 0x017f, + 0x017e, 0xa186, 0x0017, 0x00c0, 0x4312, 0x6864, 0xa606, 0x00c0, + 0x4312, 0x6868, 0xa506, 0xa084, 0xff00, 0x00c0, 0x4312, 0x6000, + 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x5b94, 0x0040, 0x4325, 0x017f, + 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x5c21, + 0x0c7f, 0x007c, 0x017f, 0x0078, 0x4320, 0x0c7f, 0x0078, 0x4322, + 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, 0x00c0, 0x4348, + 0xa596, 0xfffd, 0x00c0, 0x4338, 0x2009, 0x007f, 0x0078, 0x4375, + 0xa596, 0xfffe, 0x00c0, 0x4340, 0x2009, 0x007e, 0x0078, 0x4375, + 0xa596, 0xfffc, 0x00c0, 0x4348, 0x2009, 0x0080, 0x0078, 0x4375, 0x2011, 0x0000, 0x2021, 0x007e, 0x20a9, 0x0082, 0x2071, 0x779e, - 0x2e1c, 0x83ff, 0x00c0, 0x4362, 0x82ff, 0x00c0, 0x4371, 0x2410, - 0x0078, 0x4371, 0x2368, 0x6b10, 0x007e, 0x2100, 0xa31e, 0x007f, - 0x00c0, 0x4371, 0x6b14, 0xa31e, 0x00c0, 0x4371, 0x2408, 0x0078, - 0x437d, 0x8420, 0x8e70, 0x00f0, 0x4358, 0x82ff, 0x00c0, 0x437c, - 0xa085, 0x0001, 0x0078, 0x437e, 0x2208, 0xa006, 0x0d7f, 0x0e7f, - 0x007c, 0xa084, 0x0007, 0x0079, 0x4386, 0x007c, 0x438e, 0x438e, - 0x438e, 0x438e, 0x438e, 0x438f, 0x43a8, 0x43f0, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x43a7, 0x7120, 0x2160, 0xac8c, 0x0007, 0x00c0, - 0x43a7, 0xac8a, 0x7d00, 0x0048, 0x43a7, 0x6854, 0xac02, 0x00c8, - 0x43a7, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x5c29, 0x007c, - 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x43ee, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x43ee, 0x1078, 0x3825, - 0x00c0, 0x43ee, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, - 0x00c0, 0x43d3, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x43ee, + 0x2e1c, 0x83ff, 0x00c0, 0x435a, 0x82ff, 0x00c0, 0x4369, 0x2410, + 0x0078, 0x4369, 0x2368, 0x6b10, 0x007e, 0x2100, 0xa31e, 0x007f, + 0x00c0, 0x4369, 0x6b14, 0xa31e, 0x00c0, 0x4369, 0x2408, 0x0078, + 0x4375, 0x8420, 0x8e70, 0x00f0, 0x4350, 0x82ff, 0x00c0, 0x4374, + 0xa085, 0x0001, 0x0078, 0x4376, 0x2208, 0xa006, 0x0d7f, 0x0e7f, + 0x007c, 0xa084, 0x0007, 0x0079, 0x437e, 0x007c, 0x4386, 0x4386, + 0x4386, 0x4386, 0x4386, 0x4387, 0x43a0, 0x43e8, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x439f, 0x7120, 0x2160, 0xac8c, 0x0007, 0x00c0, + 0x439f, 0xac8a, 0x7d00, 0x0048, 0x439f, 0x6854, 0xac02, 0x00c8, + 0x439f, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x5c21, 0x007c, + 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x43e6, 0x2011, 0x7b83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x207f, 0x00c0, 0x43e6, 0x1078, 0x381d, + 0x00c0, 0x43e6, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, + 0x00c0, 0x43cb, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x43e6, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x2009, 0x0044, 0x1078, - 0x5c29, 0x0078, 0x43ee, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, - 0x43ee, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, - 0x00c0, 0x43e6, 0x6007, 0x0005, 0x0078, 0x43e8, 0x6007, 0x0001, - 0x6003, 0x0001, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0c7f, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x4406, 0x7020, 0x2060, 0xac84, 0x0007, - 0x00c0, 0x4406, 0xac82, 0x7d00, 0x0048, 0x4406, 0x6854, 0xac02, - 0x00c8, 0x4406, 0x2009, 0x0045, 0x1078, 0x5c29, 0x007c, 0x7110, - 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x4417, 0xa084, - 0x000f, 0xa08a, 0x0006, 0x10c8, 0x12d5, 0x1079, 0x4418, 0x007c, - 0x441e, 0x441f, 0x441e, 0x441e, 0x4460, 0x446f, 0x007c, 0x7110, - 0xd1bc, 0x00c0, 0x445f, 0x700c, 0x7108, 0x1078, 0x2085, 0x00c0, - 0x445f, 0x1078, 0x37ee, 0x00c0, 0x445f, 0x6612, 0x6516, 0x6204, - 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x00c0, 0x4448, 0x0c7e, - 0x1078, 0x5b9c, 0x017f, 0x0040, 0x445f, 0x611a, 0x601f, 0x0005, - 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x5c29, 0x0078, 0x445f, - 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x445f, 0x611a, 0x601f, - 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x445b, 0x2009, - 0x0005, 0x0078, 0x445d, 0x2009, 0x0001, 0x1078, 0x5c29, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x446e, 0x1078, 0x447e, 0x0040, 0x446e, - 0x7124, 0x610a, 0x2009, 0x0089, 0x1078, 0x5c29, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x447d, 0x1078, 0x447e, 0x0040, 0x447d, 0x7124, - 0x610a, 0x2009, 0x008a, 0x1078, 0x5c29, 0x007c, 0x7020, 0x2060, - 0xac84, 0x0007, 0x00c0, 0x4491, 0xac82, 0x7d00, 0x0048, 0x4491, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x4491, 0xa085, 0x0001, - 0x007c, 0xa006, 0x0078, 0x4490, 0x2071, 0x7849, 0x7003, 0x0003, + 0x5c21, 0x0078, 0x43e6, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, + 0x43e6, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, + 0x00c0, 0x43de, 0x6007, 0x0005, 0x0078, 0x43e0, 0x6007, 0x0001, + 0x6003, 0x0001, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0c7f, 0x007c, + 0x7110, 0xd1bc, 0x0040, 0x43fe, 0x7020, 0x2060, 0xac84, 0x0007, + 0x00c0, 0x43fe, 0xac82, 0x7d00, 0x0048, 0x43fe, 0x6854, 0xac02, + 0x00c8, 0x43fe, 0x2009, 0x0045, 0x1078, 0x5c21, 0x007c, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x440f, 0xa084, + 0x000f, 0xa08a, 0x0006, 0x10c8, 0x12cd, 0x1079, 0x4410, 0x007c, + 0x4416, 0x4417, 0x4416, 0x4416, 0x4458, 0x4467, 0x007c, 0x7110, + 0xd1bc, 0x00c0, 0x4457, 0x700c, 0x7108, 0x1078, 0x207f, 0x00c0, + 0x4457, 0x1078, 0x37e6, 0x00c0, 0x4457, 0x6612, 0x6516, 0x6204, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x00c0, 0x4440, 0x0c7e, + 0x1078, 0x5b94, 0x017f, 0x0040, 0x4457, 0x611a, 0x601f, 0x0005, + 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x5c21, 0x0078, 0x4457, + 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x4457, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x4453, 0x2009, + 0x0005, 0x0078, 0x4455, 0x2009, 0x0001, 0x1078, 0x5c21, 0x007c, + 0x7110, 0xd1bc, 0x0040, 0x4466, 0x1078, 0x4476, 0x0040, 0x4466, + 0x7124, 0x610a, 0x2009, 0x0089, 0x1078, 0x5c21, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x4475, 0x1078, 0x4476, 0x0040, 0x4475, 0x7124, + 0x610a, 0x2009, 0x008a, 0x1078, 0x5c21, 0x007c, 0x7020, 0x2060, + 0xac84, 0x0007, 0x00c0, 0x4489, 0xac82, 0x7d00, 0x0048, 0x4489, + 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x4489, 0xa085, 0x0001, + 0x007c, 0xa006, 0x0078, 0x4488, 0x2071, 0x7849, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, 0x7017, 0x7d00, 0x7007, - 0x0000, 0x7026, 0x702b, 0x558f, 0x7032, 0x7037, 0x55d0, 0x703b, - 0x0002, 0x703f, 0x0000, 0x007c, 0x2071, 0x7849, 0x00e0, 0x455b, - 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x4524, 0x700f, + 0x0000, 0x7026, 0x702b, 0x5587, 0x7032, 0x7037, 0x55c8, 0x703b, + 0x0002, 0x703f, 0x0000, 0x007c, 0x2071, 0x7849, 0x00e0, 0x4553, + 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x451c, 0x700f, 0x0361, 0x7007, 0x0001, 0x127e, 0x2091, 0x8000, 0x7138, 0x8109, - 0x713a, 0x00c0, 0x4522, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, - 0xa082, 0x0003, 0x00c8, 0x4522, 0x703c, 0xa086, 0x0001, 0x00c0, - 0x44ff, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, - 0x44dd, 0x6803, 0x1000, 0x0078, 0x44e4, 0x6804, 0xa084, 0x1000, - 0x0040, 0x44e4, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, - 0x2069, 0x7836, 0x6804, 0xa082, 0x0006, 0x00c0, 0x44f1, 0x6807, - 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x44f8, 0x6833, 0x0000, - 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x0d7f, 0x0078, 0x4522, 0x0d7e, - 0x2069, 0x7600, 0x6944, 0x6860, 0xa102, 0x00c8, 0x4521, 0x2069, - 0x7836, 0x6804, 0xa086, 0x0000, 0x00c0, 0x4521, 0x6830, 0xa086, - 0x0000, 0x00c0, 0x4521, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, + 0x713a, 0x00c0, 0x451a, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, + 0xa082, 0x0003, 0x00c8, 0x451a, 0x703c, 0xa086, 0x0001, 0x00c0, + 0x44f7, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, + 0x44d5, 0x6803, 0x1000, 0x0078, 0x44dc, 0x6804, 0xa084, 0x1000, + 0x0040, 0x44dc, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, + 0x2069, 0x7836, 0x6804, 0xa082, 0x0006, 0x00c0, 0x44e9, 0x6807, + 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x44f0, 0x6833, 0x0000, + 0x1078, 0x4c72, 0x1078, 0x4d32, 0x0d7f, 0x0078, 0x451a, 0x0d7e, + 0x2069, 0x7600, 0x6944, 0x6860, 0xa102, 0x00c8, 0x4519, 0x2069, + 0x7836, 0x6804, 0xa086, 0x0000, 0x00c0, 0x4519, 0x6830, 0xa086, + 0x0000, 0x00c0, 0x4519, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, 0x0003, 0x2069, 0x0100, 0x6830, 0x689e, 0x2069, 0x0140, 0x6803, - 0x0600, 0x0d7f, 0x0078, 0x4527, 0x127e, 0x2091, 0x8000, 0x7024, - 0xa00d, 0x0040, 0x4538, 0x7020, 0x8001, 0x7022, 0x00c0, 0x4538, - 0x7023, 0x0009, 0x8109, 0x7126, 0x00c0, 0x4538, 0x7028, 0x107a, - 0x7030, 0xa00d, 0x0040, 0x4549, 0x702c, 0x8001, 0x702e, 0x00c0, - 0x4549, 0x702f, 0x0009, 0x8109, 0x7132, 0x00c0, 0x4549, 0x7034, - 0x107a, 0x7018, 0xa00d, 0x0040, 0x455a, 0x7008, 0x8001, 0x700a, - 0x00c0, 0x455a, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x455a, - 0x701c, 0x107a, 0x127f, 0x7004, 0x0079, 0x455e, 0x4585, 0x4586, - 0x45a2, 0x0e7e, 0x2071, 0x7849, 0x7018, 0xa005, 0x00c0, 0x456c, + 0x0600, 0x0d7f, 0x0078, 0x451f, 0x127e, 0x2091, 0x8000, 0x7024, + 0xa00d, 0x0040, 0x4530, 0x7020, 0x8001, 0x7022, 0x00c0, 0x4530, + 0x7023, 0x0009, 0x8109, 0x7126, 0x00c0, 0x4530, 0x7028, 0x107a, + 0x7030, 0xa00d, 0x0040, 0x4541, 0x702c, 0x8001, 0x702e, 0x00c0, + 0x4541, 0x702f, 0x0009, 0x8109, 0x7132, 0x00c0, 0x4541, 0x7034, + 0x107a, 0x7018, 0xa00d, 0x0040, 0x4552, 0x7008, 0x8001, 0x700a, + 0x00c0, 0x4552, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x4552, + 0x701c, 0x107a, 0x127f, 0x7004, 0x0079, 0x4556, 0x457d, 0x457e, + 0x459a, 0x0e7e, 0x2071, 0x7849, 0x7018, 0xa005, 0x00c0, 0x4564, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, - 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4578, 0x701a, 0x701e, + 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4570, 0x701a, 0x701e, 0x007f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x6088, 0xa102, - 0x0048, 0x4583, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, - 0x3825, 0x00c0, 0x4598, 0x6088, 0x8001, 0x0048, 0x4598, 0x608a, - 0x00c0, 0x4598, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, - 0x8108, 0xa182, 0x00ff, 0x0048, 0x45a0, 0xa00e, 0x7007, 0x0002, + 0x0048, 0x457b, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, + 0x381d, 0x00c0, 0x4590, 0x6088, 0x8001, 0x0048, 0x4590, 0x608a, + 0x00c0, 0x4590, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, + 0x8108, 0xa182, 0x00ff, 0x0048, 0x4598, 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c, 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x6014, - 0xa005, 0x0040, 0x45d1, 0x8001, 0x6016, 0x00c0, 0x45d1, 0x611c, - 0xa186, 0x0003, 0x0040, 0x45b8, 0xa186, 0x0006, 0x00c0, 0x45cf, - 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x45cf, 0xa082, - 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x45c8, 0x2001, 0x1999, - 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x45d1, 0x1078, - 0x67c9, 0x127f, 0xac88, 0x0008, 0x7116, 0x2001, 0x7616, 0x2004, - 0xa102, 0x0048, 0x45df, 0x7017, 0x7d00, 0x7007, 0x0000, 0x007c, + 0xa005, 0x0040, 0x45c9, 0x8001, 0x6016, 0x00c0, 0x45c9, 0x611c, + 0xa186, 0x0003, 0x0040, 0x45b0, 0xa186, 0x0006, 0x00c0, 0x45c7, + 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x45c7, 0xa082, + 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x45c0, 0x2001, 0x1999, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x45c9, 0x1078, + 0x67c3, 0x127f, 0xac88, 0x0008, 0x7116, 0x2001, 0x7616, 0x2004, + 0xa102, 0x0048, 0x45d7, 0x7017, 0x7d00, 0x7007, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, 0x0002, 0x0e7f, 0x007c, 0x2001, 0x7852, 0x2003, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x7033, 0x07d0, 0x702f, 0x0009, 0x0e7f, @@ -1757,1536 +1738,5694 @@ 0x7849, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0c7e, 0x2061, 0x78da, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x78da, 0x2060, 0x007c, 0x6854, 0xa08a, 0x199a, - 0x0048, 0x461c, 0x2001, 0x1999, 0xa005, 0x00c0, 0x462c, 0x6944, - 0x0c7e, 0x1078, 0x460c, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x4631, - 0x2001, 0x001e, 0x0078, 0x4631, 0xa08e, 0xffff, 0x00c0, 0x4631, + 0x0048, 0x4614, 0x2001, 0x1999, 0xa005, 0x00c0, 0x4624, 0x6944, + 0x0c7e, 0x1078, 0x4604, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x4629, + 0x2001, 0x001e, 0x0078, 0x4629, 0xa08e, 0xffff, 0x00c0, 0x4629, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, - 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x466c, 0xd0b4, 0x00c0, 0x4648, - 0xd0bc, 0x00c0, 0x465a, 0x2009, 0x0006, 0x1078, 0x468f, 0x007c, - 0xd0fc, 0x0040, 0x4655, 0xa084, 0x0003, 0xa08e, 0x0003, 0x0040, - 0x4688, 0xa08e, 0x0000, 0x00c0, 0x4688, 0x2009, 0x0043, 0x1078, - 0x5c29, 0x007c, 0xd0fc, 0x0040, 0x4667, 0xa084, 0x0003, 0xa08e, - 0x0003, 0x0040, 0x4688, 0xa08e, 0x0000, 0x00c0, 0x4688, 0x2009, - 0x0042, 0x1078, 0x5c29, 0x007c, 0xd0fc, 0x0040, 0x467e, 0xa084, - 0x0003, 0xa08e, 0x0003, 0x0040, 0x4688, 0xa08e, 0x0002, 0x0040, - 0x4682, 0x2009, 0x0041, 0x1078, 0x5c29, 0x007c, 0x1078, 0x468d, - 0x0078, 0x467d, 0x2009, 0x0043, 0x1078, 0x5c29, 0x0078, 0x467d, - 0x2009, 0x0004, 0x1078, 0x468f, 0x007c, 0x2009, 0x0001, 0x6010, - 0xa0ec, 0xf000, 0x0040, 0x46b3, 0x2068, 0x6952, 0x6800, 0x6012, - 0xa186, 0x0001, 0x00c0, 0x46ad, 0x694c, 0xa18c, 0x8100, 0xa18e, - 0x8100, 0x00c0, 0x46ad, 0x0c7e, 0x6944, 0x1078, 0x460c, 0x6204, - 0x8210, 0x0048, 0x46ac, 0x6206, 0x0c7f, 0x1078, 0x3a7a, 0x6010, - 0xa06d, 0x10c0, 0x4615, 0x007c, 0x157e, 0x0c7e, 0x20a9, 0x0010, - 0x2061, 0x78da, 0x6000, 0x81ff, 0x0040, 0x46c1, 0xa205, 0x0078, - 0x46c2, 0xa204, 0x6002, 0xace0, 0x0008, 0x00f0, 0x46ba, 0x0c7f, - 0x157f, 0x007c, 0x6808, 0xa005, 0x0040, 0x46d2, 0x8001, 0x680a, + 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x4664, 0xd0b4, 0x00c0, 0x4640, + 0xd0bc, 0x00c0, 0x4652, 0x2009, 0x0006, 0x1078, 0x4687, 0x007c, + 0xd0fc, 0x0040, 0x464d, 0xa084, 0x0003, 0xa08e, 0x0003, 0x0040, + 0x4680, 0xa08e, 0x0000, 0x00c0, 0x4680, 0x2009, 0x0043, 0x1078, + 0x5c21, 0x007c, 0xd0fc, 0x0040, 0x465f, 0xa084, 0x0003, 0xa08e, + 0x0003, 0x0040, 0x4680, 0xa08e, 0x0000, 0x00c0, 0x4680, 0x2009, + 0x0042, 0x1078, 0x5c21, 0x007c, 0xd0fc, 0x0040, 0x4676, 0xa084, + 0x0003, 0xa08e, 0x0003, 0x0040, 0x4680, 0xa08e, 0x0002, 0x0040, + 0x467a, 0x2009, 0x0041, 0x1078, 0x5c21, 0x007c, 0x1078, 0x4685, + 0x0078, 0x4675, 0x2009, 0x0043, 0x1078, 0x5c21, 0x0078, 0x4675, + 0x2009, 0x0004, 0x1078, 0x4687, 0x007c, 0x2009, 0x0001, 0x6010, + 0xa0ec, 0xf000, 0x0040, 0x46ab, 0x2068, 0x6952, 0x6800, 0x6012, + 0xa186, 0x0001, 0x00c0, 0x46a5, 0x694c, 0xa18c, 0x8100, 0xa18e, + 0x8100, 0x00c0, 0x46a5, 0x0c7e, 0x6944, 0x1078, 0x4604, 0x6204, + 0x8210, 0x0048, 0x46a4, 0x6206, 0x0c7f, 0x1078, 0x3a72, 0x6010, + 0xa06d, 0x10c0, 0x460d, 0x007c, 0x157e, 0x0c7e, 0x20a9, 0x0010, + 0x2061, 0x78da, 0x6000, 0x81ff, 0x0040, 0x46b9, 0xa205, 0x0078, + 0x46ba, 0xa204, 0x6002, 0xace0, 0x0008, 0x00f0, 0x46b2, 0x0c7f, + 0x157f, 0x007c, 0x6808, 0xa005, 0x0040, 0x46ca, 0x8001, 0x680a, 0xa085, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x2079, 0x7836, 0x127f, 0x0d7e, 0x2069, 0x7836, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, 0x0d7f, 0x007c, 0x0c7e, 0x6027, - 0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x46ee, 0x46f8, 0x471d, - 0x4778, 0x46fe, 0x471d, 0x46f6, 0x46f6, 0x46f6, 0x1078, 0x12d5, - 0x1078, 0x45eb, 0x1078, 0x4c7a, 0x0c7f, 0x007c, 0x62c0, 0x82ff, - 0x00c0, 0x4704, 0x0c7f, 0x007c, 0x2011, 0x3542, 0x1078, 0x456e, - 0x7828, 0xa092, 0x0002, 0x00c8, 0x4713, 0x8000, 0x782a, 0x1078, - 0x3572, 0x0078, 0x4702, 0x1078, 0x3542, 0x7807, 0x0003, 0x7827, - 0x0000, 0x782b, 0x0000, 0x0078, 0x4702, 0x1078, 0x45eb, 0x3c00, + 0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x46e6, 0x46f0, 0x4715, + 0x4770, 0x46f6, 0x4715, 0x46ee, 0x46ee, 0x46ee, 0x1078, 0x12cd, + 0x1078, 0x45e3, 0x1078, 0x4c72, 0x0c7f, 0x007c, 0x62c0, 0x82ff, + 0x00c0, 0x46fc, 0x0c7f, 0x007c, 0x2011, 0x353a, 0x1078, 0x4566, + 0x7828, 0xa092, 0x0002, 0x00c8, 0x470b, 0x8000, 0x782a, 0x1078, + 0x356a, 0x0078, 0x46fa, 0x1078, 0x353a, 0x7807, 0x0003, 0x7827, + 0x0000, 0x782b, 0x0000, 0x0078, 0x46fa, 0x1078, 0x45e3, 0x3c00, 0x007e, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x007f, 0x20e0, - 0x82ff, 0x0040, 0x473b, 0x62c0, 0x82ff, 0x00c0, 0x473b, 0x782b, - 0x0000, 0x7824, 0xa065, 0x1040, 0x12d5, 0x2009, 0x0013, 0x1078, - 0x5c29, 0x0c7f, 0x007c, 0x3900, 0xa082, 0x797a, 0x00c8, 0x4742, - 0x1078, 0x5b2c, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x12d5, 0x7804, - 0xa086, 0x0004, 0x0040, 0x47bd, 0x7828, 0xa092, 0x2710, 0x00c8, - 0x4758, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x5574, 0x0078, 0x4739, - 0x6104, 0xa186, 0x0003, 0x00c0, 0x476f, 0x0e7e, 0x2071, 0x7600, - 0x70c8, 0x0e7f, 0xd08c, 0x0040, 0x476f, 0x0c7e, 0x0e7e, 0x2061, - 0x0100, 0x2071, 0x7600, 0x1078, 0x357b, 0x0e7f, 0x0c7f, 0x1078, - 0x75c7, 0x2009, 0x0014, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x4739, - 0x2001, 0x7852, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x478c, - 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x12d5, 0x2009, 0x0013, - 0x1078, 0x5c77, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082, - 0x797a, 0x00c8, 0x4795, 0x1078, 0x5b2c, 0x7824, 0xa005, 0x1040, - 0x12d5, 0x781c, 0xa06d, 0x1040, 0x12d5, 0x6800, 0xc0dc, 0x6802, - 0x7924, 0x2160, 0x1078, 0x5c02, 0x693c, 0x81ff, 0x1040, 0x12d5, - 0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x47b1, 0x7a1e, 0x0078, - 0x47b3, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, - 0x0c7f, 0x1078, 0x4c7a, 0x0078, 0x478a, 0x6104, 0xa186, 0x0002, - 0x0040, 0x47c8, 0xa186, 0x0004, 0x0040, 0x47c8, 0x0078, 0x474c, - 0x7808, 0xac06, 0x0040, 0x474c, 0x1078, 0x4b81, 0x1078, 0x4872, - 0x0c7f, 0x1078, 0x4c7a, 0x0078, 0x4739, 0x0c7e, 0x6027, 0x0002, - 0x2011, 0x7855, 0x2013, 0x0000, 0x62c8, 0x82ff, 0x00c0, 0x47ef, - 0x62c4, 0x82ff, 0x00c0, 0x47ef, 0x793c, 0xa1e5, 0x0000, 0x0040, - 0x47ed, 0x2009, 0x0049, 0x1078, 0x5c29, 0x0c7f, 0x007c, 0x3908, - 0xa192, 0x797a, 0x00c8, 0x47f6, 0x1078, 0x5b2c, 0x6017, 0x0010, - 0x793c, 0x81ff, 0x0040, 0x47ed, 0x7944, 0xa192, 0x7530, 0x00c8, - 0x4815, 0x8108, 0x7946, 0x1078, 0x45f0, 0x793c, 0xa188, 0x0007, - 0x210c, 0xa18e, 0x0006, 0x00c0, 0x4811, 0x6017, 0x0012, 0x0078, - 0x47ed, 0x6017, 0x0016, 0x0078, 0x47ed, 0x037e, 0x2019, 0x0001, - 0x1078, 0x5768, 0x037f, 0x1078, 0x75c7, 0x793c, 0x2160, 0x2009, - 0x004a, 0x1078, 0x5c29, 0x0078, 0x47ed, 0x007e, 0x017e, 0x0c7e, + 0x82ff, 0x0040, 0x4733, 0x62c0, 0x82ff, 0x00c0, 0x4733, 0x782b, + 0x0000, 0x7824, 0xa065, 0x1040, 0x12cd, 0x2009, 0x0013, 0x1078, + 0x5c21, 0x0c7f, 0x007c, 0x3900, 0xa082, 0x797a, 0x00c8, 0x473a, + 0x1078, 0x5b24, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x12cd, 0x7804, + 0xa086, 0x0004, 0x0040, 0x47b5, 0x7828, 0xa092, 0x2710, 0x00c8, + 0x4750, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x556c, 0x0078, 0x4731, + 0x6104, 0xa186, 0x0003, 0x00c0, 0x4767, 0x0e7e, 0x2071, 0x7600, + 0x70c8, 0x0e7f, 0xd08c, 0x0040, 0x4767, 0x0c7e, 0x0e7e, 0x2061, + 0x0100, 0x2071, 0x7600, 0x1078, 0x3573, 0x0e7f, 0x0c7f, 0x1078, + 0x75bc, 0x2009, 0x0014, 0x1078, 0x5c21, 0x0c7f, 0x0078, 0x4731, + 0x2001, 0x7852, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x4784, + 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x12cd, 0x2009, 0x0013, + 0x1078, 0x5c6f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082, + 0x797a, 0x00c8, 0x478d, 0x1078, 0x5b24, 0x7824, 0xa005, 0x1040, + 0x12cd, 0x781c, 0xa06d, 0x1040, 0x12cd, 0x6800, 0xc0dc, 0x6802, + 0x7924, 0x2160, 0x1078, 0x5bfa, 0x693c, 0x81ff, 0x1040, 0x12cd, + 0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x47a9, 0x7a1e, 0x0078, + 0x47ab, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, + 0x0c7f, 0x1078, 0x4c72, 0x0078, 0x4782, 0x6104, 0xa186, 0x0002, + 0x0040, 0x47c0, 0xa186, 0x0004, 0x0040, 0x47c0, 0x0078, 0x4744, + 0x7808, 0xac06, 0x0040, 0x4744, 0x1078, 0x4b79, 0x1078, 0x486a, + 0x0c7f, 0x1078, 0x4c72, 0x0078, 0x4731, 0x0c7e, 0x6027, 0x0002, + 0x2011, 0x7855, 0x2013, 0x0000, 0x62c8, 0x82ff, 0x00c0, 0x47e7, + 0x62c4, 0x82ff, 0x00c0, 0x47e7, 0x793c, 0xa1e5, 0x0000, 0x0040, + 0x47e5, 0x2009, 0x0049, 0x1078, 0x5c21, 0x0c7f, 0x007c, 0x3908, + 0xa192, 0x797a, 0x00c8, 0x47ee, 0x1078, 0x5b24, 0x6017, 0x0010, + 0x793c, 0x81ff, 0x0040, 0x47e5, 0x7944, 0xa192, 0x7530, 0x00c8, + 0x480d, 0x8108, 0x7946, 0x1078, 0x45e8, 0x793c, 0xa188, 0x0007, + 0x210c, 0xa18e, 0x0006, 0x00c0, 0x4809, 0x6017, 0x0012, 0x0078, + 0x47e5, 0x6017, 0x0016, 0x0078, 0x47e5, 0x037e, 0x2019, 0x0001, + 0x1078, 0x5760, 0x037f, 0x1078, 0x75bc, 0x793c, 0x2160, 0x2009, + 0x004a, 0x1078, 0x5c21, 0x0078, 0x47e5, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, - 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4840, 0xa080, + 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4838, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, - 0x6116, 0x6112, 0x0078, 0x483b, 0x0d7e, 0x2069, 0x7836, 0x6000, - 0xd0d4, 0x0040, 0x4859, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, - 0x00c0, 0x4854, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0079, - 0x4c82, 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0040, 0x486b, 0x6056, + 0x6116, 0x6112, 0x0078, 0x4833, 0x0d7e, 0x2069, 0x7836, 0x6000, + 0xd0d4, 0x0040, 0x4851, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, + 0x00c0, 0x484c, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0079, + 0x4c7a, 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0040, 0x4863, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, - 0x7836, 0x0078, 0x484b, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, - 0x0078, 0x484b, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x7836, 0x0078, 0x4843, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, + 0x0078, 0x4843, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6020, 0x8000, 0x6022, - 0x6008, 0xa005, 0x0040, 0x488d, 0xa080, 0x0003, 0x2102, 0x610a, + 0x6008, 0xa005, 0x0040, 0x4885, 0xa080, 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, 0x610e, 0x610a, 0x0078, - 0x4888, 0x0c7e, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6034, - 0xa005, 0x0040, 0x48a1, 0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, - 0x007c, 0x613a, 0x6136, 0x0078, 0x489f, 0x0f7e, 0x0e7e, 0x0d7e, + 0x4880, 0x0c7e, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6034, + 0xa005, 0x0040, 0x4899, 0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, + 0x007c, 0x613a, 0x6136, 0x0078, 0x4897, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2071, 0x7836, 0x7638, - 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x4907, 0x6018, - 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x4902, 0x703c, 0xac06, - 0x00c0, 0x48c7, 0x6003, 0x000a, 0x630a, 0x0078, 0x4902, 0x7038, - 0xac36, 0x00c0, 0x48cd, 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, - 0x48db, 0x2c00, 0xaf36, 0x0040, 0x48d9, 0x2f00, 0x7036, 0x0078, - 0x48db, 0x7037, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, - 0x48e4, 0x7e0e, 0x0078, 0x48e5, 0x2678, 0x600f, 0x0000, 0x1078, - 0x693e, 0x0040, 0x48fd, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, - 0x00c0, 0x4910, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x6b3f, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x0c7f, - 0x0078, 0x48b4, 0x2c78, 0x600c, 0x2060, 0x0078, 0x48b4, 0x127f, + 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x48ff, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x48fa, 0x703c, 0xac06, + 0x00c0, 0x48bf, 0x6003, 0x000a, 0x630a, 0x0078, 0x48fa, 0x7038, + 0xac36, 0x00c0, 0x48c5, 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, + 0x48d3, 0x2c00, 0xaf36, 0x0040, 0x48d1, 0x2f00, 0x7036, 0x0078, + 0x48d3, 0x7037, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, + 0x48dc, 0x7e0e, 0x0078, 0x48dd, 0x2678, 0x600f, 0x0000, 0x1078, + 0x6938, 0x0040, 0x48f5, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, + 0x00c0, 0x4908, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x6b34, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x0c7f, + 0x0078, 0x48ac, 0x2c78, 0x600c, 0x2060, 0x0078, 0x48ac, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, - 0x601c, 0xa086, 0x0006, 0x00c0, 0x48f2, 0x1078, 0x74fd, 0x0078, - 0x48fd, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x48ea, 0x1078, 0x74f2, 0x0078, + 0x48f5, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, 0x127e, 0x2091, 0x8000, 0x2079, 0x7836, 0x7838, 0xa065, 0x0040, - 0x4950, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, - 0x4937, 0x6003, 0x000a, 0x630a, 0x2c30, 0x0078, 0x494d, 0x1078, - 0x693e, 0x0040, 0x494b, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, - 0x00c0, 0x4959, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x007f, 0x0078, 0x4926, + 0x4948, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, + 0x492f, 0x6003, 0x000a, 0x630a, 0x2c30, 0x0078, 0x4945, 0x1078, + 0x6938, 0x0040, 0x4943, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, + 0x00c0, 0x4951, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x007f, 0x0078, 0x491e, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, 0x007f, - 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x4942, 0x1078, 0x74fd, - 0x0078, 0x494b, 0x027e, 0x1078, 0x4976, 0x1078, 0x4a0f, 0x027f, + 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x493a, 0x1078, 0x74f2, + 0x0078, 0x4943, 0x027e, 0x1078, 0x496e, 0x1078, 0x4a07, 0x027f, 0x007c, 0x0f7e, 0x127e, 0x2079, 0x7836, 0x2091, 0x8000, 0x1078, - 0x4aa6, 0x1078, 0x4b0e, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, + 0x4a9e, 0x1078, 0x4b06, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x7836, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x49fe, 0x6018, - 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x49f9, 0x7024, 0xac06, - 0x00c0, 0x49bc, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x49b7, - 0x1078, 0x5582, 0x68c3, 0x0000, 0x1078, 0x5a32, 0x7027, 0x0000, - 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x49ac, + 0x7836, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x49f6, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x49f1, 0x7024, 0xac06, + 0x00c0, 0x49b4, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x49af, + 0x1078, 0x557a, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, + 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x49a4, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, - 0x0040, 0x49b4, 0x6827, 0x0001, 0x037f, 0x0078, 0x49bc, 0x6003, - 0x0009, 0x630a, 0x0078, 0x49f9, 0x7014, 0xac36, 0x00c0, 0x49c2, - 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x49d0, 0x2c00, 0xaf36, - 0x0040, 0x49ce, 0x2f00, 0x7012, 0x0078, 0x49d0, 0x7013, 0x0000, - 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x49d9, 0x7e0e, 0x0078, - 0x49da, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x49f2, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4a06, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, 0x1078, 0x3a7a, - 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, - 0x4984, 0x2c78, 0x600c, 0x2060, 0x0078, 0x4984, 0x127f, 0x007f, + 0x0040, 0x49ac, 0x6827, 0x0001, 0x037f, 0x0078, 0x49b4, 0x6003, + 0x0009, 0x630a, 0x0078, 0x49f1, 0x7014, 0xac36, 0x00c0, 0x49ba, + 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x49c8, 0x2c00, 0xaf36, + 0x0040, 0x49c6, 0x2f00, 0x7012, 0x0078, 0x49c8, 0x7013, 0x0000, + 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x49d1, 0x7e0e, 0x0078, + 0x49d2, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x49ea, 0x601c, 0xa086, 0x0003, 0x00c0, 0x49fe, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, 0x1078, 0x3a72, + 0x1078, 0x6a89, 0x1078, 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, + 0x497c, 0x2c78, 0x600c, 0x2060, 0x0078, 0x497c, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, - 0x0006, 0x00c0, 0x49e7, 0x1078, 0x74fd, 0x0078, 0x49f2, 0x0c7e, + 0x0006, 0x00c0, 0x49df, 0x1078, 0x74f2, 0x0078, 0x49ea, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0x7720, 0x2004, 0xa065, - 0x0040, 0x4aa2, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, 0x2071, 0x7836, - 0x6654, 0x7018, 0xac06, 0x00c0, 0x4a26, 0x761a, 0x701c, 0xac06, - 0x00c0, 0x4a32, 0x86ff, 0x00c0, 0x4a31, 0x7018, 0x701e, 0x0078, - 0x4a32, 0x761e, 0x6058, 0xa07d, 0x0040, 0x4a37, 0x7e56, 0xa6ed, - 0x0000, 0x0040, 0x4a3d, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, - 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x37a2, 0x0040, - 0x4a9e, 0x7624, 0x86ff, 0x0040, 0x4a8e, 0xa680, 0x0004, 0x2004, - 0xad06, 0x00c0, 0x4a8e, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x4a85, 0x1078, 0x5582, 0x68c3, 0x0000, 0x1078, 0x5a32, + 0x0040, 0x4a9a, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, 0x2071, 0x7836, + 0x6654, 0x7018, 0xac06, 0x00c0, 0x4a1e, 0x761a, 0x701c, 0xac06, + 0x00c0, 0x4a2a, 0x86ff, 0x00c0, 0x4a29, 0x7018, 0x701e, 0x0078, + 0x4a2a, 0x761e, 0x6058, 0xa07d, 0x0040, 0x4a2f, 0x7e56, 0xa6ed, + 0x0000, 0x0040, 0x4a35, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, + 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x379a, 0x0040, + 0x4a96, 0x7624, 0x86ff, 0x0040, 0x4a86, 0xa680, 0x0004, 0x2004, + 0xad06, 0x00c0, 0x4a86, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x4a7d, 0x1078, 0x557a, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x4a6e, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x4a76, 0x6827, 0x0001, 0x037f, 0x0d7f, - 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4a7f, 0x8001, 0x603e, 0x2660, - 0x1078, 0x6aa1, 0x0c7f, 0x0078, 0x4a8e, 0x0d7f, 0x0c7e, 0x2660, - 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x4a45, 0x8dff, 0x0040, - 0x4a9a, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x1078, 0x5902, 0x0078, 0x4a45, 0x067f, 0x0d7f, + 0x0040, 0x4a66, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x4a6e, 0x6827, 0x0001, 0x037f, 0x0d7f, + 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4a77, 0x8001, 0x603e, 0x2660, + 0x1078, 0x6a96, 0x0c7f, 0x0078, 0x4a86, 0x0d7f, 0x0c7e, 0x2660, + 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x4a3d, 0x8dff, 0x0040, + 0x4a92, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x1078, 0x58fa, 0x0078, 0x4a3d, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f, 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, - 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x4afe, - 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x4ae3, - 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x4add, 0x1078, 0x5582, - 0x68c3, 0x0000, 0x1078, 0x5a32, 0x7827, 0x0000, 0x037e, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x4ad2, 0x6803, 0x0100, - 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4ada, - 0x6827, 0x0001, 0x037f, 0x0078, 0x4ae3, 0x6003, 0x0009, 0x630a, - 0x2c30, 0x0078, 0x4afb, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, - 0x4af7, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4b05, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, - 0x6aa1, 0x1078, 0x5902, 0x007f, 0x0078, 0x4aad, 0x7e16, 0x7e12, + 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x4af6, + 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x4adb, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x4ad5, 0x1078, 0x557a, + 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7827, 0x0000, 0x037e, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x4aca, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4ad2, + 0x6827, 0x0001, 0x037f, 0x0078, 0x4adb, 0x6003, 0x0009, 0x630a, + 0x2c30, 0x0078, 0x4af3, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, + 0x4aef, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4afd, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x1078, + 0x6a96, 0x1078, 0x58fa, 0x007f, 0x0078, 0x4aa5, 0x7e16, 0x7e12, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, - 0x00c0, 0x4aee, 0x1078, 0x74fd, 0x0078, 0x4af7, 0x007e, 0x067e, - 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b7a, 0x6054, 0x007e, + 0x00c0, 0x4ae6, 0x1078, 0x74f2, 0x0078, 0x4aef, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b72, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, - 0x1078, 0x37a2, 0x0040, 0x4b77, 0x7e24, 0x86ff, 0x0040, 0x4b69, - 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x4b69, 0x0d7e, 0x2069, - 0x0100, 0x68c0, 0xa005, 0x0040, 0x4b60, 0x1078, 0x5582, 0x68c3, - 0x0000, 0x1078, 0x5a32, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, - 0x6b04, 0xa384, 0x1000, 0x0040, 0x4b49, 0x6803, 0x0100, 0x6803, - 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4b51, 0x6827, - 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4b5a, - 0x8001, 0x603e, 0x2660, 0x1078, 0x6aa1, 0x0c7f, 0x0078, 0x4b69, + 0x1078, 0x379a, 0x0040, 0x4b6f, 0x7e24, 0x86ff, 0x0040, 0x4b61, + 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x4b61, 0x0d7e, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x0040, 0x4b58, 0x1078, 0x557a, 0x68c3, + 0x0000, 0x1078, 0x5a2a, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, + 0x6b04, 0xa384, 0x1000, 0x0040, 0x4b41, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4b49, 0x6827, + 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4b52, + 0x8001, 0x603e, 0x2660, 0x1078, 0x6a96, 0x0c7f, 0x0078, 0x4b61, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, - 0x4b20, 0x8dff, 0x0040, 0x4b73, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x5902, 0x0078, 0x4b20, 0x007f, - 0x0078, 0x4b13, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, + 0x4b18, 0x8dff, 0x0040, 0x4b6b, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x3a72, 0x1078, 0x58fa, 0x0078, 0x4b18, 0x007f, + 0x0078, 0x4b0b, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x0e7e, 0x0c7e, 0x2071, 0x7836, 0x7004, 0xa084, 0x0007, - 0x0079, 0x4b8a, 0x4b94, 0x4b97, 0x4bb0, 0x4bcc, 0x4c11, 0x4b94, - 0x4b94, 0x4b92, 0x1078, 0x12d5, 0x0c7f, 0x0e7f, 0x007c, 0x7024, - 0xa065, 0x0040, 0x4ba5, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, - 0x0040, 0x4bac, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, - 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x4ba5, - 0x6018, 0x2060, 0x1078, 0x37a2, 0x6000, 0xc0dc, 0x6002, 0x7020, - 0x8001, 0x7022, 0x0040, 0x4bc1, 0x6054, 0xa015, 0x0040, 0x4bc8, + 0x0079, 0x4b82, 0x4b8c, 0x4b8f, 0x4ba8, 0x4bc4, 0x4c09, 0x4b8c, + 0x4b8c, 0x4b8a, 0x1078, 0x12cd, 0x0c7f, 0x0e7f, 0x007c, 0x7024, + 0xa065, 0x0040, 0x4b9d, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, + 0x0040, 0x4ba4, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, + 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x4b9d, + 0x6018, 0x2060, 0x1078, 0x379a, 0x6000, 0xc0dc, 0x6002, 0x7020, + 0x8001, 0x7022, 0x0040, 0x4bb9, 0x6054, 0xa015, 0x0040, 0x4bc0, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, - 0x7218, 0x721e, 0x0078, 0x4bc1, 0x7024, 0xa065, 0x0040, 0x4c0e, - 0x700c, 0xac06, 0x00c0, 0x4be3, 0x1078, 0x5902, 0x600c, 0xa015, - 0x0040, 0x4bdf, 0x720e, 0x600f, 0x0000, 0x0078, 0x4c0c, 0x720e, - 0x720a, 0x0078, 0x4c0c, 0x7014, 0xac06, 0x00c0, 0x4bf6, 0x1078, - 0x5902, 0x600c, 0xa015, 0x0040, 0x4bf2, 0x7216, 0x600f, 0x0000, - 0x0078, 0x4c0c, 0x7216, 0x7212, 0x0078, 0x4c0c, 0x6018, 0x2060, - 0x1078, 0x37a2, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x5902, 0x701c, - 0xa065, 0x0040, 0x4c0c, 0x6054, 0xa015, 0x0040, 0x4c0a, 0x721e, - 0x0078, 0x4c0c, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, - 0x007c, 0x7024, 0xa065, 0x0040, 0x4c1e, 0x1078, 0x5902, 0x600c, - 0xa015, 0x0040, 0x4c25, 0x720e, 0x600f, 0x0000, 0x1078, 0x5a32, + 0x7218, 0x721e, 0x0078, 0x4bb9, 0x7024, 0xa065, 0x0040, 0x4c06, + 0x700c, 0xac06, 0x00c0, 0x4bdb, 0x1078, 0x58fa, 0x600c, 0xa015, + 0x0040, 0x4bd7, 0x720e, 0x600f, 0x0000, 0x0078, 0x4c04, 0x720e, + 0x720a, 0x0078, 0x4c04, 0x7014, 0xac06, 0x00c0, 0x4bee, 0x1078, + 0x58fa, 0x600c, 0xa015, 0x0040, 0x4bea, 0x7216, 0x600f, 0x0000, + 0x0078, 0x4c04, 0x7216, 0x7212, 0x0078, 0x4c04, 0x6018, 0x2060, + 0x1078, 0x379a, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x58fa, 0x701c, + 0xa065, 0x0040, 0x4c04, 0x6054, 0xa015, 0x0040, 0x4c02, 0x721e, + 0x0078, 0x4c04, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, + 0x007c, 0x7024, 0xa065, 0x0040, 0x4c16, 0x1078, 0x58fa, 0x600c, + 0xa015, 0x0040, 0x4c1d, 0x720e, 0x600f, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, - 0x4c1e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa084, 0x0003, 0x0079, - 0x4c31, 0x4c37, 0x4c39, 0x4c5f, 0x4c37, 0x1078, 0x12d5, 0x0d7f, - 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x4c55, 0x683c, - 0xa065, 0x0040, 0x4c4a, 0x600c, 0xa015, 0x0040, 0x4c51, 0x6a3a, + 0x4c16, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa084, 0x0003, 0x0079, + 0x4c29, 0x4c2f, 0x4c31, 0x4c57, 0x4c2f, 0x1078, 0x12cd, 0x0d7f, + 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x4c4d, 0x683c, + 0xa065, 0x0040, 0x4c42, 0x600c, 0xa015, 0x0040, 0x4c49, 0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, - 0x007c, 0x683a, 0x6836, 0x0078, 0x4c4a, 0x6843, 0x0000, 0x6838, - 0xa065, 0x0040, 0x4c4a, 0x6003, 0x0003, 0x0078, 0x4c4a, 0x0c7e, - 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x4c77, - 0x600c, 0xa015, 0x0040, 0x4c73, 0x6a3a, 0x600f, 0x0000, 0x683f, - 0x0000, 0x0078, 0x4c77, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, + 0x007c, 0x683a, 0x6836, 0x0078, 0x4c42, 0x6843, 0x0000, 0x6838, + 0xa065, 0x0040, 0x4c42, 0x6003, 0x0003, 0x0078, 0x4c42, 0x0c7e, + 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x4c6f, + 0x600c, 0xa015, 0x0040, 0x4c6b, 0x6a3a, 0x600f, 0x0000, 0x683f, + 0x0000, 0x0078, 0x4c6f, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f, 0x007c, 0x0d7e, 0x2069, 0x7836, 0x6804, 0xa084, 0x0007, - 0x0079, 0x4c82, 0x4c8c, 0x4d29, 0x4d29, 0x4d29, 0x4d29, 0x4d2b, - 0x4d29, 0x4c8a, 0x1078, 0x12d5, 0x6820, 0xa005, 0x00c0, 0x4c92, - 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4ca1, 0x6807, - 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, 0x0d7f, - 0x007c, 0x6814, 0xa065, 0x0040, 0x4caf, 0x6807, 0x0001, 0x6826, - 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, - 0x037e, 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x4d24, 0x704c, 0xa00d, - 0x0040, 0x4cbe, 0x7088, 0xa005, 0x0040, 0x4cd6, 0x7054, 0xa075, - 0x0040, 0x4cc7, 0xa20e, 0x0040, 0x4d24, 0x0078, 0x4ccc, 0x6818, - 0xa20e, 0x0040, 0x4d24, 0x2070, 0x704c, 0xa00d, 0x0040, 0x4cbe, - 0x7088, 0xa005, 0x00c0, 0x4cbe, 0x2e00, 0x681e, 0x733c, 0x7038, - 0xa302, 0x00c8, 0x4cbe, 0x1078, 0x5bd1, 0x0040, 0x4d24, 0x8318, + 0x0079, 0x4c7a, 0x4c84, 0x4d21, 0x4d21, 0x4d21, 0x4d21, 0x4d23, + 0x4d21, 0x4c82, 0x1078, 0x12cd, 0x6820, 0xa005, 0x00c0, 0x4c8a, + 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4c99, 0x6807, + 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, + 0x007c, 0x6814, 0xa065, 0x0040, 0x4ca7, 0x6807, 0x0001, 0x6826, + 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, + 0x037e, 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x4d1c, 0x704c, 0xa00d, + 0x0040, 0x4cb6, 0x7088, 0xa005, 0x0040, 0x4cce, 0x7054, 0xa075, + 0x0040, 0x4cbf, 0xa20e, 0x0040, 0x4d1c, 0x0078, 0x4cc4, 0x6818, + 0xa20e, 0x0040, 0x4d1c, 0x2070, 0x704c, 0xa00d, 0x0040, 0x4cb6, + 0x7088, 0xa005, 0x00c0, 0x4cb6, 0x2e00, 0x681e, 0x733c, 0x7038, + 0xa302, 0x00c8, 0x4cb6, 0x1078, 0x5bc9, 0x0040, 0x4d1c, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0015, 0x2004, 0xa08a, - 0x199a, 0x0048, 0x4ced, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, + 0x199a, 0x0048, 0x4ce5, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, 0x0040, - 0x4d06, 0x7100, 0xd1f4, 0x0040, 0x4d02, 0x7114, 0xa18c, 0x00ff, - 0x0078, 0x4d0b, 0x2009, 0x0000, 0x0078, 0x4d0b, 0xa1e0, 0x232f, - 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x51c2, + 0x4cfe, 0x7100, 0xd1f4, 0x0040, 0x4cfa, 0x7114, 0xa18c, 0x00ff, + 0x0078, 0x4d03, 0x2009, 0x0000, 0x0078, 0x4d03, 0xa1e0, 0x2329, + 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x51ba, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, 0x0078, - 0x4d22, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4d37, - 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, + 0x4d1a, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4d2f, + 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa086, - 0x0000, 0x00c0, 0x4d58, 0x6838, 0xa07d, 0x0040, 0x4d58, 0x6833, + 0x0000, 0x00c0, 0x4d50, 0x6838, 0xa07d, 0x0040, 0x4d50, 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, 0x2200, - 0x027f, 0x1078, 0x1a4c, 0x00c0, 0x4d5b, 0x127f, 0x1078, 0x5457, + 0x027f, 0x1078, 0x1a44, 0x00c0, 0x4d53, 0x127f, 0x1078, 0x544f, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803, 0x0002, - 0x780c, 0xa015, 0x0040, 0x4d6d, 0x6a3a, 0x780f, 0x0000, 0x6833, - 0x0000, 0x683f, 0x0000, 0x0078, 0x4d58, 0x683a, 0x6836, 0x0078, - 0x4d67, 0x601c, 0xa084, 0x000f, 0x1079, 0x4d77, 0x007c, 0x4d80, - 0x4d85, 0x508c, 0x5182, 0x4d85, 0x508c, 0x5182, 0x4d80, 0x4d85, - 0x1078, 0x4b81, 0x1078, 0x4c7a, 0x007c, 0x157e, 0x137e, 0x147e, - 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, 0x6118, - 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x4da2, 0x7900, 0xd1f4, 0x0040, - 0x4d9e, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x4da7, 0x2009, 0x0000, - 0x0078, 0x4da7, 0xa1f8, 0x232f, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, - 0x2061, 0x0100, 0x619a, 0x1079, 0x4db3, 0x0f7f, 0x0c7f, 0x147f, - 0x137f, 0x157f, 0x007c, 0x4de5, 0x4e1d, 0x4e35, 0x4eb4, 0x4ee1, - 0x4ee9, 0x4f0a, 0x4f1b, 0x4f2c, 0x4f34, 0x4f45, 0x4f34, 0x4f8d, - 0x4f1b, 0x4fae, 0x4fb6, 0x4f2c, 0x4fb6, 0x4fc7, 0x4de3, 0x4de3, - 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, - 0x4de3, 0x4de3, 0x5640, 0x5655, 0x5678, 0x569c, 0x4f0a, 0x4de3, - 0x4f0a, 0x4f34, 0x4de3, 0x4e35, 0x4eb4, 0x4de3, 0x5b4c, 0x4f34, - 0x4de3, 0x5b6f, 0x4f34, 0x1078, 0x12d5, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x0d7e, 0x2069, 0x7651, - 0x6804, 0xd084, 0x0040, 0x4dff, 0x6828, 0x20a3, 0x0000, 0x017e, - 0x1078, 0x209a, 0x21a2, 0x017f, 0x0d7f, 0x0078, 0x4e04, 0x0d7f, + 0x780c, 0xa015, 0x0040, 0x4d65, 0x6a3a, 0x780f, 0x0000, 0x6833, + 0x0000, 0x683f, 0x0000, 0x0078, 0x4d50, 0x683a, 0x6836, 0x0078, + 0x4d5f, 0x601c, 0xa084, 0x000f, 0x1079, 0x4d6f, 0x007c, 0x4d78, + 0x4d7d, 0x5084, 0x517a, 0x4d7d, 0x5084, 0x517a, 0x4d78, 0x4d7d, + 0x1078, 0x4b79, 0x1078, 0x4c72, 0x007c, 0x157e, 0x137e, 0x147e, + 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x6118, + 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x4d9a, 0x7900, 0xd1f4, 0x0040, + 0x4d96, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x4d9f, 0x2009, 0x0000, + 0x0078, 0x4d9f, 0xa1f8, 0x2329, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, + 0x2061, 0x0100, 0x619a, 0x1079, 0x4dab, 0x0f7f, 0x0c7f, 0x147f, + 0x137f, 0x157f, 0x007c, 0x4ddd, 0x4e15, 0x4e2d, 0x4eac, 0x4ed9, + 0x4ee1, 0x4f02, 0x4f13, 0x4f24, 0x4f2c, 0x4f3d, 0x4f2c, 0x4f85, + 0x4f13, 0x4fa6, 0x4fae, 0x4f24, 0x4fae, 0x4fbf, 0x4ddb, 0x4ddb, + 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, + 0x4ddb, 0x4ddb, 0x5638, 0x564d, 0x5670, 0x5694, 0x4f02, 0x4ddb, + 0x4f02, 0x4f2c, 0x4ddb, 0x4e2d, 0x4eac, 0x4ddb, 0x5b44, 0x4f2c, + 0x4ddb, 0x5b67, 0x4f2c, 0x1078, 0x12cd, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x0d7e, 0x2069, 0x7651, + 0x6804, 0xd084, 0x0040, 0x4df7, 0x6828, 0x20a3, 0x0000, 0x017e, + 0x1078, 0x2094, 0x21a2, 0x017f, 0x0d7f, 0x0078, 0x4dfc, 0x0d7f, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x7601, 0x53a6, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x001c, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6030, + 0x60c3, 0x001c, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, - 0x60c3, 0x0010, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, - 0x4e48, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0078, 0x4e4a, + 0x60c3, 0x0010, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, + 0x4e40, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0078, 0x4e42, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, - 0xa086, 0x007e, 0x00c0, 0x4e83, 0x2099, 0x7820, 0x33a6, 0x9398, + 0xa086, 0x007e, 0x00c0, 0x4e7b, 0x2099, 0x7820, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0x7601, 0x53a6, 0x20a9, 0x0010, 0x20a3, 0x0000, 0x00f0, 0x4e74, + 0x7601, 0x53a6, 0x20a9, 0x0010, 0x20a3, 0x0000, 0x00f0, 0x4e6c, 0x2099, 0x7828, 0x33a6, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, - 0x4e7d, 0x0078, 0x4ea3, 0x2099, 0x7820, 0x20a9, 0x0008, 0x53a6, + 0x4e75, 0x0078, 0x4e9b, 0x2099, 0x7820, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0x7601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e94, - 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e9a, 0x2099, 0x7828, + 0x7601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e8c, + 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e92, 0x2099, 0x7828, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, - 0x4ea5, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4eab, 0x60c3, - 0x0074, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, + 0x4e9d, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4ea3, 0x60c3, + 0x0074, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, - 0x7651, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x4ed0, 0xa085, 0x0020, - 0xd1a4, 0x0040, 0x4ed5, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x556e, - 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x5000, 0x0078, - 0x4e4a, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x2110, 0x20a3, + 0x7651, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x4ec8, 0xa085, 0x0020, + 0xd1a4, 0x0040, 0x4ecd, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x5566, + 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x5000, 0x0078, + 0x4e42, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, - 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, 0x0200, + 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, - 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, + 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, - 0x0008, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, - 0x20a3, 0x0200, 0x0078, 0x4e4a, 0x20a1, 0x020b, 0x1078, 0x5053, + 0x0008, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, + 0x20a3, 0x0200, 0x0078, 0x4e42, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x7810, 0x20a2, - 0x60c3, 0x0008, 0x1078, 0x556e, 0x007c, 0x0d7e, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, - 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x4f6b, 0x6998, - 0xa184, 0xc000, 0x00c0, 0x4f67, 0xd1ec, 0x0040, 0x4f63, 0x20a3, - 0x2100, 0x0078, 0x4f6d, 0x20a3, 0x0100, 0x0078, 0x4f6d, 0x20a3, - 0x0400, 0x0078, 0x4f6d, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, + 0x60c3, 0x0008, 0x1078, 0x5566, 0x007c, 0x0d7e, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, + 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x4f63, 0x6998, + 0xa184, 0xc000, 0x00c0, 0x4f5f, 0xd1ec, 0x0040, 0x4f5b, 0x20a3, + 0x2100, 0x0078, 0x4f65, 0x20a3, 0x0100, 0x0078, 0x4f65, 0x20a3, + 0x0400, 0x0078, 0x4f65, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0x7651, 0x7904, 0x0f7f, - 0xd1ac, 0x00c0, 0x4f7d, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f82, + 0xd1ac, 0x00c0, 0x4f75, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f7a, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, 0x60c3, - 0x0014, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, + 0x0014, 0x1078, 0x5566, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0014, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0200, 0x0078, 0x4deb, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, - 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x556e, 0x007c, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0200, 0x0078, 0x4de3, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, + 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x5566, 0x007c, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, - 0x0008, 0x1078, 0x556e, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, + 0x0008, 0x1078, 0x5566, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, - 0x4fef, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x0078, 0x501d, 0xa286, - 0x007f, 0x00c0, 0x4ffa, 0x0d7e, 0x20a3, 0x22ff, 0x20a3, 0xfffd, - 0x0078, 0x5011, 0xd2bc, 0x0040, 0x5019, 0xa286, 0x0080, 0x0d7e, - 0x00c0, 0x5008, 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0078, 0x5011, + 0x4fe7, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x0078, 0x5015, 0xa286, + 0x007f, 0x00c0, 0x4ff2, 0x0d7e, 0x20a3, 0x22ff, 0x20a3, 0xfffd, + 0x0078, 0x5009, 0xd2bc, 0x0040, 0x5011, 0xa286, 0x0080, 0x0d7e, + 0x00c0, 0x5000, 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0078, 0x5009, 0xa2e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x2200, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, - 0x5021, 0x20a3, 0x2200, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, - 0x22a2, 0x20a3, 0x0129, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, + 0x5019, 0x20a3, 0x2200, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, + 0x22a2, 0x20a3, 0x0129, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2, 0x0d7e, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x20a3, 0x2029, 0x20a3, 0x0000, - 0x0078, 0x5025, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, + 0x0078, 0x501d, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5072, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x506a, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x2300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x507a, 0x20a3, 0x2300, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0198, 0x20a3, 0x0000, 0x1078, 0x555d, + 0x0078, 0x5072, 0x20a3, 0x2300, 0x6298, 0x22a2, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0198, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, - 0x0085, 0x1048, 0x12d5, 0xa08a, 0x008c, 0x10c8, 0x12d5, 0x6118, - 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x50aa, 0x7900, 0xd1f4, 0x0040, - 0x50a6, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x50af, 0x2009, 0x0000, - 0x0078, 0x50af, 0xa1f8, 0x232f, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, - 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x1079, 0x50ba, 0x0f7f, - 0x0c7f, 0x007c, 0x50c3, 0x50ce, 0x50e8, 0x50c1, 0x50c1, 0x50c1, - 0x50c3, 0x1078, 0x12d5, 0x147e, 0x20a1, 0x020b, 0x1078, 0x50fb, - 0x60c3, 0x0000, 0x1078, 0x556e, 0x147f, 0x007c, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5128, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x0085, 0x1048, 0x12cd, 0xa08a, 0x008c, 0x10c8, 0x12cd, 0x6118, + 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x50a2, 0x7900, 0xd1f4, 0x0040, + 0x509e, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x50a7, 0x2009, 0x0000, + 0x0078, 0x50a7, 0xa1f8, 0x2329, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, + 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x1079, 0x50b2, 0x0f7f, + 0x0c7f, 0x007c, 0x50bb, 0x50c6, 0x50e0, 0x50b9, 0x50b9, 0x50b9, + 0x50bb, 0x1078, 0x12cd, 0x147e, 0x20a1, 0x020b, 0x1078, 0x50f3, + 0x60c3, 0x0000, 0x1078, 0x5566, 0x147f, 0x007c, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x5120, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x007c, - 0x147e, 0x20a1, 0x020b, 0x1078, 0x5155, 0x20a3, 0x0003, 0x20a3, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x5566, 0x147f, 0x007c, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x514d, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x1078, - 0x556e, 0x147f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x511a, + 0x5566, 0x147f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5112, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x5122, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0078, 0x5025, + 0x0078, 0x511a, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0078, 0x501d, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xa092, 0x007e, 0x0048, 0x5147, 0x0d7e, 0xa0e8, 0x7720, + 0x2004, 0xa092, 0x007e, 0x0048, 0x513f, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, - 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x514f, 0x20a3, + 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5147, 0x20a3, 0x8400, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, - 0x00d1, 0x20a3, 0x0000, 0x0078, 0x507e, 0x027e, 0x20e1, 0x9080, + 0x00d1, 0x20a3, 0x0000, 0x0078, 0x5076, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, - 0x0048, 0x5174, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0048, 0x516c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x517c, 0x20a3, 0x8500, 0x6298, 0x22a2, + 0x2da6, 0x0d7f, 0x0078, 0x5174, 0x20a3, 0x8500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x00d1, 0x20a3, 0x0000, - 0x0078, 0x507e, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, - 0x1048, 0x12d5, 0xa08a, 0x0050, 0x10c8, 0x12d5, 0x7918, 0x2160, - 0x61a0, 0xd1bc, 0x0040, 0x51a1, 0x6100, 0xd1f4, 0x0040, 0x519d, - 0x6114, 0xa18c, 0x00ff, 0x0078, 0x51a6, 0x2009, 0x0000, 0x0078, - 0x51a6, 0xa1e0, 0x232f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, - 0x619a, 0xa082, 0x0040, 0x1079, 0x51b0, 0x0f7f, 0x0c7f, 0x007c, - 0x51c2, 0x52aa, 0x5252, 0x53d2, 0x51c0, 0x51c0, 0x51c0, 0x51c0, - 0x51c0, 0x51c0, 0x51c0, 0x581b, 0x582c, 0x583d, 0x584e, 0x51c0, - 0x1078, 0x12d5, 0x0d7e, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x5215, 0x7910, 0x2168, 0x6944, 0xa18c, 0x00ff, 0x21a2, 0xa016, + 0x0078, 0x5076, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, + 0x1048, 0x12cd, 0xa08a, 0x0050, 0x10c8, 0x12cd, 0x7918, 0x2160, + 0x61a0, 0xd1bc, 0x0040, 0x5199, 0x6100, 0xd1f4, 0x0040, 0x5195, + 0x6114, 0xa18c, 0x00ff, 0x0078, 0x519e, 0x2009, 0x0000, 0x0078, + 0x519e, 0xa1e0, 0x2329, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, + 0x619a, 0xa082, 0x0040, 0x1079, 0x51a8, 0x0f7f, 0x0c7f, 0x007c, + 0x51ba, 0x52a2, 0x524a, 0x53ca, 0x51b8, 0x51b8, 0x51b8, 0x51b8, + 0x51b8, 0x51b8, 0x51b8, 0x5813, 0x5824, 0x5835, 0x5846, 0x51b8, + 0x1078, 0x12cd, 0x0d7e, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, + 0x520d, 0x7910, 0x2168, 0x6944, 0xa18c, 0x00ff, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x0006, 0x8004, 0x20a2, - 0xd1ac, 0x0040, 0x51df, 0x20a3, 0x0002, 0x0078, 0x51eb, 0xd1b4, - 0x0040, 0x51e6, 0x20a3, 0x0001, 0x0078, 0x51eb, 0x20a3, 0x0000, - 0x2230, 0x0078, 0x51ed, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0xad80, - 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x51f1, 0x22a2, + 0xd1ac, 0x0040, 0x51d7, 0x20a3, 0x0002, 0x0078, 0x51e3, 0xd1b4, + 0x0040, 0x51de, 0x20a3, 0x0001, 0x0078, 0x51e3, 0x20a3, 0x0000, + 0x2230, 0x0078, 0x51e5, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0xad80, + 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x51e9, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0x7852, 0x2003, 0x07d0, 0x2001, 0x7851, 0x2003, 0x0009, 0x2001, 0x7857, 0x2003, 0x0002, 0x1078, - 0x1504, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x20e1, + 0x14fc, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, - 0x523b, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, + 0x5233, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, - 0x0d7f, 0x0078, 0x5243, 0x20a3, 0x0600, 0x6198, 0x21a2, 0x20a3, + 0x0d7f, 0x0078, 0x523b, 0x20a3, 0x0600, 0x6198, 0x21a2, 0x20a3, 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x5272, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, + 0x1078, 0x526a, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x137f, 0x157f, + 0x20a2, 0x60c3, 0x000c, 0x1078, 0x5566, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5290, 0x0d7e, 0xa0e8, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5288, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5298, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5290, 0x20a3, 0x0500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, - 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, 0x20a3, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x539a, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x00c0, 0x52c7, 0x7810, - 0xa084, 0x0700, 0x8007, 0x1079, 0x52cf, 0x0078, 0x52ca, 0xa006, - 0x1079, 0x52cf, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x52d9, - 0x533b, 0x533f, 0x5362, 0x536f, 0x5381, 0x5385, 0x52d7, 0x1078, - 0x12d5, 0x017e, 0x037e, 0x694c, 0xa18c, 0x0003, 0xa186, 0x0000, - 0x00c0, 0x52ec, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, - 0x037f, 0x017f, 0x0078, 0x5366, 0xa186, 0x0001, 0x00c0, 0x5336, + 0x1078, 0x5392, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x00c0, 0x52bf, 0x7810, + 0xa084, 0x0700, 0x8007, 0x1079, 0x52c7, 0x0078, 0x52c2, 0xa006, + 0x1079, 0x52c7, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x52d1, + 0x5333, 0x5337, 0x535a, 0x5367, 0x5379, 0x537d, 0x52cf, 0x1078, + 0x12cd, 0x017e, 0x037e, 0x694c, 0xa18c, 0x0003, 0xa186, 0x0000, + 0x00c0, 0x52e4, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, + 0x037f, 0x017f, 0x0078, 0x535e, 0xa186, 0x0001, 0x00c0, 0x532e, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, - 0x0040, 0x5335, 0xd3c4, 0x0040, 0x5307, 0x687c, 0xa108, 0xd3cc, - 0x0040, 0x530c, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, - 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x5311, 0x157f, - 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x5335, 0x20a1, + 0x0040, 0x532d, 0xd3c4, 0x0040, 0x52ff, 0x687c, 0xa108, 0xd3cc, + 0x0040, 0x5304, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, + 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x5309, 0x157f, + 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x532d, 0x20a1, 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0898, 0x20a2, - 0x1078, 0x555d, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, 0x017f, - 0x1078, 0x556e, 0x007c, 0x20a3, 0x0008, 0x0078, 0x5364, 0x20a3, + 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, 0x017f, + 0x1078, 0x5566, 0x007c, 0x20a3, 0x0008, 0x0078, 0x535c, 0x20a3, 0x0302, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x1078, - 0x556e, 0x007c, 0x20a3, 0x0028, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x556e, 0x007c, 0x20a3, + 0x5566, 0x007c, 0x20a3, 0x0028, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x5566, 0x007c, 0x20a3, 0x0100, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x556e, - 0x007c, 0x20a3, 0x0008, 0x0078, 0x5364, 0x037e, 0x7b10, 0xa384, - 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x5393, 0x22a2, - 0x037f, 0x0078, 0x5364, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x037f, - 0x0078, 0x5366, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x53b8, 0x0d7e, 0xa0e8, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x5566, + 0x007c, 0x20a3, 0x0008, 0x0078, 0x535c, 0x037e, 0x7b10, 0xa384, + 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x538b, 0x22a2, + 0x037f, 0x0078, 0x535c, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x037f, + 0x0078, 0x535e, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x53b0, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53c0, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53b8, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, - 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, 0x20a3, + 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, - 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x53e5, 0x037f, 0x017f, - 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x53ed, 0x53ed, 0x53ef, - 0x53ed, 0x53ed, 0x53ed, 0x5414, 0x53ed, 0x1078, 0x12d5, 0x7910, + 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x53dd, 0x037f, 0x017f, + 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x53e5, 0x53e5, 0x53e7, + 0x53e5, 0x53e5, 0x53e5, 0x540c, 0x53e5, 0x1078, 0x12cd, 0x7910, 0xa18c, 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, - 0x0003, 0x1078, 0x541e, 0x0d7e, 0x2069, 0x7651, 0x6804, 0xd0bc, - 0x0040, 0x5409, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, - 0x540b, 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, - 0x0001, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, - 0x1078, 0x541e, 0x20a3, 0x7f00, 0x0078, 0x540c, 0x027e, 0x20e1, + 0x0003, 0x1078, 0x5416, 0x0d7e, 0x2069, 0x7651, 0x6804, 0xd0bc, + 0x0040, 0x5401, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, + 0x5403, 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, + 0x0001, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, + 0x1078, 0x5416, 0x20a3, 0x7f00, 0x0078, 0x5404, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, - 0x0040, 0x543c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0040, 0x5434, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x5444, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x2da6, 0x0d7f, 0x0078, 0x543c, 0x20a3, 0x0100, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, - 0x21a2, 0x1078, 0x555d, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x21a2, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0x7600, 0x6130, 0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, - 0x5470, 0xa080, 0x232f, 0x2014, 0xa294, 0x00ff, 0x0078, 0x5474, + 0x5468, 0xa080, 0x2329, 0x2014, 0xa294, 0x00ff, 0x0078, 0x546c, 0x6910, 0x6a14, 0x7364, 0x7468, 0x781c, 0xa086, 0x0006, 0x0040, - 0x54c8, 0xd5bc, 0x0040, 0x5484, 0xa185, 0x0100, 0x6062, 0x6266, - 0x636a, 0x646e, 0x0078, 0x548a, 0x6063, 0x0100, 0x6266, 0x606b, + 0x54c0, 0xd5bc, 0x0040, 0x547c, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x5482, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, - 0x54bc, 0x6a00, 0xd2f4, 0x0040, 0x54ba, 0x6a14, 0xa294, 0x00ff, - 0x0078, 0x54bc, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, - 0x45f0, 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0x54b4, 0x6a00, 0xd2f4, 0x0040, 0x54b2, 0x6a14, 0xa294, 0x00ff, + 0x0078, 0x54b4, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, + 0x45e8, 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, - 0x5517, 0xd5bc, 0x0040, 0x54dc, 0xa185, 0x0100, 0x6062, 0x6266, - 0x636a, 0x646e, 0x0078, 0x54e2, 0x6063, 0x0100, 0x6266, 0x606b, + 0x550f, 0xd5bc, 0x0040, 0x54d4, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x54da, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, - 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x5512, 0x6a00, - 0xd2f4, 0x0040, 0x5510, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5512, - 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x54bf, 0xd5bc, - 0x0040, 0x5522, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, - 0x0078, 0x5528, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, + 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x550a, 0x6a00, + 0xd2f4, 0x0040, 0x5508, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x550a, + 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x54b7, 0xd5bc, + 0x0040, 0x551a, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, + 0x0078, 0x5520, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, - 0x0000, 0xa582, 0x0080, 0x0048, 0x5558, 0x6a00, 0xd2f4, 0x0040, - 0x5556, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5558, 0x2011, 0x0000, - 0x629e, 0x6017, 0x0016, 0x0078, 0x54bf, 0x7a18, 0xa280, 0x0023, + 0x0000, 0xa582, 0x0080, 0x0048, 0x5550, 0x6a00, 0xd2f4, 0x0040, + 0x554e, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5550, 0x2011, 0x0000, + 0x629e, 0x6017, 0x0016, 0x0078, 0x54b7, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, 0x7836, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, - 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5579, 0x1078, 0x45e0, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5571, 0x1078, 0x45d8, 0x007c, 0x007e, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, 0x007c, 0x007e, 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, - 0x0d7e, 0x017e, 0x027e, 0x1078, 0x45eb, 0x2061, 0x0100, 0x2069, - 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55cc, 0x1078, 0x5582, + 0x0d7e, 0x017e, 0x027e, 0x1078, 0x45e3, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55c4, 0x1078, 0x557a, 0x6803, 0x1000, 0x6803, 0x0000, 0x0c7e, 0x2061, 0x7836, 0x6128, - 0xa192, 0x0002, 0x00c8, 0x55b9, 0x8108, 0x612a, 0x6124, 0x0c7f, - 0x81ff, 0x0040, 0x55c7, 0x1078, 0x45e0, 0x1078, 0x5579, 0x0078, - 0x55c7, 0x6124, 0xa1e5, 0x0000, 0x0040, 0x55c4, 0x1078, 0x75c7, - 0x2009, 0x0014, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x55c7, 0x027f, - 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x1078, 0x357b, 0x0078, 0x55c7, - 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x45f9, 0x2071, - 0x7836, 0x713c, 0x81ff, 0x0040, 0x55fa, 0x2061, 0x0100, 0x2069, - 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x5600, 0x6803, 0x1000, - 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x5768, 0x037f, - 0x713c, 0x2160, 0x1078, 0x75c7, 0x2009, 0x004a, 0x1078, 0x5c29, - 0x0078, 0x55fa, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, - 0x7144, 0xa192, 0x0002, 0x00c8, 0x55ea, 0x8108, 0x7146, 0x1078, - 0x45f0, 0x0078, 0x55fa, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, + 0xa192, 0x0002, 0x00c8, 0x55b1, 0x8108, 0x612a, 0x6124, 0x0c7f, + 0x81ff, 0x0040, 0x55bf, 0x1078, 0x45d8, 0x1078, 0x5571, 0x0078, + 0x55bf, 0x6124, 0xa1e5, 0x0000, 0x0040, 0x55bc, 0x1078, 0x75bc, + 0x2009, 0x0014, 0x1078, 0x5c21, 0x0c7f, 0x0078, 0x55bf, 0x027f, + 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x1078, 0x3573, 0x0078, 0x55bf, + 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x45f1, 0x2071, + 0x7836, 0x713c, 0x81ff, 0x0040, 0x55f2, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55f8, 0x6803, 0x1000, + 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x5760, 0x037f, + 0x713c, 0x2160, 0x1078, 0x75bc, 0x2009, 0x004a, 0x1078, 0x5c21, + 0x0078, 0x55f2, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, + 0x7144, 0xa192, 0x0002, 0x00c8, 0x55e2, 0x8108, 0x7146, 0x1078, + 0x45e8, 0x0078, 0x55f2, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, - 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x5637, 0x68a0, - 0xa406, 0x0040, 0x5627, 0x6854, 0x2068, 0x0078, 0x561c, 0x6010, + 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x562f, 0x68a0, + 0xa406, 0x0040, 0x561f, 0x6854, 0x2068, 0x0078, 0x5614, 0x6010, 0x2060, 0x643c, 0x6540, 0x6644, 0xa6b4, 0x000f, 0x2d60, 0x1078, - 0x38f9, 0x0040, 0x5637, 0x1078, 0x5902, 0xa085, 0x0001, 0x127f, + 0x38f1, 0x0040, 0x562f, 0x1078, 0x58fa, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, - 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x0f00, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, - 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5053, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a9, + 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a9, 0x0006, 0x2011, 0x7640, 0x2019, 0x7641, 0x23a6, 0x22a6, 0xa398, - 0x0002, 0xa290, 0x0002, 0x00f0, 0x5665, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x001c, 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, - 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x5033, - 0x1078, 0x504a, 0x7810, 0x007e, 0xa080, 0x0015, 0x2098, 0x7808, + 0x0002, 0xa290, 0x0002, 0x00f0, 0x565d, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x001c, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, + 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x502b, + 0x1078, 0x5042, 0x7810, 0x007e, 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, - 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x556e, 0x027f, + 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x5566, 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x4fdc, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x556e, 0x147f, 0x157f, + 0x1078, 0x4fd4, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x7836, 0x700c, 0x2060, 0x8cff, 0x0040, 0x56cd, 0x1078, 0x6ace, - 0x00c0, 0x56c4, 0x1078, 0x5e57, 0x600c, 0x007e, 0x1078, 0x5c02, - 0x1078, 0x5902, 0x0c7f, 0x0078, 0x56bb, 0x700f, 0x0000, 0x700b, + 0x7836, 0x700c, 0x2060, 0x8cff, 0x0040, 0x56c5, 0x1078, 0x6ac3, + 0x00c0, 0x56bc, 0x1078, 0x5e4d, 0x600c, 0x007e, 0x1078, 0x5bfa, + 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x56b3, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x7836, 0x7024, - 0x2060, 0x8cff, 0x0040, 0x5726, 0x1078, 0x5582, 0x68c3, 0x0000, - 0x1078, 0x45eb, 0x2009, 0x0013, 0x1078, 0x5c29, 0x20a9, 0x01f4, - 0x6824, 0xd094, 0x0040, 0x5709, 0x6827, 0x0004, 0x7804, 0xa084, - 0x4000, 0x0040, 0x571b, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, - 0x571b, 0xd084, 0x0040, 0x5710, 0x6827, 0x0001, 0x0078, 0x5712, - 0x00f0, 0x56f8, 0x7804, 0xa084, 0x1000, 0x0040, 0x571b, 0x7803, + 0x2060, 0x8cff, 0x0040, 0x571e, 0x1078, 0x557a, 0x68c3, 0x0000, + 0x1078, 0x45e3, 0x2009, 0x0013, 0x1078, 0x5c21, 0x20a9, 0x01f4, + 0x6824, 0xd094, 0x0040, 0x5701, 0x6827, 0x0004, 0x7804, 0xa084, + 0x4000, 0x0040, 0x5713, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0x5713, 0xd084, 0x0040, 0x5708, 0x6827, 0x0001, 0x0078, 0x570a, + 0x00f0, 0x56f0, 0x7804, 0xa084, 0x1000, 0x0040, 0x5713, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x2001, 0x7600, - 0x2004, 0xa096, 0x0001, 0x0040, 0x575e, 0xa096, 0x0004, 0x0040, - 0x575e, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x3542, 0x1078, - 0x456e, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x574c, 0x6827, - 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x575e, 0x7803, 0x1000, - 0x7803, 0x0000, 0x0078, 0x575e, 0xd084, 0x0040, 0x5753, 0x6827, - 0x0001, 0x0078, 0x5755, 0x00f0, 0x573b, 0x7804, 0xa084, 0x1000, - 0x0040, 0x575e, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f, + 0x2004, 0xa096, 0x0001, 0x0040, 0x5756, 0xa096, 0x0004, 0x0040, + 0x5756, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x353a, 0x1078, + 0x4566, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x5744, 0x6827, + 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x5756, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0x5756, 0xd084, 0x0040, 0x574b, 0x6827, + 0x0001, 0x0078, 0x574d, 0x00f0, 0x5733, 0x7804, 0xa084, 0x1000, + 0x0040, 0x5756, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, - 0x7836, 0x703c, 0x2060, 0x8cff, 0x0040, 0x57b6, 0x6817, 0x0010, - 0x68cb, 0x0000, 0x68c7, 0x0000, 0x1078, 0x45f9, 0x1078, 0x1c19, - 0xa39d, 0x0000, 0x00c0, 0x5790, 0x2009, 0x0049, 0x1078, 0x5c29, - 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x57a3, 0x6827, 0x0004, - 0x7804, 0xa084, 0x4000, 0x0040, 0x57b5, 0x7803, 0x1000, 0x7803, - 0x0000, 0x0078, 0x57b5, 0xd094, 0x0040, 0x57aa, 0x6827, 0x0002, - 0x0078, 0x57ac, 0x00f0, 0x5792, 0x7804, 0xa084, 0x1000, 0x0040, - 0x57b5, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, + 0x7836, 0x703c, 0x2060, 0x8cff, 0x0040, 0x57ae, 0x6817, 0x0010, + 0x68cb, 0x0000, 0x68c7, 0x0000, 0x1078, 0x45f1, 0x1078, 0x1c13, + 0xa39d, 0x0000, 0x00c0, 0x5788, 0x2009, 0x0049, 0x1078, 0x5c21, + 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x579b, 0x6827, 0x0004, + 0x7804, 0xa084, 0x4000, 0x0040, 0x57ad, 0x7803, 0x1000, 0x7803, + 0x0000, 0x0078, 0x57ad, 0xd094, 0x0040, 0x57a2, 0x6827, 0x0002, + 0x0078, 0x57a4, 0x00f0, 0x578a, 0x7804, 0xa084, 0x1000, 0x0040, + 0x57ad, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0x7836, 0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0x7836, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0x7836, 0x7614, 0x2660, 0x2678, 0x2091, - 0x8000, 0x8cff, 0x0040, 0x5814, 0x601c, 0xa206, 0x00c0, 0x580f, - 0x7014, 0xac36, 0x00c0, 0x57ee, 0x660c, 0x7616, 0x7010, 0xac36, - 0x00c0, 0x57fc, 0x2c00, 0xaf36, 0x0040, 0x57fa, 0x2f00, 0x7012, - 0x0078, 0x57fc, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, - 0x0040, 0x5805, 0x7e0e, 0x0078, 0x5806, 0x2678, 0x600f, 0x0000, - 0x1078, 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, 0x57e1, 0x2c78, - 0x600c, 0x2060, 0x0078, 0x57e1, 0x127f, 0x007f, 0x067f, 0x0c7f, + 0x8000, 0x8cff, 0x0040, 0x580c, 0x601c, 0xa206, 0x00c0, 0x5807, + 0x7014, 0xac36, 0x00c0, 0x57e6, 0x660c, 0x7616, 0x7010, 0xac36, + 0x00c0, 0x57f4, 0x2c00, 0xaf36, 0x0040, 0x57f2, 0x2f00, 0x7012, + 0x0078, 0x57f4, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, + 0x0040, 0x57fd, 0x7e0e, 0x0078, 0x57fe, 0x2678, 0x600f, 0x0000, + 0x1078, 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x57d9, 0x2c78, + 0x600c, 0x2060, 0x0078, 0x57d9, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, - 0x20a3, 0x4000, 0x0078, 0x585d, 0x157e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x20a3, 0x2000, 0x0078, 0x585d, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x585d, 0x157e, 0x147e, - 0x20a1, 0x020b, 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x590d, 0x60c3, - 0x0020, 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x127e, 0x0c7e, - 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0, 0x5875, - 0xd1bc, 0x00c0, 0x58bf, 0x0078, 0x58ff, 0x2009, 0x017f, 0x200b, + 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a3, 0x4000, 0x0078, 0x5855, 0x157e, 0x147e, 0x20a1, 0x020b, + 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x2000, 0x0078, 0x5855, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x5855, 0x157e, 0x147e, + 0x20a1, 0x020b, 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x5905, 0x60c3, + 0x0020, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x127e, 0x0c7e, + 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0, 0x586d, + 0xd1bc, 0x00c0, 0x58b7, 0x0078, 0x58f7, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, - 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x58b6, 0x6020, - 0xd0b4, 0x0040, 0x58b6, 0x6024, 0xd094, 0x00c0, 0x58b6, 0x2104, - 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x58b6, 0x00f0, 0x5882, + 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x58ae, 0x6020, + 0xd0b4, 0x0040, 0x58ae, 0x6024, 0xd094, 0x00c0, 0x58ae, 0x2104, + 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x58ae, 0x00f0, 0x587a, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, 0xbc91, 0x6043, 0x0001, - 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0, 0x58b5, - 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58ac, 0x027f, 0x0d7f, 0x007f, - 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x58ff, 0x2009, + 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0, 0x58ad, + 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58a4, 0x027f, 0x0d7f, 0x007f, + 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x58f7, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, - 0x58f8, 0x6020, 0xd0bc, 0x0040, 0x58f8, 0x2104, 0xa084, 0x000f, - 0xa086, 0x0004, 0x00c0, 0x58f8, 0x00f0, 0x58cc, 0x027e, 0x6164, + 0x58f0, 0x6020, 0xd0bc, 0x0040, 0x58f0, 0x2104, 0xa084, 0x000f, + 0xa086, 0x0004, 0x00c0, 0x58f0, 0x00f0, 0x58c4, 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, 0x6043, 0x0000, - 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58f2, 0x027f, + 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58ea, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0x7836, 0x7020, 0xa005, 0x0040, - 0x590b, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008, 0x20a2, - 0x00f0, 0x590f, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, + 0x5903, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008, 0x20a2, + 0x00f0, 0x5907, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, 0x0040, - 0x59a5, 0x8cff, 0x0040, 0x59a5, 0x601c, 0xa086, 0x0006, 0x00c0, - 0x59a0, 0x88ff, 0x0040, 0x593c, 0x2800, 0xac06, 0x00c0, 0x59a0, - 0x2039, 0x0000, 0x0078, 0x5940, 0x6018, 0xa206, 0x00c0, 0x59a0, - 0x7024, 0xac06, 0x00c0, 0x596e, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x5969, 0x6817, 0x0008, 0x68c3, 0x0000, 0x1078, 0x5a32, + 0x599d, 0x8cff, 0x0040, 0x599d, 0x601c, 0xa086, 0x0006, 0x00c0, + 0x5998, 0x88ff, 0x0040, 0x5934, 0x2800, 0xac06, 0x00c0, 0x5998, + 0x2039, 0x0000, 0x0078, 0x5938, 0x6018, 0xa206, 0x00c0, 0x5998, + 0x7024, 0xac06, 0x00c0, 0x5966, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x5961, 0x6817, 0x0008, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x595e, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x5966, 0x6827, 0x0001, 0x037f, 0x0078, - 0x596e, 0x6003, 0x0009, 0x630a, 0x0078, 0x59a0, 0x7014, 0xac36, - 0x00c0, 0x5974, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x5982, - 0x2c00, 0xaf36, 0x0040, 0x5980, 0x2f00, 0x7012, 0x0078, 0x5982, - 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x598b, - 0x7e0e, 0x0078, 0x598c, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x5996, 0x1078, 0x74fd, 0x1078, 0x6aa1, - 0x1078, 0x5902, 0x88ff, 0x00c0, 0x59af, 0x0c7f, 0x0078, 0x5926, - 0x2c78, 0x600c, 0x2060, 0x0078, 0x5926, 0xa006, 0x127f, 0x007f, + 0x0040, 0x5956, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x595e, 0x6827, 0x0001, 0x037f, 0x0078, + 0x5966, 0x6003, 0x0009, 0x630a, 0x0078, 0x5998, 0x7014, 0xac36, + 0x00c0, 0x596c, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x597a, + 0x2c00, 0xaf36, 0x0040, 0x5978, 0x2f00, 0x7012, 0x0078, 0x597a, + 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5983, + 0x7e0e, 0x0078, 0x5984, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, + 0x1078, 0x6938, 0x0040, 0x598e, 0x1078, 0x74f2, 0x1078, 0x6a96, + 0x1078, 0x58fa, 0x88ff, 0x00c0, 0x59a7, 0x0c7f, 0x0078, 0x591e, + 0x2c78, 0x600c, 0x2060, 0x0078, 0x591e, 0xa006, 0x127f, 0x007f, 0x067f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, - 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x59a6, 0x0f7e, 0x0e7e, + 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x599e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, - 0x2071, 0x7836, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a21, - 0x601c, 0xa086, 0x0006, 0x00c0, 0x5a1c, 0x88ff, 0x0040, 0x59d6, - 0x2800, 0xac06, 0x00c0, 0x5a1c, 0x0078, 0x59da, 0x6018, 0xa206, - 0x00c0, 0x5a1c, 0x703c, 0xac06, 0x00c0, 0x59ec, 0x037e, 0x2019, - 0x0001, 0x1078, 0x5768, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, - 0x0000, 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x59f2, - 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x5a00, 0x2c00, 0xaf36, - 0x0040, 0x59fe, 0x2f00, 0x7036, 0x0078, 0x5a00, 0x7037, 0x0000, - 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5a09, 0x7e0e, 0x0078, - 0x5a0a, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x5a14, 0x1078, 0x74fd, 0x1078, 0x6aa1, 0x88ff, 0x00c0, - 0x5a2b, 0x0c7f, 0x0078, 0x59c5, 0x2c78, 0x600c, 0x2060, 0x0078, - 0x59c5, 0xa006, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, + 0x2071, 0x7836, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a19, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x5a14, 0x88ff, 0x0040, 0x59ce, + 0x2800, 0xac06, 0x00c0, 0x5a14, 0x0078, 0x59d2, 0x6018, 0xa206, + 0x00c0, 0x5a14, 0x703c, 0xac06, 0x00c0, 0x59e4, 0x037e, 0x2019, + 0x0001, 0x1078, 0x5760, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, + 0x0000, 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x59ea, + 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x59f8, 0x2c00, 0xaf36, + 0x0040, 0x59f6, 0x2f00, 0x7036, 0x0078, 0x59f8, 0x7037, 0x0000, + 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5a01, 0x7e0e, 0x0078, + 0x5a02, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x5a0c, 0x1078, 0x74f2, 0x1078, 0x6a96, 0x88ff, 0x00c0, + 0x5a23, 0x0c7f, 0x0078, 0x59bd, 0x2c78, 0x600c, 0x2060, 0x0078, + 0x59bd, 0xa006, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, 0x0001, - 0x0078, 0x5a22, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, - 0xa086, 0x0002, 0x00c0, 0x5a40, 0x7007, 0x0005, 0x0078, 0x5a42, + 0x0078, 0x5a1a, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, + 0xa086, 0x0002, 0x00c0, 0x5a38, 0x7007, 0x0005, 0x0078, 0x5a3a, 0x7007, 0x0000, 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x2c10, - 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a82, 0x2200, 0xac06, - 0x00c0, 0x5a7d, 0x7038, 0xac36, 0x00c0, 0x5a60, 0x660c, 0x763a, - 0x7034, 0xac36, 0x00c0, 0x5a6e, 0x2c00, 0xaf36, 0x0040, 0x5a6c, - 0x2f00, 0x7036, 0x0078, 0x5a6e, 0x7037, 0x0000, 0x660c, 0x2c00, - 0xaf06, 0x0040, 0x5a76, 0x7e0e, 0x0078, 0x5a77, 0x2678, 0x600f, - 0x0000, 0xa085, 0x0001, 0x0078, 0x5a82, 0x2c78, 0x600c, 0x2060, - 0x0078, 0x5a53, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, + 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a7a, 0x2200, 0xac06, + 0x00c0, 0x5a75, 0x7038, 0xac36, 0x00c0, 0x5a58, 0x660c, 0x763a, + 0x7034, 0xac36, 0x00c0, 0x5a66, 0x2c00, 0xaf36, 0x0040, 0x5a64, + 0x2f00, 0x7036, 0x0078, 0x5a66, 0x7037, 0x0000, 0x660c, 0x2c00, + 0xaf06, 0x0040, 0x5a6e, 0x7e0e, 0x0078, 0x5a6f, 0x2678, 0x600f, + 0x0000, 0xa085, 0x0001, 0x0078, 0x5a7a, 0x2c78, 0x600c, 0x2060, + 0x0078, 0x5a4b, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x760c, 0x2660, 0x2678, - 0x8cff, 0x0040, 0x5b1b, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, - 0x00c0, 0x5b16, 0x7024, 0xac06, 0x00c0, 0x5ac9, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x5ac9, 0x1078, 0x5582, 0x68c3, 0x0000, - 0x1078, 0x5a32, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, - 0xa384, 0x1000, 0x0040, 0x5ac0, 0x6803, 0x0100, 0x6803, 0x0000, - 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ac8, 0x6827, 0x0001, - 0x037f, 0x700c, 0xac36, 0x00c0, 0x5acf, 0x660c, 0x760e, 0x7008, - 0xac36, 0x00c0, 0x5add, 0x2c00, 0xaf36, 0x0040, 0x5adb, 0x2f00, - 0x700a, 0x0078, 0x5add, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, - 0xaf06, 0x0040, 0x5ae6, 0x7e0e, 0x0078, 0x5ae7, 0x2678, 0x600f, - 0x0000, 0x1078, 0x6aba, 0x00c0, 0x5af1, 0x1078, 0x22dd, 0x0078, - 0x5b0d, 0x1078, 0x6ace, 0x00c0, 0x5af9, 0x1078, 0x5e57, 0x0078, - 0x5b0d, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x5b0d, 0x601c, - 0xa086, 0x0003, 0x00c0, 0x5b23, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x6003, 0x0000, 0x1078, - 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, 0x5a98, 0x2c78, 0x600c, - 0x2060, 0x0078, 0x5a98, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, - 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5b04, - 0x1078, 0x74fd, 0x0078, 0x5b0d, 0x037e, 0x157e, 0x137e, 0x147e, - 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x214f, 0x00c0, - 0x5b3d, 0x8210, 0x8000, 0x0078, 0x5b34, 0xa005, 0x0040, 0x5b47, + 0x8cff, 0x0040, 0x5b13, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, + 0x00c0, 0x5b0e, 0x7024, 0xac06, 0x00c0, 0x5ac1, 0x2069, 0x0100, + 0x68c0, 0xa005, 0x0040, 0x5ac1, 0x1078, 0x557a, 0x68c3, 0x0000, + 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0040, 0x5ab8, 0x6803, 0x0100, 0x6803, 0x0000, + 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ac0, 0x6827, 0x0001, + 0x037f, 0x700c, 0xac36, 0x00c0, 0x5ac7, 0x660c, 0x760e, 0x7008, + 0xac36, 0x00c0, 0x5ad5, 0x2c00, 0xaf36, 0x0040, 0x5ad3, 0x2f00, + 0x700a, 0x0078, 0x5ad5, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, + 0xaf06, 0x0040, 0x5ade, 0x7e0e, 0x0078, 0x5adf, 0x2678, 0x600f, + 0x0000, 0x1078, 0x6aaf, 0x00c0, 0x5ae9, 0x1078, 0x22d7, 0x0078, + 0x5b05, 0x1078, 0x6ac3, 0x00c0, 0x5af1, 0x1078, 0x5e4d, 0x0078, + 0x5b05, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x5b05, 0x601c, + 0xa086, 0x0003, 0x00c0, 0x5b1b, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x6003, 0x0000, 0x1078, + 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x5a90, 0x2c78, 0x600c, + 0x2060, 0x0078, 0x5a90, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5afc, + 0x1078, 0x74f2, 0x0078, 0x5b05, 0x037e, 0x157e, 0x137e, 0x147e, + 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x2149, 0x00c0, + 0x5b35, 0x8210, 0x8000, 0x0078, 0x5b2c, 0xa005, 0x0040, 0x5b3f, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x147f, 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, - 0x5053, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, + 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x514c, 0x20a3, 0x4f47, 0x20a3, 0x4943, 0x20a3, 0x2020, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, - 0x020b, 0x1078, 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x1078, 0x5566, 0x0d7f, 0x007c, 0x20a1, + 0x020b, 0x1078, 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0018, 0x1078, 0x556e, 0x007c, 0x2061, 0x7d00, 0x2a70, 0x7060, + 0x0018, 0x1078, 0x5566, 0x007c, 0x2061, 0x7d00, 0x2a70, 0x7060, 0x7046, 0x704b, 0x7d00, 0x007c, 0x0e7e, 0x127e, 0x2071, 0x7600, - 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0048, 0x5bce, 0x7048, - 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bba, 0xace0, 0x0008, - 0x7054, 0xac02, 0x00c8, 0x5bb6, 0x0078, 0x5ba9, 0x2061, 0x7d00, - 0x0078, 0x5ba9, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0008, - 0x7054, 0xa502, 0x00c8, 0x5bca, 0x754a, 0xa085, 0x0001, 0x127f, - 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bc5, 0xa006, 0x0078, - 0x5bc7, 0x0e7e, 0x2071, 0x7600, 0x7544, 0xa582, 0x0001, 0x0048, - 0x5bff, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bec, - 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x5be8, 0x0078, 0x5bdb, - 0x2061, 0x7d00, 0x0078, 0x5bdb, 0x6003, 0x0008, 0x8529, 0x7546, - 0xaca8, 0x0008, 0x7054, 0xa502, 0x00c8, 0x5bfb, 0x754a, 0xa085, - 0x0001, 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bf7, 0xa006, - 0x0078, 0x5bf9, 0xac82, 0x7d00, 0x1048, 0x12d5, 0x2001, 0x7615, - 0x2004, 0xac02, 0x10c8, 0x12d5, 0xa006, 0x6006, 0x600a, 0x600e, + 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0048, 0x5bc6, 0x7048, + 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bb2, 0xace0, 0x0008, + 0x7054, 0xac02, 0x00c8, 0x5bae, 0x0078, 0x5ba1, 0x2061, 0x7d00, + 0x0078, 0x5ba1, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0008, + 0x7054, 0xa502, 0x00c8, 0x5bc2, 0x754a, 0xa085, 0x0001, 0x127f, + 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bbd, 0xa006, 0x0078, + 0x5bbf, 0x0e7e, 0x2071, 0x7600, 0x7544, 0xa582, 0x0001, 0x0048, + 0x5bf7, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5be4, + 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x5be0, 0x0078, 0x5bd3, + 0x2061, 0x7d00, 0x0078, 0x5bd3, 0x6003, 0x0008, 0x8529, 0x7546, + 0xaca8, 0x0008, 0x7054, 0xa502, 0x00c8, 0x5bf3, 0x754a, 0xa085, + 0x0001, 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bef, 0xa006, + 0x0078, 0x5bf1, 0xac82, 0x7d00, 0x1048, 0x12cd, 0x2001, 0x7615, + 0x2004, 0xac02, 0x10c8, 0x12cd, 0xa006, 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x2061, - 0x7600, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0040, 0x5c21, - 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x0078, - 0x5c20, 0x601c, 0xa084, 0x000f, 0x0079, 0x5c2e, 0x5c37, 0x5c3f, - 0x5c5b, 0x5c77, 0x6b4b, 0x6b67, 0x6b83, 0x5c37, 0x5c3f, 0xa18e, - 0x0047, 0x00c0, 0x5c3e, 0xa016, 0x1078, 0x1572, 0x007c, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x5c49, 0x067f, - 0x007c, 0x5c59, 0x5d40, 0x5e72, 0x5c59, 0x5ec9, 0x5c59, 0x5c59, - 0x5c59, 0x5cef, 0x6182, 0x5c59, 0x5c59, 0x5c59, 0x5c59, 0x5c59, - 0x5c59, 0x1078, 0x12d5, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x5c65, 0x067f, 0x007c, 0x5c75, 0x5c75, 0x5c75, - 0x5c75, 0x5c75, 0x5c75, 0x5c75, 0x5c75, 0x65f2, 0x66b8, 0x5c75, - 0x660b, 0x6664, 0x660b, 0x6664, 0x5c75, 0x1078, 0x12d5, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x5c81, 0x067f, - 0x007c, 0x5c91, 0x61c0, 0x6266, 0x6328, 0x647c, 0x5c91, 0x5c91, - 0x5c91, 0x619e, 0x65a7, 0x65ab, 0x5c91, 0x5c91, 0x5c91, 0x5c91, - 0x65d1, 0x1078, 0x12d5, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, + 0x7600, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0040, 0x5c19, + 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x0078, + 0x5c18, 0x601c, 0xa084, 0x000f, 0x0079, 0x5c26, 0x5c2f, 0x5c37, + 0x5c53, 0x5c6f, 0x6b40, 0x6b5c, 0x6b78, 0x5c2f, 0x5c37, 0xa18e, + 0x0047, 0x00c0, 0x5c36, 0xa016, 0x1078, 0x156a, 0x007c, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x5c41, 0x067f, + 0x007c, 0x5c51, 0x5d38, 0x5e68, 0x5c51, 0x5ebf, 0x5c51, 0x5c51, + 0x5c51, 0x5ce7, 0x6178, 0x5c51, 0x5c51, 0x5c51, 0x5c51, 0x5c51, + 0x5c51, 0x1078, 0x12cd, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x5c5d, 0x067f, 0x007c, 0x5c6d, 0x5c6d, 0x5c6d, + 0x5c6d, 0x5c6d, 0x5c6d, 0x5c6d, 0x5c6d, 0x65ec, 0x66b2, 0x5c6d, + 0x6605, 0x665e, 0x6605, 0x665e, 0x5c6d, 0x1078, 0x12cd, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x5c79, 0x067f, + 0x007c, 0x5c89, 0x61b6, 0x625c, 0x631e, 0x6476, 0x5c89, 0x5c89, + 0x5c89, 0x6194, 0x65a1, 0x65a5, 0x5c89, 0x5c89, 0x5c89, 0x5c89, + 0x65cb, 0x1078, 0x12cd, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, 0xa5a8, 0x0002, 0xa398, - 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x5ca1, 0x0e7e, 0x1078, 0x693e, - 0x0040, 0x5cb8, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, - 0x0e7f, 0x1078, 0x5c02, 0x007c, 0x0d7e, 0x037e, 0x7330, 0xa386, - 0x0200, 0x00c0, 0x5cc9, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, - 0xfffd, 0x6010, 0xa005, 0x0040, 0x5cd3, 0x2068, 0x6807, 0x0000, - 0x6837, 0x0103, 0x6b32, 0x1078, 0x5c02, 0x037f, 0x0d7f, 0x007c, + 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x5c99, 0x0e7e, 0x1078, 0x6938, + 0x0040, 0x5cb0, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, + 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x0d7e, 0x037e, 0x7330, 0xa386, + 0x0200, 0x00c0, 0x5cc1, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, + 0xfffd, 0x6010, 0xa005, 0x0040, 0x5ccb, 0x2068, 0x6807, 0x0000, + 0x6837, 0x0103, 0x6b32, 0x1078, 0x5bfa, 0x037f, 0x0d7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0xa1b6, - 0x0015, 0x00c0, 0x5cec, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, - 0x680e, 0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x5cad, 0x2100, - 0xa1b2, 0x0030, 0x10c8, 0x12d5, 0x0079, 0x5cf6, 0x5d28, 0x5d34, - 0x5d28, 0x5d28, 0x5d28, 0x5d28, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d28, 0x5d26, 0x5d28, - 0x5d28, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d28, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x1078, 0x12d5, - 0x6003, 0x0001, 0x6106, 0x1078, 0x4872, 0x127e, 0x2091, 0x8000, - 0x1078, 0x4c7a, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4872, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12d5, 0xa1b6, 0x0013, 0x00c0, - 0x5d4c, 0x2008, 0x0079, 0x5dd5, 0xa1b6, 0x0027, 0x00c0, 0x5da2, - 0x1078, 0x4b81, 0x6004, 0x1078, 0x6aba, 0x0040, 0x5d65, 0x1078, - 0x6ace, 0x0040, 0x5d9a, 0xa08e, 0x0021, 0x0040, 0x5d9e, 0xa08e, - 0x0022, 0x0040, 0x5d9a, 0x0078, 0x5d95, 0x1078, 0x22dd, 0x2001, - 0x0007, 0x1078, 0x37d1, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, - 0x5e57, 0xa186, 0x007e, 0x00c0, 0x5d7b, 0x2001, 0x762f, 0x2014, - 0xa295, 0x0001, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, - 0x0028, 0x1078, 0x4962, 0x1078, 0x48a5, 0x0c7e, 0x6018, 0xa065, - 0x0040, 0x5d8c, 0x1078, 0x39a6, 0x0c7f, 0x2c08, 0x1078, 0x737b, - 0x037f, 0x027f, 0x017f, 0x1078, 0x380d, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5e57, 0x0078, 0x5d95, 0x1078, 0x5e66, - 0x0078, 0x5d95, 0xa186, 0x0014, 0x00c0, 0x5d99, 0x1078, 0x4b81, - 0x1078, 0x22bb, 0x1078, 0x6aba, 0x00c0, 0x5dc2, 0x1078, 0x22dd, - 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, 0x5e57, 0xa186, 0x007e, - 0x00c0, 0x5dc0, 0x2001, 0x762f, 0x200c, 0xa18d, 0x0001, 0x2102, - 0x0078, 0x5d95, 0x1078, 0x6ace, 0x00c0, 0x5dca, 0x1078, 0x5e57, - 0x0078, 0x5d95, 0x6004, 0xa08e, 0x0021, 0x0040, 0x5dc6, 0xa08e, - 0x0022, 0x1040, 0x5e66, 0x0078, 0x5d95, 0x5e07, 0x5e09, 0x5e0d, - 0x5e11, 0x5e15, 0x5e19, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e1d, 0x5e23, 0x5e05, 0x5e2d, 0x5e23, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e23, 0x5e23, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x1078, 0x12d5, 0x0078, - 0x5e23, 0x2001, 0x000b, 0x0078, 0x5e36, 0x2001, 0x0003, 0x0078, - 0x5e36, 0x2001, 0x0005, 0x0078, 0x5e36, 0x2001, 0x0001, 0x0078, - 0x5e36, 0x2001, 0x0009, 0x0078, 0x5e36, 0x1078, 0x12d5, 0x0078, - 0x5e35, 0x1078, 0x37d1, 0x1078, 0x4b81, 0x6003, 0x0002, 0x6017, - 0x0028, 0x1078, 0x4c7a, 0x0078, 0x5e35, 0x1078, 0x4b81, 0x6003, - 0x0004, 0x6017, 0x0028, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x37d1, - 0x1078, 0x4b81, 0x6003, 0x0002, 0x037e, 0x2019, 0x765c, 0x2304, - 0xa084, 0xff00, 0x00c0, 0x5e48, 0x2019, 0x0028, 0x0078, 0x5e51, - 0x8007, 0xa09a, 0x0004, 0x0048, 0x5e44, 0x8003, 0x801b, 0x831b, - 0xa318, 0x6316, 0x037f, 0x1078, 0x4c7a, 0x0078, 0x5e35, 0x0e7e, - 0x1078, 0x693e, 0x0040, 0x5e64, 0x6010, 0x2070, 0x7007, 0x0000, - 0x7037, 0x0103, 0x7033, 0x0100, 0x0e7f, 0x007c, 0x0e7e, 0xacf0, - 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, - 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, - 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x12d5, 0x6604, 0xa6b6, 0x0028, - 0x00c0, 0x5e86, 0x1078, 0x6b03, 0x0078, 0x5eb8, 0x6604, 0xa6b6, - 0x0029, 0x00c0, 0x5e8f, 0x1078, 0x6b1d, 0x0078, 0x5eb8, 0x6604, - 0xa6b6, 0x001f, 0x00c0, 0x5e98, 0x1078, 0x5c93, 0x0078, 0x5eb8, - 0x6604, 0xa6b6, 0x0000, 0x00c0, 0x5ea1, 0x1078, 0x5cd8, 0x0078, - 0x5eb8, 0x6604, 0xa6b6, 0x0022, 0x00c0, 0x5eaa, 0x1078, 0x5cbc, - 0x0078, 0x5eb8, 0xa1b6, 0x0015, 0x00c0, 0x5eb2, 0x1079, 0x5ebd, - 0x0078, 0x5eb8, 0xa1b6, 0x0016, 0x00c0, 0x5eb9, 0x1079, 0x5ffa, - 0x007c, 0x1078, 0x5c37, 0x0078, 0x5eb8, 0x5ee1, 0x5ee4, 0x5ee1, - 0x5f25, 0x5ee1, 0x5f96, 0x5ee1, 0x5ee1, 0x5ee1, 0x5fd2, 0x5ee1, - 0x5fe8, 0xa1b6, 0x0048, 0x0040, 0x5ed5, 0x20e1, 0x0005, 0x3d18, - 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, 0x0e7e, 0xacf0, 0x0004, - 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x5c02, - 0x007c, 0x0005, 0x0005, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, - 0xa086, 0x0074, 0x00c0, 0x5f0e, 0x1078, 0x734f, 0x00c0, 0x5f00, - 0x0d7e, 0x6018, 0x2068, 0x1078, 0x5f12, 0x0d7f, 0x2001, 0x0006, - 0x1078, 0x37d1, 0x1078, 0x22dd, 0x1078, 0x5c02, 0x0078, 0x5f10, - 0x2001, 0x000a, 0x1078, 0x37d1, 0x1078, 0x22dd, 0x6003, 0x0001, - 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x5f10, 0x1078, 0x5f86, - 0x0e7f, 0x007c, 0x6800, 0xd084, 0x0040, 0x5f24, 0x2001, 0x0000, - 0x1078, 0x37bd, 0x2069, 0x7651, 0x6804, 0xd0a4, 0x0040, 0x5f24, - 0x2001, 0x0006, 0x1078, 0x37df, 0x007c, 0x0d7e, 0x2011, 0x761e, - 0x2204, 0xa086, 0x0074, 0x00c0, 0x5f82, 0x1078, 0x60d4, 0x6018, - 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x0040, 0x5f4d, - 0xa286, 0x0080, 0x00c0, 0x5f76, 0x6813, 0x00ff, 0x6817, 0xfffc, - 0x6010, 0xa005, 0x0040, 0x5f6c, 0x2068, 0x6807, 0x0000, 0x6837, - 0x0103, 0x6833, 0x0200, 0x0078, 0x5f6c, 0x0e7e, 0x0f7e, 0x6813, - 0x00ff, 0x6817, 0xfffe, 0x2071, 0x762f, 0x2e04, 0xa085, 0x0003, - 0x2072, 0x2071, 0x7b80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, - 0x2069, 0x7619, 0x206a, 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x761a, - 0x206a, 0x78ea, 0x0f7f, 0x0e7f, 0x2001, 0x0006, 0x1078, 0x37d1, - 0x1078, 0x22dd, 0x1078, 0x5c02, 0x0078, 0x5f84, 0x2001, 0x0004, - 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x4872, - 0x0078, 0x5f84, 0x1078, 0x5f86, 0x0d7f, 0x007c, 0x2001, 0x7600, - 0x2004, 0xa086, 0x0003, 0x0040, 0x5f91, 0x2001, 0x0007, 0x1078, - 0x37d1, 0x1078, 0x22dd, 0x1078, 0x5c02, 0x007c, 0x0e7e, 0x2071, - 0x7600, 0x7078, 0xa086, 0x0014, 0x00c0, 0x5fcc, 0x7000, 0xa086, - 0x0003, 0x00c0, 0x5fa9, 0x6010, 0xa005, 0x00c0, 0x5fa9, 0x1078, - 0x2dc8, 0x0d7e, 0x6018, 0x2068, 0x1078, 0x38a1, 0x1078, 0x5f12, - 0x0d7f, 0x1078, 0x60de, 0x00c0, 0x5fcc, 0x2001, 0x0006, 0x1078, - 0x37d1, 0x0e7e, 0x6010, 0xa005, 0x0040, 0x5fc5, 0x2070, 0x7007, - 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x0e7f, 0x1078, 0x22dd, - 0x1078, 0x5c02, 0x0078, 0x5fd0, 0x1078, 0x5e57, 0x1078, 0x5f86, - 0x0e7f, 0x007c, 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, - 0x5fe5, 0x2001, 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, - 0x0001, 0x1078, 0x4872, 0x0078, 0x5fe7, 0x1078, 0x5f86, 0x007c, - 0x2011, 0x761e, 0x2204, 0xa086, 0x0004, 0x00c0, 0x5ff7, 0x2001, - 0x0007, 0x1078, 0x37d1, 0x1078, 0x5c02, 0x0078, 0x5ff9, 0x1078, - 0x5f86, 0x007c, 0x5ee1, 0x6006, 0x5ee1, 0x602c, 0x5ee1, 0x6087, - 0x5ee1, 0x5ee1, 0x5ee1, 0x609c, 0x5ee1, 0x60af, 0x0c7e, 0x1078, - 0x60c2, 0x00c0, 0x601b, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, - 0x4872, 0x0078, 0x602a, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, - 0xa086, 0x1900, 0x00c0, 0x6028, 0x1078, 0x5c02, 0x0078, 0x602a, - 0x1078, 0x5f86, 0x0c7f, 0x007c, 0x1078, 0x60d1, 0x00c0, 0x6040, - 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, 0x0002, 0x1078, 0x37d1, - 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x4872, 0x0078, 0x6062, - 0x1078, 0x5e57, 0x2009, 0x7b8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, - 0x0005, 0x0040, 0x6063, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, - 0xa086, 0x1900, 0x00c0, 0x6060, 0xa686, 0x0009, 0x0040, 0x6063, - 0x2001, 0x0004, 0x1078, 0x37d1, 0x1078, 0x5c02, 0x0078, 0x6062, - 0x1078, 0x5f86, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x6071, 0x6838, 0xd0fc, 0x0040, 0x6071, 0x0d7f, 0x0078, - 0x6060, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, - 0x6082, 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f, - 0x0078, 0x6062, 0x1078, 0x22bb, 0x0d7f, 0x0078, 0x6060, 0x1078, - 0x60d1, 0x00c0, 0x6097, 0x2001, 0x0004, 0x1078, 0x37d1, 0x6003, - 0x0001, 0x6007, 0x0003, 0x1078, 0x4872, 0x0078, 0x609b, 0x1078, - 0x5e57, 0x1078, 0x5f86, 0x007c, 0x1078, 0x60d1, 0x00c0, 0x60ac, - 0x2001, 0x0008, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0005, - 0x1078, 0x4872, 0x0078, 0x60ae, 0x1078, 0x5f86, 0x007c, 0x1078, - 0x60d1, 0x00c0, 0x60bf, 0x2001, 0x000a, 0x1078, 0x37d1, 0x6003, - 0x0001, 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x60c1, 0x1078, - 0x5f86, 0x007c, 0x2009, 0x7b8e, 0x2104, 0xa086, 0x0003, 0x00c0, - 0x60d0, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, - 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, - 0x2164, 0x1078, 0x3837, 0x017f, 0x0c7f, 0x007c, 0x0e7e, 0x2071, - 0x7b8c, 0x7004, 0xa086, 0x0014, 0x00c0, 0x6101, 0x7008, 0xa086, - 0x0800, 0x00c0, 0x6101, 0x700c, 0xd0ec, 0x0040, 0x60ff, 0xa084, - 0x0f00, 0xa086, 0x0100, 0x00c0, 0x60ff, 0x7024, 0xd0a4, 0x0040, - 0x60ff, 0xd08c, 0x0040, 0x60ff, 0xa006, 0x0078, 0x6101, 0xa085, - 0x0001, 0x0e7f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, - 0x047e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, - 0x252c, 0x2021, 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, - 0x7244, 0x7060, 0xa202, 0x00c8, 0x6158, 0x1078, 0x7559, 0x0040, - 0x6150, 0x671c, 0xa786, 0x0001, 0x0040, 0x6150, 0xa786, 0x0007, - 0x0040, 0x6150, 0x2500, 0xac06, 0x0040, 0x6150, 0x2400, 0xac06, - 0x0040, 0x6150, 0x0c7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x613a, - 0x1078, 0x1676, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x614d, - 0xa786, 0x0003, 0x00c0, 0x6162, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x0c7f, - 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x6158, 0x0078, 0x6118, - 0x127f, 0x007f, 0x027f, 0x047f, 0x057f, 0x077f, 0x0c7f, 0x0d7f, - 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, 0x6144, 0x1078, 0x74fd, - 0x0078, 0x614d, 0x220c, 0x2304, 0xa106, 0x00c0, 0x6175, 0x8210, - 0x8318, 0x00f0, 0x616a, 0xa006, 0x007c, 0x2304, 0xa102, 0x0048, - 0x617d, 0x2001, 0x0001, 0x0078, 0x617f, 0x2001, 0x0000, 0xa18d, - 0x0001, 0x007c, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, 0x1078, - 0x6aba, 0x0040, 0x6191, 0x1078, 0x6ace, 0x0040, 0x619a, 0x0078, - 0x6193, 0x1078, 0x22dd, 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5e57, 0x0078, 0x6193, 0xa182, 0x0040, - 0x0079, 0x61a2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, - 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b4, 0x61b4, 0x61b4, - 0x61b4, 0x61b2, 0x1078, 0x12d5, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0xa186, 0x0013, 0x00c0, 0x61c9, 0x6004, 0xa082, 0x0040, 0x0079, - 0x623f, 0xa186, 0x0027, 0x00c0, 0x61e6, 0x1078, 0x4b81, 0x1078, - 0x22bb, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, 0x0040, 0x61e0, - 0x6837, 0x0103, 0x684b, 0x0029, 0x1078, 0x3a7a, 0x1078, 0x6a94, - 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0xa186, 0x0014, - 0x00c0, 0x61ef, 0x6004, 0xa082, 0x0040, 0x0079, 0x620f, 0xa186, - 0x0047, 0x10c0, 0x12d5, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, - 0x620c, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, - 0x46e6, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, - 0x00c0, 0x620c, 0x0078, 0x6266, 0x1078, 0x5c37, 0x007c, 0x6221, - 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, - 0x621f, 0x621f, 0x6238, 0x6238, 0x6238, 0x6238, 0x621f, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, - 0x0040, 0x6232, 0x6837, 0x0103, 0x684b, 0x0006, 0x1078, 0x3a7a, - 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x6251, - 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, - 0x624f, 0x624f, 0x625f, 0x625f, 0x625f, 0x625f, 0x624f, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x6003, 0x0002, 0x1078, 0x4c7a, 0x6010, - 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, - 0x4b81, 0x6003, 0x000f, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x0040, - 0x0079, 0x626a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627c, - 0x6305, 0x631d, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, - 0x627a, 0x627a, 0x1078, 0x12d5, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, - 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, 0x62e9, - 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x62ae, 0xa186, 0x0028, - 0x00c0, 0x6298, 0x1078, 0x6aa8, 0x684b, 0x001c, 0x0078, 0x62b0, - 0xd6dc, 0x0040, 0x62a3, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x62b0, 0xd6d4, 0x0040, 0x62ae, 0x684b, 0x0007, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x62b0, 0x684b, 0x0000, - 0x6837, 0x0103, 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x62c3, 0x7328, - 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, - 0x1078, 0x6727, 0x037f, 0xd6cc, 0x0040, 0x62f9, 0x7124, 0x695a, - 0xa192, 0x0021, 0x00c8, 0x62d7, 0x2071, 0x7b98, 0x831c, 0x2300, - 0xae18, 0xad90, 0x001d, 0x1078, 0x6727, 0x0078, 0x62f9, 0x6838, - 0xd0fc, 0x0040, 0x62e0, 0x2009, 0x0020, 0x695a, 0x0078, 0x62cc, - 0x0f7e, 0x2d78, 0x1078, 0x66bf, 0x0f7f, 0x1078, 0x6714, 0x0078, - 0x62fb, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, - 0x0040, 0x62f9, 0x6810, 0x6914, 0xa115, 0x0040, 0x62f9, 0x1078, - 0x646d, 0x1078, 0x3a7a, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, - 0x0d7f, 0x0e7f, 0x1078, 0x5c02, 0x007c, 0x0f7e, 0x6003, 0x0003, - 0x2079, 0x7b8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, - 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19cf, - 0x1078, 0x4891, 0x1078, 0x4d3a, 0x007c, 0x6003, 0x0004, 0x6110, - 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, - 0xa182, 0x0040, 0x0079, 0x632c, 0x633c, 0x633c, 0x633c, 0x633c, - 0x633c, 0x633e, 0x63d5, 0x633c, 0x633c, 0x63eb, 0x644d, 0x633c, - 0x633c, 0x633c, 0x633c, 0x6454, 0x1078, 0x12d5, 0x077e, 0x0f7e, - 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, - 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, - 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x63d0, 0xa694, 0xff00, 0xa284, - 0x0c00, 0x0040, 0x635f, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, - 0x0300, 0x0040, 0x63d0, 0x1078, 0x132f, 0x1040, 0x12d5, 0x2d00, - 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, - 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, - 0x0002, 0x0040, 0x6399, 0xa186, 0x0028, 0x00c0, 0x6383, 0x684b, - 0x001c, 0x0078, 0x639b, 0xd6dc, 0x0040, 0x638e, 0x684b, 0x0015, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x639b, 0xd6d4, 0x0040, - 0x6399, 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, - 0x639b, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, - 0xa01e, 0xd6c4, 0x0040, 0x63b0, 0x7328, 0x732c, 0x6b56, 0x037e, - 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6727, 0x037f, - 0xd6cc, 0x0040, 0x63d0, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, - 0x63c4, 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, - 0x1078, 0x6727, 0x0078, 0x63d0, 0x7838, 0xd0fc, 0x0040, 0x63cd, - 0x2009, 0x0020, 0x695a, 0x0078, 0x63b9, 0x2d78, 0x1078, 0x66bf, - 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, - 0x2079, 0x7b8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, - 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19cf, - 0x1078, 0x5567, 0x007c, 0x0d7e, 0x6003, 0x0002, 0x1078, 0x4c29, - 0x1078, 0x4d3a, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x644b, - 0xd1cc, 0x0040, 0x6426, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x641e, - 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, - 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, - 0x8210, 0x00f0, 0x640d, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, - 0x017f, 0x2168, 0x1078, 0x1358, 0x0078, 0x6449, 0x017e, 0x1078, - 0x1358, 0x0d7f, 0x1078, 0x6714, 0x0078, 0x6449, 0x6837, 0x0103, - 0x6944, 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x6445, 0xa086, - 0x0028, 0x00c0, 0x6437, 0x684b, 0x001c, 0x0078, 0x6447, 0xd1dc, - 0x0040, 0x643e, 0x684b, 0x0015, 0x0078, 0x6447, 0xd1d4, 0x0040, - 0x6445, 0x684b, 0x0007, 0x0078, 0x6447, 0x684b, 0x0000, 0x1078, - 0x3a7a, 0x1078, 0x5c02, 0x0d7f, 0x007c, 0x6003, 0x0002, 0x1078, - 0x4c29, 0x1078, 0x4d3a, 0x007c, 0x1078, 0x4c29, 0x1078, 0x22bb, - 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, 0x0040, 0x6467, 0x6837, - 0x0103, 0x684b, 0x0029, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, - 0x1078, 0x5c02, 0x1078, 0x4d3a, 0x007c, 0x684b, 0x0015, 0xd1fc, - 0x0040, 0x6479, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, - 0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x6480, - 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6492, 0x6490, 0x6536, - 0x653e, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, - 0x1078, 0x12d5, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, - 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, - 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, - 0x6528, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x64b3, 0x7018, - 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x6525, 0x1078, - 0x132f, 0x1040, 0x12d5, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, - 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, - 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x64ee, - 0xa186, 0x0028, 0x00c0, 0x64d8, 0x684b, 0x001c, 0x0078, 0x64f0, - 0xd6dc, 0x0040, 0x64e3, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x64f0, 0xd6d4, 0x0040, 0x64ee, 0x684b, 0x0007, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64f0, 0x684b, 0x0000, - 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, - 0x6505, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, 0x7b98, - 0xad90, 0x0019, 0x1078, 0x6727, 0x037f, 0xd6cc, 0x0040, 0x6525, - 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x6519, 0x2071, 0x7b98, - 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x6727, 0x0078, - 0x6525, 0x7838, 0xd0fc, 0x0040, 0x6522, 0x2009, 0x0020, 0x695a, - 0x0078, 0x650e, 0x2d78, 0x1078, 0x66bf, 0xd6dc, 0x00c0, 0x652b, - 0xa006, 0x0078, 0x652f, 0x2001, 0x0001, 0x7218, 0x731c, 0x1078, - 0x15b6, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x20e1, 0x0005, - 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, 0x0d7e, 0x6003, - 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x65a5, 0xd1cc, - 0x0040, 0x6575, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x656d, 0x017e, - 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, 0x000d, - 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, - 0x00f0, 0x655c, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, - 0x2168, 0x1078, 0x1358, 0x0078, 0x65a3, 0x017e, 0x1078, 0x1358, - 0x0d7f, 0x1078, 0x6714, 0x0078, 0x65a3, 0x6837, 0x0103, 0x6944, - 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x6594, 0xa086, 0x0028, - 0x00c0, 0x6586, 0x684b, 0x001c, 0x0078, 0x65a1, 0xd1dc, 0x0040, - 0x658d, 0x684b, 0x0015, 0x0078, 0x65a1, 0xd1d4, 0x0040, 0x6594, - 0x684b, 0x0007, 0x0078, 0x65a1, 0x684b, 0x0000, 0x684c, 0xd0ac, - 0x0040, 0x65a1, 0x6810, 0x6914, 0xa115, 0x0040, 0x65a1, 0x1078, - 0x646d, 0x1078, 0x3a7a, 0x1078, 0x5c02, 0x0d7f, 0x007c, 0x1078, - 0x4b81, 0x0078, 0x65ad, 0x1078, 0x4c29, 0x1078, 0x693e, 0x0040, - 0x65c4, 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0x760c, - 0x210c, 0xd18c, 0x00c0, 0x65cd, 0xd184, 0x00c0, 0x65c9, 0x6108, - 0x694a, 0x1078, 0x3a7a, 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, - 0x007c, 0x684b, 0x0004, 0x0078, 0x65c1, 0x684b, 0x0004, 0x0078, - 0x65c1, 0xa182, 0x0040, 0x0079, 0x65d5, 0x65e5, 0x65e5, 0x65e5, - 0x65e5, 0x65e5, 0x65e7, 0x65e5, 0x65ea, 0x65e5, 0x65e5, 0x65e5, - 0x65e5, 0x65e5, 0x65e5, 0x65e5, 0x65e5, 0x1078, 0x12d5, 0x1078, - 0x5c02, 0x007c, 0x007e, 0x027e, 0xa016, 0x1078, 0x1572, 0x027f, - 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, 0x65f6, 0x65ff, 0x65fd, - 0x65fd, 0x65fd, 0x65fd, 0x65fd, 0x65fd, 0x1078, 0x12d5, 0x6003, - 0x0001, 0x6106, 0x1078, 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, - 0x4c7a, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x6615, 0x6004, - 0xa082, 0x0085, 0x2008, 0x0079, 0x6649, 0xa186, 0x0027, 0x00c0, - 0x6636, 0x1078, 0x4b81, 0x1078, 0x22bb, 0x0d7e, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x662c, 0x6837, 0x0103, 0x684b, 0x0029, - 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5c37, 0x0078, 0x6631, 0xa186, 0x0014, - 0x00c0, 0x6632, 0x1078, 0x4b81, 0x0d7e, 0x6010, 0x2068, 0x1078, - 0x693e, 0x0040, 0x662c, 0x6837, 0x0103, 0x684b, 0x0006, 0x0078, - 0x6628, 0x6652, 0x6650, 0x6650, 0x6650, 0x6650, 0x6650, 0x665b, - 0x1078, 0x12d5, 0x1078, 0x4b81, 0x6017, 0x0014, 0x6003, 0x000c, - 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x6017, 0x0014, 0x6003, - 0x000e, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x008c, 0x00c8, 0x666e, - 0xa182, 0x0085, 0x0048, 0x666e, 0x0079, 0x6671, 0x1078, 0x5c37, - 0x007c, 0x6678, 0x6678, 0x6678, 0x6678, 0x667a, 0x6699, 0x6678, - 0x1078, 0x12d5, 0x0d7e, 0x1078, 0x6a94, 0x1078, 0x693e, 0x0040, - 0x6695, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, - 0x668d, 0x684b, 0x0006, 0x0078, 0x6691, 0x684b, 0x0005, 0x1078, - 0x6b47, 0x6847, 0x0000, 0x1078, 0x3a7a, 0x1078, 0x5c02, 0x0d7f, - 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x66b4, - 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x66aa, 0x684b, 0x0006, - 0x0078, 0x66ae, 0x684b, 0x0005, 0x1078, 0x6b47, 0x6847, 0x0000, - 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x007c, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x057e, - 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, 0x0101, 0x00c8, - 0x66cb, 0x0078, 0x66cd, 0x2009, 0x0100, 0x2130, 0x2069, 0x7b98, - 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, 0x001d, 0x1078, - 0x6727, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, 0x66e1, 0x1078, - 0x1358, 0x1078, 0x132f, 0x0040, 0x670b, 0x8528, 0x6837, 0x0110, - 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x00c8, 0x66f7, - 0x2608, 0xad90, 0x000f, 0x1078, 0x6727, 0x0078, 0x670b, 0xa6b2, - 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, 0x1078, 0x6727, - 0x0078, 0x66e1, 0x0f7f, 0x852f, 0xa5ad, 0x0003, 0x7d36, 0xa5ac, - 0x0000, 0x0078, 0x6710, 0x0f7f, 0x852f, 0xa5ad, 0x0003, 0x7d36, - 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, 0x0040, 0x6725, - 0x6804, 0xa07d, 0x0040, 0x6723, 0x6807, 0x0000, 0x1078, 0x3a7a, - 0x2f68, 0x0078, 0x6718, 0x1078, 0x3a7a, 0x0f7f, 0x007c, 0x157e, - 0xa184, 0x0001, 0x0040, 0x672d, 0x8108, 0x810c, 0x21a8, 0x2304, - 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x672f, 0x157f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x601c, 0xa084, 0x000f, 0x1079, 0x6742, - 0x127f, 0x007c, 0x6751, 0x674a, 0x674c, 0x676a, 0x674a, 0x674c, - 0x674c, 0x674c, 0x1078, 0x12d5, 0xa006, 0x007c, 0xa085, 0x0001, - 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x6767, - 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b0a, 0x1078, 0x6b47, 0x1078, - 0x3a7a, 0x1078, 0x5c02, 0xa085, 0x0001, 0x0d7f, 0x007c, 0xa006, - 0x0078, 0x6765, 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12d5, 0x1079, - 0x6772, 0x007c, 0x6782, 0x679f, 0x6784, 0x67b0, 0x679b, 0x6782, - 0x674c, 0x6751, 0x6751, 0x674c, 0x674c, 0x674c, 0x674c, 0x674c, - 0x674c, 0x674c, 0x1078, 0x12d5, 0x0d7e, 0x6010, 0x2068, 0x1078, - 0x693e, 0x0040, 0x678d, 0x1078, 0x6b47, 0x0d7f, 0x6007, 0x0085, - 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x4825, 0x1078, 0x4c7a, - 0xa085, 0x0001, 0x007c, 0x1078, 0x1676, 0x0078, 0x6784, 0x0e7e, - 0x2071, 0x7836, 0x7024, 0xac06, 0x00c0, 0x67a8, 0x1078, 0x56d6, - 0x1078, 0x560b, 0x0e7f, 0x00c0, 0x6784, 0x1078, 0x674c, 0x007c, - 0x037e, 0x0e7e, 0x2071, 0x7836, 0x703c, 0xac06, 0x00c0, 0x67c0, - 0x2019, 0x0000, 0x1078, 0x5768, 0x0e7f, 0x037f, 0x0078, 0x6784, - 0x1078, 0x5a44, 0x0e7f, 0x037f, 0x00c0, 0x6784, 0x1078, 0x674c, - 0x007c, 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x67d1, 0x0c7f, - 0x007c, 0x67e0, 0x683d, 0x68e2, 0x67e4, 0x67e0, 0x67e0, 0x71dd, - 0x5c02, 0x683d, 0x1078, 0x6ace, 0x00c0, 0x67e0, 0x1078, 0x5e57, - 0x007c, 0x6017, 0x0001, 0x007c, 0x6000, 0xa08a, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x67ec, 0x007c, 0x67fc, 0x67fe, 0x681e, 0x6830, - 0x6830, 0x67fc, 0x67e0, 0x67e0, 0x67e0, 0x6830, 0x6830, 0x67fc, - 0x67fc, 0x67fc, 0x67fc, 0x683a, 0x1078, 0x12d5, 0x0e7e, 0x6010, - 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x7836, 0x7024, 0xac06, - 0x0040, 0x681a, 0x1078, 0x560b, 0x6007, 0x0085, 0x6003, 0x000b, - 0x601f, 0x0002, 0x6017, 0x0014, 0x1078, 0x4825, 0x1078, 0x4c7a, - 0x0e7f, 0x007c, 0x6017, 0x0001, 0x0078, 0x6818, 0x0d7e, 0x6010, - 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x6007, 0x0085, 0x6003, - 0x000b, 0x601f, 0x0002, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x007c, - 0x0d7e, 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, - 0x0d7f, 0x007c, 0x1078, 0x5c02, 0x007c, 0x6000, 0xa08a, 0x0010, - 0x10c8, 0x12d5, 0x1079, 0x6845, 0x007c, 0x6855, 0x67e1, 0x6857, - 0x6855, 0x6857, 0x6855, 0x6855, 0x6855, 0x67da, 0x67da, 0x6855, - 0x6855, 0x6855, 0x6855, 0x6855, 0x6855, 0x1078, 0x12d5, 0x0d7e, - 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c, - 0x10c8, 0x12d5, 0x1079, 0x6865, 0x007c, 0x6871, 0x6890, 0x6871, - 0x6890, 0x6871, 0x6890, 0x6873, 0x687c, 0x6871, 0x6890, 0x6871, - 0x6889, 0x1078, 0x12d5, 0x6004, 0xa08e, 0x0004, 0x0040, 0x688b, - 0xa08e, 0x0002, 0x0040, 0x688b, 0x6004, 0x1078, 0x6ace, 0x0040, - 0x68da, 0xa08e, 0x0021, 0x0040, 0x68de, 0xa08e, 0x0022, 0x0040, - 0x68da, 0x1078, 0x22bb, 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, - 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, 0x68ca, 0xa186, - 0x0002, 0x00c0, 0x68b9, 0x6018, 0x2068, 0x68a0, 0xd0bc, 0x00c0, - 0x68b9, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x68b9, 0x8001, - 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0398, 0x1078, - 0x5b9c, 0x0040, 0x68b9, 0x2d00, 0x601a, 0x601f, 0x0001, 0x0078, - 0x68ca, 0x0d7f, 0x0c7f, 0x1078, 0x5e57, 0x1078, 0x22bb, 0x0e7e, - 0x127e, 0x2091, 0x8000, 0x1078, 0x22dd, 0x127f, 0x0e7f, 0x1078, - 0x5c02, 0x007c, 0x2001, 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, - 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0d7f, 0x0c7f, - 0x0078, 0x68c9, 0x1078, 0x5e57, 0x0078, 0x688d, 0x1078, 0x5e66, - 0x0078, 0x688d, 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12d5, 0x1079, - 0x68ea, 0x007c, 0x68fa, 0x68fa, 0x68fa, 0x68fa, 0x68fa, 0x68fa, - 0x68fa, 0x68fa, 0x68fa, 0x67e0, 0x68fa, 0x67e1, 0x68fc, 0x67e1, - 0x6905, 0x68fa, 0x1078, 0x12d5, 0x6007, 0x008b, 0x6003, 0x000d, - 0x1078, 0x4825, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x6a94, 0x1078, - 0x693e, 0x0040, 0x6927, 0x1078, 0x22bb, 0x0d7e, 0x1078, 0x693e, - 0x0040, 0x691a, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, - 0x1078, 0x3a7a, 0x0d7f, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, - 0x0001, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0078, 0x6929, 0x1078, - 0x5c02, 0x007c, 0xa284, 0x0007, 0x00c0, 0x693b, 0xa282, 0x7d00, - 0x0048, 0x693b, 0x2001, 0x7615, 0x2004, 0xa202, 0x00c8, 0x693b, - 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x693a, 0x027e, 0x0e7e, - 0x2071, 0x7600, 0x6210, 0x7058, 0xa202, 0x0048, 0x6950, 0x705c, - 0xa202, 0x00c8, 0x6950, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, - 0xa006, 0x0078, 0x694d, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, - 0x2091, 0x8000, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7344, 0x7060, - 0xa302, 0x00c8, 0x6979, 0x601c, 0xa206, 0x00c0, 0x6971, 0x1078, - 0x6ace, 0x00c0, 0x696d, 0x1078, 0x5e57, 0x0c7e, 0x1078, 0x5c02, - 0x0c7f, 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x6979, 0x0078, - 0x695e, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, - 0x0c7e, 0x017e, 0xa188, 0x7720, 0x210c, 0x81ff, 0x0040, 0x699c, - 0x2061, 0x7d00, 0x2071, 0x7600, 0x7344, 0x7060, 0xa302, 0x00c8, - 0x699c, 0x017e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x699f, 0x611a, - 0x1078, 0x22bb, 0x1078, 0x5c02, 0xa006, 0x0078, 0x69a1, 0xa085, - 0x0001, 0x017f, 0x0c7f, 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, - 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x057f, 0x0040, 0x69be, - 0x6612, 0x651a, 0x601f, 0x0003, 0x2009, 0x004b, 0x1078, 0x5c29, - 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x69ba, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, - 0x1078, 0x5b9c, 0x057f, 0x0040, 0x69e8, 0x6013, 0x0000, 0x651a, - 0x601f, 0x0003, 0x0c7e, 0x2560, 0x1078, 0x39a6, 0x0c7f, 0x1078, - 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x2009, 0x004c, - 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x69e4, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, - 0x62a0, 0x0c7e, 0x1078, 0x5b9c, 0x057f, 0x0040, 0x6a13, 0x6612, + 0x0015, 0x00c0, 0x5ce4, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, + 0x680e, 0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x5ca5, 0x2100, + 0xa1b2, 0x0030, 0x10c8, 0x12cd, 0x0079, 0x5cee, 0x5d20, 0x5d2c, + 0x5d20, 0x5d20, 0x5d20, 0x5d20, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d20, 0x5d1e, 0x5d20, + 0x5d20, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d20, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x1078, 0x12cd, + 0x6003, 0x0001, 0x6106, 0x1078, 0x486a, 0x127e, 0x2091, 0x8000, + 0x1078, 0x4c72, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, + 0x486a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, + 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12cd, 0xa1b6, 0x0013, 0x00c0, + 0x5d44, 0x2008, 0x0079, 0x5dcb, 0xa1b6, 0x0027, 0x00c0, 0x5d99, + 0x1078, 0x4b79, 0x6004, 0x1078, 0x6aaf, 0x0040, 0x5d5d, 0x1078, + 0x6ac3, 0x0040, 0x5d91, 0xa08e, 0x0021, 0x0040, 0x5d95, 0xa08e, + 0x0022, 0x0040, 0x5d91, 0x0078, 0x5d8c, 0x1078, 0x22d7, 0x2001, + 0x0007, 0x1078, 0x37c9, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, + 0x5e4d, 0xa186, 0x007e, 0x00c0, 0x5d72, 0x2001, 0x762f, 0x2014, + 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, + 0x1078, 0x495a, 0x1078, 0x489d, 0x0c7e, 0x6018, 0xa065, 0x0040, + 0x5d83, 0x1078, 0x399e, 0x0c7f, 0x2c08, 0x1078, 0x7370, 0x037f, + 0x027f, 0x017f, 0x1078, 0x3805, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x1078, 0x5e4d, 0x0078, 0x5d8c, 0x1078, 0x5e5c, 0x0078, + 0x5d8c, 0xa186, 0x0014, 0x00c0, 0x5d90, 0x1078, 0x4b79, 0x1078, + 0x22b5, 0x1078, 0x6aaf, 0x00c0, 0x5db8, 0x1078, 0x22d7, 0x6018, + 0xa080, 0x0028, 0x200c, 0x1078, 0x5e4d, 0xa186, 0x007e, 0x00c0, + 0x5db6, 0x2001, 0x762f, 0x200c, 0xc185, 0x2102, 0x0078, 0x5d8c, + 0x1078, 0x6ac3, 0x00c0, 0x5dc0, 0x1078, 0x5e4d, 0x0078, 0x5d8c, + 0x6004, 0xa08e, 0x0021, 0x0040, 0x5dbc, 0xa08e, 0x0022, 0x1040, + 0x5e5c, 0x0078, 0x5d8c, 0x5dfd, 0x5dff, 0x5e03, 0x5e07, 0x5e0b, + 0x5e0f, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5e13, 0x5e19, 0x5dfb, 0x5e23, 0x5e19, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5e19, 0x5e19, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x1078, 0x12cd, 0x0078, 0x5e19, 0x2001, + 0x000b, 0x0078, 0x5e2c, 0x2001, 0x0003, 0x0078, 0x5e2c, 0x2001, + 0x0005, 0x0078, 0x5e2c, 0x2001, 0x0001, 0x0078, 0x5e2c, 0x2001, + 0x0009, 0x0078, 0x5e2c, 0x1078, 0x12cd, 0x0078, 0x5e2b, 0x1078, + 0x37c9, 0x1078, 0x4b79, 0x6003, 0x0002, 0x6017, 0x0028, 0x1078, + 0x4c72, 0x0078, 0x5e2b, 0x1078, 0x4b79, 0x6003, 0x0004, 0x6017, + 0x0028, 0x1078, 0x4c72, 0x007c, 0x1078, 0x37c9, 0x1078, 0x4b79, + 0x6003, 0x0002, 0x037e, 0x2019, 0x765c, 0x2304, 0xa084, 0xff00, + 0x00c0, 0x5e3e, 0x2019, 0x0028, 0x0078, 0x5e47, 0x8007, 0xa09a, + 0x0004, 0x0048, 0x5e3a, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, + 0x037f, 0x1078, 0x4c72, 0x0078, 0x5e2b, 0x0e7e, 0x1078, 0x6938, + 0x0040, 0x5e5a, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, + 0x7033, 0x0100, 0x0e7f, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, + 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, 0x0e7f, 0x007c, + 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa0b2, + 0x000c, 0x10c8, 0x12cd, 0x6604, 0xa6b6, 0x0028, 0x00c0, 0x5e7c, + 0x1078, 0x6af8, 0x0078, 0x5eae, 0x6604, 0xa6b6, 0x0029, 0x00c0, + 0x5e85, 0x1078, 0x6b12, 0x0078, 0x5eae, 0x6604, 0xa6b6, 0x001f, + 0x00c0, 0x5e8e, 0x1078, 0x5c8b, 0x0078, 0x5eae, 0x6604, 0xa6b6, + 0x0000, 0x00c0, 0x5e97, 0x1078, 0x5cd0, 0x0078, 0x5eae, 0x6604, + 0xa6b6, 0x0022, 0x00c0, 0x5ea0, 0x1078, 0x5cb4, 0x0078, 0x5eae, + 0xa1b6, 0x0015, 0x00c0, 0x5ea8, 0x1079, 0x5eb3, 0x0078, 0x5eae, + 0xa1b6, 0x0016, 0x00c0, 0x5eaf, 0x1079, 0x5ff0, 0x007c, 0x1078, + 0x5c2f, 0x0078, 0x5eae, 0x5ed7, 0x5eda, 0x5ed7, 0x5f1b, 0x5ed7, + 0x5f8c, 0x5ed7, 0x5ed7, 0x5ed7, 0x5fc8, 0x5ed7, 0x5fde, 0xa1b6, + 0x0048, 0x0040, 0x5ecb, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x1078, 0x156a, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, + 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x0005, + 0x0005, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, 0xa086, 0x0074, + 0x00c0, 0x5f04, 0x1078, 0x7344, 0x00c0, 0x5ef6, 0x0d7e, 0x6018, + 0x2068, 0x1078, 0x5f08, 0x0d7f, 0x2001, 0x0006, 0x1078, 0x37c9, + 0x1078, 0x22d7, 0x1078, 0x5bfa, 0x0078, 0x5f06, 0x2001, 0x000a, + 0x1078, 0x37c9, 0x1078, 0x22d7, 0x6003, 0x0001, 0x6007, 0x0001, + 0x1078, 0x486a, 0x0078, 0x5f06, 0x1078, 0x5f7c, 0x0e7f, 0x007c, + 0x6800, 0xd084, 0x0040, 0x5f1a, 0x2001, 0x0000, 0x1078, 0x37b5, + 0x2069, 0x7651, 0x6804, 0xd0a4, 0x0040, 0x5f1a, 0x2001, 0x0006, + 0x1078, 0x37d7, 0x007c, 0x0d7e, 0x2011, 0x761e, 0x2204, 0xa086, + 0x0074, 0x00c0, 0x5f78, 0x1078, 0x60ca, 0x6018, 0x2068, 0xa080, + 0x0028, 0x2014, 0xa286, 0x007e, 0x0040, 0x5f43, 0xa286, 0x0080, + 0x00c0, 0x5f6c, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, + 0x0040, 0x5f62, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, + 0x0200, 0x0078, 0x5f62, 0x0e7e, 0x0f7e, 0x6813, 0x00ff, 0x6817, + 0xfffe, 0x2071, 0x762f, 0x2e04, 0xa085, 0x0003, 0x2072, 0x2071, + 0x7b80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0x7619, + 0x206a, 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x761a, 0x206a, 0x78ea, + 0x0f7f, 0x0e7f, 0x2001, 0x0006, 0x1078, 0x37c9, 0x1078, 0x22d7, + 0x1078, 0x5bfa, 0x0078, 0x5f7a, 0x2001, 0x0004, 0x1078, 0x37c9, + 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x486a, 0x0078, 0x5f7a, + 0x1078, 0x5f7c, 0x0d7f, 0x007c, 0x2001, 0x7600, 0x2004, 0xa086, + 0x0003, 0x0040, 0x5f87, 0x2001, 0x0007, 0x1078, 0x37c9, 0x1078, + 0x22d7, 0x1078, 0x5bfa, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, + 0xa086, 0x0014, 0x00c0, 0x5fc2, 0x7000, 0xa086, 0x0003, 0x00c0, + 0x5f9f, 0x6010, 0xa005, 0x00c0, 0x5f9f, 0x1078, 0x2db9, 0x0d7e, + 0x6018, 0x2068, 0x1078, 0x3899, 0x1078, 0x5f08, 0x0d7f, 0x1078, + 0x60d4, 0x00c0, 0x5fc2, 0x2001, 0x0006, 0x1078, 0x37c9, 0x0e7e, + 0x6010, 0xa005, 0x0040, 0x5fbb, 0x2070, 0x7007, 0x0000, 0x7037, + 0x0103, 0x7033, 0x0200, 0x0e7f, 0x1078, 0x22d7, 0x1078, 0x5bfa, + 0x0078, 0x5fc6, 0x1078, 0x5e4d, 0x1078, 0x5f7c, 0x0e7f, 0x007c, + 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, 0x5fdb, 0x2001, + 0x0002, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, + 0x486a, 0x0078, 0x5fdd, 0x1078, 0x5f7c, 0x007c, 0x2011, 0x761e, + 0x2204, 0xa086, 0x0004, 0x00c0, 0x5fed, 0x2001, 0x0007, 0x1078, + 0x37c9, 0x1078, 0x5bfa, 0x0078, 0x5fef, 0x1078, 0x5f7c, 0x007c, + 0x5ed7, 0x5ffc, 0x5ed7, 0x6022, 0x5ed7, 0x607d, 0x5ed7, 0x5ed7, + 0x5ed7, 0x6092, 0x5ed7, 0x60a5, 0x0c7e, 0x1078, 0x60b8, 0x00c0, + 0x6011, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, + 0x37c9, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x486a, 0x0078, + 0x6020, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, + 0x00c0, 0x601e, 0x1078, 0x5bfa, 0x0078, 0x6020, 0x1078, 0x5f7c, + 0x0c7f, 0x007c, 0x1078, 0x60c7, 0x00c0, 0x6036, 0x2001, 0x0000, + 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x6003, 0x0001, + 0x6007, 0x0002, 0x1078, 0x486a, 0x0078, 0x6058, 0x1078, 0x5e4d, + 0x2009, 0x7b8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x0040, + 0x6059, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, + 0x00c0, 0x6056, 0xa686, 0x0009, 0x0040, 0x6059, 0x2001, 0x0004, + 0x1078, 0x37c9, 0x1078, 0x5bfa, 0x0078, 0x6058, 0x1078, 0x5f7c, + 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6067, + 0x6838, 0xd0fc, 0x0040, 0x6067, 0x0d7f, 0x0078, 0x6056, 0x6018, + 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x6078, 0x8001, + 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f, 0x0078, 0x6058, + 0x1078, 0x22b5, 0x0d7f, 0x0078, 0x6056, 0x1078, 0x60c7, 0x00c0, + 0x608d, 0x2001, 0x0004, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, + 0x0003, 0x1078, 0x486a, 0x0078, 0x6091, 0x1078, 0x5e4d, 0x1078, + 0x5f7c, 0x007c, 0x1078, 0x60c7, 0x00c0, 0x60a2, 0x2001, 0x0008, + 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, 0x0005, 0x1078, 0x486a, + 0x0078, 0x60a4, 0x1078, 0x5f7c, 0x007c, 0x1078, 0x60c7, 0x00c0, + 0x60b5, 0x2001, 0x000a, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, + 0x0001, 0x1078, 0x486a, 0x0078, 0x60b7, 0x1078, 0x5f7c, 0x007c, + 0x2009, 0x7b8e, 0x2104, 0xa086, 0x0003, 0x00c0, 0x60c6, 0x2009, + 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x007c, 0xa085, + 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, 0x2164, 0x1078, + 0x382f, 0x017f, 0x0c7f, 0x007c, 0x0e7e, 0x2071, 0x7b8c, 0x7004, + 0xa086, 0x0014, 0x00c0, 0x60f7, 0x7008, 0xa086, 0x0800, 0x00c0, + 0x60f7, 0x700c, 0xd0ec, 0x0040, 0x60f5, 0xa084, 0x0f00, 0xa086, + 0x0100, 0x00c0, 0x60f5, 0x7024, 0xd0a4, 0x0040, 0x60f5, 0xd08c, + 0x0040, 0x60f5, 0xa006, 0x0078, 0x60f7, 0xa085, 0x0001, 0x0e7f, + 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, + 0x007e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, 0x2021, + 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7244, 0x7060, + 0xa202, 0x00c8, 0x614e, 0x1078, 0x754e, 0x0040, 0x6146, 0x671c, + 0xa786, 0x0001, 0x0040, 0x6146, 0xa786, 0x0007, 0x0040, 0x6146, + 0x2500, 0xac06, 0x0040, 0x6146, 0x2400, 0xac06, 0x0040, 0x6146, + 0x0c7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x6130, 0x1078, 0x166e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6143, 0xa786, 0x0003, + 0x00c0, 0x6158, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x0c7f, 0xace0, 0x0008, + 0x7054, 0xac02, 0x00c8, 0x614e, 0x0078, 0x610e, 0x127f, 0x007f, + 0x027f, 0x047f, 0x057f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0xa786, 0x0006, 0x00c0, 0x613a, 0x1078, 0x74f2, 0x0078, 0x6143, + 0x220c, 0x2304, 0xa106, 0x00c0, 0x616b, 0x8210, 0x8318, 0x00f0, + 0x6160, 0xa006, 0x007c, 0x2304, 0xa102, 0x0048, 0x6173, 0x2001, + 0x0001, 0x0078, 0x6175, 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, + 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x1078, 0x6aaf, 0x0040, + 0x6187, 0x1078, 0x6ac3, 0x0040, 0x6190, 0x0078, 0x6189, 0x1078, + 0x22d7, 0x1078, 0x4b79, 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, + 0x1078, 0x5e4d, 0x0078, 0x6189, 0xa182, 0x0040, 0x0079, 0x6198, + 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, + 0x61a8, 0x61a8, 0x61a8, 0x61aa, 0x61aa, 0x61aa, 0x61aa, 0x61a8, + 0x1078, 0x12cd, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, + 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0xa186, 0x0013, + 0x00c0, 0x61bf, 0x6004, 0xa082, 0x0040, 0x0079, 0x6235, 0xa186, + 0x0027, 0x00c0, 0x61dc, 0x1078, 0x4b79, 0x1078, 0x22b5, 0x0d7e, + 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, 0x61d6, 0x6837, 0x0103, + 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0xa186, 0x0014, 0x00c0, 0x61e5, + 0x6004, 0xa082, 0x0040, 0x0079, 0x6205, 0xa186, 0x0047, 0x10c0, + 0x12cd, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, 0x6202, 0x127e, + 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, 0x46de, 0x027f, + 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, 0x00c0, 0x6202, + 0x0078, 0x625c, 0x1078, 0x5c2f, 0x007c, 0x6217, 0x6215, 0x6215, + 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, + 0x622e, 0x622e, 0x622e, 0x622e, 0x6215, 0x1078, 0x12cd, 0x1078, + 0x4b79, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, 0x6228, + 0x6837, 0x0103, 0x684b, 0x0006, 0x1078, 0x3a72, 0x1078, 0x6a89, + 0x0d7f, 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x1078, 0x4b79, + 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x6247, 0x6245, 0x6245, + 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, + 0x6255, 0x6255, 0x6255, 0x6255, 0x6245, 0x1078, 0x12cd, 0x1078, + 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, 0x6010, 0xa088, 0x0013, + 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, 0x4b79, 0x6003, + 0x000f, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x6260, + 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6272, 0x62fb, 0x6313, + 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, + 0x1078, 0x12cd, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, 0x6110, 0x2168, + 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, 0x62df, 0xa68c, 0x00ff, + 0xa186, 0x0002, 0x0040, 0x62a4, 0xa186, 0x0028, 0x00c0, 0x628e, + 0x1078, 0x6a9d, 0x684b, 0x001c, 0x0078, 0x62a6, 0xd6dc, 0x0040, + 0x6299, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, + 0x62a6, 0xd6d4, 0x0040, 0x62a4, 0x684b, 0x0007, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0x0078, 0x62a6, 0x684b, 0x0000, 0x6837, 0x0103, + 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x62b9, 0x7328, 0x732c, 0x6b56, + 0x037e, 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, + 0x037f, 0xd6cc, 0x0040, 0x62ef, 0x7124, 0x695a, 0xa192, 0x0021, + 0x00c8, 0x62cd, 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, + 0x001d, 0x1078, 0x6721, 0x0078, 0x62ef, 0x6838, 0xd0fc, 0x0040, + 0x62d6, 0x2009, 0x0020, 0x695a, 0x0078, 0x62c2, 0x0f7e, 0x2d78, + 0x1078, 0x66b9, 0x0f7f, 0x1078, 0x670e, 0x0078, 0x62f1, 0x684b, + 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x62ef, + 0x6810, 0x6914, 0xa115, 0x0040, 0x62ef, 0x1078, 0x6467, 0x1078, + 0x3a72, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x0d7f, 0x0e7f, + 0x1078, 0x5bfa, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0x7b8c, + 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, + 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19c7, 0x1078, 0x4889, + 0x1078, 0x4d32, 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, + 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, 0x007c, 0xa182, 0x0040, + 0x0079, 0x6322, 0x6332, 0x6332, 0x6332, 0x6332, 0x6332, 0x6334, + 0x63cb, 0x6332, 0x6332, 0x63e1, 0x6443, 0x6332, 0x6332, 0x6332, + 0x6332, 0x644e, 0x1078, 0x12cd, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, + 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0040, 0x63c6, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, + 0x6355, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, + 0x63c6, 0x1078, 0x1327, 0x1040, 0x12cd, 0x2d00, 0x784a, 0x7f4c, + 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, + 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, + 0x638f, 0xa186, 0x0028, 0x00c0, 0x6379, 0x684b, 0x001c, 0x0078, + 0x6391, 0xd6dc, 0x0040, 0x6384, 0x684b, 0x0015, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0x0078, 0x6391, 0xd6d4, 0x0040, 0x638f, 0x684b, + 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x6391, 0x684b, + 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, + 0x0040, 0x63a6, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, + 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, 0x037f, 0xd6cc, 0x0040, + 0x63c6, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x63ba, 0x2071, + 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x6721, + 0x0078, 0x63c6, 0x7838, 0xd0fc, 0x0040, 0x63c3, 0x2009, 0x0020, + 0x695a, 0x0078, 0x63af, 0x2d78, 0x1078, 0x66b9, 0x0d7f, 0x0e7f, + 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0x7b8c, + 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, + 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19c7, 0x1078, 0x555f, + 0x007c, 0x0d7e, 0x6003, 0x0002, 0x1078, 0x4c21, 0x1078, 0x4d32, + 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x6441, 0xd1cc, 0x0040, + 0x641c, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x6414, 0x017e, 0x684c, + 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, + 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x00f0, + 0x6403, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, 0x2168, + 0x1078, 0x1350, 0x0078, 0x643f, 0x017e, 0x1078, 0x1350, 0x0d7f, + 0x1078, 0x670e, 0x0078, 0x643f, 0x6837, 0x0103, 0x6944, 0xa184, + 0x00ff, 0xa186, 0x0002, 0x0040, 0x643b, 0xa086, 0x0028, 0x00c0, + 0x642d, 0x684b, 0x001c, 0x0078, 0x643d, 0xd1dc, 0x0040, 0x6434, + 0x684b, 0x0015, 0x0078, 0x643d, 0xd1d4, 0x0040, 0x643b, 0x684b, + 0x0007, 0x0078, 0x643d, 0x684b, 0x0000, 0x1078, 0x3a72, 0x1078, + 0x5bfa, 0x0d7f, 0x007c, 0x2019, 0x0001, 0x1078, 0x5760, 0x6003, + 0x0002, 0x1078, 0x4c21, 0x1078, 0x4d32, 0x007c, 0x1078, 0x4c21, + 0x1078, 0x22b5, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, + 0x6461, 0x6837, 0x0103, 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, + 0x6a89, 0x0d7f, 0x1078, 0x5bfa, 0x1078, 0x4d32, 0x007c, 0x684b, + 0x0015, 0xd1fc, 0x0040, 0x6473, 0x684b, 0x0007, 0x8002, 0x8000, + 0x810a, 0xa189, 0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, + 0x0079, 0x647a, 0x648a, 0x648a, 0x648a, 0x648a, 0x648a, 0x648c, + 0x648a, 0x6530, 0x6538, 0x648a, 0x648a, 0x648a, 0x648a, 0x648a, + 0x648a, 0x648a, 0x1078, 0x12cd, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, + 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0040, 0x6522, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, + 0x64ad, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, + 0x651f, 0x1078, 0x1327, 0x1040, 0x12cd, 0x2d00, 0x784a, 0x7f4c, + 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, + 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, + 0x0040, 0x64e8, 0xa186, 0x0028, 0x00c0, 0x64d2, 0x684b, 0x001c, + 0x0078, 0x64ea, 0xd6dc, 0x0040, 0x64dd, 0x684b, 0x0015, 0x7318, + 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64ea, 0xd6d4, 0x0040, 0x64e8, + 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64ea, + 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, + 0xd6c4, 0x0040, 0x64ff, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, + 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, 0x037f, 0xd6cc, + 0x0040, 0x651f, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x6513, + 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, + 0x6721, 0x0078, 0x651f, 0x7838, 0xd0fc, 0x0040, 0x651c, 0x2009, + 0x0020, 0x695a, 0x0078, 0x6508, 0x2d78, 0x1078, 0x66b9, 0xd6dc, + 0x00c0, 0x6525, 0xa006, 0x0078, 0x6529, 0x2001, 0x0001, 0x7218, + 0x731c, 0x1078, 0x15ae, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, 0x007c, + 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, + 0x659f, 0xd1cc, 0x0040, 0x656f, 0x6948, 0x6838, 0xd0fc, 0x0040, + 0x6567, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, + 0xa198, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, + 0x8318, 0x8210, 0x00f0, 0x6556, 0x157f, 0x007f, 0x6852, 0x007f, + 0x684e, 0x017f, 0x2168, 0x1078, 0x1350, 0x0078, 0x659d, 0x017e, + 0x1078, 0x1350, 0x0d7f, 0x1078, 0x670e, 0x0078, 0x659d, 0x6837, + 0x0103, 0x6944, 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x658e, + 0xa086, 0x0028, 0x00c0, 0x6580, 0x684b, 0x001c, 0x0078, 0x659b, + 0xd1dc, 0x0040, 0x6587, 0x684b, 0x0015, 0x0078, 0x659b, 0xd1d4, + 0x0040, 0x658e, 0x684b, 0x0007, 0x0078, 0x659b, 0x684b, 0x0000, + 0x684c, 0xd0ac, 0x0040, 0x659b, 0x6810, 0x6914, 0xa115, 0x0040, + 0x659b, 0x1078, 0x6467, 0x1078, 0x3a72, 0x1078, 0x5bfa, 0x0d7f, + 0x007c, 0x1078, 0x4b79, 0x0078, 0x65a7, 0x1078, 0x4c21, 0x1078, + 0x6938, 0x0040, 0x65be, 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, + 0x2009, 0x760c, 0x210c, 0xd18c, 0x00c0, 0x65c7, 0xd184, 0x00c0, + 0x65c3, 0x6108, 0x694a, 0x1078, 0x3a72, 0x0d7f, 0x1078, 0x5bfa, + 0x1078, 0x4c72, 0x007c, 0x684b, 0x0004, 0x0078, 0x65bb, 0x684b, + 0x0004, 0x0078, 0x65bb, 0xa182, 0x0040, 0x0079, 0x65cf, 0x65df, + 0x65df, 0x65df, 0x65df, 0x65df, 0x65e1, 0x65df, 0x65e4, 0x65df, + 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x1078, + 0x12cd, 0x1078, 0x5bfa, 0x007c, 0x007e, 0x027e, 0xa016, 0x1078, + 0x156a, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, 0x65f0, + 0x65f9, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x1078, + 0x12cd, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, 0x2091, + 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, + 0x660f, 0x6004, 0xa082, 0x0085, 0x2008, 0x0079, 0x6643, 0xa186, + 0x0027, 0x00c0, 0x6630, 0x1078, 0x4b79, 0x1078, 0x22b5, 0x0d7e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6626, 0x6837, 0x0103, + 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x1078, 0x5c2f, 0x0078, 0x662b, + 0xa186, 0x0014, 0x00c0, 0x662c, 0x1078, 0x4b79, 0x0d7e, 0x6010, + 0x2068, 0x1078, 0x6938, 0x0040, 0x6626, 0x6837, 0x0103, 0x684b, + 0x0006, 0x0078, 0x6622, 0x664c, 0x664a, 0x664a, 0x664a, 0x664a, + 0x664a, 0x6655, 0x1078, 0x12cd, 0x1078, 0x4b79, 0x6017, 0x0014, + 0x6003, 0x000c, 0x1078, 0x4c72, 0x007c, 0x1078, 0x4b79, 0x6017, + 0x0014, 0x6003, 0x000e, 0x1078, 0x4c72, 0x007c, 0xa182, 0x008c, + 0x00c8, 0x6668, 0xa182, 0x0085, 0x0048, 0x6668, 0x0079, 0x666b, + 0x1078, 0x5c2f, 0x007c, 0x6672, 0x6672, 0x6672, 0x6672, 0x6674, + 0x6693, 0x6672, 0x1078, 0x12cd, 0x0d7e, 0x1078, 0x6a89, 0x1078, + 0x6938, 0x0040, 0x668f, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, + 0xd0b4, 0x0040, 0x6687, 0x684b, 0x0006, 0x0078, 0x668b, 0x684b, + 0x0005, 0x1078, 0x6b3c, 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, + 0x5bfa, 0x0d7f, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x66ae, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x66a4, + 0x684b, 0x0006, 0x0078, 0x66a8, 0x684b, 0x0005, 0x1078, 0x6b3c, + 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x007c, 0x1078, 0x4b79, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, + 0x0101, 0x00c8, 0x66c5, 0x0078, 0x66c7, 0x2009, 0x0100, 0x2130, + 0x2069, 0x7b98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, + 0x001d, 0x1078, 0x6721, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, + 0x66db, 0x1078, 0x1350, 0x1078, 0x1327, 0x0040, 0x6705, 0x8528, + 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, + 0x00c8, 0x66f1, 0x2608, 0xad90, 0x000f, 0x1078, 0x6721, 0x0078, + 0x6705, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, + 0x1078, 0x6721, 0x0078, 0x66db, 0x0f7f, 0x852f, 0xa5ad, 0x0003, + 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x670a, 0x0f7f, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, + 0x0040, 0x671f, 0x6804, 0xa07d, 0x0040, 0x671d, 0x6807, 0x0000, + 0x1078, 0x3a72, 0x2f68, 0x0078, 0x6712, 0x1078, 0x3a72, 0x0f7f, + 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x6727, 0x8108, 0x810c, + 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x6729, + 0x157f, 0x007c, 0x127e, 0x2091, 0x8000, 0x601c, 0xa084, 0x000f, + 0x1079, 0x673c, 0x127f, 0x007c, 0x674b, 0x6744, 0x6746, 0x6764, + 0x6744, 0x6746, 0x6746, 0x6746, 0x1078, 0x12cd, 0xa006, 0x007c, + 0xa085, 0x0001, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x6761, 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b02, 0x1078, + 0x6b3c, 0x1078, 0x3a72, 0x1078, 0x5bfa, 0xa085, 0x0001, 0x0d7f, + 0x007c, 0xa006, 0x0078, 0x675f, 0x6000, 0xa08a, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x676c, 0x007c, 0x677c, 0x6799, 0x677e, 0x67aa, + 0x6795, 0x677c, 0x6746, 0x674b, 0x674b, 0x6746, 0x6746, 0x6746, + 0x6746, 0x6746, 0x6746, 0x6746, 0x1078, 0x12cd, 0x0d7e, 0x6010, + 0x2068, 0x1078, 0x6938, 0x0040, 0x6787, 0x1078, 0x6b3c, 0x0d7f, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x481d, + 0x1078, 0x4c72, 0xa085, 0x0001, 0x007c, 0x1078, 0x166e, 0x0078, + 0x677e, 0x0e7e, 0x2071, 0x7836, 0x7024, 0xac06, 0x00c0, 0x67a2, + 0x1078, 0x56ce, 0x1078, 0x5603, 0x0e7f, 0x00c0, 0x677e, 0x1078, + 0x6746, 0x007c, 0x037e, 0x0e7e, 0x2071, 0x7836, 0x703c, 0xac06, + 0x00c0, 0x67ba, 0x2019, 0x0000, 0x1078, 0x5760, 0x0e7f, 0x037f, + 0x0078, 0x677e, 0x1078, 0x5a3c, 0x0e7f, 0x037f, 0x00c0, 0x677e, + 0x1078, 0x6746, 0x007c, 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, + 0x67cb, 0x0c7f, 0x007c, 0x67da, 0x6837, 0x68dc, 0x67de, 0x67da, + 0x67da, 0x71d2, 0x5bfa, 0x6837, 0x1078, 0x6ac3, 0x00c0, 0x67da, + 0x1078, 0x5e4d, 0x007c, 0x6017, 0x0001, 0x007c, 0x6000, 0xa08a, + 0x0010, 0x10c8, 0x12cd, 0x1079, 0x67e6, 0x007c, 0x67f6, 0x67f8, + 0x6818, 0x682a, 0x682a, 0x67f6, 0x67da, 0x67da, 0x67da, 0x682a, + 0x682a, 0x67f6, 0x67f6, 0x67f6, 0x67f6, 0x6834, 0x1078, 0x12cd, + 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x7836, + 0x7024, 0xac06, 0x0040, 0x6814, 0x1078, 0x5603, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x6017, 0x0014, 0x1078, 0x481d, + 0x1078, 0x4c72, 0x0e7f, 0x007c, 0x6017, 0x0001, 0x0078, 0x6812, + 0x0d7e, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x6007, + 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x481d, 0x1078, + 0x4c72, 0x007c, 0x0d7e, 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, + 0xc0b5, 0x6852, 0x0d7f, 0x007c, 0x1078, 0x5bfa, 0x007c, 0x6000, + 0xa08a, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x683f, 0x007c, 0x684f, + 0x67db, 0x6851, 0x684f, 0x6851, 0x684f, 0x684f, 0x684f, 0x67d4, + 0x67d4, 0x684f, 0x684f, 0x684f, 0x684f, 0x684f, 0x684f, 0x1078, + 0x12cd, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, + 0xa08a, 0x000c, 0x10c8, 0x12cd, 0x1079, 0x685f, 0x007c, 0x686b, + 0x688a, 0x686b, 0x688a, 0x686b, 0x688a, 0x686d, 0x6876, 0x686b, + 0x688a, 0x686b, 0x6883, 0x1078, 0x12cd, 0x6004, 0xa08e, 0x0004, + 0x0040, 0x6885, 0xa08e, 0x0002, 0x0040, 0x6885, 0x6004, 0x1078, + 0x6ac3, 0x0040, 0x68d4, 0xa08e, 0x0021, 0x0040, 0x68d8, 0xa08e, + 0x0022, 0x0040, 0x68d4, 0x1078, 0x22b5, 0x1078, 0x5e4d, 0x1078, + 0x5bfa, 0x007c, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, + 0x68c4, 0xa186, 0x0002, 0x00c0, 0x68b3, 0x6018, 0x2068, 0x68a0, + 0xd0bc, 0x00c0, 0x68b3, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, + 0x68b3, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, + 0x0398, 0x1078, 0x5b94, 0x0040, 0x68b3, 0x2d00, 0x601a, 0x601f, + 0x0001, 0x0078, 0x68c4, 0x0d7f, 0x0c7f, 0x1078, 0x5e4d, 0x1078, + 0x22b5, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x22d7, 0x127f, + 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x2001, 0x0002, 0x1078, 0x37c9, + 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x486a, 0x1078, 0x4c72, + 0x0d7f, 0x0c7f, 0x0078, 0x68c3, 0x1078, 0x5e4d, 0x0078, 0x6887, + 0x1078, 0x5e5c, 0x0078, 0x6887, 0x6000, 0xa08a, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x68e4, 0x007c, 0x68f4, 0x68f4, 0x68f4, 0x68f4, + 0x68f4, 0x68f4, 0x68f4, 0x68f4, 0x68f4, 0x67da, 0x68f4, 0x67db, + 0x68f6, 0x67db, 0x68ff, 0x68f4, 0x1078, 0x12cd, 0x6007, 0x008b, + 0x6003, 0x000d, 0x1078, 0x481d, 0x1078, 0x4c72, 0x007c, 0x1078, + 0x6a89, 0x1078, 0x6938, 0x0040, 0x6921, 0x1078, 0x22b5, 0x0d7e, + 0x1078, 0x6938, 0x0040, 0x6914, 0x6010, 0x2068, 0x6837, 0x0103, + 0x684b, 0x0006, 0x1078, 0x3a72, 0x0d7f, 0x601f, 0x0001, 0x6007, + 0x0001, 0x6003, 0x0001, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0078, + 0x6923, 0x1078, 0x5bfa, 0x007c, 0xa284, 0x0007, 0x00c0, 0x6935, + 0xa282, 0x7d00, 0x0048, 0x6935, 0x2001, 0x7615, 0x2004, 0xa202, + 0x00c8, 0x6935, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x6934, + 0x027e, 0x0e7e, 0x2071, 0x7600, 0x6210, 0x7058, 0xa202, 0x0048, + 0x694a, 0x705c, 0xa202, 0x00c8, 0x694a, 0xa085, 0x0001, 0x0e7f, + 0x027f, 0x007c, 0xa006, 0x0078, 0x6947, 0x0e7e, 0x0c7e, 0x037e, + 0x007e, 0x127e, 0x2091, 0x8000, 0x2061, 0x7d00, 0x2071, 0x7600, + 0x7344, 0x7060, 0xa302, 0x00c8, 0x6973, 0x601c, 0xa206, 0x00c0, + 0x696b, 0x1078, 0x6ac3, 0x00c0, 0x6967, 0x1078, 0x5e4d, 0x0c7e, + 0x1078, 0x5bfa, 0x0c7f, 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, + 0x6973, 0x0078, 0x6958, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0x7720, 0x210c, 0x81ff, + 0x0040, 0x6991, 0x2061, 0x7d00, 0x2071, 0x7600, 0x017e, 0x1078, + 0x5b94, 0x017f, 0x0040, 0x6994, 0x611a, 0x1078, 0x22b5, 0x1078, + 0x5bfa, 0xa006, 0x0078, 0x6996, 0xa085, 0x0001, 0x017f, 0x0c7f, + 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x5b94, 0x057f, 0x0040, 0x69b3, 0x6612, 0x651a, 0x601f, + 0x0003, 0x2009, 0x004b, 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x69af, 0x0c7e, 0x057e, + 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x5b94, 0x057f, + 0x0040, 0x69dd, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, + 0x2560, 0x1078, 0x399e, 0x0c7f, 0x1078, 0x495a, 0x1078, 0x489d, + 0x2c08, 0x1078, 0x7370, 0x2009, 0x004c, 0x1078, 0x5c21, 0xa085, + 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x69d9, + 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, + 0x5b94, 0x057f, 0x0040, 0x6a08, 0x6612, 0x651a, 0x601f, 0x0003, + 0x2019, 0x0005, 0x0c7e, 0x2560, 0x1078, 0x399e, 0x0c7f, 0x1078, + 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x2009, 0x004d, + 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, + 0xa006, 0x0078, 0x6a04, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, + 0x62a0, 0x0c7e, 0x1078, 0x5b94, 0x057f, 0x0040, 0x6a33, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, 0x0c7e, 0x2560, 0x1078, - 0x39a6, 0x0c7f, 0x1078, 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, - 0x737b, 0x2009, 0x004d, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, - 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a0f, 0x0c7e, 0x057e, - 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x5b9c, 0x057f, - 0x0040, 0x6a3e, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, - 0x0c7e, 0x2560, 0x1078, 0x39a6, 0x0c7f, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x2c08, 0x1078, 0x737b, 0x2009, 0x004e, 0x1078, 0x5c29, - 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x6a3a, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, - 0x017f, 0x0040, 0x6a5a, 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, - 0x6012, 0x2009, 0x001f, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, - 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a57, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x6a76, 0x660a, - 0x611a, 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x1078, - 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x6a73, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, - 0x017f, 0x0040, 0x6a91, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, - 0x2009, 0x0000, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, - 0x007c, 0xa006, 0x0078, 0x6a8e, 0x027e, 0x0d7e, 0x6218, 0x2268, - 0x6a3c, 0x82ff, 0x0040, 0x6a9e, 0x8211, 0x6a3e, 0x0d7f, 0x027f, - 0x007c, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0014, 0x007c, - 0x067e, 0x0c7e, 0x0d7e, 0x2031, 0x7652, 0x2634, 0xd6e4, 0x0040, - 0x6ab6, 0x6618, 0x2660, 0x6e44, 0x1078, 0x38de, 0x0d7f, 0x0c7f, - 0x067f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, - 0x6acb, 0xa08e, 0x0003, 0x0040, 0x6acb, 0xa08e, 0x0004, 0x0040, - 0x6acb, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x007e, 0x017e, - 0x6004, 0xa08e, 0x0000, 0x0040, 0x6ae3, 0xa08e, 0x001f, 0x0040, - 0x6ae3, 0xa08e, 0x0028, 0x0040, 0x6ae3, 0xa08e, 0x0029, 0x0040, - 0x6ae3, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x127e, - 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x6b00, - 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x1078, 0x22bb, 0x2009, - 0x0028, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x6afd, 0xa186, 0x0015, 0x00c0, 0x6b18, 0x2011, - 0x761e, 0x2204, 0xa086, 0x0074, 0x00c0, 0x6b18, 0x1078, 0x60d4, - 0x6003, 0x0001, 0x6007, 0x0029, 0x1078, 0x4872, 0x0078, 0x6b1c, - 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, 0xa186, 0x0015, 0x00c0, - 0x6b3a, 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, 0x6b3a, - 0x0d7e, 0x6018, 0x2068, 0x1078, 0x38a1, 0x0d7f, 0x1078, 0x60de, - 0x00c0, 0x6b3a, 0x2001, 0x0006, 0x1078, 0x37d1, 0x1078, 0x5cad, - 0x0078, 0x6b3e, 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, 0x6848, - 0xa086, 0x0005, 0x00c0, 0x6b46, 0x1078, 0x6b47, 0x007c, 0x6850, - 0xc0ad, 0x6852, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x6b55, 0x067f, 0x007c, 0x6b65, 0x6d3c, 0x6e1d, - 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b9f, 0x6e8b, 0x6b65, - 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x1078, 0x12d5, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x6b71, 0x067f, - 0x007c, 0x6b81, 0x718c, 0x6b81, 0x6b81, 0x6b81, 0x6b81, 0x6b81, - 0x6b81, 0x7167, 0x71d6, 0x6b81, 0x6b81, 0x6b81, 0x6b81, 0x6b81, - 0x6b81, 0x1078, 0x12d5, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x6b8d, 0x067f, 0x007c, 0x6b9d, 0x6fd8, 0x704a, - 0x706c, 0x70b8, 0x6b9d, 0x6b9d, 0x7112, 0x6e97, 0x714f, 0x7153, - 0x6b9d, 0x6b9d, 0x6b9d, 0x6b9d, 0x6b9d, 0x1078, 0x12d5, 0xa1b2, - 0x0030, 0x10c8, 0x12d5, 0x2100, 0x0079, 0x6ba6, 0x6bd6, 0x6cb3, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd8, 0x6c07, 0x6c12, - 0x6c3a, 0x6c40, 0x6c74, 0x6cac, 0x6bd6, 0x6bd6, 0x6cbb, 0x6bd6, - 0x6bd6, 0x6cc2, 0x6cc9, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6ce6, 0x6bd6, 0x6bd6, 0x6cf1, 0x6bd6, 0x6bd6, 0x1078, 0x12d5, - 0x1078, 0x3a26, 0x6618, 0x0c7e, 0x2660, 0x1078, 0x3837, 0x0c7f, + 0x399e, 0x0c7f, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, + 0x7370, 0x2009, 0x004e, 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a2f, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x6a4f, + 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, + 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, + 0x0078, 0x6a4c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x5b94, 0x017f, 0x0040, 0x6a6b, 0x660a, 0x611a, 0x601f, 0x0008, + 0x2d00, 0x6012, 0x2009, 0x0021, 0x1078, 0x5c21, 0xa085, 0x0001, + 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a68, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x6a86, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x1078, + 0x5c21, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x6a83, 0x027e, 0x0d7e, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0040, + 0x6a93, 0x8211, 0x6a3e, 0x0d7f, 0x027f, 0x007c, 0x6013, 0x0000, + 0x601f, 0x0007, 0x6017, 0x0014, 0x007c, 0x067e, 0x0c7e, 0x0d7e, + 0x2031, 0x7652, 0x2634, 0xd6e4, 0x0040, 0x6aab, 0x6618, 0x2660, + 0x6e44, 0x1078, 0x38d6, 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, + 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, 0x6ac0, 0xa08e, 0x0003, + 0x0040, 0x6ac0, 0xa08e, 0x0004, 0x0040, 0x6ac0, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0000, + 0x0040, 0x6ad8, 0xa08e, 0x001f, 0x0040, 0x6ad8, 0xa08e, 0x0028, + 0x0040, 0x6ad8, 0xa08e, 0x0029, 0x0040, 0x6ad8, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x5b94, 0x017f, 0x0040, 0x6af5, 0x611a, 0x601f, 0x0001, + 0x2d00, 0x6012, 0x1078, 0x22b5, 0x2009, 0x0028, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6af2, + 0xa186, 0x0015, 0x00c0, 0x6b0d, 0x2011, 0x761e, 0x2204, 0xa086, + 0x0074, 0x00c0, 0x6b0d, 0x1078, 0x60ca, 0x6003, 0x0001, 0x6007, + 0x0029, 0x1078, 0x486a, 0x0078, 0x6b11, 0x1078, 0x5e4d, 0x1078, + 0x5bfa, 0x007c, 0xa186, 0x0015, 0x00c0, 0x6b2f, 0x2011, 0x761e, + 0x2204, 0xa086, 0x0014, 0x00c0, 0x6b2f, 0x0d7e, 0x6018, 0x2068, + 0x1078, 0x3899, 0x0d7f, 0x1078, 0x60d4, 0x00c0, 0x6b2f, 0x2001, + 0x0006, 0x1078, 0x37c9, 0x1078, 0x5ca5, 0x0078, 0x6b33, 0x1078, + 0x5e4d, 0x1078, 0x5bfa, 0x007c, 0x6848, 0xa086, 0x0005, 0x00c0, + 0x6b3b, 0x1078, 0x6b3c, 0x007c, 0x6850, 0xc0ad, 0x6852, 0x007c, + 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x6b4a, + 0x067f, 0x007c, 0x6b5a, 0x6d31, 0x6e12, 0x6b5a, 0x6b5a, 0x6b5a, + 0x6b5a, 0x6b5a, 0x6b94, 0x6e80, 0x6b5a, 0x6b5a, 0x6b5a, 0x6b5a, + 0x6b5a, 0x6b5a, 0x1078, 0x12cd, 0x067e, 0x6000, 0xa0b2, 0x0010, + 0x10c8, 0x12cd, 0x1079, 0x6b66, 0x067f, 0x007c, 0x6b76, 0x7181, + 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x715c, 0x71cb, + 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x1078, 0x12cd, + 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x6b82, + 0x067f, 0x007c, 0x6b92, 0x6fcd, 0x703f, 0x7061, 0x70ad, 0x6b92, + 0x6b92, 0x7107, 0x6e8c, 0x7144, 0x7148, 0x6b92, 0x6b92, 0x6b92, + 0x6b92, 0x6b92, 0x1078, 0x12cd, 0xa1b2, 0x0030, 0x10c8, 0x12cd, + 0x2100, 0x0079, 0x6b9b, 0x6bcb, 0x6ca8, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcd, 0x6bfc, 0x6c07, 0x6c2f, 0x6c35, 0x6c69, + 0x6ca1, 0x6bcb, 0x6bcb, 0x6cb0, 0x6bcb, 0x6bcb, 0x6cb7, 0x6cbe, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6cdb, 0x6bcb, 0x6bcb, + 0x6ce6, 0x6bcb, 0x6bcb, 0x1078, 0x12cd, 0x1078, 0x3a1e, 0x6618, + 0x0c7e, 0x2660, 0x1078, 0x382f, 0x0c7f, 0xa6b0, 0x0001, 0x2634, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x6bee, 0x1078, 0x72ac, + 0x00c0, 0x6c29, 0x1078, 0x724a, 0x00c0, 0x6bea, 0x6007, 0x0008, + 0x0078, 0x6ca3, 0x6007, 0x0009, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6bf8, 0x1078, 0x72ac, 0x0040, 0x6be2, 0x0078, 0x6c29, + 0x6013, 0x1900, 0x0078, 0x6bea, 0x6106, 0x1078, 0x720c, 0x6007, + 0x0006, 0x0078, 0x6ca3, 0x6007, 0x0007, 0x0078, 0x6ca3, 0x0d7e, + 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, + 0x0040, 0x6c19, 0xa686, 0x0004, 0x0040, 0x6c19, 0x0d7f, 0x0078, + 0x6c29, 0x1078, 0x730a, 0x00c0, 0x6c24, 0x1078, 0x3899, 0x6007, + 0x000a, 0x0d7f, 0x0078, 0x6ca3, 0x6007, 0x000b, 0x0d7f, 0x0078, + 0x6ca3, 0x1078, 0x22b5, 0x6007, 0x0001, 0x0078, 0x6ca3, 0x1078, + 0x22b5, 0x6007, 0x000c, 0x0078, 0x6ca3, 0x1078, 0x3a1e, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, - 0x6bf9, 0x1078, 0x72b7, 0x00c0, 0x6c34, 0x1078, 0x7255, 0x00c0, - 0x6bf5, 0x6007, 0x0008, 0x0078, 0x6cae, 0x6007, 0x0009, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6c03, 0x1078, 0x72b7, 0x0040, - 0x6bed, 0x0078, 0x6c34, 0x6013, 0x1900, 0x0078, 0x6bf5, 0x6106, - 0x1078, 0x7217, 0x6007, 0x0006, 0x0078, 0x6cae, 0x6007, 0x0007, - 0x0078, 0x6cae, 0x0d7e, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, - 0x8637, 0xa686, 0x0006, 0x0040, 0x6c24, 0xa686, 0x0004, 0x0040, - 0x6c24, 0x0d7f, 0x0078, 0x6c34, 0x1078, 0x7315, 0x00c0, 0x6c2f, - 0x1078, 0x38a1, 0x6007, 0x000a, 0x0d7f, 0x0078, 0x6cae, 0x6007, - 0x000b, 0x0d7f, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x0001, - 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x000c, 0x0078, 0x6cae, - 0x1078, 0x3a26, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, - 0xa082, 0x0006, 0x0048, 0x6c61, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0006, 0x00c0, 0x6c34, 0x1078, 0x7324, 0x00c0, 0x6c5b, 0x6007, - 0x000e, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x000f, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6c6e, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0040, 0x6c53, 0x0078, 0x6c34, 0x6013, 0x1900, - 0x6007, 0x0009, 0x0078, 0x6cae, 0x1078, 0x3a26, 0x6618, 0xa6b0, - 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x6c99, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x00c0, 0x6c34, 0x1078, - 0x734f, 0x00c0, 0x6c93, 0x1078, 0x7255, 0x00c0, 0x6c93, 0x6007, - 0x0010, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x0011, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6ca6, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0040, 0x6c87, 0x0078, 0x6c34, 0x6013, 0x1900, - 0x6007, 0x0009, 0x0078, 0x6cae, 0x6007, 0x0012, 0x6003, 0x0001, - 0x1078, 0x4872, 0x007c, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, - 0x4872, 0x0078, 0x6cb2, 0x6007, 0x0020, 0x6003, 0x0001, 0x1078, - 0x4872, 0x007c, 0x6007, 0x0023, 0x6003, 0x0001, 0x1078, 0x4872, - 0x007c, 0x017e, 0x027e, 0x2011, 0x7b88, 0x2214, 0x2c08, 0x1078, - 0x7514, 0x00c0, 0x6cda, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, - 0x0078, 0x6cdf, 0x1078, 0x5c02, 0x2160, 0x6007, 0x0025, 0x6003, - 0x0001, 0x1078, 0x4872, 0x027f, 0x017f, 0x007c, 0x6106, 0x1078, - 0x6cf8, 0x6007, 0x002b, 0x0078, 0x6cae, 0x6007, 0x002c, 0x0078, - 0x6cae, 0x6106, 0x1078, 0x6cfd, 0x6007, 0x002e, 0x0078, 0x6cae, - 0x0d7e, 0x1078, 0x6d23, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x6d32, - 0x00c0, 0x6d1c, 0x680c, 0xa08c, 0xff00, 0x6824, 0xa084, 0x00ff, - 0xa115, 0x6212, 0xd1e4, 0x0040, 0x6d11, 0x2009, 0x0001, 0x0078, - 0x6d18, 0xd1ec, 0x0040, 0x6d1c, 0x2009, 0x0000, 0xa294, 0x00ff, - 0x1078, 0x22ff, 0x0078, 0x6d20, 0xa085, 0x0001, 0x0078, 0x6d21, - 0xa006, 0x0d7f, 0x007c, 0x2069, 0x7b8d, 0x6800, 0xa082, 0x0010, - 0x00c8, 0x6d30, 0x6013, 0x0000, 0xa085, 0x0001, 0x0078, 0x6d31, - 0xa006, 0x007c, 0x6013, 0x0000, 0x2069, 0x7b8c, 0x6808, 0xa084, - 0xff00, 0xa086, 0x0800, 0x007c, 0x6004, 0xa0b2, 0x0030, 0x10c8, - 0x12d5, 0xa1b6, 0x0013, 0x00c0, 0x6d48, 0x2008, 0x0079, 0x6d5b, - 0xa1b6, 0x0027, 0x0040, 0x6d50, 0xa1b6, 0x0014, 0x10c0, 0x12d5, - 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, - 0x1078, 0x4c7a, 0x007c, 0x6d8b, 0x6d8d, 0x6d8b, 0x6d8b, 0x6d8b, - 0x6d8d, 0x6d95, 0x6df8, 0x6dbb, 0x6df8, 0x6dcf, 0x6df8, 0x6d95, - 0x6df8, 0x6df0, 0x6df8, 0x6df0, 0x6df8, 0x6df8, 0x6d8b, 0x6d8b, - 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, - 0x6d8b, 0x6d8b, 0x6d8b, 0x6df8, 0x6d8b, 0x6d8b, 0x6df8, 0x6d8b, - 0x6df8, 0x6df8, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6df8, 0x6df8, - 0x6d8b, 0x6df8, 0x6df8, 0x1078, 0x12d5, 0x1078, 0x4b81, 0x6003, - 0x0002, 0x1078, 0x4c7a, 0x0078, 0x6dfe, 0x0f7e, 0x2079, 0x7651, - 0x7804, 0x0f7f, 0xd0ac, 0x00c0, 0x6df8, 0x2001, 0x0000, 0x1078, - 0x37bd, 0x2001, 0x0002, 0x1078, 0x37d1, 0x1078, 0x4b81, 0x601f, - 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, - 0x4c7a, 0x0c7e, 0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x457b, - 0x0c7f, 0x0078, 0x6dfe, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6df8, 0xa686, - 0x0004, 0x0040, 0x6df8, 0x2001, 0x0004, 0x0078, 0x6df6, 0x2001, - 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x6dd8, 0x1078, 0x2dc8, - 0x2001, 0x0006, 0x1078, 0x6dff, 0x6618, 0x0d7e, 0x2668, 0x6e04, - 0x0d7f, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6df8, - 0x2001, 0x0006, 0x0078, 0x6df6, 0x2001, 0x0004, 0x0078, 0x6df6, - 0x2001, 0x0006, 0x1078, 0x6dff, 0x0078, 0x6df8, 0x1078, 0x37df, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x017e, - 0x0d7e, 0x6118, 0x2168, 0x6900, 0xd184, 0x0040, 0x6e1a, 0x6104, - 0xa18e, 0x000a, 0x00c0, 0x6e12, 0x699c, 0xd1a4, 0x00c0, 0x6e12, - 0x2001, 0x0007, 0x1078, 0x37d1, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x1078, 0x22dd, 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, - 0x6804, 0xa084, 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, - 0x12d5, 0xa1b6, 0x0015, 0x00c0, 0x6e31, 0x1079, 0x6e38, 0x0078, - 0x6e37, 0xa1b6, 0x0016, 0x10c0, 0x12d5, 0x1079, 0x6e70, 0x007c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x6e44, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x0f7e, 0x2079, 0x7651, 0x7804, - 0x0f7f, 0xd0ac, 0x00c0, 0x6e60, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x2001, 0x0002, 0x1078, 0x37d1, 0x601f, 0x0001, 0x6003, 0x0001, - 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0078, 0x6e6f, - 0x2011, 0x7b83, 0x220c, 0x017e, 0x0c7e, 0x1078, 0x3825, 0x00c0, - 0x6e6f, 0x1078, 0x3621, 0x0c7f, 0x017f, 0x1078, 0x5c02, 0x007c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x6e7c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x1078, 0x60d1, 0x00c0, 0x6e88, - 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x6e8a, - 0x1078, 0x5c02, 0x007c, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, - 0x1078, 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, - 0x0040, 0x0079, 0x6e9b, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6ead, - 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, - 0x6eab, 0x6eab, 0x6eab, 0x1078, 0x12d5, 0x0d7e, 0x0e7e, 0x0f7e, - 0x157e, 0x047e, 0x027e, 0x6106, 0x2071, 0x7b80, 0x7444, 0xa4a4, - 0xe600, 0x0040, 0x6f1e, 0xa486, 0x2000, 0x0040, 0x6edd, 0xa486, - 0x0400, 0x0040, 0x6edd, 0x7130, 0xa18c, 0x00ff, 0xa182, 0x0010, - 0x00c8, 0x6fb0, 0x0c7e, 0x1078, 0x460c, 0x2c68, 0x0c7f, 0x6a00, - 0xa284, 0x0001, 0x0040, 0x6f91, 0x1078, 0x46ca, 0x0040, 0x6fbc, - 0xa295, 0x0200, 0x6a02, 0x0078, 0x6ee3, 0x2009, 0x0001, 0x2011, - 0x0200, 0x1078, 0x46b4, 0x1078, 0x132f, 0x1040, 0x12d5, 0x6003, - 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, - 0x6c5a, 0x2c00, 0x685e, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, - 0xa18c, 0x00ff, 0xa10d, 0x6946, 0x684f, 0x0000, 0x6857, 0x0036, - 0x1078, 0x3a7a, 0xa486, 0x2000, 0x00c0, 0x6f0c, 0x2019, 0x0017, - 0x1078, 0x74d9, 0x0078, 0x6f7e, 0xa486, 0x0400, 0x00c0, 0x6f16, - 0x2019, 0x0002, 0x1078, 0x74d9, 0x0078, 0x6f7e, 0xa486, 0x0200, - 0x00c0, 0x6f1c, 0x1078, 0x74ca, 0x0078, 0x6f7e, 0x7130, 0xa184, - 0xff00, 0x00c0, 0x6fd0, 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, - 0x6fd0, 0x0c7e, 0x1078, 0x460c, 0x2c68, 0x0c7f, 0x6a00, 0xa284, - 0x0001, 0x0040, 0x6fd4, 0xa284, 0x0300, 0x00c0, 0x6fcc, 0x6804, - 0xa005, 0x0040, 0x6fbc, 0x8001, 0x6806, 0x6003, 0x0007, 0x1078, - 0x1314, 0x0040, 0x6f85, 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, - 0x0116, 0x683b, 0x0000, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, - 0x8007, 0xa10d, 0x6946, 0x6853, 0x003d, 0x7044, 0xa084, 0x0003, - 0xa086, 0x0002, 0x00c0, 0x6f60, 0x684f, 0x0040, 0x0078, 0x6f6a, - 0xa086, 0x0001, 0x00c0, 0x6f68, 0x684f, 0x0080, 0x0078, 0x6f6a, - 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0x7b90, 0xad90, 0x0015, - 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x6f70, 0x200c, - 0x6982, 0x8000, 0x200c, 0x697e, 0x1078, 0x3a7a, 0x027f, 0x047f, - 0x157f, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, - 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x0078, - 0x6f7e, 0x2069, 0x7b92, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, - 0x00c0, 0x6fb0, 0x2069, 0x7b80, 0x686c, 0xa084, 0x00ff, 0x017e, - 0x6110, 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, - 0x6007, 0x0043, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x0078, 0x6f7e, - 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, - 0x1078, 0x4c7a, 0x0078, 0x6f7e, 0x6013, 0x0300, 0x0078, 0x6fc2, - 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, - 0x1078, 0x4c7a, 0x0078, 0x6f7e, 0x6013, 0x0500, 0x0078, 0x6fc2, - 0x6013, 0x0600, 0x0078, 0x6f91, 0x6013, 0x0200, 0x0078, 0x6f91, - 0xa186, 0x0013, 0x00c0, 0x6fea, 0x6004, 0xa08a, 0x0040, 0x1048, - 0x12d5, 0xa08a, 0x0050, 0x10c8, 0x12d5, 0xa082, 0x0040, 0x2008, - 0x0079, 0x701b, 0xa186, 0x0047, 0x00c0, 0x6ff0, 0x0078, 0x704a, - 0xa186, 0x0027, 0x0040, 0x6ff8, 0xa186, 0x0014, 0x10c0, 0x12d5, - 0x6004, 0xa082, 0x0040, 0x2008, 0x0079, 0x6ffe, 0x700e, 0x7010, - 0x7010, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, - 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x1078, 0x12d5, - 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, - 0x1078, 0x4c7a, 0x007c, 0x702b, 0x703b, 0x7034, 0x7044, 0x702b, - 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, - 0x702b, 0x702b, 0x702b, 0x1078, 0x12d5, 0x6010, 0xa088, 0x0013, - 0x2104, 0xa085, 0x0400, 0x200a, 0x1078, 0x4b81, 0x6003, 0x0002, - 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x1078, 0x468d, 0x1078, - 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x2009, 0x0041, - 0x0078, 0x7112, 0xa182, 0x0040, 0x0079, 0x704e, 0x705e, 0x7060, - 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x7061, 0x705e, 0x705e, - 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x1078, 0x12d5, - 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, - 0x2c10, 0x1078, 0x1572, 0x007c, 0xa182, 0x0040, 0x0079, 0x7070, - 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, - 0x7080, 0x7082, 0x70a5, 0x7080, 0x7080, 0x7080, 0x7080, 0x70a5, - 0x1078, 0x12d5, 0x1078, 0x4c29, 0x1078, 0x4d3a, 0x6010, 0x0d7e, - 0x2068, 0x684c, 0xd0fc, 0x0040, 0x7098, 0xa08c, 0x0003, 0xa18e, - 0x0002, 0x0040, 0x709e, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x7112, - 0x6003, 0x0007, 0x1078, 0x468d, 0x0d7f, 0x007c, 0x1078, 0x468d, - 0x1078, 0x5c02, 0x0d7f, 0x0078, 0x709d, 0x037e, 0x1078, 0x4c29, - 0x1078, 0x4d3a, 0x6010, 0x0d7e, 0x2068, 0x2019, 0x0004, 0x1078, - 0x74fd, 0x1078, 0x6aa1, 0x6017, 0x0028, 0x0d7f, 0x037f, 0x007c, - 0xa186, 0x0013, 0x00c0, 0x70c6, 0x6004, 0xa086, 0x0042, 0x10c0, - 0x12d5, 0x1078, 0x4b81, 0x1078, 0x4c7a, 0x007c, 0xa186, 0x0027, - 0x0040, 0x70ce, 0xa186, 0x0014, 0x00c0, 0x70de, 0x6004, 0xa086, - 0x0042, 0x10c0, 0x12d5, 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, - 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x0040, - 0x0079, 0x70e2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, - 0x70f2, 0x70f4, 0x7100, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, - 0x70f2, 0x70f2, 0x1078, 0x12d5, 0x037e, 0x047e, 0x20e1, 0x0005, - 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x047f, 0x037f, 0x007c, - 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x710c, 0x2009, - 0x0041, 0x0d7f, 0x0078, 0x7112, 0x6003, 0x0007, 0x1078, 0x468d, - 0x0d7f, 0x007c, 0xa182, 0x0040, 0x0079, 0x7116, 0x7126, 0x7128, - 0x7134, 0x7140, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, - 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x1078, 0x12d5, - 0x6003, 0x0001, 0x6106, 0x1078, 0x4825, 0x127e, 0x2091, 0x8000, - 0x1078, 0x4c7a, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, 0x19cf, 0x127e, 0x2091, - 0x8000, 0x1078, 0x4891, 0x1078, 0x4d3a, 0x127f, 0x007c, 0x1078, - 0x4b81, 0x0078, 0x7155, 0x1078, 0x4c29, 0x6110, 0x81ff, 0x0040, - 0x7162, 0x0d7e, 0x2168, 0x037e, 0x2019, 0x0029, 0x1078, 0x74fd, - 0x037f, 0x0d7f, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, - 0x0085, 0x0079, 0x716b, 0x7172, 0x7172, 0x7172, 0x7174, 0x7172, - 0x7172, 0x7172, 0x1078, 0x12d5, 0x027e, 0x0e7e, 0x2071, 0x7b80, - 0x7220, 0x1078, 0x7417, 0x0040, 0x7181, 0x6007, 0x0086, 0x0078, - 0x7183, 0x6007, 0x0087, 0x6003, 0x0001, 0x1078, 0x4825, 0x1078, - 0x4c7a, 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x719d, - 0x6004, 0xa08a, 0x0085, 0x1048, 0x12d5, 0xa08a, 0x008c, 0x10c8, - 0x12d5, 0xa082, 0x0085, 0x0079, 0x71b0, 0xa186, 0x0027, 0x0040, - 0x71a5, 0xa186, 0x0014, 0x10c0, 0x12d5, 0x2001, 0x0007, 0x1078, - 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, - 0x71b7, 0x71b9, 0x71b9, 0x71b7, 0x71b7, 0x71b7, 0x71b7, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, - 0xa182, 0x0085, 0x1048, 0x12d5, 0xa182, 0x008c, 0x10c8, 0x12d5, - 0xa182, 0x0085, 0x0079, 0x71cc, 0x71d3, 0x71d3, 0x71d3, 0x71d5, - 0x71d3, 0x71d3, 0x71d3, 0x1078, 0x12d5, 0x007c, 0x1078, 0x4b81, - 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0x037e, 0x2019, 0x000b, - 0x1078, 0x71e6, 0x601f, 0x0006, 0x037f, 0x007c, 0x127e, 0x037e, - 0x087e, 0x2091, 0x8000, 0x2c40, 0x1078, 0x5915, 0x00c0, 0x7213, - 0x1078, 0x59b6, 0x00c0, 0x7213, 0x6000, 0xa086, 0x0000, 0x0040, - 0x7213, 0x601c, 0xa086, 0x0007, 0x0040, 0x7213, 0x0d7e, 0x6000, - 0xa086, 0x0004, 0x00c0, 0x7206, 0x1078, 0x1676, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x720e, 0x1078, 0x74fd, 0x0d7f, 0x6013, - 0x0000, 0x601f, 0x0007, 0x087f, 0x037f, 0x127f, 0x007c, 0x0f7e, - 0x0c7e, 0x037e, 0x157e, 0x2079, 0x7b80, 0x7838, 0xa08c, 0x00ff, - 0x783c, 0x1078, 0x2085, 0x00c0, 0x724e, 0x017e, 0x0c7e, 0x1078, - 0x3825, 0x00c0, 0x724e, 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, - 0x0004, 0x1078, 0x616a, 0x00c0, 0x724e, 0x017f, 0x027f, 0x027e, - 0x017e, 0x2019, 0x0029, 0x1078, 0x5a8a, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x017f, 0x1078, 0x737b, 0x1078, 0x39a6, 0x017f, 0x1078, - 0x3621, 0x6612, 0x6516, 0xa006, 0x0078, 0x7250, 0x0c7f, 0x017f, - 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, - 0x2009, 0x761e, 0x2104, 0xa086, 0x0074, 0x00c0, 0x72ac, 0x2069, - 0x7b8e, 0x690c, 0xa182, 0x0100, 0x0048, 0x729c, 0x6908, 0xa184, - 0x8000, 0x0040, 0x72a8, 0xa184, 0x0800, 0x0040, 0x72a8, 0x6910, - 0xa18a, 0x0001, 0x0048, 0x72a0, 0x6914, 0x2069, 0x7bae, 0x6904, - 0x81ff, 0x00c0, 0x7294, 0x690c, 0xa182, 0x0100, 0x0048, 0x729c, - 0x6908, 0x81ff, 0x00c0, 0x7298, 0x6910, 0xa18a, 0x0001, 0x0048, - 0x72a0, 0x6918, 0xa18a, 0x0001, 0x0048, 0x72a8, 0x0078, 0x72b2, - 0x6013, 0x0100, 0x0078, 0x72ae, 0x6013, 0x0300, 0x0078, 0x72ae, - 0x6013, 0x0500, 0x0078, 0x72ae, 0x6013, 0x0700, 0x0078, 0x72ae, - 0x6013, 0x0900, 0x0078, 0x72ae, 0x6013, 0x0b00, 0x0078, 0x72ae, - 0x6013, 0x0f00, 0x0078, 0x72ae, 0x6013, 0x2d00, 0xa085, 0x0001, - 0x0078, 0x72b3, 0xa006, 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, - 0x0d7e, 0x027e, 0x037e, 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, - 0x00ff, 0xa286, 0x0006, 0x0040, 0x72db, 0xa286, 0x0004, 0x0040, - 0x72db, 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x72db, - 0xa286, 0x0004, 0x0040, 0x72db, 0x0c7e, 0x2d60, 0x1078, 0x3837, - 0x0c7f, 0x0078, 0x730e, 0x2011, 0x7b96, 0xad98, 0x000a, 0x20a9, - 0x0004, 0x1078, 0x616a, 0x00c0, 0x730f, 0x2011, 0x7b9a, 0xad98, - 0x0006, 0x20a9, 0x0004, 0x1078, 0x616a, 0x00c0, 0x730f, 0x047e, - 0x017e, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x7652, - 0x210c, 0xd1a4, 0x0040, 0x7303, 0x2009, 0x0029, 0x1078, 0x7541, - 0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x2c08, 0x1078, 0x737b, 0x017f, 0x047f, 0xa006, 0x157f, - 0x037f, 0x027f, 0x0d7f, 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0x7b8e, - 0x6800, 0xa086, 0x0800, 0x0040, 0x7321, 0x6013, 0x0000, 0x0078, - 0x7322, 0xa006, 0x0d7f, 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, - 0x037e, 0x157e, 0x2079, 0x7b8c, 0x7930, 0x7834, 0x1078, 0x2085, - 0x00c0, 0x7348, 0x1078, 0x3825, 0x00c0, 0x7348, 0x2011, 0x7b90, - 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x616a, 0x00c0, 0x7348, - 0x2011, 0x7b94, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, 0x616a, - 0x157f, 0x037f, 0x027f, 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, - 0x007e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x7374, 0x1078, 0x3825, - 0x00c0, 0x7374, 0x2011, 0x7b96, 0xac98, 0x000a, 0x20a9, 0x0004, - 0x1078, 0x616a, 0x00c0, 0x7374, 0x2011, 0x7b9a, 0xac98, 0x0006, - 0x20a9, 0x0004, 0x1078, 0x616a, 0x157f, 0x037f, 0x027f, 0x017f, - 0x007f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, - 0x047e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, - 0x2021, 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7644, - 0x7060, 0x8001, 0xa602, 0x00c8, 0x73e0, 0x2100, 0xac06, 0x0040, - 0x73d6, 0x1078, 0x7559, 0x0040, 0x73d6, 0x671c, 0xa786, 0x0001, - 0x0040, 0x73f5, 0xa786, 0x0007, 0x0040, 0x73d6, 0x2500, 0xac06, - 0x0040, 0x73d6, 0x2400, 0xac06, 0x0040, 0x73d6, 0x1078, 0x756d, - 0x00c0, 0x73d6, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x73bc, - 0x017e, 0x1078, 0x1676, 0x017f, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x73d3, 0xa786, 0x0003, 0x00c0, 0x73e9, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x017e, 0x1078, 0x6b3f, 0x1078, 0x3a7a, - 0x017f, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x6aa1, 0xace0, 0x0008, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x73e0, 0x0078, 0x738d, - 0x127f, 0x027f, 0x047f, 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, - 0x007c, 0xa786, 0x0006, 0x00c0, 0x73c6, 0xa386, 0x0005, 0x0040, - 0x73d6, 0x1078, 0x74fd, 0x0078, 0x73d3, 0x1078, 0x756d, 0x00c0, - 0x73d6, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x00c0, 0x73d6, - 0x6000, 0xa086, 0x0002, 0x00c0, 0x73d6, 0x1078, 0x6aba, 0x0040, - 0x7411, 0x1078, 0x6ace, 0x00c0, 0x73d6, 0x1078, 0x5e57, 0x0078, - 0x7413, 0x1078, 0x22dd, 0x1078, 0x6aa1, 0x0078, 0x73d6, 0x0c7e, - 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x7514, 0x017f, 0x0040, - 0x7426, 0x601c, 0xa084, 0x000f, 0x1079, 0x7429, 0x0e7f, 0x0c7f, - 0x007c, 0x7431, 0x7431, 0x7431, 0x7431, 0x7431, 0x7431, 0x7433, - 0x7431, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, 0xa080, 0x0028, - 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x1078, - 0x7541, 0x017f, 0x047f, 0x037e, 0x2019, 0x0002, 0x1078, 0x71e6, - 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0001, 0x1078, 0x37bd, - 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, 0x7605, - 0x2011, 0x7b96, 0x1078, 0x616a, 0x037f, 0x027f, 0x017f, 0x157f, - 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x027e, - 0x127e, 0x2091, 0x8000, 0x2061, 0x7d00, 0x2079, 0x0001, 0x8fff, - 0x0040, 0x74bd, 0x2071, 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, - 0x00c8, 0x74bd, 0x88ff, 0x0040, 0x7483, 0x2800, 0xac06, 0x00c0, - 0x74b3, 0x2079, 0x0000, 0x1078, 0x7559, 0x0040, 0x74b3, 0x2400, - 0xac06, 0x0040, 0x74b3, 0x671c, 0xa786, 0x0006, 0x00c0, 0x74b3, - 0xa786, 0x0007, 0x0040, 0x74b3, 0x88ff, 0x00c0, 0x749b, 0x6018, - 0xa206, 0x00c0, 0x74b3, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, - 0x74a3, 0x1078, 0x1676, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, - 0x74ad, 0x047e, 0x1078, 0x74fd, 0x047f, 0x0d7f, 0x1078, 0x6aa1, - 0x88ff, 0x00c0, 0x74c6, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, - 0xac02, 0x00c8, 0x74bd, 0x0078, 0x746f, 0xa006, 0x127f, 0x027f, - 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, - 0x0078, 0x74be, 0x087e, 0x2041, 0x0000, 0x2c20, 0x2019, 0x0002, - 0x6218, 0x1078, 0x5915, 0x1078, 0x59b6, 0x1078, 0x7462, 0x087f, - 0x007c, 0x027e, 0x047e, 0x087e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x017e, 0x037e, 0x1078, 0x3825, 0x00c0, - 0x74f2, 0x2c10, 0x2041, 0x0000, 0x1078, 0x5915, 0x1078, 0x59b6, - 0x1078, 0x7462, 0x037f, 0x017f, 0x8108, 0x00f0, 0x74e3, 0x157f, - 0x0c7f, 0x087f, 0x047f, 0x027f, 0x007c, 0x017e, 0x0f7e, 0x8dff, - 0x0040, 0x7511, 0x6800, 0xa07d, 0x0040, 0x750e, 0x6803, 0x0000, - 0x6b52, 0x1078, 0x3a7a, 0x2f68, 0x0078, 0x7502, 0x6b52, 0x1078, - 0x3a7a, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, - 0x7d00, 0x2071, 0x7600, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, - 0x753c, 0x2100, 0xac06, 0x0040, 0x752e, 0x6000, 0xa086, 0x0000, - 0x0040, 0x752e, 0x6008, 0xa206, 0x0040, 0x7538, 0xace0, 0x0008, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x753c, 0x0078, 0x7519, - 0xa085, 0x0001, 0x0078, 0x753d, 0xa006, 0x037f, 0x047f, 0x0e7f, - 0x007c, 0x0d7e, 0x007e, 0x1078, 0x132f, 0x007f, 0x1040, 0x12d5, - 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, - 0x685e, 0x6956, 0x6c46, 0x684f, 0x0000, 0x1078, 0x3a7a, 0x0d7f, - 0x007c, 0x6700, 0xa786, 0x0000, 0x0040, 0x756c, 0xa786, 0x0001, - 0x0040, 0x756c, 0xa786, 0x000a, 0x0040, 0x756c, 0xa786, 0x0009, - 0x0040, 0x756c, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x6018, 0x2070, - 0x70a0, 0xa206, 0x0e7f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, - 0x8000, 0x2071, 0x7640, 0xd5a4, 0x0040, 0x7581, 0x7034, 0x8000, - 0x7036, 0xd5b4, 0x0040, 0x7587, 0x7030, 0x8000, 0x7032, 0xd5ac, - 0x0040, 0x758e, 0x2071, 0x764a, 0x1078, 0x75bd, 0x0e7f, 0x007f, - 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, - 0x7640, 0xd5a4, 0x0040, 0x759f, 0x7034, 0x8000, 0x7036, 0xd5b4, - 0x0040, 0x75a5, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0x75ac, - 0x2071, 0x764a, 0x1078, 0x75bd, 0x0e7f, 0x007f, 0x127f, 0x007c, - 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7642, 0x1078, - 0x75bd, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, - 0x00c8, 0x75c6, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, - 0x2071, 0x7640, 0x1078, 0x75bd, 0x0e7f, 0x007c, 0x0e7e, 0x2071, - 0x7644, 0x1078, 0x75bd, 0x0e7f, 0x007c, 0x0001, 0x0002, 0x0004, - 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, - 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0xaaff + 0x6c56, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x00c0, 0x6c29, + 0x1078, 0x7319, 0x00c0, 0x6c50, 0x6007, 0x000e, 0x0078, 0x6ca3, + 0x1078, 0x22b5, 0x6007, 0x000f, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6c63, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, + 0x6c48, 0x0078, 0x6c29, 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, + 0x6ca3, 0x1078, 0x3a1e, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, + 0x00ff, 0xa082, 0x0006, 0x0048, 0x6c8e, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0006, 0x00c0, 0x6c29, 0x1078, 0x7344, 0x00c0, 0x6c88, + 0x1078, 0x724a, 0x00c0, 0x6c88, 0x6007, 0x0010, 0x0078, 0x6ca3, + 0x1078, 0x22b5, 0x6007, 0x0011, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6c9b, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, + 0x6c7c, 0x0078, 0x6c29, 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, + 0x6ca3, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, + 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x486a, 0x0078, 0x6ca7, + 0x6007, 0x0020, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, 0x6007, + 0x0023, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, 0x017e, 0x027e, + 0x2011, 0x7b88, 0x2214, 0x2c08, 0x1078, 0x7509, 0x00c0, 0x6ccf, + 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x0078, 0x6cd4, 0x1078, + 0x5bfa, 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x486a, + 0x027f, 0x017f, 0x007c, 0x6106, 0x1078, 0x6ced, 0x6007, 0x002b, + 0x0078, 0x6ca3, 0x6007, 0x002c, 0x0078, 0x6ca3, 0x6106, 0x1078, + 0x6cf2, 0x6007, 0x002e, 0x0078, 0x6ca3, 0x0d7e, 0x1078, 0x6d18, + 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x6d27, 0x00c0, 0x6d11, 0x680c, + 0xa08c, 0xff00, 0x6824, 0xa084, 0x00ff, 0xa115, 0x6212, 0xd1e4, + 0x0040, 0x6d06, 0x2009, 0x0001, 0x0078, 0x6d0d, 0xd1ec, 0x0040, + 0x6d11, 0x2009, 0x0000, 0xa294, 0x00ff, 0x1078, 0x22f9, 0x0078, + 0x6d15, 0xa085, 0x0001, 0x0078, 0x6d16, 0xa006, 0x0d7f, 0x007c, + 0x2069, 0x7b8d, 0x6800, 0xa082, 0x0010, 0x00c8, 0x6d25, 0x6013, + 0x0000, 0xa085, 0x0001, 0x0078, 0x6d26, 0xa006, 0x007c, 0x6013, + 0x0000, 0x2069, 0x7b8c, 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, + 0x007c, 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12cd, 0xa1b6, 0x0013, + 0x00c0, 0x6d3d, 0x2008, 0x0079, 0x6d50, 0xa1b6, 0x0027, 0x0040, + 0x6d45, 0xa1b6, 0x0014, 0x10c0, 0x12cd, 0x2001, 0x0007, 0x1078, + 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, + 0x6d80, 0x6d82, 0x6d80, 0x6d80, 0x6d80, 0x6d82, 0x6d8a, 0x6ded, + 0x6db0, 0x6ded, 0x6dc4, 0x6ded, 0x6d8a, 0x6ded, 0x6de5, 0x6ded, + 0x6de5, 0x6ded, 0x6ded, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, + 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, + 0x6ded, 0x6d80, 0x6d80, 0x6ded, 0x6d80, 0x6ded, 0x6ded, 0x6d80, + 0x6d80, 0x6d80, 0x6d80, 0x6ded, 0x6ded, 0x6d80, 0x6ded, 0x6ded, + 0x1078, 0x12cd, 0x1078, 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, + 0x0078, 0x6df3, 0x0f7e, 0x2079, 0x7651, 0x7804, 0x0f7f, 0xd0ac, + 0x00c0, 0x6ded, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, + 0x1078, 0x37c9, 0x1078, 0x4b79, 0x601f, 0x0001, 0x6003, 0x0001, + 0x6007, 0x0002, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0c7e, 0x6118, + 0x2160, 0x2009, 0x0001, 0x1078, 0x4573, 0x0c7f, 0x0078, 0x6df3, + 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0006, 0x0040, 0x6ded, 0xa686, 0x0004, 0x0040, 0x6ded, + 0x2001, 0x0004, 0x0078, 0x6deb, 0x2001, 0x7600, 0x2004, 0xa086, + 0x0003, 0x00c0, 0x6dcd, 0x1078, 0x2db9, 0x2001, 0x0006, 0x1078, + 0x6df4, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x6ded, 0x2001, 0x0006, 0x0078, + 0x6deb, 0x2001, 0x0004, 0x0078, 0x6deb, 0x2001, 0x0006, 0x1078, + 0x6df4, 0x0078, 0x6ded, 0x1078, 0x37d7, 0x1078, 0x4b79, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x017e, 0x0d7e, 0x6118, 0x2168, + 0x6900, 0xd184, 0x0040, 0x6e0f, 0x6104, 0xa18e, 0x000a, 0x00c0, + 0x6e07, 0x699c, 0xd1a4, 0x00c0, 0x6e07, 0x2001, 0x0007, 0x1078, + 0x37c9, 0x2001, 0x0000, 0x1078, 0x37b5, 0x1078, 0x22d7, 0x0d7f, + 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0xff00, + 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x12cd, 0xa1b6, 0x0015, + 0x00c0, 0x6e26, 0x1079, 0x6e2d, 0x0078, 0x6e2c, 0xa1b6, 0x0016, + 0x10c0, 0x12cd, 0x1079, 0x6e65, 0x007c, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x5ed7, 0x5ed7, 0x5ed7, 0x6e39, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x0f7e, 0x2079, 0x7651, 0x7804, 0x0f7f, 0xd0ac, 0x00c0, + 0x6e55, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, + 0x37c9, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, + 0x486a, 0x1078, 0x4c72, 0x0078, 0x6e64, 0x2011, 0x7b83, 0x220c, + 0x017e, 0x0c7e, 0x1078, 0x381d, 0x00c0, 0x6e64, 0x1078, 0x3619, + 0x0c7f, 0x017f, 0x1078, 0x5bfa, 0x007c, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x5ed7, 0x5ed7, 0x5ed7, 0x6e71, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x1078, 0x60c7, 0x00c0, 0x6e7d, 0x6003, 0x0001, 0x6007, + 0x0001, 0x1078, 0x486a, 0x0078, 0x6e7f, 0x1078, 0x5bfa, 0x007c, + 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x1078, 0x4b79, 0x1078, + 0x6a96, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x6e90, + 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea2, 0x6ea0, 0x6ea0, 0x6ea0, + 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, + 0x1078, 0x12cd, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, 0x027e, + 0x6106, 0x2071, 0x7b80, 0x7444, 0xa4a4, 0xe600, 0x0040, 0x6f13, + 0xa486, 0x2000, 0x0040, 0x6ed2, 0xa486, 0x0400, 0x0040, 0x6ed2, + 0x7130, 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, 0x6fa5, 0x0c7e, + 0x1078, 0x4604, 0x2c68, 0x0c7f, 0x6a00, 0xa284, 0x0001, 0x0040, + 0x6f86, 0x1078, 0x46c2, 0x0040, 0x6fb1, 0xa295, 0x0200, 0x6a02, + 0x0078, 0x6ed8, 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x46ac, + 0x1078, 0x1327, 0x1040, 0x12cd, 0x6003, 0x0007, 0x2d00, 0x6837, + 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, + 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0xa18c, 0x00ff, 0xa10d, + 0x6946, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x3a72, 0xa486, + 0x2000, 0x00c0, 0x6f01, 0x2019, 0x0017, 0x1078, 0x74ce, 0x0078, + 0x6f73, 0xa486, 0x0400, 0x00c0, 0x6f0b, 0x2019, 0x0002, 0x1078, + 0x74ce, 0x0078, 0x6f73, 0xa486, 0x0200, 0x00c0, 0x6f11, 0x1078, + 0x74bf, 0x0078, 0x6f73, 0x7130, 0xa184, 0xff00, 0x00c0, 0x6fc5, + 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, 0x6fc5, 0x0c7e, 0x1078, + 0x4604, 0x2c68, 0x0c7f, 0x6a00, 0xa284, 0x0001, 0x0040, 0x6fc9, + 0xa284, 0x0300, 0x00c0, 0x6fc1, 0x6804, 0xa005, 0x0040, 0x6fb1, + 0x8001, 0x6806, 0x6003, 0x0007, 0x1078, 0x130c, 0x0040, 0x6f7a, + 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, + 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0xa10d, 0x6946, + 0x6853, 0x003d, 0x7044, 0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, + 0x6f55, 0x684f, 0x0040, 0x0078, 0x6f5f, 0xa086, 0x0001, 0x00c0, + 0x6f5d, 0x684f, 0x0080, 0x0078, 0x6f5f, 0x684f, 0x0000, 0x20a9, + 0x000a, 0x2001, 0x7b90, 0xad90, 0x0015, 0x200c, 0x810f, 0x2112, + 0x8000, 0x8210, 0x00f0, 0x6f65, 0x200c, 0x6982, 0x8000, 0x200c, + 0x697e, 0x1078, 0x3a72, 0x027f, 0x047f, 0x157f, 0x0f7f, 0x0e7f, + 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, + 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, 0x6f73, 0x2069, 0x7b92, + 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x00c0, 0x6fa5, 0x2069, + 0x7b80, 0x686c, 0xa084, 0x00ff, 0x017e, 0x6110, 0xa18c, 0x0700, + 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, 0x6007, 0x0043, 0x1078, + 0x481d, 0x1078, 0x4c72, 0x0078, 0x6f73, 0x6013, 0x0200, 0x6003, + 0x0001, 0x6007, 0x0041, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, + 0x6f73, 0x6013, 0x0300, 0x0078, 0x6fb7, 0x6013, 0x0100, 0x6003, + 0x0001, 0x6007, 0x0041, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, + 0x6f73, 0x6013, 0x0500, 0x0078, 0x6fb7, 0x6013, 0x0600, 0x0078, + 0x6f86, 0x6013, 0x0200, 0x0078, 0x6f86, 0xa186, 0x0013, 0x00c0, + 0x6fdf, 0x6004, 0xa08a, 0x0040, 0x1048, 0x12cd, 0xa08a, 0x0050, + 0x10c8, 0x12cd, 0xa082, 0x0040, 0x2008, 0x0079, 0x7010, 0xa186, + 0x0047, 0x00c0, 0x6fe5, 0x0078, 0x703f, 0xa186, 0x0027, 0x0040, + 0x6fed, 0xa186, 0x0014, 0x10c0, 0x12cd, 0x6004, 0xa082, 0x0040, + 0x2008, 0x0079, 0x6ff3, 0x7003, 0x7005, 0x7005, 0x7003, 0x7003, + 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, + 0x7003, 0x7003, 0x7003, 0x1078, 0x12cd, 0x2001, 0x0007, 0x1078, + 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, + 0x7020, 0x7030, 0x7029, 0x7039, 0x7020, 0x7020, 0x7020, 0x7020, + 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, + 0x1078, 0x12cd, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, + 0x200a, 0x1078, 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, 0x007c, + 0x1078, 0x4b79, 0x1078, 0x4685, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x1078, 0x4b79, 0x2009, 0x0041, 0x0078, 0x7107, 0xa182, + 0x0040, 0x0079, 0x7043, 0x7053, 0x7055, 0x7053, 0x7053, 0x7053, + 0x7053, 0x7053, 0x7056, 0x7053, 0x7053, 0x7053, 0x7053, 0x7053, + 0x7053, 0x7053, 0x7053, 0x1078, 0x12cd, 0x007c, 0x6003, 0x0004, + 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, + 0x007c, 0xa182, 0x0040, 0x0079, 0x7065, 0x7075, 0x7075, 0x7075, + 0x7075, 0x7075, 0x7075, 0x7075, 0x7075, 0x7075, 0x7077, 0x709a, + 0x7075, 0x7075, 0x7075, 0x7075, 0x709a, 0x1078, 0x12cd, 0x1078, + 0x4c21, 0x1078, 0x4d32, 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, + 0x0040, 0x708d, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0040, 0x7093, + 0x2009, 0x0041, 0x0d7f, 0x0078, 0x7107, 0x6003, 0x0007, 0x1078, + 0x4685, 0x0d7f, 0x007c, 0x1078, 0x4685, 0x1078, 0x5bfa, 0x0d7f, + 0x0078, 0x7092, 0x037e, 0x1078, 0x4c21, 0x1078, 0x4d32, 0x6010, + 0x0d7e, 0x2068, 0x2019, 0x0004, 0x1078, 0x74f2, 0x1078, 0x6a96, + 0x6017, 0x0028, 0x0d7f, 0x037f, 0x007c, 0xa186, 0x0013, 0x00c0, + 0x70bb, 0x6004, 0xa086, 0x0042, 0x10c0, 0x12cd, 0x1078, 0x4b79, + 0x1078, 0x4c72, 0x007c, 0xa186, 0x0027, 0x0040, 0x70c3, 0xa186, + 0x0014, 0x00c0, 0x70d3, 0x6004, 0xa086, 0x0042, 0x10c0, 0x12cd, + 0x2001, 0x0007, 0x1078, 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, + 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x70d7, 0x70e7, + 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e9, 0x70f5, + 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x1078, + 0x12cd, 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x1078, 0x156a, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, 0x2068, + 0x684c, 0xd0fc, 0x0040, 0x7101, 0x2009, 0x0041, 0x0d7f, 0x0078, + 0x7107, 0x6003, 0x0007, 0x1078, 0x4685, 0x0d7f, 0x007c, 0xa182, + 0x0040, 0x0079, 0x710b, 0x711b, 0x711d, 0x7129, 0x7135, 0x711b, + 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, + 0x711b, 0x711b, 0x711b, 0x1078, 0x12cd, 0x6003, 0x0001, 0x6106, + 0x1078, 0x481d, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, + 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, 0x2091, + 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0x6003, 0x0003, 0x6106, + 0x2c10, 0x1078, 0x19c7, 0x127e, 0x2091, 0x8000, 0x1078, 0x4889, + 0x1078, 0x4d32, 0x127f, 0x007c, 0x1078, 0x4b79, 0x0078, 0x714a, + 0x1078, 0x4c21, 0x6110, 0x81ff, 0x0040, 0x7157, 0x0d7e, 0x2168, + 0x037e, 0x2019, 0x0029, 0x1078, 0x74f2, 0x037f, 0x0d7f, 0x1078, + 0x6a96, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0085, 0x0079, 0x7160, + 0x7167, 0x7167, 0x7167, 0x7169, 0x7167, 0x7167, 0x7167, 0x1078, + 0x12cd, 0x027e, 0x0e7e, 0x2071, 0x7b80, 0x7220, 0x1078, 0x740c, + 0x0040, 0x7176, 0x6007, 0x0086, 0x0078, 0x7178, 0x6007, 0x0087, + 0x6003, 0x0001, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0e7f, 0x027f, + 0x007c, 0xa186, 0x0013, 0x00c0, 0x7192, 0x6004, 0xa08a, 0x0085, + 0x1048, 0x12cd, 0xa08a, 0x008c, 0x10c8, 0x12cd, 0xa082, 0x0085, + 0x0079, 0x71a5, 0xa186, 0x0027, 0x0040, 0x719a, 0xa186, 0x0014, + 0x10c0, 0x12cd, 0x2001, 0x0007, 0x1078, 0x37d7, 0x1078, 0x4b79, + 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, 0x71ac, 0x71ae, 0x71ae, + 0x71ac, 0x71ac, 0x71ac, 0x71ac, 0x1078, 0x12cd, 0x1078, 0x4b79, + 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0085, 0x1048, + 0x12cd, 0xa182, 0x008c, 0x10c8, 0x12cd, 0xa182, 0x0085, 0x0079, + 0x71c1, 0x71c8, 0x71c8, 0x71c8, 0x71ca, 0x71c8, 0x71c8, 0x71c8, + 0x1078, 0x12cd, 0x007c, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, + 0x4c72, 0x007c, 0x037e, 0x2019, 0x000b, 0x1078, 0x71db, 0x601f, + 0x0006, 0x037f, 0x007c, 0x127e, 0x037e, 0x087e, 0x2091, 0x8000, + 0x2c40, 0x1078, 0x590d, 0x00c0, 0x7208, 0x1078, 0x59ae, 0x00c0, + 0x7208, 0x6000, 0xa086, 0x0000, 0x0040, 0x7208, 0x601c, 0xa086, + 0x0007, 0x0040, 0x7208, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, + 0x71fb, 0x1078, 0x166e, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, + 0x7203, 0x1078, 0x74f2, 0x0d7f, 0x6013, 0x0000, 0x601f, 0x0007, + 0x087f, 0x037f, 0x127f, 0x007c, 0x0f7e, 0x0c7e, 0x037e, 0x157e, + 0x2079, 0x7b80, 0x7838, 0xa08c, 0x00ff, 0x783c, 0x1078, 0x207f, + 0x00c0, 0x7243, 0x017e, 0x0c7e, 0x1078, 0x381d, 0x00c0, 0x7243, + 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, + 0x00c0, 0x7243, 0x017f, 0x027f, 0x027e, 0x017e, 0x2019, 0x0029, + 0x1078, 0x5a82, 0x1078, 0x495a, 0x1078, 0x489d, 0x017f, 0x1078, + 0x7370, 0x1078, 0x399e, 0x017f, 0x1078, 0x3619, 0x6612, 0x6516, + 0xa006, 0x0078, 0x7245, 0x0c7f, 0x017f, 0x157f, 0x037f, 0x0c7f, + 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, 0x2009, 0x761e, 0x2104, + 0xa086, 0x0074, 0x00c0, 0x72a1, 0x2069, 0x7b8e, 0x690c, 0xa182, + 0x0100, 0x0048, 0x7291, 0x6908, 0xa184, 0x8000, 0x0040, 0x729d, + 0xa184, 0x0800, 0x0040, 0x729d, 0x6910, 0xa18a, 0x0001, 0x0048, + 0x7295, 0x6914, 0x2069, 0x7bae, 0x6904, 0x81ff, 0x00c0, 0x7289, + 0x690c, 0xa182, 0x0100, 0x0048, 0x7291, 0x6908, 0x81ff, 0x00c0, + 0x728d, 0x6910, 0xa18a, 0x0001, 0x0048, 0x7295, 0x6918, 0xa18a, + 0x0001, 0x0048, 0x729d, 0x0078, 0x72a7, 0x6013, 0x0100, 0x0078, + 0x72a3, 0x6013, 0x0300, 0x0078, 0x72a3, 0x6013, 0x0500, 0x0078, + 0x72a3, 0x6013, 0x0700, 0x0078, 0x72a3, 0x6013, 0x0900, 0x0078, + 0x72a3, 0x6013, 0x0b00, 0x0078, 0x72a3, 0x6013, 0x0f00, 0x0078, + 0x72a3, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x72a8, 0xa006, + 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e, + 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006, + 0x0040, 0x72d0, 0xa286, 0x0004, 0x0040, 0x72d0, 0xa394, 0xff00, + 0x8217, 0xa286, 0x0006, 0x0040, 0x72d0, 0xa286, 0x0004, 0x0040, + 0x72d0, 0x0c7e, 0x2d60, 0x1078, 0x382f, 0x0c7f, 0x0078, 0x7303, + 0x2011, 0x7b96, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, + 0x00c0, 0x7304, 0x2011, 0x7b9a, 0xad98, 0x0006, 0x20a9, 0x0004, + 0x1078, 0x6160, 0x00c0, 0x7304, 0x047e, 0x017e, 0x6aa0, 0xa294, + 0x00ff, 0x8227, 0xa006, 0x2009, 0x7652, 0x210c, 0xd1a4, 0x0040, + 0x72f8, 0x2009, 0x0029, 0x1078, 0x7536, 0x6800, 0xc0e5, 0x6802, + 0x2019, 0x0029, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, + 0x7370, 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f, + 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0x7b8e, 0x6800, 0xa086, 0x0800, + 0x0040, 0x7316, 0x6013, 0x0000, 0x0078, 0x7317, 0xa006, 0x0d7f, + 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079, + 0x7b8c, 0x7930, 0x7834, 0x1078, 0x207f, 0x00c0, 0x733d, 0x1078, + 0x381d, 0x00c0, 0x733d, 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, + 0x0004, 0x1078, 0x6160, 0x00c0, 0x733d, 0x2011, 0x7b94, 0xac98, + 0x0006, 0x20a9, 0x0004, 0x1078, 0x6160, 0x157f, 0x037f, 0x027f, + 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e, + 0x037e, 0x157e, 0x2011, 0x7b83, 0x2204, 0x8211, 0x220c, 0x1078, + 0x207f, 0x00c0, 0x7369, 0x1078, 0x381d, 0x00c0, 0x7369, 0x2011, + 0x7b96, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, 0x00c0, + 0x7369, 0x2011, 0x7b9a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, + 0x6160, 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c, + 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x127e, + 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, 0x2021, 0x7845, 0x2424, + 0x2061, 0x7d00, 0x2071, 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, + 0x00c8, 0x73d5, 0x2100, 0xac06, 0x0040, 0x73cb, 0x1078, 0x754e, + 0x0040, 0x73cb, 0x671c, 0xa786, 0x0001, 0x0040, 0x73ea, 0xa786, + 0x0007, 0x0040, 0x73cb, 0x2500, 0xac06, 0x0040, 0x73cb, 0x2400, + 0xac06, 0x0040, 0x73cb, 0x1078, 0x7562, 0x00c0, 0x73cb, 0x0d7e, + 0x6000, 0xa086, 0x0004, 0x00c0, 0x73b1, 0x017e, 0x1078, 0x166e, + 0x017f, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x73c8, 0xa786, + 0x0003, 0x00c0, 0x73de, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x017e, 0x1078, 0x6b34, 0x1078, 0x3a72, 0x017f, 0x1078, 0x6a89, + 0x0d7f, 0x1078, 0x6a96, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x73d5, 0x0078, 0x7382, 0x127f, 0x027f, 0x047f, + 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, + 0x00c0, 0x73bb, 0xa386, 0x0005, 0x0040, 0x73cb, 0x1078, 0x74f2, + 0x0078, 0x73c8, 0x1078, 0x7562, 0x00c0, 0x73cb, 0xa180, 0x0001, + 0x2004, 0xa086, 0x0018, 0x00c0, 0x73cb, 0x6000, 0xa086, 0x0002, + 0x00c0, 0x73cb, 0x1078, 0x6aaf, 0x0040, 0x7406, 0x1078, 0x6ac3, + 0x00c0, 0x73cb, 0x1078, 0x5e4d, 0x0078, 0x7408, 0x1078, 0x22d7, + 0x1078, 0x6a96, 0x0078, 0x73cb, 0x0c7e, 0x0e7e, 0x017e, 0x2c08, + 0x2170, 0x1078, 0x7509, 0x017f, 0x0040, 0x741b, 0x601c, 0xa084, + 0x000f, 0x1079, 0x741e, 0x0e7f, 0x0c7f, 0x007c, 0x7426, 0x7426, + 0x7426, 0x7426, 0x7426, 0x7426, 0x7428, 0x7426, 0xa006, 0x007c, + 0x047e, 0x017e, 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, + 0x8427, 0x2c00, 0x2009, 0x0020, 0x1078, 0x7536, 0x017f, 0x047f, + 0x037e, 0x2019, 0x0002, 0x1078, 0x71db, 0x037f, 0xa085, 0x0001, + 0x007c, 0x2001, 0x0001, 0x1078, 0x37b5, 0x157e, 0x017e, 0x027e, + 0x037e, 0x20a9, 0x0004, 0x2019, 0x7605, 0x2011, 0x7b96, 0x1078, + 0x6160, 0x037f, 0x027f, 0x017f, 0x157f, 0xa005, 0x007c, 0x0f7e, + 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, + 0x2061, 0x7d00, 0x2079, 0x0001, 0x8fff, 0x0040, 0x74b2, 0x2071, + 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, 0x00c8, 0x74b2, 0x88ff, + 0x0040, 0x7478, 0x2800, 0xac06, 0x00c0, 0x74a8, 0x2079, 0x0000, + 0x1078, 0x754e, 0x0040, 0x74a8, 0x2400, 0xac06, 0x0040, 0x74a8, + 0x671c, 0xa786, 0x0006, 0x00c0, 0x74a8, 0xa786, 0x0007, 0x0040, + 0x74a8, 0x88ff, 0x00c0, 0x7490, 0x6018, 0xa206, 0x00c0, 0x74a8, + 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x7498, 0x1078, 0x166e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x74a2, 0x047e, 0x1078, + 0x74f2, 0x047f, 0x0d7f, 0x1078, 0x6a96, 0x88ff, 0x00c0, 0x74bb, + 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x74b2, + 0x0078, 0x7464, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f, 0x0c7f, + 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078, 0x74b3, 0x087e, + 0x2041, 0x0000, 0x2c20, 0x2019, 0x0002, 0x6218, 0x1078, 0x590d, + 0x1078, 0x59ae, 0x1078, 0x7457, 0x087f, 0x007c, 0x027e, 0x047e, + 0x087e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x017e, 0x037e, 0x1078, 0x381d, 0x00c0, 0x74e7, 0x2c10, 0x2041, + 0x0000, 0x1078, 0x590d, 0x1078, 0x59ae, 0x1078, 0x7457, 0x037f, + 0x017f, 0x8108, 0x00f0, 0x74d8, 0x157f, 0x0c7f, 0x087f, 0x047f, + 0x027f, 0x007c, 0x017e, 0x0f7e, 0x8dff, 0x0040, 0x7506, 0x6800, + 0xa07d, 0x0040, 0x7503, 0x6803, 0x0000, 0x6b52, 0x1078, 0x3a72, + 0x2f68, 0x0078, 0x74f7, 0x6b52, 0x1078, 0x3a72, 0x0f7f, 0x017f, + 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, 0x7d00, 0x2071, 0x7600, + 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, 0x7531, 0x2100, 0xac06, + 0x0040, 0x7523, 0x6000, 0xa086, 0x0000, 0x0040, 0x7523, 0x6008, + 0xa206, 0x0040, 0x752d, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x7531, 0x0078, 0x750e, 0xa085, 0x0001, 0x0078, + 0x7532, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, 0x0d7e, 0x007e, + 0x1078, 0x1327, 0x007f, 0x1040, 0x12cd, 0x6837, 0x010d, 0x6803, + 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x685e, 0x6956, 0x6c46, + 0x684f, 0x0000, 0x1078, 0x3a72, 0x0d7f, 0x007c, 0x6700, 0xa786, + 0x0000, 0x0040, 0x7561, 0xa786, 0x0001, 0x0040, 0x7561, 0xa786, + 0x000a, 0x0040, 0x7561, 0xa786, 0x0009, 0x0040, 0x7561, 0xa085, + 0x0001, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x70a0, 0xa206, 0x0e7f, + 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7640, + 0xd5a4, 0x0040, 0x7576, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, + 0x757c, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0x7583, 0x2071, + 0x764a, 0x1078, 0x75b2, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, + 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7640, 0xd5a4, 0x0040, + 0x7594, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0x759a, 0x7030, + 0x8000, 0x7032, 0xd5ac, 0x0040, 0x75a1, 0x2071, 0x764a, 0x1078, + 0x75b2, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0x7642, 0x1078, 0x75b2, 0x0e7f, 0x007f, + 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, 0x00c8, 0x75bb, 0x8e70, + 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, 0x2071, 0x7640, 0x1078, + 0x75b2, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7644, 0x1078, 0x75b2, + 0x0e7f, 0x007c, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x8000, 0x2212 +}; + +/* + * Firmware Version 2.00.16 (09:36 Jun 29, 1999) + */ + +unsigned short risc_code2200[] = { + 0x0470, 0x0000, 0x0000, 0x81bd, 0x0000, 0x0002, 0x0000, 0x0010, + 0x0027, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, + 0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x322e, 0x3030, 0x2e31, 0x3620, 0x2020, 0x2020, 0x2400, 0x20c1, + 0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0x96ff, 0x2091, + 0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x2490, + 0x2051, 0x9200, 0x2a70, 0x2029, 0xb100, 0x2031, 0xffff, 0x2039, + 0xb0f5, 0x2021, 0x0200, 0x0804, 0x136b, 0x20a1, 0x91bd, 0xa00e, + 0x20a9, 0x0743, 0x41a4, 0x3400, 0x755e, 0x7662, 0x775a, 0x7466, + 0x746a, 0x20a1, 0x9900, 0x7160, 0x810d, 0x810d, 0x810d, 0x810d, + 0xa18c, 0x000f, 0x2001, 0x0009, 0xa112, 0xa00e, 0x21a8, 0x41a4, + 0x3400, 0x8211, 0x1dd8, 0x7160, 0x3400, 0xa102, 0x0120, 0x0218, + 0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0x9200, + 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001, + 0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0, + 0x2009, 0x9200, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e, + 0x41a4, 0x080c, 0x1322, 0x080c, 0x14b6, 0x080c, 0x1649, 0x080c, + 0x1c81, 0x080c, 0x41d4, 0x080c, 0x7494, 0x080c, 0x1439, 0x080c, + 0x2819, 0x080c, 0x4e42, 0x080c, 0x4757, 0x080c, 0x5874, 0x080c, + 0x56c0, 0x080c, 0x2138, 0x080c, 0x5ed0, 0x080c, 0x532f, 0x080c, + 0x206a, 0x080c, 0x210e, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, + 0x10c7, 0x7820, 0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, + 0x10bf, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, + 0x7003, 0x0000, 0x2a70, 0x7000, 0xa08e, 0x0003, 0x1168, 0x080c, + 0x36d4, 0x080c, 0x2840, 0x080c, 0x4e90, 0x080c, 0x493b, 0x080c, + 0x58b1, 0x080c, 0x56d8, 0x0c70, 0x000b, 0x0c88, 0x10e8, 0x10e9, + 0x11b8, 0x10e6, 0x123f, 0x131f, 0x1320, 0x1321, 0x080c, 0x13fe, + 0x0005, 0x0126, 0x00f6, 0x2091, 0x8000, 0x080c, 0x4dc5, 0x0150, + 0x080c, 0x4deb, 0x11f8, 0x2079, 0x0100, 0x7828, 0xa085, 0x1800, + 0x782a, 0x00c0, 0x080c, 0x4d10, 0x7088, 0xa086, 0x0026, 0x1904, + 0x119d, 0x2079, 0x0100, 0x7827, 0xffff, 0x782b, 0x1c2b, 0x2011, + 0x4ce2, 0x080c, 0x5731, 0x2011, 0x8030, 0x2019, 0x0000, 0x7087, + 0x0000, 0x00a8, 0x080c, 0x3a6a, 0x2079, 0x0100, 0x7844, 0xa005, + 0x1904, 0x119d, 0x2011, 0x40af, 0x080c, 0x5731, 0x780f, 0x03ff, + 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, 0x73c4, 0x080c, + 0x3698, 0x080c, 0x706b, 0x2011, 0x0004, 0x080c, 0x82f3, 0x080c, + 0x46a8, 0x080c, 0x4dc5, 0x0158, 0x080c, 0x41bd, 0x0140, 0x7087, + 0x0001, 0x70bf, 0x0000, 0x080c, 0x3bfd, 0x0804, 0x119d, 0x70d3, + 0x0000, 0x70cf, 0x0000, 0x706f, 0x0000, 0x7073, 0x0000, 0x080c, + 0x11a0, 0x72c8, 0x080c, 0x4dc5, 0x1160, 0x2011, 0x0000, 0x2001, + 0x0204, 0x2004, 0x2019, 0x94c8, 0x201a, 0x704f, 0xffff, 0x7053, + 0x00ef, 0x2079, 0x9251, 0x7804, 0xd0ac, 0x0108, 0xc295, 0x72ca, + 0x080c, 0x4dc5, 0x0118, 0xa296, 0x0004, 0x0500, 0x2011, 0x0001, + 0x080c, 0x82f3, 0x080c, 0x854a, 0x7097, 0x0000, 0x709b, 0xffff, + 0x7003, 0x0002, 0x00fe, 0x080c, 0x251c, 0x2011, 0x0005, 0x080c, + 0x718f, 0x080c, 0x6462, 0x080c, 0x4dc5, 0x0130, 0x00c6, 0x2061, + 0x0100, 0x60e3, 0x0008, 0x00ce, 0x012e, 0x00c8, 0x080c, 0x854a, + 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, + 0x080c, 0x718f, 0x080c, 0x6462, 0x080c, 0x4dc5, 0x0130, 0x00c6, + 0x2061, 0x0100, 0x60e3, 0x0008, 0x00ce, 0x00fe, 0x012e, 0x0005, + 0x00c6, 0x080c, 0x4dc5, 0x1118, 0x20a9, 0x0100, 0x0010, 0x20a9, + 0x0082, 0x080c, 0x4dc5, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, + 0x007e, 0x080c, 0x441f, 0x8108, 0x1f04, 0x11b1, 0x00ce, 0x0005, + 0x0126, 0x2091, 0x8000, 0x7098, 0xa086, 0xffff, 0x0130, 0x080c, + 0x251c, 0x080c, 0x6462, 0x0804, 0x123d, 0x70c8, 0xd0ac, 0x1110, + 0xd09c, 0x0558, 0xd084, 0x0548, 0x0006, 0x70c8, 0xa084, 0x0030, + 0x000e, 0x1138, 0x00f6, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, + 0x00fe, 0xd08c, 0x01d0, 0x70cc, 0xa086, 0xffff, 0x0190, 0x080c, + 0x25fd, 0x080c, 0x6462, 0x70c8, 0xd094, 0x1904, 0x123d, 0x2011, + 0x0001, 0x2019, 0x0000, 0x080c, 0x2631, 0x080c, 0x6462, 0x0804, + 0x123d, 0x70d0, 0xa005, 0x1904, 0x123d, 0x7094, 0xa005, 0x1904, + 0x123d, 0x70c8, 0xd0a4, 0x0110, 0xd0b4, 0x05f8, 0x2001, 0x9252, + 0x2004, 0xd0ac, 0x01c0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x0016, 0x080c, 0x4434, 0x1118, 0x6000, 0xd0ec, 0x1138, + 0x001e, 0x8108, 0x1f04, 0x1209, 0x00ce, 0x015e, 0x0020, 0x001e, + 0x00ce, 0x015e, 0x0410, 0x00f6, 0x2079, 0x0100, 0x780c, 0xc0b5, + 0x780e, 0x00fe, 0x7003, 0x0003, 0x709b, 0xffff, 0xa006, 0x080c, + 0x23ba, 0x080c, 0x370a, 0x2001, 0x94e6, 0x2004, 0xa086, 0x0005, + 0x1120, 0x2011, 0x0000, 0x080c, 0x718f, 0x2011, 0x0000, 0x080c, + 0x7199, 0x080c, 0x6462, 0x080c, 0x651c, 0x012e, 0x0005, 0x0016, + 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, + 0x080c, 0x4186, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, + 0x0110, 0x7827, 0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, + 0x0036, 0x0156, 0x7954, 0xd1ac, 0x1904, 0x12a5, 0x080c, 0x4dd7, + 0x0158, 0x080c, 0x4deb, 0x1128, 0x2001, 0x94d7, 0x2003, 0x0000, + 0x0070, 0x080c, 0x4dcd, 0x0dc0, 0x2001, 0x94d7, 0x2003, 0xaaaa, + 0x2001, 0x94d8, 0x2003, 0x0001, 0x080c, 0x4d10, 0x0058, 0x080c, + 0x4dc5, 0x0140, 0x2009, 0x00f8, 0x080c, 0x4186, 0x7843, 0x0090, + 0x7843, 0x0010, 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, + 0x4dc5, 0x0138, 0x7824, 0xd0ac, 0x1904, 0x130d, 0x1f04, 0x1284, + 0x0070, 0x7824, 0x080c, 0x4de1, 0x0118, 0xd0ac, 0x1904, 0x130d, + 0xa084, 0x1800, 0x0d98, 0x7003, 0x0001, 0x0804, 0x130d, 0x2001, + 0x0001, 0x080c, 0x23ba, 0x0804, 0x1318, 0x7850, 0xa084, 0x0180, + 0x7852, 0x782f, 0x0020, 0x20a9, 0x0050, 0x1d04, 0x12ad, 0x2091, + 0x6000, 0x1f04, 0x12ad, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, + 0x7852, 0x782f, 0x0000, 0x080c, 0x4dd7, 0x0158, 0x080c, 0x4deb, + 0x1128, 0x2001, 0x94d7, 0x2003, 0x0000, 0x0070, 0x080c, 0x4dcd, + 0x0dc0, 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x0020, 0x2009, 0x00f8, 0x080c, 0x4186, + 0x20a9, 0x000e, 0xe000, 0x1f04, 0x12da, 0x7850, 0xa084, 0x0180, + 0xa085, 0x1400, 0x7852, 0x080c, 0x4dc5, 0x0120, 0x7843, 0x0090, + 0x7843, 0x0010, 0x2019, 0x61a8, 0x7820, 0xd09c, 0x1130, 0x080c, + 0x4dc5, 0x0130, 0x7824, 0xd0ac, 0x11c0, 0x8319, 0x1da8, 0x0080, + 0x7827, 0x1800, 0xe000, 0xe000, 0x7824, 0x080c, 0x4de1, 0x0110, + 0xd0ac, 0x1158, 0xa084, 0x1800, 0x0d80, 0x7003, 0x0001, 0x0028, + 0x2001, 0x0001, 0x080c, 0x23ba, 0x0028, 0x7827, 0x0048, 0x7828, + 0xc09d, 0x782a, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, + 0x015e, 0x003e, 0x000e, 0x012e, 0x00fe, 0x001e, 0x0005, 0x0005, + 0x0005, 0x0005, 0x2a70, 0x2001, 0x94d7, 0x2003, 0x0000, 0x7087, + 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0218, 0x704f, + 0xffff, 0x0010, 0x704f, 0x0000, 0x7057, 0xffff, 0x706f, 0x0000, + 0x7073, 0x0000, 0x080c, 0x854a, 0x2061, 0x94c7, 0x6003, 0x0909, + 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, + 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0x94cf, + 0x6003, 0x8800, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, + 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, 0x0000, + 0x2061, 0x94df, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, + 0x600f, 0x2020, 0x0005, 0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, + 0xa186, 0x0001, 0x1148, 0x2031, 0x8fff, 0x2039, 0xa501, 0x2021, + 0x0100, 0x2029, 0xa500, 0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, + 0x0000, 0x00b8, 0xa186, 0x0005, 0x1118, 0x2011, 0x0001, 0x0088, + 0xa186, 0x0009, 0x1118, 0x2011, 0x0002, 0x0058, 0xa186, 0x000a, + 0x1118, 0x2011, 0x0002, 0x0028, 0xa186, 0x0055, 0x1110, 0x2011, + 0x0003, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, + 0xa00e, 0x2011, 0x0003, 0x2019, 0x13a7, 0x0804, 0x13f8, 0x2019, + 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, + 0xa306, 0x2262, 0x1110, 0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, + 0x13ba, 0x04f0, 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, + 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, + 0x2061, 0xffff, 0x2262, 0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, + 0x2011, 0x0002, 0x2019, 0x13d5, 0x0418, 0x2061, 0xffff, 0x2019, + 0xaaaa, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, + 0x1180, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, + 0x2c04, 0x2061, 0xffff, 0x2262, 0xa306, 0x1110, 0xc195, 0x0008, + 0xc19d, 0x2011, 0x0001, 0x2019, 0x13f6, 0x0010, 0x0804, 0x136c, + 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0837, 0x2091, 0x8000, + 0x0e04, 0x1400, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084, + 0x1de8, 0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900, + 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0156, + 0x0146, 0x20a9, 0x0010, 0x20a1, 0x95e6, 0x2091, 0x2000, 0x40a1, + 0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010, 0x2091, + 0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1, 0x014e, + 0x015e, 0x2079, 0x9200, 0x7803, 0x0005, 0x2091, 0x4080, 0x0cf8, + 0x0005, 0x2071, 0x9200, 0x715c, 0x712e, 0x2021, 0x0001, 0xa190, + 0x0030, 0xa298, 0x0030, 0x0240, 0x7060, 0xa302, 0x1228, 0x220a, + 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800, 0xd08c, 0x0148, 0x7060, + 0xa086, 0x9200, 0x0128, 0x7063, 0x9200, 0x2011, 0x1000, 0x0c48, + 0x200b, 0x0000, 0x74aa, 0x74ae, 0x70df, 0x0010, 0x0005, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x2071, 0x9200, 0x70ac, 0x0016, 0x2008, + 0x70dc, 0xa16a, 0x2100, 0x001e, 0x0268, 0x8001, 0x70ae, 0x702c, + 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, + 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x2071, 0x9200, 0x0126, + 0x2091, 0x8000, 0x70ac, 0x8001, 0x0260, 0x70ae, 0x702c, 0x2068, + 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, + 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, + 0x9200, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, 0x70ae, + 0x012e, 0x00ee, 0x0005, 0x8dff, 0x0138, 0x6804, 0x6807, 0x0000, + 0x0006, 0x0c49, 0x00de, 0x0cb8, 0x0005, 0x00e6, 0x2071, 0x9200, + 0x70ac, 0xa08a, 0x0010, 0xa00d, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x9508, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, + 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x00ee, 0x0005, 0x00e6, + 0x2270, 0x700b, 0x0000, 0x2071, 0x9508, 0x7018, 0xa088, 0x9511, + 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x1128, + 0x00f6, 0x2079, 0x0010, 0x0081, 0x00fe, 0x00ee, 0x0005, 0x00e6, + 0x2071, 0x9508, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, + 0x0019, 0x00fe, 0x00ee, 0x0005, 0x7000, 0x0002, 0x14f3, 0x1557, + 0x1574, 0x1574, 0x1f79, 0x7018, 0x711c, 0xa106, 0x1118, 0x7007, + 0x0000, 0x0005, 0x00d6, 0xa180, 0x9511, 0x2004, 0x700a, 0x2068, + 0x8108, 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, + 0x6828, 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, + 0x680c, 0x7016, 0x6804, 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, + 0x0029, 0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, + 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, + 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, + 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, 0x2011, + 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x22a8, + 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, 0x7016, 0x7803, + 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x0136, + 0x0146, 0x0156, 0x2099, 0x930e, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0041, + 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, 0x9309, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2001, + 0x933d, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, 0x2001, 0x933e, + 0x20ac, 0x53a6, 0x2099, 0x933f, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0001, + 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0x933a, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0016, 0x00e6, 0x2071, 0x9508, + 0x00f6, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, 0xd1fc, 0x0120, + 0xa18c, 0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, + 0x14ec, 0x15b8, 0x15e2, 0x1608, 0x1638, 0x1f96, 0x15b7, 0x0cf8, + 0xa18c, 0x0700, 0x1508, 0x0136, 0x0146, 0x0156, 0x7014, 0x20a0, + 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, + 0x7016, 0x015e, 0x014e, 0x013e, 0x700c, 0xa005, 0x0530, 0x080c, + 0x151e, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, + 0x0000, 0x080c, 0x14ec, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0200, 0x0ca8, 0xa18c, 0x0700, 0x1130, 0x700c, 0xa005, 0x0168, + 0x080c, 0x1533, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, + 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, 0x00d6, 0x7008, 0x2068, + 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, 0x6832, + 0x680b, 0x0100, 0x00de, 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, + 0xa18c, 0x0700, 0x1540, 0x0136, 0x0146, 0x0156, 0x2001, 0x930c, + 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, + 0x20a9, 0x0020, 0x53a5, 0x2001, 0x930e, 0x2004, 0xd0bc, 0x0148, + 0x2001, 0x9317, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, + 0x53a5, 0x015e, 0x014e, 0x013e, 0x7007, 0x0000, 0x080c, 0x4f27, + 0x080c, 0x14ec, 0x0005, 0x2011, 0x8003, 0x080c, 0x3698, 0x0cf8, + 0xa18c, 0x0700, 0x1148, 0x2001, 0x933c, 0x2003, 0x0100, 0x7007, + 0x0000, 0x080c, 0x14ec, 0x0005, 0x2011, 0x8004, 0x080c, 0x3698, + 0x0cf8, 0x0126, 0x2091, 0x2200, 0x2079, 0x0030, 0x2071, 0x9519, + 0x7003, 0x0000, 0x700f, 0x9520, 0x7013, 0x9520, 0x780f, 0x00f0, + 0x012e, 0x0005, 0x6934, 0xa184, 0x0007, 0x0002, 0x1666, 0x16ab, + 0x1666, 0x1666, 0x166a, 0x1693, 0x167a, 0x1671, 0xa085, 0x0001, + 0x0804, 0x16c5, 0xa186, 0x0024, 0x05f0, 0xa186, 0x002c, 0x05d8, + 0x0ca8, 0x684c, 0xd0bc, 0x0d90, 0x6860, 0x682e, 0x685c, 0x682a, + 0x6858, 0x04c8, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d38, 0x684c, + 0xd0bc, 0x0d20, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, + 0x6832, 0x6858, 0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x1970, + 0x684c, 0xd0ac, 0x0958, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, + 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, 0x6832, 0xa006, 0x682e, + 0x682a, 0x6858, 0x0080, 0x684c, 0xd0ac, 0x0904, 0x1666, 0xa006, + 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, 0x1f59, 0x210d, + 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, + 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007, + 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x82ff, 0x0178, 0xa280, + 0x0004, 0x00d6, 0x206c, 0x684c, 0xd0dc, 0x1120, 0x080c, 0x165a, + 0x190c, 0x13fe, 0x6808, 0x8000, 0x680a, 0x00de, 0x0126, 0x0046, + 0x0036, 0x0026, 0x2091, 0x2200, 0x002e, 0x003e, 0x004e, 0x7000, + 0xa005, 0x0178, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, + 0x8108, 0xa182, 0x953b, 0x0210, 0x2009, 0x9520, 0x710e, 0x012e, + 0x0005, 0x7206, 0x2001, 0x16f7, 0x0006, 0x2260, 0x0804, 0x17e8, + 0x0126, 0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200, 0x000e, + 0x004e, 0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110, 0x2168, + 0x6a62, 0x6b5e, 0xa005, 0x05b8, 0x6808, 0xa005, 0x0904, 0x177c, + 0x7000, 0xa005, 0x1108, 0x0430, 0x700c, 0x7110, 0xa106, 0x1904, + 0x1784, 0x7004, 0xa406, 0x11f0, 0x2001, 0x0005, 0x2004, 0xd08c, + 0x0130, 0x0046, 0x080c, 0x1942, 0x004e, 0x2460, 0x0c28, 0x2001, + 0x0207, 0x2004, 0xd09c, 0x1d80, 0x7804, 0xa084, 0x6000, 0x0120, + 0xa086, 0x6000, 0x0108, 0x0c40, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x15f0, 0x2009, 0x0048, + 0x080c, 0x7518, 0x04c8, 0x6808, 0xa005, 0x0570, 0x7000, 0xa005, + 0x0558, 0x700c, 0x7110, 0xa106, 0x1118, 0x7004, 0xa406, 0x1520, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0130, 0x0046, 0x080c, 0x1942, + 0x004e, 0x2460, 0x0c40, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d80, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x1d80, 0x7804, 0xa084, 0x6000, + 0x0118, 0xa086, 0x6000, 0x1d20, 0x7818, 0x6812, 0x781c, 0x6816, + 0x7803, 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x1120, + 0x2009, 0x0048, 0x080c, 0x7518, 0x00ce, 0x00de, 0x012e, 0x0005, + 0x00f6, 0x00e6, 0x0026, 0x0036, 0x0046, 0x080c, 0x1c26, 0x0026, + 0x2071, 0x9519, 0x7000, 0xa086, 0x0000, 0x0580, 0x7004, 0xac06, + 0x11f8, 0x2079, 0x0030, 0x7000, 0xa086, 0x0003, 0x01c8, 0x7804, + 0xd0fc, 0x1198, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1dc0, 0x7803, + 0x0004, 0x7804, 0xd0ac, 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, + 0x7003, 0x0003, 0x7007, 0x0000, 0x0018, 0x080c, 0x1942, 0x08d0, + 0x0156, 0x20a9, 0x0009, 0x2009, 0x9520, 0x2104, 0xac06, 0x1108, + 0x200a, 0xa188, 0x0003, 0x1f04, 0x17bd, 0x015e, 0x002e, 0x2001, + 0x015d, 0x201c, 0x831a, 0x2302, 0x2001, 0x0138, 0x2202, 0x004e, + 0x003e, 0x002e, 0x00ee, 0x00fe, 0x0005, 0x700c, 0x7110, 0xa106, + 0x0904, 0x182c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, + 0x2124, 0x8108, 0xa182, 0x953b, 0x0210, 0x2009, 0x9520, 0x7112, + 0x8cff, 0x05a0, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, 0x1598, + 0x682c, 0xa306, 0x1580, 0x684c, 0xd0f4, 0x1540, 0x6850, 0xd0f4, + 0x1130, 0x7803, 0x0004, 0x6810, 0x781a, 0x6814, 0x781e, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x6834, 0xa08c, 0x00ff, 0xa186, 0x0024, 0x0118, 0xa186, 0x002c, + 0x1120, 0x2009, 0x0011, 0x00d9, 0x0038, 0x2009, 0x0011, 0x00b9, + 0x0118, 0x2009, 0x0001, 0x0099, 0x2d58, 0x0005, 0x7803, 0x0004, + 0x080c, 0x1be2, 0x0cd0, 0x601c, 0xa086, 0x0008, 0x1108, 0x0858, + 0x080c, 0x1fa7, 0x1d98, 0x0838, 0x7003, 0x0000, 0x0005, 0x8aff, + 0x0904, 0x191c, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11b8, 0xd0f4, + 0x1538, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x18b6, 0x1867, + 0x1867, 0x18b6, 0x18b9, 0x18ae, 0x18b6, 0x1867, 0x18b6, 0x1878, + 0x1878, 0x18b6, 0x18b9, 0x18b6, 0x18a6, 0x1878, 0x7803, 0x0004, + 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6, 0xd99c, + 0x0904, 0x1909, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x0804, 0x1909, + 0xc0f4, 0x6852, 0x6b6c, 0x6a70, 0x00d6, 0x0804, 0x1910, 0x2d10, + 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, 0xa096, 0x0024, + 0x0904, 0x18e9, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0804, 0x1909, + 0x2d10, 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, 0xa096, + 0x002c, 0x0904, 0x18c6, 0x7b0c, 0xd3bc, 0x01c0, 0x7004, 0x00e6, + 0x2070, 0x701c, 0x00ee, 0xa086, 0x0008, 0x1180, 0x7b08, 0xa39c, + 0x0fff, 0x2d20, 0x7a1c, 0x82ff, 0x1120, 0x7818, 0xa302, 0x0208, + 0x7b18, 0xa016, 0x7a1e, 0x7b1a, 0x2468, 0x0010, 0x6b10, 0x6a14, + 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0804, 0x1909, 0x00de, 0x00d6, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1140, 0x00de, 0x080c, + 0x1f1b, 0x1904, 0x182f, 0xa00e, 0x0804, 0x191c, 0x00de, 0x080c, + 0x13fe, 0x2d10, 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, + 0xa096, 0x0024, 0x0530, 0xa096, 0x002c, 0x1d80, 0x6b10, 0xa3a6, + 0xffff, 0x1130, 0x2d10, 0x00de, 0x00d6, 0x080c, 0x59f4, 0x2268, + 0x2d10, 0x00de, 0x00d6, 0x7314, 0x685c, 0xa086, 0x0001, 0x1120, + 0x6868, 0xa005, 0x0108, 0x2018, 0x2268, 0x2011, 0x0000, 0x6d00, + 0x6c04, 0x6f08, 0x6e0c, 0x780f, 0x00f0, 0xe000, 0xe000, 0xe000, + 0x0400, 0x6b08, 0xa3a6, 0xffff, 0x1130, 0x2d10, 0x00de, 0x00d6, + 0x080c, 0x59f4, 0x2268, 0x2d10, 0x00de, 0x00d6, 0x7314, 0x685c, + 0xa086, 0x0001, 0x1120, 0x6868, 0xa005, 0x0108, 0x2018, 0x2268, + 0x2011, 0x0000, 0x6d00, 0x6c04, 0x780f, 0x00f0, 0xe000, 0xe000, + 0xe000, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, + 0x7000, 0x8000, 0x7002, 0x00de, 0x6828, 0xa300, 0x682a, 0x682c, + 0xa201, 0x682e, 0x080c, 0x1f1b, 0x0005, 0x080c, 0x13fe, 0x7803, + 0x0004, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x7003, 0x0000, + 0x080c, 0x1c02, 0x080c, 0x82ee, 0x0170, 0x6808, 0x8001, 0x680a, + 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x80f6, 0x0804, 0x1b4b, + 0x080c, 0x13fe, 0x0126, 0x2091, 0x2200, 0x0006, 0x0016, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x1978, + 0xa184, 0x0003, 0xa086, 0x0003, 0x0d58, 0x7000, 0x0002, 0x195f, + 0x1961, 0x1aa6, 0x1b20, 0x1b3a, 0x195f, 0x195f, 0x195f, 0x080c, + 0x13fe, 0x8001, 0x7002, 0xa184, 0x0880, 0x1904, 0x19a8, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0024, 0x0130, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x1518, 0x6864, 0x8000, 0x6866, 0xd19c, 0x0140, + 0x7004, 0x2060, 0x2009, 0x0102, 0x080c, 0x7518, 0x0804, 0x1a64, + 0x8aff, 0x0130, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, + 0x7004, 0x2060, 0x2009, 0x0106, 0x080c, 0x7518, 0x7007, 0x0000, + 0x7803, 0x0009, 0x7003, 0x0003, 0x0804, 0x1b4b, 0xd19c, 0x1904, + 0x1a49, 0x8aff, 0x0904, 0x1a49, 0x2009, 0x0001, 0x080c, 0x182f, + 0x0904, 0x1b4b, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, + 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1a18, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0024, 0x0130, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x1138, 0xd19c, 0x0128, 0x6864, 0x8000, 0x6866, + 0x0804, 0x1978, 0x0026, 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, + 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, + 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, + 0x0070, 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, 0x0140, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x002c, 0x0110, 0x080c, 0x1b4f, 0x6b28, + 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, 0xa213, 0x6b2a, + 0x6a2e, 0x003e, 0x002e, 0x6e1e, 0x6f22, 0x080c, 0x1f31, 0x2a00, + 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, + 0x6808, 0x8001, 0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004, + 0x2060, 0x2009, 0x0048, 0x080c, 0x7518, 0x7000, 0xa086, 0x0004, + 0x0904, 0x1b4b, 0x7003, 0x0000, 0x080c, 0x17d5, 0x0804, 0x1b4b, + 0x0056, 0x7d0c, 0xd5bc, 0x1110, 0x080c, 0x9171, 0x005e, 0x080c, + 0x1c02, 0x7004, 0x7007, 0x0000, 0x2060, 0x601c, 0xa086, 0x0009, + 0x1198, 0x790c, 0x0016, 0x2009, 0x0106, 0x080c, 0x7518, 0x001e, + 0xd0ec, 0x1118, 0x2009, 0x0009, 0x0010, 0x2009, 0x0019, 0x7902, + 0x7003, 0x0003, 0x0804, 0x1b4b, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, + 0x1b4b, 0x7818, 0x6812, 0x7a1c, 0x6a16, 0xd19c, 0x0118, 0xa205, + 0x1904, 0x19a8, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x1180, + 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x1130, 0x7004, 0x2060, + 0x2009, 0x0048, 0x080c, 0x7518, 0x080c, 0x17d5, 0x0804, 0x1b4b, + 0x7818, 0x6812, 0x781c, 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, + 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, 0x8004, + 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x080c, 0x1c40, 0x7803, + 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc, 0x0de8, + 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x00f0, 0x7004, 0x7007, + 0x0000, 0x2060, 0x2009, 0x0048, 0x080c, 0x7518, 0x080c, 0x1c62, + 0x0958, 0x7908, 0xd1ec, 0x1118, 0x2009, 0x0009, 0x0010, 0x2009, + 0x0019, 0x7902, 0x7003, 0x0003, 0x0804, 0x1b4b, 0x8001, 0x7002, + 0xd194, 0x0178, 0x7804, 0xd0fc, 0x1904, 0x194a, 0xd09c, 0x11a8, + 0x8aff, 0x0904, 0x1b4b, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, + 0x1b4b, 0xa184, 0x0888, 0x1148, 0x8aff, 0x0904, 0x1b4b, 0x2009, + 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, 0x7803, 0x0004, 0x7003, + 0x0000, 0xd1bc, 0x1904, 0x1b0d, 0x0026, 0x0036, 0x7c20, 0x7d24, + 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, 0x0201, + 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, 0x0009, + 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, 0x1b4f, 0x001e, 0x6b28, + 0x6a2c, 0x080c, 0x1f31, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, + 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, + 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, 0x19e9, 0x2a00, 0x6826, + 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001, 0x680a, 0x6b2a, + 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1a64, 0x0056, 0x7d0c, 0x080c, + 0x9171, 0x005e, 0x080c, 0x1c02, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0458, + 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0180, 0x6808, + 0x8001, 0x680a, 0x1160, 0x7004, 0x2060, 0x2009, 0x0048, 0x601c, + 0xa086, 0x0009, 0x1110, 0x080c, 0x13fe, 0x080c, 0x7518, 0x080c, + 0x17d5, 0x0088, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, + 0x6b2c, 0x080c, 0x17e8, 0x001e, 0x000e, 0x012e, 0x0005, 0x700c, + 0x7110, 0xa106, 0x0904, 0x1bd6, 0x7004, 0x0016, 0x210c, 0xa106, + 0x001e, 0x0904, 0x1bd6, 0x00d6, 0x00c6, 0x216c, 0x2d00, 0xa005, + 0x0904, 0x1bd4, 0x6810, 0x2068, 0x6834, 0xa084, 0x00ff, 0xa086, + 0x0024, 0x0904, 0x1bd4, 0x6834, 0xa084, 0x00ff, 0xa086, 0x002c, + 0x0904, 0x1bd4, 0x6850, 0xd0fc, 0x0558, 0x8108, 0x2104, 0x6b2c, + 0xa306, 0x1904, 0x1bd4, 0x8108, 0x2104, 0x6a28, 0xa206, 0x1904, + 0x1bd4, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870, + 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034, + 0xd09c, 0x0150, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, 0x783a, + 0x680c, 0x783e, 0x00de, 0x0490, 0xa006, 0x783a, 0x783e, 0x0470, + 0x8108, 0x2104, 0xa005, 0x1580, 0x8108, 0x2104, 0xa005, 0x1560, + 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2005, 0x6918, 0xa160, 0x6834, + 0xd09c, 0x1170, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, + 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0070, + 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, + 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x6810, 0x781a, + 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce, 0x00de, 0x0005, 0x2011, + 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, 0x1118, 0x8109, 0x1dd8, + 0x0005, 0x0005, 0x0ca1, 0x01e0, 0x7908, 0xd1ec, 0x1160, 0x080c, + 0x1c62, 0x0148, 0x7803, 0x0009, 0x7904, 0xd1fc, 0x0de8, 0x7803, + 0x0006, 0x0c29, 0x0168, 0x780c, 0xd0a4, 0x1150, 0x7007, 0x0000, + 0x080c, 0x1c62, 0x0130, 0x7803, 0x0019, 0x7003, 0x0003, 0x0008, + 0x0009, 0x0005, 0x00c6, 0x0411, 0x20e1, 0x9028, 0x700c, 0x7110, + 0xa106, 0x0190, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, + 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0x953b, 0x0210, + 0x2009, 0x9520, 0x7112, 0x0c50, 0x2001, 0x015d, 0x200c, 0x810a, + 0x2102, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x2001, 0x0138, + 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, + 0xd3dc, 0x1168, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x1138, + 0x2001, 0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x0005, + 0x3c00, 0x0006, 0x00e6, 0x2071, 0x0200, 0x7808, 0xa084, 0xf000, + 0xa10d, 0x08e1, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, 0x7028, + 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, 0x7037, + 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x00ee, 0x000e, + 0x20e0, 0x0005, 0x3c00, 0x0006, 0x7908, 0xa18c, 0x0fff, 0xa182, + 0x0009, 0x0218, 0xa085, 0x0001, 0x0088, 0x2001, 0x020a, 0x81ff, + 0x0130, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, + 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x000e, 0x20e0, + 0x0005, 0x00e6, 0x2071, 0x953b, 0x7003, 0x0000, 0x00ee, 0x0005, + 0x00d6, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904, 0x1d0d, + 0x6934, 0xa184, 0x0007, 0x0002, 0x1c9c, 0x1cf8, 0x1c9c, 0x1c9e, + 0x1c9c, 0x1cdf, 0x1cbe, 0x1cad, 0x080c, 0x13fe, 0x2100, 0xa084, + 0x00ff, 0xa086, 0x0013, 0x0904, 0x1cf8, 0x2100, 0xa084, 0x00ff, + 0xa086, 0x001b, 0x0904, 0x1cf8, 0x0c78, 0x684c, 0xd0b4, 0x0904, + 0x1e15, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, + 0x680a, 0x6880, 0x680e, 0x6958, 0x0804, 0x1d00, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x19c0, 0x684c, 0xd0b4, 0x0904, 0x1e15, + 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, + 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, + 0x000f, 0xa080, 0x1f59, 0x2005, 0x6832, 0x6958, 0x0450, 0xa18c, + 0x00ff, 0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4, 0x0904, 0x1e15, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x1f59, 0x2005, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0088, + 0x684c, 0xd0b4, 0x0904, 0x191d, 0x6958, 0xa006, 0x682e, 0x682a, + 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, + 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de, 0x0005, 0x00f6, + 0x2079, 0x0020, 0x7804, 0xd0fc, 0x190c, 0x1e3b, 0x00e6, 0x00d6, + 0x2071, 0x953b, 0x7000, 0xa005, 0x1904, 0x1d81, 0x00c6, 0x7206, + 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, + 0x00d6, 0x2068, 0x686c, 0x7812, 0x6890, 0x00f6, 0x20e1, 0x9040, + 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, + 0x00de, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, + 0x6034, 0xa0cc, 0x000f, 0x6908, 0xa184, 0x0007, 0x0128, 0x0016, + 0x2009, 0x0008, 0xa102, 0x001e, 0xa108, 0x791a, 0x7116, 0x701e, + 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, + 0x7004, 0x692c, 0x6814, 0xa106, 0x1120, 0x6928, 0x6810, 0xa106, + 0x0158, 0x0036, 0x0046, 0x6b14, 0x6c10, 0x080c, 0x1fa7, 0x004e, + 0x003e, 0x0110, 0x00ce, 0x00a8, 0x8aff, 0x1120, 0x00ce, 0xa085, + 0x0001, 0x0078, 0x0126, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, + 0x0001, 0x0059, 0x0118, 0x2009, 0x0001, 0x0039, 0x012e, 0x00ce, + 0xa006, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0076, 0x0066, 0x0056, + 0x0046, 0x0036, 0x0026, 0x8aff, 0x0904, 0x1e0e, 0x700c, 0x7214, + 0xa23a, 0x7010, 0x7218, 0xa203, 0x0a04, 0x1e0d, 0xa705, 0x0904, + 0x1e0d, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11a8, 0x00d6, 0x2805, + 0xac68, 0x2900, 0x0002, 0x1ddc, 0x1dc1, 0x1dc1, 0x1ddc, 0x1ddc, + 0x1dd5, 0x1ddc, 0x1dc1, 0x1ddc, 0x1dc6, 0x1dc6, 0x1ddc, 0x1ddc, + 0x1ddc, 0x1dcd, 0x1dc6, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, + 0x6c20, 0xd99c, 0x05c8, 0x00d6, 0x2805, 0xac68, 0x6f08, 0x6e0c, + 0x0490, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0468, 0x6b10, 0x6a14, + 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0430, 0x00de, 0x00d6, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x1138, 0x00de, 0x080c, 0x1f1b, + 0x1904, 0x1d8b, 0xa00e, 0x0490, 0x2d10, 0x00de, 0x00d6, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0013, 0x2268, 0x09d8, 0x2d10, 0x00de, + 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001b, 0x2268, 0x09b0, + 0x00de, 0x080c, 0x13fe, 0x00de, 0x7b22, 0x7a26, 0x7d32, 0x7c36, + 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, + 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, + 0xa201, 0x7012, 0x080c, 0x1f1b, 0x0008, 0xa006, 0x002e, 0x003e, + 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, 0x13fe, 0x2001, + 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, + 0x0000, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0118, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x80f6, 0x20e1, + 0x9040, 0x080c, 0x7366, 0x2011, 0x0000, 0x080c, 0x7199, 0x080c, + 0x651c, 0x0804, 0x1ef0, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071, 0x953b, + 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, + 0x1930, 0x7000, 0x0002, 0x1ef0, 0x1e57, 0x1ec3, 0x1eee, 0x8001, + 0x7002, 0xd19c, 0x1170, 0x8aff, 0x0540, 0x2009, 0x0001, 0x080c, + 0x1d85, 0x0904, 0x1ef0, 0x2009, 0x0001, 0x080c, 0x1d85, 0x0804, + 0x1ef0, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc, 0x6852, + 0x8aff, 0x1148, 0x684c, 0xc0f5, 0x684e, 0x0028, 0x080c, 0x1f31, + 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, + 0x6832, 0x7003, 0x0000, 0x0804, 0x1ef0, 0x711c, 0x81ff, 0x0190, + 0x7918, 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, + 0x7002, 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, + 0x0804, 0x1ef0, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, + 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, + 0x7820, 0xd0bc, 0x1de8, 0x79c8, 0x000e, 0xa102, 0x001e, 0x0006, + 0x0016, 0x79c4, 0x000e, 0xa102, 0x78c6, 0x000e, 0x78ca, 0xa284, + 0x0004, 0xa085, 0x0012, 0x7816, 0x002e, 0x00fe, 0x7803, 0x0008, + 0x7003, 0x0000, 0x0468, 0x8001, 0x7002, 0xd194, 0x0168, 0x7804, + 0xd0fc, 0x1904, 0x1e4b, 0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, + 0x0001, 0x080c, 0x1d85, 0x00e0, 0x0026, 0x0036, 0x6b28, 0x6a2c, + 0x080c, 0x1f31, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, 0x1128, + 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, 0x6814, + 0xa213, 0x00de, 0x0804, 0x1e76, 0x0804, 0x1e76, 0x080c, 0x13fe, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, + 0x00f6, 0x00e6, 0x2071, 0x953b, 0x7000, 0xa086, 0x0000, 0x01c0, + 0x2079, 0x0020, 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0dd8, 0x080c, + 0x1e3b, 0x7000, 0xa086, 0x0000, 0x1da8, 0x7803, 0x0004, 0x7804, + 0xd0ac, 0x1de8, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, + 0x00ee, 0x00fe, 0x0005, 0x8840, 0x2805, 0xa005, 0x1170, 0x6004, + 0xa005, 0x0168, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, + 0x1f59, 0x2045, 0x88ff, 0x090c, 0x13fe, 0x8a51, 0x0005, 0x2050, + 0x0005, 0x8a50, 0x8841, 0x2805, 0xa005, 0x1190, 0x2c00, 0xad06, + 0x0120, 0x6000, 0xa005, 0x1108, 0x2d00, 0x2060, 0x681a, 0x6034, + 0xa084, 0x000f, 0xa080, 0x1f69, 0x2045, 0x88ff, 0x090c, 0x13fe, + 0x0005, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, + 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, + 0x0000, 0x0000, 0x1f4e, 0x1f4a, 0x1f4e, 0x1f4e, 0x1f58, 0x0000, + 0x1f4e, 0x0000, 0x1f55, 0x1f52, 0x1f55, 0x1f55, 0x0000, 0x1f58, + 0x1f55, 0x0000, 0x1f50, 0x1f50, 0x0000, 0x1f50, 0x1f58, 0x0000, + 0x1f50, 0x0000, 0x1f56, 0x1f56, 0x0000, 0x1f56, 0x0000, 0x1f58, + 0x1f56, 0x0136, 0x0146, 0x0156, 0x2099, 0x9359, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, + 0x7803, 0x0041, 0x7007, 0x0005, 0x7000, 0xc094, 0x7002, 0x700b, + 0x9354, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005, 0x2099, 0x0014, + 0x7803, 0x0040, 0x2001, 0x9359, 0x2004, 0x2010, 0x080c, 0x59a7, + 0x080c, 0x5949, 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, 0x00a6, + 0x0096, 0x0086, 0x6858, 0xa055, 0x0904, 0x2036, 0x2d60, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x1f59, 0xa986, 0x0007, 0x0130, 0xa986, + 0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422, 0x6060, + 0xa31a, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2036, 0x6004, + 0xa065, 0x0904, 0x2036, 0x0c18, 0x2805, 0xa005, 0x01a8, 0xac68, + 0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020, 0x6810, + 0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150, 0x8a51, + 0x0904, 0x2036, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904, 0x2036, + 0x0830, 0x8a51, 0x0904, 0x2036, 0x8840, 0x2805, 0xa005, 0x1158, + 0x6004, 0xa065, 0x0904, 0x2036, 0x6034, 0xa0cc, 0x000f, 0xa9c0, + 0x1f59, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0458, + 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68, 0x6c6e, + 0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x0a0c, 0x13fe, 0x6800, 0xa420, 0x6804, 0xa319, + 0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x0a0c, + 0x13fe, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, + 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, + 0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e, 0x009e, + 0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, 0xa084, + 0x0007, 0x0002, 0x204a, 0x204b, 0x204e, 0x2051, 0x2056, 0x2059, + 0x205e, 0x2063, 0x0005, 0x080c, 0x1e3b, 0x0005, 0x080c, 0x1942, + 0x0005, 0x080c, 0x1942, 0x080c, 0x1e3b, 0x0005, 0x080c, 0x159c, + 0x0005, 0x080c, 0x1e3b, 0x080c, 0x159c, 0x0005, 0x080c, 0x1942, + 0x080c, 0x159c, 0x0005, 0x080c, 0x1942, 0x080c, 0x1e3b, 0x080c, + 0x159c, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, + 0x9780, 0x2069, 0x9200, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, + 0x080c, 0x23e6, 0x781b, 0x0002, 0x783b, 0x001f, 0x20e1, 0x8700, + 0x012e, 0x0005, 0x0126, 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, + 0x210b, 0xa084, 0x0007, 0x0002, 0x20a6, 0x2094, 0x2097, 0x209a, + 0x209f, 0x20a1, 0x20a3, 0x20a5, 0x080c, 0x5338, 0x0078, 0x080c, + 0x536c, 0x0060, 0x080c, 0x5338, 0x080c, 0x536c, 0x0038, 0x0041, + 0x0028, 0x0031, 0x0018, 0x0021, 0x0008, 0x0011, 0x012e, 0x0005, + 0x0006, 0x0016, 0x0026, 0x7930, 0xa184, 0x0003, 0x0118, 0x20e1, + 0x9040, 0x00b8, 0xa184, 0x0030, 0x0150, 0x6a00, 0xa286, 0x0003, + 0x1108, 0x0010, 0x080c, 0x4105, 0x20e1, 0x9010, 0x0050, 0xa184, + 0x00c0, 0x0110, 0x080c, 0x13fe, 0xa184, 0x0300, 0x0110, 0x20e1, + 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005, 0x0016, 0x00e6, + 0x00f6, 0x2071, 0x9200, 0x7128, 0x2001, 0x94ca, 0x2102, 0x2001, + 0x94d2, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009, 0x0008, 0x0400, + 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0xa182, 0x02c1, + 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, 0x1218, 0x2009, + 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, 0x0004, 0x0040, + 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, 0x0002, + 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c, 0x23e6, 0x00fe, + 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x13fe, 0x0126, 0x2091, + 0x2400, 0x2061, 0x0100, 0x2071, 0x9200, 0x6024, 0x6026, 0x080c, + 0x2425, 0x6050, 0xa084, 0xfe7f, 0x6052, 0x2009, 0x00ef, 0x6132, + 0x6136, 0x080c, 0x2435, 0x60e7, 0x0000, 0x61ea, 0x60e3, 0x0008, + 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, + 0x6007, 0x0c9f, 0x600f, 0x03ff, 0x602b, 0x002f, 0x012e, 0x0005, + 0x2001, 0x9230, 0x2003, 0x0000, 0x2001, 0x922f, 0x2003, 0x0001, + 0x0005, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, 0x6124, + 0x0066, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x006e, 0x11c0, + 0x6020, 0xd0bc, 0x01a8, 0xd1bc, 0x0198, 0x783c, 0xa005, 0x0180, + 0x00e6, 0x0006, 0x2070, 0x701c, 0xa086, 0x0009, 0x000e, 0x00ee, + 0x1138, 0x00e6, 0x783c, 0x2070, 0x7008, 0xd0fc, 0x00ee, 0x1130, + 0xa184, 0x1c2c, 0x1118, 0xa184, 0x0007, 0x002a, 0xa195, 0x0004, + 0xa284, 0x0007, 0x0002, 0x2195, 0x217b, 0x217e, 0x2181, 0x2186, + 0x2188, 0x218c, 0x2190, 0x080c, 0x5ee3, 0x00b8, 0x080c, 0x5fbe, + 0x00a0, 0x080c, 0x5fbe, 0x080c, 0x5ee3, 0x0078, 0x0099, 0x0068, + 0x080c, 0x5ee3, 0x0079, 0x0048, 0x080c, 0x5fbe, 0x0059, 0x0028, + 0x080c, 0x5fbe, 0x080c, 0x5ee3, 0x0029, 0x002e, 0x001e, 0x000e, + 0x012e, 0x0005, 0xd19c, 0x1904, 0x238f, 0x080c, 0x4dc5, 0x01a0, + 0x080c, 0x4deb, 0x15c0, 0x6024, 0xa084, 0x1800, 0x1108, 0x0498, + 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, 0x0001, + 0x080c, 0x4d10, 0x0804, 0x238f, 0xd1ac, 0x1528, 0x6024, 0xd0dc, + 0x1130, 0xd0e4, 0x1148, 0xd0d4, 0x1180, 0x0804, 0x238f, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x0068, 0xa085, 0x0001, 0x080c, 0x4e05, + 0x2001, 0x94d8, 0x2003, 0x0002, 0x0020, 0x2001, 0x94d8, 0x2003, + 0x0003, 0x0016, 0x2001, 0x9200, 0x2003, 0x0001, 0x080c, 0x4d10, + 0x001e, 0x0804, 0x238f, 0x6220, 0xd1bc, 0x0568, 0xd2bc, 0x0558, + 0x783c, 0xa005, 0x0540, 0x00e6, 0x2070, 0x7008, 0xd0fc, 0x00ee, + 0x0510, 0x6028, 0xc0bc, 0x602a, 0x0026, 0x0036, 0x6288, 0x638c, + 0x608b, 0xbc91, 0x608f, 0xffff, 0x6043, 0x0001, 0xe000, 0xe000, + 0x6027, 0x0080, 0x6017, 0x0000, 0x6043, 0x0000, 0x628a, 0x638e, + 0x003e, 0x002e, 0x0016, 0x2001, 0x9295, 0x200c, 0xc184, 0x2102, + 0x001e, 0x0804, 0x23b6, 0xd1ac, 0x0904, 0x22d7, 0x080c, 0x4dc5, + 0x1550, 0x6027, 0x0020, 0x0006, 0x0026, 0x0036, 0x2001, 0x94d8, + 0x080c, 0x4de1, 0x11d8, 0x2011, 0x9225, 0x2204, 0xa005, 0x1140, + 0x8000, 0x2012, 0x2011, 0x8036, 0x2019, 0x0001, 0x080c, 0x3698, + 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, 0x2003, 0x0001, + 0x080c, 0x4d10, 0x003e, 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, + 0x000e, 0x080c, 0x4ca5, 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, + 0xf0f0, 0x1138, 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, + 0x0010, 0x74c6, 0xa48c, 0xff00, 0xa196, 0xff00, 0x01e8, 0x7050, + 0xa084, 0x00ff, 0x810f, 0xa116, 0x01b8, 0x7130, 0xd18c, 0x11a0, + 0x2011, 0x9252, 0x2214, 0xd2ec, 0x0118, 0xc18d, 0x7132, 0x0060, + 0x6240, 0xa294, 0x0010, 0x0904, 0x22ad, 0x6248, 0xa294, 0xff00, + 0xa296, 0xff00, 0x1904, 0x22ad, 0x70bc, 0xa005, 0x1138, 0x0036, + 0x73c4, 0x2011, 0x8013, 0x080c, 0x3698, 0x003e, 0x7130, 0xc185, + 0x7132, 0x2011, 0x9252, 0x220c, 0xd1a4, 0x01d0, 0x0016, 0x2009, + 0x0001, 0x2011, 0x0100, 0x080c, 0x585b, 0x2019, 0x000e, 0x080c, + 0x9071, 0xa484, 0x00ff, 0xa080, 0x2719, 0x200d, 0xa18c, 0xff00, + 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, 0x90d7, 0x001e, + 0xd1ac, 0x1128, 0x2019, 0x0004, 0x080c, 0x264b, 0x0070, 0x0156, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, 0x4434, 0x1110, 0x080c, + 0x41e0, 0x8108, 0x1f04, 0x22a4, 0x015e, 0x00ce, 0x004e, 0x2011, + 0x0003, 0x080c, 0x718f, 0x2011, 0x0002, 0x080c, 0x7199, 0x080c, + 0x708d, 0x080c, 0x57a1, 0x0036, 0x2019, 0x0000, 0x080c, 0x7110, + 0x003e, 0x60e3, 0x0000, 0x001e, 0x2001, 0x9200, 0x2014, 0xa296, + 0x0004, 0x1128, 0xd19c, 0x1118, 0x6228, 0xc29d, 0x622a, 0x2003, + 0x0001, 0x2001, 0x9222, 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, + 0x0904, 0x238f, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2340, 0x080c, + 0x57a1, 0x080c, 0x6f1e, 0x6027, 0x0004, 0x00f6, 0x2019, 0x94ee, + 0x2304, 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, + 0x00c6, 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, + 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, + 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, + 0x080c, 0x6389, 0x080c, 0x6462, 0x7810, 0x2070, 0x7037, 0x0103, + 0x2f60, 0x080c, 0x74f2, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, + 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, + 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, + 0x94e5, 0x6028, 0xa09a, 0x0002, 0x1238, 0x8000, 0x602a, 0x00ce, + 0x080c, 0x6f11, 0x0804, 0x238e, 0x2019, 0x94ee, 0x2304, 0xa065, + 0x0120, 0x2009, 0x0027, 0x080c, 0x7518, 0x00ce, 0x0804, 0x238e, + 0xd2bc, 0x0904, 0x238e, 0x080c, 0x57ae, 0x6017, 0x0010, 0x6027, + 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0120, + 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, 0x94e5, + 0x6044, 0xa09a, 0x0002, 0x12e0, 0x8000, 0x6046, 0x603c, 0x00ce, + 0xa005, 0x0560, 0x2009, 0x07d0, 0x080c, 0x57a6, 0xa080, 0x0007, + 0x2004, 0xa086, 0x0006, 0x1118, 0x6017, 0x0012, 0x00f8, 0xa080, + 0x0007, 0x2004, 0xa086, 0x0009, 0x0db8, 0x6017, 0x0016, 0x00b0, + 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, 0x003e, 0x2019, 0x94f4, + 0x2304, 0xa065, 0x0150, 0x2009, 0x004f, 0x601c, 0xa086, 0x0009, + 0x1110, 0x2009, 0x0105, 0x080c, 0x7518, 0x00ce, 0x001e, 0xd19c, + 0x0528, 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, + 0x718f, 0x2011, 0x0002, 0x080c, 0x7199, 0x080c, 0x708d, 0x080c, + 0x57a1, 0x0036, 0x2019, 0x0000, 0x080c, 0x7110, 0x003e, 0x60e3, + 0x0000, 0x080c, 0x918b, 0x080c, 0x91a6, 0x2001, 0x9200, 0x2003, + 0x0004, 0x6027, 0x0008, 0x080c, 0x123f, 0x001e, 0xa18c, 0xffd0, + 0x6126, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x9200, 0x71bc, 0x70be, 0xa116, 0x01b8, + 0x81ff, 0x0128, 0x2011, 0x8011, 0x080c, 0x3698, 0x0080, 0x2011, + 0x8012, 0x080c, 0x3698, 0x0036, 0x00c6, 0x080c, 0x2480, 0x2061, + 0x0100, 0x2019, 0x0028, 0x080c, 0x264b, 0x00ce, 0x003e, 0x012e, + 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005, 0x00c6, 0x00f6, + 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, 0x23f9, 0x2205, 0x60f2, + 0x2011, 0x2406, 0x2205, 0x60ee, 0x002e, 0x000e, 0x00fe, 0x00ce, + 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, 0x0348, 0x02c0, + 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8, + 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, 0x2130, 0xa094, + 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, 0x550c, 0x0038, 0xa080, + 0x2719, 0x200d, 0xa18c, 0xff00, 0x810f, 0xa006, 0x0005, 0xa080, + 0x2719, 0x200d, 0xa18c, 0x00ff, 0x0005, 0x00d6, 0x2069, 0x0140, + 0x2001, 0x9214, 0x2003, 0x00ef, 0x20a9, 0x0010, 0xa006, 0x6852, + 0x6856, 0x1f04, 0x2430, 0x00de, 0x0005, 0x0006, 0x00d6, 0x0026, + 0x2069, 0x0140, 0x2001, 0x9214, 0x2102, 0x8114, 0x8214, 0x8214, + 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0xa006, 0x82ff, 0x1128, + 0xa184, 0x000f, 0xa080, 0x91ac, 0x2005, 0x6856, 0x8211, 0x1f04, + 0x2445, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6, 0x2061, 0x9200, + 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032, 0x00ce, 0x0005, + 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069, 0x0140, 0x6980, + 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, 0x8210, 0x22a8, 0x2001, + 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e, 0x1f04, 0x2475, + 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de, 0x015e, 0x0005, + 0x2001, 0x9252, 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, + 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0x90d7, 0x004e, 0x0005, + 0x24b0, 0x24b4, 0x24b8, 0x24be, 0x24c4, 0x24ca, 0x24d0, 0x24d8, + 0x24df, 0x24e4, 0x24e9, 0x24f0, 0x24f7, 0x24fe, 0x2505, 0x250e, + 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, + 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, + 0x0106, 0x0006, 0x0804, 0x2519, 0x0106, 0x0006, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x0804, 0x2519, 0x0106, 0x0006, + 0x080c, 0x2141, 0x0804, 0x2519, 0x0106, 0x0006, 0x080c, 0x203c, + 0x0804, 0x2519, 0x0106, 0x0006, 0x080c, 0x203c, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x203c, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x203c, 0x04d0, 0x0106, + 0x0006, 0x080c, 0x2082, 0x04a8, 0x0106, 0x0006, 0x080c, 0x2082, + 0x0480, 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x2082, 0x0448, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x2082, 0x0410, 0x0106, + 0x0006, 0x080c, 0x203c, 0x080c, 0x2082, 0x00d8, 0x0106, 0x0006, + 0x080c, 0x203c, 0x080c, 0x2082, 0x00a0, 0x0106, 0x0006, 0x080c, + 0x2141, 0x080c, 0x203c, 0x080c, 0x2082, 0x0058, 0x0106, 0x0006, + 0x080c, 0x2141, 0x080c, 0x203c, 0x080c, 0x2082, 0x0010, 0xe000, + 0x0cf0, 0x000e, 0x010e, 0x000d, 0x00c6, 0x0026, 0x2041, 0x007e, + 0x70c8, 0xd09c, 0x0110, 0x2041, 0x007f, 0xd094, 0x2001, 0x9214, + 0x203c, 0x15d8, 0x7284, 0x82ff, 0x05c0, 0x0036, 0x7398, 0xa38e, + 0xffff, 0x1110, 0x2019, 0x0001, 0x8314, 0xa2e0, 0x98c0, 0x2c04, + 0xa38c, 0x0001, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, + 0x00ff, 0xa70e, 0x01c8, 0xa08e, 0x00ff, 0x01d0, 0x2009, 0x0000, + 0x080c, 0x240b, 0x080c, 0x4400, 0x1188, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x1120, 0x080c, 0x25b1, 0x0140, 0x0028, 0x080c, + 0x26ad, 0x080c, 0x25d7, 0x0110, 0x8318, 0x08b0, 0x739a, 0x0010, + 0x709b, 0xffff, 0x003e, 0x0804, 0x25ae, 0xa780, 0x2719, 0x203d, + 0xa7bc, 0xff00, 0x873f, 0x7098, 0xa096, 0xffff, 0x0128, 0xa812, + 0x12c8, 0x709b, 0xffff, 0x04b8, 0x2009, 0x0000, 0x70c8, 0xd09c, + 0x0120, 0xd094, 0x0110, 0x2009, 0x007e, 0x2001, 0x94d7, 0x2004, + 0xa005, 0x0120, 0x2009, 0x007e, 0x2041, 0x007f, 0x2100, 0xa802, + 0x20a8, 0x0020, 0x2008, 0x2810, 0xa202, 0x20a8, 0x2700, 0x0156, + 0x0016, 0xa106, 0x0180, 0x080c, 0x4400, 0x11a8, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x1118, 0x00a1, 0x0168, 0x0020, 0x080c, + 0x26ad, 0x04a9, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x258e, + 0x709b, 0xffff, 0x0018, 0x001e, 0x015e, 0x719a, 0x002e, 0x00ce, + 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x080c, 0x749c, + 0x01c8, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x2001, 0x0000, 0x080c, 0x43e3, 0x0126, 0x2091, 0x8000, + 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0004, 0x080c, 0x7518, + 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x0016, + 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x080c, 0x749c, 0x01c8, 0x2d00, + 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, + 0x0002, 0x080c, 0x43e3, 0x0126, 0x2091, 0x8000, 0x7094, 0x8000, + 0x7096, 0x012e, 0x2009, 0x0002, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x0026, 0x2009, + 0x0080, 0x080c, 0x4400, 0x1120, 0x0031, 0x0110, 0x70cf, 0xffff, + 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, + 0x080c, 0x749c, 0x01c8, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, + 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, 0x080c, 0x43e3, 0x0126, + 0x2091, 0x8000, 0x70d0, 0x8000, 0x70d2, 0x012e, 0x2009, 0x0002, + 0x080c, 0x7518, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, + 0x0005, 0x00c6, 0x00d6, 0x2009, 0x007f, 0x080c, 0x4400, 0x1180, + 0x2c68, 0x080c, 0x749c, 0x0160, 0x2d00, 0x601a, 0x6312, 0x601f, + 0x0001, 0x620a, 0x2009, 0x0022, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, 0x0026, + 0x080c, 0x6133, 0x080c, 0x60dc, 0x080c, 0x7a8c, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1120, 0x080c, 0x460d, + 0x080c, 0x41e0, 0x001e, 0x8108, 0x1f04, 0x265a, 0x002e, 0x003e, + 0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, + 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, + 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, + 0x8ee4, 0x008e, 0x001e, 0x2e60, 0x080c, 0x460d, 0x6210, 0x6314, + 0x080c, 0x41e0, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x0006, 0x6018, 0xa080, 0x0028, 0x2004, + 0xa086, 0x0080, 0x0150, 0x2071, 0x9200, 0x7094, 0xa005, 0x0110, + 0x8001, 0x7096, 0x000e, 0x00ee, 0x0005, 0x2071, 0x9200, 0x70d0, + 0xa005, 0x0dc0, 0x8001, 0x70d2, 0x0ca8, 0x6000, 0xc08c, 0x6002, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, + 0x2178, 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0x9252, + 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, + 0x2009, 0x002d, 0x080c, 0x90d7, 0x004e, 0x20a9, 0x00ff, 0x2011, + 0x0000, 0x0026, 0xa288, 0x936e, 0x210c, 0x81ff, 0x0508, 0x8fff, + 0x0559, 0x2019, 0x0029, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, + 0x080c, 0x606d, 0x00c6, 0x0026, 0x2160, 0x6204, 0xa294, 0x00ff, + 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x002e, 0x00ce, 0x0016, + 0x2c08, 0x080c, 0x8ee4, 0x001e, 0x008e, 0x2160, 0x080c, 0x460d, + 0x002e, 0x8210, 0x1f04, 0x26d1, 0x015e, 0x001e, 0x002e, 0x003e, + 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x2001, + 0x9252, 0x2004, 0xd0c4, 0x0148, 0xd0a4, 0x0138, 0xa006, 0x2220, + 0x8427, 0x2009, 0x0029, 0x080c, 0x90d7, 0x001e, 0x002e, 0x004e, + 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, + 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, + 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, + 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, + 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, + 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, + 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, + 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, + 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, + 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, + 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, + 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, + 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, + 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, + 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, + 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, + 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, + 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, + 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, + 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, + 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, + 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, + 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, + 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, + 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, + 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, + 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x2071, 0x9296, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, + 0x703a, 0x703e, 0x7033, 0x92a6, 0x7037, 0x92a6, 0x7007, 0x0001, + 0x2061, 0x92e6, 0x6003, 0x0002, 0x0005, 0x1004, 0x283f, 0x0e04, + 0x283f, 0x2071, 0x9296, 0x2b78, 0x7818, 0xd084, 0x1140, 0x2a60, + 0x7820, 0xa08e, 0x0069, 0x1904, 0x2924, 0x0804, 0x28bd, 0x0005, + 0x2071, 0x9296, 0x7004, 0x0002, 0x2848, 0x2849, 0x2852, 0x2863, + 0x0005, 0x1004, 0x2851, 0x0e04, 0x2851, 0x2b78, 0x7818, 0xd084, + 0x01e8, 0x0005, 0x2b78, 0x2061, 0x92e6, 0x6008, 0xa08e, 0x0100, + 0x0128, 0xa086, 0x0200, 0x0904, 0x291e, 0x0005, 0x7014, 0x2068, + 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068, 0x6834, 0xa086, 0x0103, + 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018, 0x0807, 0x2a60, 0x7820, + 0xa08a, 0x0040, 0x1210, 0x61bc, 0x0042, 0x2100, 0xa08a, 0x003f, + 0x1a04, 0x291b, 0x61bc, 0x0804, 0x28bd, 0x28ff, 0x292a, 0x2932, + 0x2936, 0x293e, 0x2944, 0x2948, 0x2951, 0x2954, 0x295e, 0x2961, + 0x291b, 0x291b, 0x291b, 0x2964, 0x291b, 0x2973, 0x298a, 0x29a1, + 0x2a18, 0x2a1d, 0x2a46, 0x2a97, 0x2aa8, 0x2ac6, 0x2af2, 0x2afc, + 0x2b09, 0x2b1c, 0x2b3c, 0x2b45, 0x2b7b, 0x2b81, 0x291b, 0x2ba4, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2ba8, 0x2bae, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2bb6, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2bc3, 0x2bc9, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x0002, 0x2bdb, 0x2c2e, + 0x2c88, 0x2c98, 0x291b, 0x2cb2, 0x309c, 0x291b, 0x291b, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x295e, 0x2961, + 0x291b, 0x291b, 0x309e, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x30a2, 0x31e7, + 0x31fb, 0x3215, 0x3276, 0x32c7, 0x32d2, 0x3309, 0x3318, 0x3327, + 0x3336, 0x335e, 0x33a8, 0x340a, 0x3417, 0x3501, 0x35f6, 0x361f, + 0x3716, 0x3732, 0x373e, 0x3777, 0x381e, 0x3878, 0x38ff, 0x3908, + 0x390b, 0x3920, 0x393b, 0x39ab, 0x3a5b, 0x713c, 0x0000, 0x2021, + 0x4000, 0x080c, 0x3675, 0x0126, 0x2091, 0x8000, 0x0e04, 0x290b, + 0x7818, 0xd084, 0x0110, 0x012e, 0x0cb0, 0x7c22, 0x7926, 0x7a2a, + 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x012e, 0x0005, 0x2021, 0x4001, 0x0c18, 0x2021, 0x4002, + 0x0c00, 0x2021, 0x4003, 0x08e8, 0x2021, 0x4005, 0x08d0, 0x2021, + 0x4006, 0x08b8, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, + 0x0804, 0x3682, 0x7823, 0x0004, 0x7824, 0x0807, 0xa02e, 0x2520, + 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3685, 0x7924, 0x7828, + 0x2114, 0x200a, 0x0804, 0x28ff, 0x7924, 0x2114, 0x0804, 0x28ff, + 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, 0x0007, 0x53a3, 0x0804, + 0x28ff, 0x7824, 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0000, + 0x2019, 0x0010, 0x783b, 0x0027, 0x0804, 0x28ff, 0x7d38, 0x7c3c, + 0x0858, 0x7d38, 0x7c3c, 0x08a0, 0x2061, 0x1000, 0xe10c, 0xa006, + 0x2c15, 0xa200, 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, + 0x28ff, 0x0804, 0x2921, 0x2069, 0x9251, 0x7824, 0x7930, 0xa11a, + 0x1a04, 0x2927, 0x8019, 0x0904, 0x2927, 0x684a, 0x6942, 0x782c, + 0x6852, 0x7828, 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x4e5d, + 0x0804, 0x28ff, 0x2069, 0x9251, 0x7824, 0x7934, 0xa11a, 0x1a04, + 0x2927, 0x8019, 0x0904, 0x2927, 0x684e, 0x6946, 0x782c, 0x6862, + 0x7828, 0x6866, 0xa006, 0x686a, 0x686e, 0x080c, 0x47d8, 0x0804, + 0x28ff, 0xa02e, 0x2520, 0x81ff, 0x1904, 0x2924, 0x7924, 0x7b28, + 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0x929d, 0x41a1, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0023, 0x080c, 0x3682, 0x701b, 0x29b9, + 0x0005, 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0120, + 0xa096, 0x0019, 0x1904, 0x2924, 0x810f, 0xa18c, 0x00ff, 0x0904, + 0x2924, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0023, 0x2061, 0x92e6, 0x6224, 0x6328, + 0x642c, 0x6530, 0xa290, 0x0046, 0xa399, 0x0000, 0xa4a1, 0x0000, + 0xa5a9, 0x0000, 0x080c, 0x3682, 0x701b, 0x29e7, 0x0005, 0x6834, + 0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, 0x1904, + 0x2924, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x4337, 0x1128, 0x7007, 0x0003, 0x701b, 0x2a01, 0x0005, 0x080c, + 0x492c, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0x929d, + 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, + 0x0000, 0xad80, 0x000d, 0x2009, 0x0023, 0x012e, 0x0804, 0x3685, + 0x61a4, 0x7824, 0x60a6, 0x0804, 0x28ff, 0x2091, 0x8000, 0x7823, + 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, + 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, + 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, + 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, + 0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, 0x1904, + 0x2924, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1904, + 0x2927, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, 0x0804, + 0x2927, 0x7c28, 0x7d2c, 0x080c, 0x45d4, 0xd28c, 0x1118, 0x080c, + 0x457f, 0x0010, 0x080c, 0x45ad, 0x1518, 0x2061, 0x9900, 0x0126, + 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, 0xa06d, + 0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, 0x012e, + 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, 0xac02, 0x1a04, 0x2924, + 0x0c30, 0x080c, 0x80f6, 0x012e, 0x0904, 0x2924, 0x0804, 0x28ff, + 0xa00e, 0x2001, 0x0005, 0x080c, 0x492c, 0x0126, 0x2091, 0x8000, + 0x080c, 0x852d, 0x080c, 0x4809, 0x012e, 0x0804, 0x28ff, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x44d4, + 0x0904, 0x2924, 0x080c, 0x45e0, 0x0904, 0x2924, 0x0804, 0x28ff, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, 0x080c, + 0x4644, 0x0904, 0x2924, 0x2019, 0x0005, 0x080c, 0x45fb, 0x0904, + 0x2924, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2927, 0x8003, 0x800b, + 0x810b, 0xa108, 0x080c, 0x573d, 0x0804, 0x28ff, 0x0126, 0x2091, + 0x8000, 0x81ff, 0x1508, 0x2029, 0x00ff, 0x644c, 0x2400, 0xa506, + 0x01b0, 0x2508, 0x080c, 0x4434, 0x1190, 0x080c, 0x4644, 0x01a0, + 0x2019, 0x0004, 0x080c, 0x45fb, 0x0178, 0x7824, 0xa08a, 0x1000, + 0x1270, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x573d, 0x8529, + 0x1e28, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, 0x2924, 0x012e, + 0x0804, 0x2927, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x453a, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x080c, + 0x3656, 0x0904, 0x2927, 0x080c, 0x452b, 0x080c, 0x45d4, 0x0804, + 0x28ff, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x45af, 0x0904, 0x2924, 0x080c, 0x4373, 0x080c, 0x4578, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x44d4, 0x0904, 0x2924, 0x62a0, 0x2019, 0x0005, 0x00c6, + 0x080c, 0x460d, 0x2061, 0x0000, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x00ce, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x45d4, 0x2208, 0x0804, 0x28ff, 0x0156, 0x00d6, 0x00e6, + 0x2069, 0x9328, 0x6810, 0x6914, 0xa10a, 0x1210, 0x2009, 0x0000, + 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, + 0x936e, 0x2d04, 0xa075, 0x0130, 0x704c, 0x0071, 0xa210, 0x7080, + 0x0059, 0xa318, 0x8d68, 0x1f04, 0x2b59, 0x2300, 0xa218, 0x00ee, + 0x00de, 0x015e, 0x0804, 0x28ff, 0x00f6, 0x0016, 0xa07d, 0x0140, + 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, + 0x001e, 0x00fe, 0x0005, 0x2069, 0x9328, 0x6910, 0x62a8, 0x0804, + 0x28ff, 0x81ff, 0x1904, 0x2924, 0x614c, 0xa190, 0x2719, 0x2215, + 0xa294, 0x00ff, 0x636c, 0x83ff, 0x0108, 0x6270, 0x67c8, 0xd79c, + 0x0118, 0x2031, 0x0001, 0x0060, 0xd7ac, 0x0118, 0x2031, 0x0003, + 0x0038, 0xd7a4, 0x0118, 0x2031, 0x0002, 0x0010, 0x2031, 0x0000, + 0x7e3a, 0x7f3e, 0x0804, 0x28ff, 0x613c, 0x6240, 0x0804, 0x28ff, + 0x080c, 0x3666, 0x0904, 0x2927, 0x0804, 0x28ff, 0x080c, 0x3666, + 0x0904, 0x2927, 0x6244, 0x6338, 0x0804, 0x28ff, 0x613c, 0x6240, + 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0x9251, 0x831f, 0xa305, + 0x6816, 0x0804, 0x28ff, 0x080c, 0x3666, 0x0904, 0x2927, 0x0804, + 0x28ff, 0x080c, 0x3666, 0x0904, 0x2927, 0x7828, 0xa00d, 0x0904, + 0x2927, 0x782c, 0xa005, 0x0904, 0x2927, 0x6244, 0x6146, 0x6338, + 0x603a, 0x0804, 0x28ff, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2924, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, + 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0x9214, 0x2004, 0xa085, + 0xff00, 0x0078, 0xa182, 0x007f, 0x1698, 0xa188, 0x2719, 0x210d, + 0xa18c, 0x00ff, 0x2001, 0x9214, 0x2004, 0xa116, 0x0548, 0x810f, + 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x749c, 0x000e, + 0x01e0, 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x080c, 0x3641, + 0x01d0, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x701b, 0x2c81, 0x2d00, 0x6012, 0x2009, 0x0032, + 0x080c, 0x7518, 0x012e, 0x00ce, 0x0005, 0x00ce, 0x0804, 0x2924, + 0x00ce, 0x0804, 0x2927, 0x080c, 0x74f2, 0x0cb8, 0x2001, 0x9200, + 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x00c6, 0x2061, 0x0100, + 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, + 0x9214, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, 0x007f, 0x1698, + 0xa188, 0x2719, 0x210d, 0xa18c, 0x00ff, 0x2001, 0x9214, 0x2004, + 0xa116, 0x0548, 0x810f, 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, + 0x080c, 0x749c, 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, 0x601f, + 0x0001, 0x080c, 0x3641, 0x01d0, 0x6837, 0x0000, 0x7007, 0x0003, + 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, 0x2c81, 0x2d00, + 0x6012, 0x2009, 0x0032, 0x080c, 0x7518, 0x012e, 0x00ce, 0x0005, + 0x00ce, 0x0804, 0x2924, 0x00ce, 0x0804, 0x2927, 0x080c, 0x74f2, + 0x0cb8, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, + 0x2061, 0x9566, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0128, + 0x6104, 0x6208, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, 0x2927, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x4dc5, 0x0904, 0x2924, 0x0126, + 0x2091, 0x8000, 0x6244, 0x6064, 0xa202, 0x0248, 0xa085, 0x0001, + 0x080c, 0x2455, 0x080c, 0x3bfd, 0x012e, 0x0804, 0x28ff, 0x012e, + 0x0804, 0x2927, 0x0126, 0x2091, 0x8000, 0x7824, 0xa084, 0x0007, + 0x0002, 0x2cc4, 0x2ccd, 0x2cd4, 0x2cc1, 0x2cc1, 0x2cc1, 0x2cc1, + 0x2cc1, 0x012e, 0x0804, 0x2927, 0x2009, 0x0114, 0x2104, 0xa085, + 0x0800, 0x200a, 0x080c, 0x2e1e, 0x0070, 0x2009, 0x010b, 0x200b, + 0x0010, 0x080c, 0x2e1e, 0x0038, 0x81ff, 0x0128, 0x012e, 0x2021, + 0x400b, 0x0804, 0x2901, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, + 0x00d6, 0x00e6, 0x00f6, 0x2009, 0x0101, 0x210c, 0x0016, 0x2001, + 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001, 0x007a, 0x2034, + 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050, 0x2058, 0x080c, + 0x302f, 0x080c, 0x2f99, 0xa03e, 0x2720, 0x00f6, 0x00e6, 0x00c6, + 0x2d60, 0x2071, 0x953b, 0x2079, 0x0020, 0x2011, 0x0001, 0x080c, + 0x2f45, 0x080c, 0x2f45, 0x00ce, 0x00ee, 0x00fe, 0x080c, 0x2ea6, + 0x080c, 0x2f6d, 0x080c, 0x2eea, 0x080c, 0x2e65, 0x080c, 0x2e96, + 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x01d8, 0x7817, 0x0010, + 0x2079, 0x0140, 0x2001, 0x0109, 0x2004, 0xd0ac, 0x11a8, 0x7804, + 0xd0dc, 0x0dc0, 0x2079, 0x0100, 0x7827, 0x0086, 0x7817, 0x0032, + 0x7824, 0xd0ac, 0x1148, 0xd0bc, 0x0dd8, 0x7827, 0x0080, 0xa026, + 0x7c16, 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, 0x2e06, 0x00fe, + 0x0804, 0x2dd0, 0x00fe, 0x1d04, 0x2d55, 0x2091, 0x6000, 0x8420, + 0xa486, 0x0064, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, + 0x007b, 0x2502, 0x080c, 0x2e06, 0x0088, 0x87ff, 0x0140, 0x2001, + 0x0201, 0x2004, 0xa005, 0x1904, 0x2d10, 0x8739, 0x0038, 0x2001, + 0x9519, 0x2004, 0xa086, 0x0000, 0x1904, 0x2d10, 0x2001, 0x0033, + 0x2003, 0x00f0, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, + 0x2dd0, 0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, + 0x2dd0, 0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, + 0xd0ac, 0x1148, 0x2001, 0x9519, 0x2003, 0x0003, 0x2001, 0x0030, + 0x2003, 0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, + 0xa005, 0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, + 0x681a, 0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, + 0x00c6, 0x20a9, 0x0008, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, + 0x0203, 0x2004, 0x1f04, 0x2da5, 0x00ce, 0x0040, 0x6827, 0x0001, + 0x2001, 0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, + 0x2079, 0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, + 0x2004, 0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, + 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x2cfd, + 0x2061, 0x0100, 0x6027, 0x0002, 0x20e1, 0x9028, 0x6050, 0xa084, + 0xf7ef, 0x6052, 0x602f, 0x0000, 0x001e, 0x61e2, 0x001e, 0x6106, + 0x7824, 0xa084, 0x0003, 0xa086, 0x0002, 0x0148, 0x602c, 0xc0ac, + 0x602e, 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, + 0x2a10, 0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, + 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, + 0x28ff, 0x012e, 0x2021, 0x400c, 0x0804, 0x2901, 0x2001, 0x0105, + 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001, 0x0020, + 0x2003, 0x0004, 0x2001, 0x9519, 0x2003, 0x0000, 0x2001, 0x953b, + 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6, 0x2079, + 0x0100, 0x7850, 0xa084, 0x0990, 0x7852, 0x782c, 0xa085, 0x0020, + 0x782e, 0x20a9, 0x0008, 0x1d04, 0x2e2b, 0x2091, 0x6000, 0x1f04, + 0x2e2b, 0x7850, 0xa085, 0x0400, 0x7852, 0x784b, 0xf7f7, 0x7843, + 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e, 0xe000, 0x1f04, 0x2e3d, + 0x7850, 0xa085, 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854, 0xe000, + 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850, + 0xa085, 0x0400, 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4, 0xe000, + 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140, 0x2003, 0x0100, 0x7843, + 0x0000, 0x2003, 0x0000, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, + 0x00f6, 0x00e6, 0x2071, 0x9519, 0x2079, 0x0030, 0x2001, 0x0201, + 0x2004, 0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, + 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, + 0x00fe, 0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, + 0x260a, 0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, + 0x0108, 0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, + 0x0200, 0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, + 0x2001, 0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, + 0x0100, 0x2009, 0x9214, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166, + 0x719e, 0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078, + 0xa080, 0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa, + 0xa006, 0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af, + 0x95d5, 0x7027, 0x0080, 0x7017, 0x0032, 0x080c, 0x2f6d, 0x7024, + 0xd0ac, 0x1120, 0xd0bc, 0x0dc8, 0x7027, 0x0080, 0x00f6, 0x00e6, + 0x2071, 0x9519, 0x2079, 0x0030, 0x2011, 0x0011, 0x080c, 0x2f45, + 0x2011, 0x0001, 0x080c, 0x2f45, 0x00ee, 0x00fe, 0x7017, 0x0000, + 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x9519, 0x2079, 0x0030, + 0x7904, 0xd1fc, 0x0904, 0x2f42, 0x7803, 0x0002, 0xa026, 0xd19c, + 0x1904, 0x2f3e, 0x7000, 0x0002, 0x2f42, 0x2f00, 0x2f24, 0x2f3e, + 0xd1bc, 0x1150, 0xd1dc, 0x1150, 0x8001, 0x7002, 0x2011, 0x0001, + 0x04e1, 0x05c0, 0x04d1, 0x04b0, 0x780f, 0x0000, 0x7820, 0x7924, + 0x7803, 0x0004, 0x7822, 0x7926, 0x2001, 0x0201, 0x200c, 0x81ff, + 0x0de8, 0x080c, 0x2e82, 0x2009, 0x0001, 0x7808, 0xd0ec, 0x0110, + 0x2009, 0x0011, 0x7902, 0x00f0, 0x8001, 0x7002, 0xa184, 0x0880, + 0x1138, 0x7804, 0xd0fc, 0x1940, 0x2011, 0x0001, 0x00b1, 0x0090, + 0x6030, 0xa092, 0x0004, 0xa086, 0x0009, 0x1120, 0x6000, 0x601a, + 0x2011, 0x0025, 0x6232, 0xd1dc, 0x1988, 0x0870, 0x7803, 0x0004, + 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x6024, 0xa005, 0x0520, + 0x8001, 0x6026, 0x6018, 0x6130, 0xa140, 0x2804, 0x7832, 0x8840, + 0x2804, 0x7836, 0x8840, 0x2804, 0x7822, 0x8840, 0x2804, 0x7826, + 0x8840, 0x7a02, 0x7000, 0x8000, 0x7002, 0x6018, 0xa802, 0xa08a, + 0x0029, 0x1138, 0x6018, 0xa080, 0x0001, 0x2004, 0x601a, 0x2001, + 0x000d, 0x6032, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x2071, 0x953b, 0x2079, 0x0020, 0x7904, 0xd1fc, 0x01f0, 0x7803, + 0x0002, 0x2d60, 0xa026, 0x7000, 0x0002, 0x2f95, 0x2f80, 0x2f8c, + 0x8001, 0x7002, 0xd19c, 0x1188, 0x2011, 0x0001, 0x080c, 0x2f45, + 0x0160, 0x080c, 0x2f45, 0x0048, 0x8001, 0x7002, 0x7804, 0xd0fc, + 0x1d30, 0x2011, 0x0001, 0x080c, 0x2f45, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x601b, 0x0004, + 0x2061, 0x0100, 0x60cf, 0x0400, 0x6004, 0xc0ac, 0xa085, 0x0200, + 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038, 0x2001, + 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3089, 0x6833, + 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, 0x2138, + 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, 0x000d, + 0x04a1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3089, 0x6833, + 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001, 0x0076, + 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061, 0x0020, + 0x2079, 0x0100, 0x6013, 0x0400, 0x20e1, 0x9040, 0x2001, 0x0072, + 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a, 0x0006, 0x2001, 0x0073, + 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e, 0x78ca, 0xa006, 0x603a, + 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0010, + 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026, 0x7432, 0x7336, 0xa006, + 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7122, 0x7003, + 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003, 0x0002, 0x7003, 0x0040, + 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180, 0x00c6, 0x00d6, 0x2d60, + 0x00c6, 0x080c, 0x3641, 0x00ce, 0x6018, 0x2070, 0x2d00, 0x7006, + 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, + 0x2001, 0x0075, 0x2004, 0xa005, 0x0508, 0x2038, 0x2001, 0x0078, + 0x2024, 0x2001, 0x0079, 0x201c, 0x080c, 0x3089, 0x2d60, 0x6833, + 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, 0x2138, + 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, 0x000d, + 0x080c, 0x2ffd, 0x1d88, 0x2d00, 0x681a, 0x00d8, 0x0491, 0x2d60, + 0x6033, 0x000d, 0x2070, 0x6027, 0x0001, 0x2c00, 0x601a, 0x2001, + 0x0078, 0x2004, 0x2072, 0x2001, 0x0079, 0x2004, 0x7006, 0x2001, + 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x2001, 0x0073, 0x2004, + 0x700e, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac, 0x1178, + 0x2001, 0x0101, 0x200c, 0xc1ed, 0x2102, 0x6027, 0x0000, 0x2001, + 0x9519, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003, 0x0009, 0x00ee, + 0x0005, 0x080c, 0x147c, 0x0178, 0xa006, 0x6802, 0x7010, 0xa005, + 0x1120, 0x2d00, 0x7012, 0x7016, 0x0020, 0x7014, 0x6802, 0x2d00, + 0x7016, 0xad80, 0x000d, 0x0005, 0x0804, 0x28ff, 0x7d38, 0x7c3c, + 0x0804, 0x29a3, 0x080c, 0x3641, 0x0904, 0x2924, 0x080c, 0x4dc5, + 0x0110, 0x080c, 0x41c5, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x080c, 0x3682, 0x701b, 0x30b6, 0x0005, 0xade8, 0x000d, + 0x6800, 0xa005, 0x0904, 0x2927, 0x6804, 0xd0ac, 0x0118, 0xd0a4, + 0x0904, 0x2927, 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0xa18d, + 0x0020, 0x6106, 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, + 0x0118, 0xa18d, 0x0010, 0x0010, 0xa18c, 0xffef, 0x6106, 0x00ce, + 0x2009, 0x0100, 0x210c, 0xa18a, 0x0002, 0x0268, 0xd084, 0x0158, + 0x6a28, 0xa28a, 0x007f, 0x1a04, 0x2927, 0xa288, 0x2719, 0x210d, + 0xa18c, 0x00ff, 0x6156, 0xd0dc, 0x0130, 0x6828, 0xa08a, 0x007f, + 0x1a04, 0x2927, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0a04, 0x2927, + 0xa08a, 0x0841, 0x1a04, 0x2927, 0xa084, 0x0007, 0x1904, 0x2927, + 0x680c, 0xa005, 0x0904, 0x2927, 0x6810, 0xa005, 0x0904, 0x2927, + 0x6848, 0x6940, 0xa10a, 0x1a04, 0x2927, 0x8001, 0x0904, 0x2927, + 0x684c, 0x6944, 0xa10a, 0x1a04, 0x2927, 0x8001, 0x0904, 0x2927, + 0x6804, 0xd0fc, 0x01f8, 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, + 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, + 0x0000, 0x080c, 0x3682, 0x701b, 0x312e, 0x0005, 0xade8, 0x000d, + 0x20a9, 0x0014, 0x2d98, 0x2069, 0x926d, 0x2da0, 0x53a3, 0x7010, + 0xa0e8, 0x000d, 0x20a9, 0x001c, 0x2d98, 0x2069, 0x9251, 0x2da0, + 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, + 0x6042, 0x080c, 0x4e5d, 0x080c, 0x4780, 0x080c, 0x47d8, 0x6000, + 0xa086, 0x0000, 0x1904, 0x31e5, 0x6808, 0x602a, 0x080c, 0x20ce, + 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, + 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, + 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, + 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x080c, 0x57bc, + 0x6904, 0xd1fc, 0x0520, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, + 0x6b70, 0xd384, 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, + 0x080c, 0x532a, 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, + 0x8007, 0x600a, 0xa184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, + 0x0003, 0x0010, 0x6003, 0x0001, 0x1f04, 0x3184, 0x00ce, 0x2069, + 0x9251, 0x2001, 0x94d7, 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, + 0x0178, 0xa28e, 0x0010, 0x0118, 0xa28e, 0x0020, 0x0148, 0x2003, + 0xaaaa, 0x2001, 0x0204, 0x2004, 0x2009, 0x94c8, 0x200a, 0x0008, + 0x2102, 0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, + 0x00ce, 0x080c, 0x4dc5, 0x0128, 0x080c, 0x3912, 0x0110, 0x080c, + 0x2455, 0x60c0, 0xa005, 0x01a8, 0x6003, 0x0001, 0x2091, 0x301d, + 0x080c, 0x4dc5, 0x1158, 0x2011, 0x4ce2, 0x080c, 0x5731, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0038, 0x080c, 0x4105, + 0x0020, 0x6003, 0x0004, 0x2091, 0x301d, 0x0804, 0x28ff, 0x6000, + 0xa086, 0x0000, 0x0904, 0x2924, 0x2069, 0x9251, 0x7830, 0x6842, + 0x7834, 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0804, 0x3685, 0x81ff, 0x1904, 0x2924, 0x080c, 0x4dc5, + 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x0038, 0xa006, 0x080c, 0x2455, 0x080c, + 0x41c5, 0x080c, 0x4105, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, + 0x080c, 0x4dc5, 0x1110, 0x0804, 0x2924, 0x6184, 0x81ff, 0x0198, + 0x703f, 0x0000, 0x2001, 0x98c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0126, 0x2091, 0x8000, 0x080c, 0x3685, 0x701b, + 0x28fd, 0x012e, 0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0x98c0, + 0x20a9, 0x0040, 0x20a1, 0x98c0, 0x2019, 0xffff, 0x43a4, 0x654c, + 0xa588, 0x2719, 0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, + 0x0002, 0x2100, 0xa506, 0x01a8, 0x080c, 0x4434, 0x1190, 0x6014, + 0x821c, 0x0238, 0xa398, 0x98c0, 0xa085, 0xff00, 0x8007, 0x201a, + 0x0038, 0xa398, 0x98c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, + 0x8210, 0x8108, 0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, + 0x2d0c, 0xa105, 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0x98c0, + 0x2099, 0x98c0, 0x080c, 0x4166, 0x0804, 0x3222, 0x080c, 0x3666, + 0x0904, 0x2927, 0x00c6, 0x080c, 0x3641, 0x00ce, 0x0904, 0x2924, + 0x080c, 0x4dc5, 0x0500, 0x2001, 0x9252, 0x2004, 0xd0b4, 0x01d8, + 0x6000, 0xd08c, 0x11c0, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x1190, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x8476, + 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x329f, 0x0005, 0x080c, + 0x3666, 0x0904, 0x2927, 0x20a9, 0x002d, 0x2c98, 0xade8, 0x0002, + 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, + 0x0006, 0x20a0, 0x080c, 0x4166, 0x20a9, 0x0004, 0xac80, 0x000a, + 0x2098, 0xad80, 0x000a, 0x20a0, 0x080c, 0x4166, 0x2d00, 0x2009, + 0x002f, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x45e9, + 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x7828, 0xa08a, 0x1000, + 0x1a04, 0x2927, 0x080c, 0x3666, 0x0904, 0x2927, 0x080c, 0x4644, + 0x0904, 0x2924, 0x2019, 0x0004, 0x080c, 0x45fb, 0x7924, 0x810f, + 0x7a28, 0x0011, 0x0804, 0x28ff, 0xa186, 0x00ff, 0x0110, 0x0071, + 0x0060, 0x2029, 0x007e, 0x2061, 0x9200, 0x644c, 0x2400, 0xa506, + 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, 0x4434, + 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x573d, + 0x0005, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x44d4, 0x0904, 0x2924, 0x080c, 0x45f2, 0x0804, 0x28ff, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, + 0x44d4, 0x0904, 0x2924, 0x080c, 0x45e0, 0x0804, 0x28ff, 0x6100, + 0x2001, 0x94d8, 0x2014, 0xa282, 0x0003, 0x1210, 0x0804, 0x28ff, + 0x2011, 0x0000, 0x0804, 0x28ff, 0x0804, 0x28ff, 0x080c, 0x3666, + 0x0904, 0x2927, 0x6004, 0xa086, 0x0707, 0x0904, 0x2927, 0x2001, + 0x9200, 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x00d6, 0xace8, + 0x000a, 0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007, + 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, + 0x00de, 0x6100, 0xa18c, 0x0200, 0x0804, 0x28ff, 0x7824, 0xa09c, + 0x00ff, 0xa39a, 0x0003, 0x1a04, 0x2924, 0x624c, 0xa294, 0x00ff, + 0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0x9240, 0x2009, + 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x1904, 0x2924, 0x00c6, 0x080c, 0x3641, + 0x00ce, 0x0904, 0x2924, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x080c, 0x8428, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3399, + 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0xad80, 0x000e, + 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, + 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0118, 0x81ff, 0x1904, + 0x2924, 0x080c, 0x4dc5, 0x0128, 0xa006, 0x080c, 0x2455, 0x080c, + 0x41c5, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2927, 0x7924, 0xa18c, + 0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f, 0x1a04, + 0x2927, 0x2100, 0x080c, 0x241f, 0x0026, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x2061, 0x94f8, 0x601b, 0x0000, 0x601f, 0x0000, 0x080c, + 0x4dc5, 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x00a0, 0x2061, 0x0100, 0x2001, + 0x9214, 0x2004, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, + 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, 0x412a, 0x080c, + 0x57b3, 0x7924, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4dc5, 0x1110, + 0x2009, 0x00ff, 0x7a28, 0x080c, 0x32ec, 0x012e, 0x00ce, 0x002e, + 0x0804, 0x28ff, 0x7924, 0xa18c, 0xff00, 0x810f, 0x00c6, 0x080c, + 0x4400, 0x2c08, 0x00ce, 0x1904, 0x2927, 0x0804, 0x28ff, 0x81ff, + 0x1904, 0x2924, 0x60c8, 0xd0ac, 0x1118, 0xd09c, 0x0904, 0x2924, + 0x080c, 0x3641, 0x0904, 0x2924, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x080c, 0x3682, 0x701b, 0x342e, 0x0005, 0x2009, 0x0080, + 0x080c, 0x4434, 0x1130, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0120, 0x2021, 0x400a, 0x0804, 0x2901, 0x00d6, 0xade8, 0x000d, + 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, + 0x0100, 0x0904, 0x34a1, 0xa0be, 0x0112, 0x0904, 0x34a1, 0xa0be, + 0x0113, 0x0904, 0x34a1, 0xa0be, 0x0114, 0x0904, 0x34a1, 0xa0be, + 0x0117, 0x0904, 0x34a1, 0xa0be, 0x011a, 0x0904, 0x34a1, 0xa0be, + 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, 0x0171, 0x05c8, + 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, 0x6830, 0x8007, + 0x6832, 0x04a0, 0xa0be, 0x0212, 0x0540, 0xa0be, 0x0213, 0x0528, + 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, 0xa0be, 0x021a, + 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, 0x0300, 0x01c8, + 0x00de, 0x0804, 0x2927, 0xad80, 0x0010, 0x20a9, 0x0007, 0x080c, + 0x34dd, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x34dd, 0x0048, + 0xad80, 0x000c, 0x080c, 0x34eb, 0x0048, 0xad80, 0x000e, 0x080c, + 0x34eb, 0xad80, 0x000c, 0x20a9, 0x0001, 0x04b9, 0x00c6, 0x080c, + 0x3641, 0x0540, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, + 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, + 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, + 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, + 0x0000, 0x080c, 0x8442, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, + 0x34d6, 0x0005, 0x00ce, 0x00de, 0x0804, 0x2924, 0x6820, 0xa086, + 0x8001, 0x0904, 0x2924, 0x0804, 0x28ff, 0x0016, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x1f04, + 0x34df, 0x001e, 0x0005, 0x0016, 0x00a6, 0x00b6, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, + 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x00be, 0x00ae, 0x001e, + 0x0005, 0x81ff, 0x1904, 0x2924, 0x7924, 0x2140, 0xa18c, 0xff00, + 0x810f, 0x60c8, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2927, + 0xa182, 0x00ff, 0x1a04, 0x2927, 0x7a2c, 0x7b28, 0x606c, 0xa306, + 0x1140, 0x6070, 0xa24e, 0x0904, 0x2927, 0xa9cc, 0xff00, 0x0904, + 0x2927, 0x00c6, 0x080c, 0x359b, 0x2c68, 0x00ce, 0x01c0, 0xa0c6, + 0x4000, 0x1108, 0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, + 0xa0c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, + 0x1108, 0x0010, 0x2001, 0x4006, 0x2020, 0x0804, 0x2901, 0x2d00, + 0x7022, 0x0016, 0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x749c, + 0x05b8, 0x2d00, 0x601a, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, + 0x3641, 0x00ce, 0x2b70, 0x1140, 0x080c, 0x74f2, 0x00ee, 0x00ce, + 0x00be, 0x001e, 0x0804, 0x2924, 0x6837, 0x0000, 0x683b, 0x0000, + 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0xd88c, 0x0108, + 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x266c, 0x012e, + 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, + 0x080c, 0x43e3, 0x2009, 0x0002, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00ee, 0x00ce, 0x00be, 0x001e, 0x0904, 0x2924, 0x7007, 0x0003, + 0x701b, 0x358b, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, + 0x7020, 0x2060, 0x2009, 0x0000, 0x080c, 0x46a5, 0x1110, 0x2009, + 0x0001, 0x0804, 0x28ff, 0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, + 0x9232, 0x2004, 0xd0ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, + 0x2071, 0x936e, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, + 0x93ee, 0x2e04, 0xa005, 0x1130, 0x2100, 0xa406, 0x1548, 0x2428, + 0xc5fd, 0x0430, 0x2068, 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, + 0x2600, 0xa206, 0x1190, 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, + 0x0540, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1510, 0x2001, + 0x4000, 0x0400, 0x2001, 0x4007, 0x00e8, 0x2400, 0xa106, 0x1140, + 0x6e14, 0x87ff, 0x1110, 0x86ff, 0x09d0, 0x2001, 0x4008, 0x0090, + 0x8420, 0x8e70, 0x1f04, 0x35b1, 0x85ff, 0x1130, 0x2001, 0x4009, + 0x0048, 0x2001, 0x0001, 0x0030, 0x080c, 0x4400, 0x1dd0, 0x6312, + 0x6216, 0xa006, 0xa005, 0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, + 0x2924, 0x080c, 0x3641, 0x0904, 0x2924, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x7824, 0xa005, 0x0904, 0x2927, 0xa096, 0x00ff, + 0x0120, 0xa092, 0x0004, 0x1a04, 0x2927, 0x2010, 0x2d18, 0x080c, + 0x2631, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3618, 0x0005, + 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, 0x7924, + 0xa18c, 0xff00, 0x810f, 0x60c8, 0xd0ac, 0x1120, 0xa182, 0x0080, + 0x0a04, 0x2927, 0xa182, 0x00ff, 0x1a04, 0x2927, 0x0126, 0x2091, + 0x8000, 0x080c, 0x831a, 0x1150, 0xa190, 0x936e, 0x2204, 0xa065, + 0x0128, 0x080c, 0x41e0, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, + 0x2924, 0x080c, 0x147c, 0x0188, 0xa006, 0x6802, 0x7010, 0xa005, + 0x1120, 0x2d00, 0x7012, 0x7016, 0x0030, 0x7014, 0x6802, 0x2060, + 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, 0x0005, 0x7924, 0x810f, + 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1130, 0x7e28, 0xa684, 0x3fff, + 0xa082, 0x4000, 0x0208, 0xa066, 0x8cff, 0x0005, 0x7e24, 0x860f, + 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1128, 0xa6b4, 0x00ff, 0xa682, + 0x4000, 0x0208, 0xa066, 0x8cff, 0x0005, 0x0016, 0x7110, 0x81ff, + 0x0128, 0x2168, 0x6904, 0x080c, 0x1493, 0x0cc8, 0x7112, 0x7116, + 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, 0x2031, 0x0000, 0x2061, + 0x92e6, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, + 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x28ff, 0x0005, + 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, 0x92a4, + 0x2004, 0xa005, 0x1168, 0x0e04, 0x36b0, 0x7818, 0xd084, 0x1140, + 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001, 0x2091, 0x4080, 0x0408, + 0x0016, 0x00c6, 0x00e6, 0x2071, 0x9296, 0x7138, 0xa182, 0x0010, + 0x0218, 0x7030, 0x2060, 0x0078, 0x7030, 0xa0e0, 0x0004, 0xac82, + 0x92e6, 0x0210, 0x2061, 0x92a6, 0x2c00, 0x7032, 0x81ff, 0x1108, + 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x00ee, 0x00ce, + 0x001e, 0x012e, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x9296, 0x7038, + 0xa005, 0x0570, 0x0126, 0x2091, 0x8000, 0x0e04, 0x3707, 0x00f6, + 0x2079, 0x0000, 0x7818, 0xd084, 0x1508, 0x00c6, 0x7034, 0x2060, + 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, 0x782a, 0x781b, 0x0001, + 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0xa005, 0x1130, 0x7033, + 0x92a6, 0x7037, 0x92a6, 0x00ce, 0x0048, 0xac80, 0x0004, 0xa0fa, + 0x92e6, 0x0210, 0x2001, 0x92a6, 0x7036, 0x00ce, 0x00fe, 0x012e, + 0x00ee, 0x0005, 0x0026, 0x2001, 0x9252, 0x2004, 0xd0c4, 0x0120, + 0x2011, 0x8014, 0x080c, 0x3698, 0x002e, 0x0005, 0x81ff, 0x1904, + 0x2924, 0x0126, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x080c, + 0x4dc5, 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x0010, 0x080c, 0x4105, 0x012e, + 0x0804, 0x28ff, 0x7824, 0x2008, 0xa18c, 0xfffd, 0x1128, 0x61d4, + 0xa10d, 0x61d6, 0x0804, 0x28ff, 0x0804, 0x2927, 0x81ff, 0x1904, + 0x2924, 0x6000, 0xa086, 0x0003, 0x1904, 0x2924, 0x2001, 0x9252, + 0x2004, 0xd0a4, 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120, 0x7828, 0xa005, + 0x0904, 0x28ff, 0x00c6, 0x080c, 0x3641, 0x00ce, 0x0904, 0x2924, + 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x84d7, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3770, 0x0005, + 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, 0x2001, + 0x9200, 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x7f24, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, + 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, + 0x0005, 0x7026, 0x20a0, 0x080c, 0x4434, 0x15e0, 0x6004, 0xa0c4, + 0x00ff, 0xa8c6, 0x0006, 0x0150, 0xa0c4, 0xff00, 0xa8c6, 0x0600, + 0x0128, 0xa084, 0x00ff, 0xa082, 0x0006, 0x1660, 0xd784, 0x0150, + 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, + 0x34eb, 0x0048, 0xac80, 0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, + 0x53a3, 0x080c, 0x34eb, 0xa186, 0x007e, 0x0178, 0xa186, 0x0080, + 0x0160, 0x6004, 0xa084, 0x00ff, 0xa0c2, 0x0006, 0x1210, 0xc1fd, + 0x0020, 0x080c, 0x46a5, 0x1108, 0xc1fd, 0x21a2, 0xc1fc, 0x94a0, + 0xa6b0, 0x0005, 0x8108, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x0118, + 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186, 0x0100, 0x0148, + 0x0018, 0xa186, 0x007e, 0x0128, 0xa686, 0x0028, 0x0150, 0x0804, + 0x3793, 0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x28ff, 0x702f, + 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0x92e6, + 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3809, + 0x0005, 0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, + 0x2031, 0x0000, 0x2061, 0x92e6, 0x6224, 0x6328, 0x642c, 0x6530, + 0x0804, 0x3793, 0x7120, 0x810b, 0x0804, 0x28ff, 0x2029, 0x007e, + 0x7924, 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, + 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa184, 0x00ff, + 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa284, + 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, + 0x2927, 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, + 0x0a04, 0x2927, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, + 0x2927, 0xa502, 0x0a04, 0x2927, 0xa384, 0x00ff, 0xa0e2, 0x0020, + 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa484, 0xff00, 0x8007, + 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa484, + 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, + 0x2061, 0x94df, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x28ff, + 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, 0x0015, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x080c, 0x3682, 0x701b, 0x3887, 0x0005, 0xade8, + 0x000d, 0x6800, 0xa005, 0x0904, 0x2927, 0x6804, 0x2008, 0xa18c, + 0xfff8, 0x1904, 0x2927, 0x680c, 0xa005, 0x0904, 0x2927, 0xa082, + 0xff01, 0x1a04, 0x2927, 0x6810, 0xa082, 0x005c, 0x0a04, 0x2927, + 0x6824, 0x2008, 0xa082, 0x0008, 0x0a04, 0x2927, 0xa182, 0x0400, + 0x1a04, 0x2927, 0x080c, 0x5a84, 0x6944, 0x6820, 0xa102, 0x0a04, + 0x2927, 0x6828, 0x6944, 0x810c, 0xa102, 0x0a04, 0x2927, 0x6840, + 0xa082, 0x000f, 0x1a04, 0x2927, 0x00d6, 0x080c, 0x145f, 0x0904, + 0x2924, 0x2d00, 0x00de, 0x684e, 0x00d6, 0x6848, 0xa005, 0x0148, + 0x2008, 0x2069, 0x9200, 0x68dc, 0xa108, 0x68a8, 0xa102, 0x1208, + 0x69de, 0x00de, 0x20a9, 0x0015, 0x2d98, 0x2069, 0x9281, 0x2da0, + 0x53a3, 0x080c, 0x5957, 0x0904, 0x2924, 0x080c, 0x5885, 0x1904, + 0x2924, 0x00c6, 0x2061, 0x0100, 0x6104, 0xa18d, 0x8000, 0x6106, + 0x610c, 0xa18d, 0x0100, 0x610e, 0x2061, 0x0140, 0x610c, 0xa18d, + 0x0100, 0x6902, 0x6b10, 0x2061, 0x9519, 0x6316, 0x080c, 0x4716, + 0x2001, 0x9295, 0x2003, 0x0000, 0x00ce, 0x0804, 0x28ff, 0xe000, + 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0x0804, 0x28ff, + 0x7824, 0x0804, 0x28ff, 0x7824, 0x00e6, 0x2071, 0x9281, 0x00ee, + 0x0804, 0x28ff, 0x0006, 0x2001, 0x9252, 0x2004, 0xd0cc, 0x000e, + 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xd0bc, 0x000e, 0x0005, + 0x6164, 0x7a24, 0x6300, 0x82ff, 0x1118, 0x7926, 0x0804, 0x28ff, + 0x83ff, 0x1904, 0x2927, 0x2001, 0xfff0, 0xa200, 0x1a04, 0x2927, + 0x2019, 0xffff, 0x6068, 0xa302, 0xa200, 0x0a04, 0x2927, 0x7926, + 0x6266, 0x0804, 0x28ff, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2924, 0x7c28, 0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0000, 0x2019, 0x0000, 0x7023, 0x0000, + 0x702f, 0x0000, 0xad80, 0x0003, 0x7026, 0x20a0, 0xa1e0, 0x936e, + 0x2c64, 0x8cff, 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0130, 0x6004, 0xa084, 0xff00, 0xa086, 0x0600, 0x1158, 0x6014, + 0x20a2, 0x94a0, 0x6010, 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, + 0xa398, 0x0002, 0x8108, 0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, + 0x0148, 0x08e0, 0x83ff, 0x1120, 0x7120, 0x810c, 0x0804, 0x28ff, + 0x702f, 0x0001, 0x711e, 0x7020, 0xa300, 0x7022, 0x2061, 0x92e6, + 0x6007, 0x0000, 0x6312, 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, + 0x6732, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3999, + 0x0005, 0x702c, 0xa005, 0x1158, 0x711c, 0x7024, 0x20a0, 0x2019, + 0x0000, 0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x3956, 0x7120, + 0x810c, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x60c8, 0xd0ac, + 0x1118, 0xd09c, 0x0904, 0x2924, 0x080c, 0x3641, 0x0904, 0x2924, + 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3682, 0x701b, + 0x39c2, 0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, + 0x0148, 0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, + 0x0804, 0x2927, 0x6820, 0x6924, 0x080c, 0x240b, 0x1500, 0x080c, + 0x4400, 0x11e8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, + 0x3641, 0x01a8, 0x080c, 0x3641, 0x0190, 0x00ce, 0x00de, 0x6837, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x080c, 0x845c, + 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x39fa, 0x0005, 0x00de, + 0x0804, 0x2924, 0x7120, 0x080c, 0x441f, 0x6820, 0xa086, 0x8001, + 0x0904, 0x2924, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, 0x0006, + 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4166, 0x000e, 0xade8, + 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0x92e6, 0x6007, + 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018, 0xa7c6, + 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2927, 0x2009, 0x0004, + 0x0804, 0x3685, 0xa7c6, 0x7200, 0x1904, 0x2927, 0xa6c2, 0x0054, + 0x0a04, 0x2927, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3a41, + 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, + 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4166, + 0x000e, 0x2009, 0x002a, 0x2061, 0x92e6, 0x6224, 0x6328, 0x642c, + 0x6530, 0x0804, 0x3685, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, + 0x0904, 0x2927, 0x080c, 0x44d4, 0x0904, 0x2924, 0x080c, 0x4604, + 0x0804, 0x28ff, 0x0126, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, + 0x9200, 0x6044, 0xd0a4, 0x11b0, 0xd084, 0x0118, 0x080c, 0x3bd7, + 0x0068, 0xd08c, 0x0118, 0x080c, 0x3af8, 0x0040, 0xd094, 0x0118, + 0x080c, 0x3ad0, 0x0018, 0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, + 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, + 0x001e, 0x0ca0, 0x624c, 0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, + 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0478, + 0xa294, 0xff00, 0xa296, 0xf700, 0x0160, 0x6240, 0xa295, 0x0100, + 0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x4186, + 0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0040, 0x6042, 0x6043, + 0x0000, 0x7077, 0x0000, 0x7093, 0x0001, 0x70b3, 0x0000, 0x70cb, + 0x0000, 0x2009, 0x98c0, 0x200b, 0x0000, 0x7087, 0x0000, 0x707b, + 0x000f, 0x2009, 0x000f, 0x2011, 0x40a8, 0x080c, 0x57b3, 0x0005, + 0x0156, 0x7078, 0xa005, 0x1510, 0x2011, 0x40a8, 0x080c, 0x5731, + 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, + 0x6044, 0xd08c, 0x1168, 0x1f04, 0x3ae0, 0x6242, 0x708b, 0x0000, + 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, 0x0030, + 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, 0x0000, 0x015e, 0x0005, + 0x707c, 0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, 0x13fe, + 0x0005, 0x3b04, 0x3b54, 0x3bd6, 0x00f6, 0x707f, 0x0001, 0x20e1, + 0xa000, 0xe000, 0x20e1, 0x8700, 0x080c, 0x20ce, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2079, 0x9700, 0x207b, 0x2200, 0x7807, 0x00ef, + 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, + 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, + 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0x970c, 0x207b, 0x1101, + 0x7807, 0x0000, 0x2099, 0x9205, 0x20a1, 0x970e, 0x20a9, 0x0004, + 0x53a3, 0x2079, 0x9712, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, + 0x9700, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, + 0x600f, 0x0000, 0x080c, 0x40ec, 0x00fe, 0x7083, 0x0000, 0x6043, + 0x0008, 0x6043, 0x0000, 0x0005, 0x00d6, 0x7080, 0x7083, 0x0000, + 0xa025, 0x0904, 0x3bbe, 0x6020, 0xd0b4, 0x1904, 0x3bbc, 0x7190, + 0x81ff, 0x0904, 0x3ba6, 0xa486, 0x000c, 0x1904, 0x3bb1, 0xa480, + 0x0018, 0x8004, 0x20a8, 0x2011, 0x9780, 0x2019, 0x9700, 0x220c, + 0x2304, 0xa106, 0x1188, 0x8210, 0x8318, 0x1f04, 0x3b6f, 0x6043, + 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707f, + 0x0002, 0x708b, 0x0002, 0x04c0, 0x2069, 0x9780, 0x6930, 0xa18e, + 0x1101, 0x1538, 0x6834, 0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, + 0x1118, 0x6804, 0xa005, 0x0190, 0x2011, 0x978e, 0x2019, 0x9205, + 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0230, 0x1190, 0x8210, + 0x8318, 0x1f04, 0x3b9a, 0x0068, 0x7093, 0x0000, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x20a9, 0x0014, + 0x53a6, 0x6043, 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x1120, + 0x60c3, 0x000c, 0x080c, 0x40ec, 0x00de, 0x0005, 0x6040, 0xa085, + 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c, 0x2011, + 0x94ef, 0x2013, 0x0000, 0x7083, 0x0000, 0x20e1, 0x9080, 0x60a3, + 0x0056, 0x60a7, 0x9575, 0x080c, 0x6f15, 0x0c30, 0x0005, 0x7088, + 0xa08a, 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x13fe, 0x0005, + 0x3c0a, 0x3c19, 0x3c43, 0x3c58, 0x3c7e, 0x3ca6, 0x3ccc, 0x3cfd, + 0x3d23, 0x3d4b, 0x3d86, 0x3dae, 0x3dca, 0x3de0, 0x3e00, 0x3e13, + 0x3e1b, 0x3e45, 0x3e6b, 0x3e93, 0x3eb9, 0x3eea, 0x3f25, 0x3f54, + 0x3f70, 0x3faf, 0x3fcf, 0x3fe8, 0x3fe9, 0x00c6, 0x2061, 0x9200, + 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, + 0x00ce, 0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, + 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x40af, 0x080c, 0x5725, + 0x0005, 0x00f6, 0x7080, 0xa086, 0x0014, 0x1518, 0x6043, 0x0000, + 0x6020, 0xd0b4, 0x11f0, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1102, + 0x11b0, 0x7834, 0xa005, 0x1198, 0x7a38, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x2011, 0x40af, + 0x080c, 0x5731, 0x708b, 0x0010, 0x080c, 0x3e1b, 0x0010, 0x7083, + 0x0000, 0x00fe, 0x0005, 0x708b, 0x0003, 0x6043, 0x0004, 0x080c, + 0x416e, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, 0x20a3, + 0x0000, 0x1f04, 0x3c4f, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, + 0x00f6, 0x7080, 0xa005, 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, + 0xa086, 0x0014, 0x11b8, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1102, + 0x1188, 0x7834, 0xa005, 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x708b, 0x0004, + 0x0029, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0005, + 0x080c, 0x416e, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, + 0x978e, 0x080c, 0x41bd, 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, + 0xa186, 0xffff, 0x0128, 0x080c, 0x4074, 0x0110, 0x080c, 0x419d, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, + 0xa005, 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, + 0x11b8, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1103, 0x1188, 0x7834, + 0xa005, 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, + 0x080c, 0x419d, 0x70b3, 0x0001, 0x708b, 0x0006, 0x0029, 0x0010, + 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0007, 0x080c, 0x416e, + 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, + 0x41bd, 0x11a8, 0x7074, 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, + 0x0170, 0xa180, 0x2719, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, + 0x4074, 0x0128, 0x080c, 0x3919, 0x0110, 0x080c, 0x2455, 0x20a9, + 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, + 0x2079, 0x9780, 0x7a30, 0xa296, 0x1104, 0x1188, 0x7834, 0xa005, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x0008, 0x0029, 0x0010, 0x080c, + 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0009, 0x080c, 0x416e, 0x20a3, + 0x1105, 0x20a3, 0x0100, 0x3430, 0x080c, 0x41bd, 0x1150, 0x7074, + 0xa005, 0x1138, 0x080c, 0x3fea, 0x1170, 0xa085, 0x0001, 0x080c, + 0x2455, 0x20a9, 0x0008, 0x2099, 0x978e, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0010, + 0x080c, 0x3bfd, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05a8, 0x2011, + 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x1560, 0x2079, 0x9780, + 0x7a30, 0xa296, 0x1105, 0x1530, 0x7834, 0x2011, 0x0100, 0xa21e, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x000a, 0x00c1, 0x00a8, 0xa005, + 0x1188, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x7087, 0x0000, 0x708b, 0x000e, 0x080c, + 0x3e00, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x000b, + 0x2011, 0x970e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, + 0x20a9, 0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x416e, 0x20a3, + 0x1106, 0x20a3, 0x0000, 0x080c, 0x41bd, 0x0118, 0x2013, 0x0000, + 0x0020, 0x7050, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, + 0x53a6, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, + 0xa005, 0x01b0, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0084, + 0x1168, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, + 0xa005, 0x1120, 0x708b, 0x000c, 0x0029, 0x0010, 0x080c, 0x41b6, + 0x00fe, 0x0005, 0x708b, 0x000d, 0x080c, 0x416e, 0x20a3, 0x1107, + 0x20a3, 0x0000, 0x2099, 0x978e, 0x20a9, 0x0040, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, + 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x40af, 0x080c, 0x5731, + 0xa086, 0x0084, 0x1188, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1107, + 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, 0x4160, + 0x708b, 0x000e, 0x0029, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, + 0x708b, 0x000f, 0x7083, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, + 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x40af, + 0x080c, 0x5725, 0x0005, 0x7080, 0xa005, 0x0120, 0x2011, 0x40af, + 0x080c, 0x5731, 0x0005, 0x708b, 0x0011, 0x716c, 0x81ff, 0x0170, + 0x2009, 0x0000, 0x7070, 0xa084, 0x00ff, 0x080c, 0x240b, 0xa186, + 0x0080, 0x0120, 0x2011, 0x978e, 0x080c, 0x4074, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x7480, 0xa480, + 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, + 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, + 0x2079, 0x9780, 0x7a30, 0xa296, 0x1103, 0x1188, 0x7834, 0xa005, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x0012, 0x0029, 0x0010, 0x7083, + 0x0000, 0x00fe, 0x0005, 0x708b, 0x0013, 0x080c, 0x417a, 0x20a3, + 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, 0x41bd, + 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, 0xa186, 0xffff, 0x0128, + 0x080c, 0x4074, 0x0110, 0x080c, 0x419d, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, 0x0500, 0x2011, + 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, 0x2079, 0x9780, + 0x7a30, 0xa296, 0x1104, 0x1188, 0x7834, 0xa005, 0x1170, 0x7a38, + 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, + 0x0001, 0x708b, 0x0014, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, + 0x0005, 0x708b, 0x0015, 0x080c, 0x417a, 0x20a3, 0x1104, 0x20a3, + 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, 0x41bd, 0x11a8, 0x7074, + 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170, 0xa180, 0x2719, + 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4074, 0x0128, 0x080c, + 0x3919, 0x0110, 0x080c, 0x2455, 0x20a9, 0x0008, 0x2298, 0x26a0, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, + 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05a8, 0x2011, 0x40af, + 0x080c, 0x5731, 0xa086, 0x0014, 0x1560, 0x2079, 0x9780, 0x7a30, + 0xa296, 0x1105, 0x1530, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1178, + 0x7a38, 0xd2f4, 0x0110, 0x70cb, 0x0008, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x0070, 0xa005, + 0x1180, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x7087, 0x0000, 0x708b, 0x0016, 0x0029, + 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, + 0x3430, 0x2011, 0x978e, 0x708b, 0x0017, 0x080c, 0x41bd, 0x1150, + 0x7074, 0xa005, 0x1138, 0x080c, 0x3fea, 0x1170, 0xa085, 0x0001, + 0x080c, 0x2455, 0x20a9, 0x0008, 0x2099, 0x978e, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, + 0x0010, 0x080c, 0x3bfd, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01b0, + 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0084, 0x1168, 0x2079, + 0x9780, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, 0xa005, 0x1120, + 0x708b, 0x0018, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, + 0x708b, 0x0019, 0x080c, 0x417a, 0x20a3, 0x1106, 0x20a3, 0x0000, + 0x3430, 0x2099, 0x978e, 0x2039, 0x970e, 0x27a0, 0x20a9, 0x0040, + 0x53a3, 0x080c, 0x41bd, 0x11e8, 0x2728, 0x2514, 0x8207, 0xa084, + 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, + 0x7050, 0x2310, 0x8214, 0xa2a0, 0x970e, 0x2414, 0xa38c, 0x0001, + 0x0118, 0xa294, 0xff00, 0x0018, 0xa294, 0x00ff, 0x8007, 0xa215, + 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, 0x00f6, + 0x7080, 0xa005, 0x01d0, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, + 0x0084, 0x1188, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1107, 0x1158, + 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, 0x4160, 0x708b, + 0x001a, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x708b, + 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, + 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, + 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, + 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0x9252, 0x252c, 0x20a9, + 0x0008, 0x2041, 0x970e, 0x28a0, 0x2099, 0x978e, 0x53a3, 0x20a9, + 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110, 0x2011, 0x0000, 0x2800, + 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148, 0xd5d4, 0x0110, 0x8210, + 0x0008, 0x8211, 0x1f04, 0x3fff, 0x0804, 0x406c, 0x82ff, 0x1160, + 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90, 0x0020, 0xa1a6, 0x3fff, + 0x0904, 0x406c, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, + 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0110, 0x8423, + 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319, 0x0008, 0x8318, + 0x1f04, 0x4025, 0x04c8, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, + 0x1f04, 0x4037, 0x2328, 0x8529, 0xa2be, 0x0007, 0x0158, 0x0006, + 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e, 0x27a8, 0xa5a8, 0x0010, + 0x1f04, 0x4046, 0x754e, 0xa5c8, 0x2719, 0x292d, 0xa5ac, 0x00ff, + 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x2435, 0x001e, 0x60e7, + 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405, 0x201a, 0x7077, 0x0001, + 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0xa085, 0x0001, 0x0028, 0xa006, 0x0018, 0xa006, 0x080c, + 0x13fe, 0x009e, 0x008e, 0x0005, 0x2118, 0x2021, 0x0000, 0x2001, + 0x0007, 0xa39a, 0x0010, 0x0218, 0x8420, 0x8001, 0x0cd0, 0x2118, + 0x84ff, 0x0120, 0xa39a, 0x0010, 0x8421, 0x1de0, 0x2021, 0x0001, + 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8, 0xa238, 0x2704, 0xa42c, + 0x11b0, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x2719, 0x242d, 0xa5ac, + 0x00ff, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x2435, 0x001e, + 0x60e7, 0x0000, 0x65ea, 0x7077, 0x0001, 0xa084, 0x0000, 0x0005, + 0x00e6, 0x2071, 0x9200, 0x707b, 0x0000, 0x00ee, 0x0005, 0x00e6, + 0x00f6, 0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x6f1e, 0x7004, + 0xa084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, + 0x4dcd, 0x01b0, 0x080c, 0x4deb, 0x1198, 0x2001, 0x94d7, 0x2003, + 0xaaaa, 0x2001, 0x0204, 0x2004, 0x0016, 0x2009, 0x94c8, 0x200a, + 0x001e, 0x2001, 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0080, + 0x0126, 0x2091, 0x8000, 0x2071, 0x9222, 0x2073, 0x0000, 0x7840, + 0x0026, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42, 0x002e, + 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x2011, + 0x94ef, 0x2013, 0x0000, 0x7083, 0x0000, 0x012e, 0x20e1, 0x9080, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x6f15, 0x2009, 0x07d0, + 0x2011, 0x40af, 0x080c, 0x57b3, 0x0005, 0x0016, 0x0026, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x2009, 0x00f7, 0x080c, 0x4186, 0x2061, + 0x94f8, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x9200, 0x6003, + 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, + 0x001e, 0x2011, 0x412a, 0x080c, 0x5725, 0x012e, 0x00ce, 0x002e, + 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x0100, 0x080c, 0x6f1e, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, + 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x4dcd, 0x01b0, + 0x080c, 0x4deb, 0x1198, 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, + 0x0204, 0x2004, 0x0016, 0x2009, 0x94c8, 0x200a, 0x001e, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0030, 0x2001, 0x0001, + 0x080c, 0x23ba, 0x080c, 0x4105, 0x012e, 0x000e, 0x00ee, 0x0005, + 0x20a9, 0x0040, 0x20a1, 0x98c0, 0x2099, 0x978e, 0x3304, 0x8007, + 0x20a2, 0x9398, 0x94a0, 0x1f04, 0x4166, 0x0005, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9700, 0x20a1, 0x020b, 0x20a9, 0x000c, + 0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x9780, + 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, 0x0006, + 0x2061, 0x0100, 0x810f, 0x2001, 0x922f, 0x2004, 0xa005, 0x1138, + 0x2001, 0x9214, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, 0xa185, + 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001, + 0x9252, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, + 0x080c, 0x90d7, 0x2001, 0x920c, 0x200c, 0xc195, 0x2102, 0x2019, + 0x002a, 0x080c, 0x264b, 0x004e, 0x001e, 0x0005, 0x080c, 0x4105, + 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006, 0x2001, 0x920c, + 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, 0x0016, 0x0126, + 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, + 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, 0x20a9, 0x00ff, 0x2009, + 0x936e, 0xa006, 0x200a, 0x8108, 0x1f04, 0x41da, 0x015e, 0x0005, + 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, 0x2069, 0x9251, 0xa006, + 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x2719, + 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, + 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, + 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, + 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, + 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x61a2, + 0x00d6, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x1493, 0x60a7, 0x0000, + 0x60a8, 0xa06d, 0x0110, 0x080c, 0x1493, 0x60ab, 0x0000, 0x00de, + 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0xa006, 0x60b2, + 0x60ae, 0x60b6, 0x60bb, 0x0520, 0x6814, 0xa084, 0x00ff, 0x6042, + 0x014e, 0x013e, 0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, + 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, + 0x42cf, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x1a04, 0x42d4, + 0x2001, 0x920c, 0x2004, 0xa084, 0x0003, 0x1904, 0x42bd, 0xa188, + 0x936e, 0x2104, 0xa065, 0x0904, 0x42a9, 0x6004, 0xa084, 0x00ff, + 0xa08e, 0x0006, 0x1904, 0x42ae, 0x60a4, 0xa00d, 0x0118, 0x080c, + 0x4630, 0x05d0, 0x60a8, 0xa00d, 0x0188, 0x080c, 0x467a, 0x1170, + 0x694c, 0xd1fc, 0x1118, 0x080c, 0x43c4, 0x0448, 0x080c, 0x4386, + 0x694c, 0xd1ec, 0x1520, 0x080c, 0x452b, 0x0408, 0x694c, 0xa184, + 0xa000, 0x0178, 0xd1ec, 0x0140, 0xd1fc, 0x0118, 0x080c, 0x453a, + 0x0028, 0x080c, 0x453a, 0x0028, 0xd1fc, 0x0118, 0x080c, 0x4386, + 0x0070, 0x6050, 0xa00d, 0x0130, 0x2d00, 0x200a, 0x6803, 0x0000, + 0x6052, 0x0028, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x080c, + 0x6015, 0xa006, 0x012e, 0x0005, 0x2001, 0x0005, 0x2009, 0x0000, + 0x0478, 0x2001, 0x0028, 0x2009, 0x0000, 0x0450, 0xa082, 0x0006, + 0x1260, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1120, 0x60a0, 0xd0bc, + 0x0904, 0x4264, 0x2001, 0x0028, 0x0078, 0x2009, 0x920c, 0x210c, + 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0010, 0x2001, 0x0029, 0x2009, 0x0000, 0x0048, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, + 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, 0x6844, + 0x0006, 0x000e, 0x0006, 0x000e, 0xa084, 0xff00, 0xa08e, 0xff00, + 0x1120, 0x2001, 0x94c6, 0x2064, 0x0098, 0x6844, 0x8007, 0xa084, + 0x00ff, 0x2008, 0xa182, 0x00ff, 0x16c8, 0xa188, 0x936e, 0x2104, + 0xa065, 0x01f0, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11d8, + 0x2c70, 0x080c, 0x749c, 0x0580, 0x2e00, 0x601a, 0x2d00, 0x6012, + 0x601f, 0x0009, 0x600b, 0x0000, 0x6844, 0xa08e, 0xff00, 0x1110, + 0x600b, 0x8000, 0x2009, 0x0100, 0x080c, 0x7518, 0xa006, 0x00c8, + 0x2001, 0x0028, 0x00a8, 0xa082, 0x0006, 0x0e10, 0x2009, 0x920c, + 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, + 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, + 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, 0x002c, 0x0cc8, 0x6944, + 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1678, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x00ff, 0x12e0, 0xa188, 0x936e, 0x2104, 0xa065, + 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11b0, 0x684c, + 0xd0ec, 0x0120, 0x080c, 0x453a, 0x0489, 0x0030, 0x0479, 0x684c, + 0xd0fc, 0x0110, 0x080c, 0x452b, 0x080c, 0x4578, 0xa006, 0x0088, + 0x2001, 0x0028, 0x2009, 0x0000, 0x0060, 0xa082, 0x0006, 0x0e38, + 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, + 0x0000, 0xa005, 0x0005, 0x0126, 0x2091, 0x8000, 0x6050, 0xa00d, + 0x0138, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x012e, 0x0005, + 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, 0x0126, 0x2091, + 0x8000, 0x604c, 0xa005, 0x0170, 0x00e6, 0x2071, 0x94e5, 0x7004, + 0xa086, 0x0002, 0x0168, 0x00ee, 0x604c, 0x6802, 0x2d00, 0x604e, + 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, + 0x701c, 0xac06, 0x1d80, 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, + 0x7002, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x604c, + 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, + 0x012e, 0x0005, 0x604c, 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, + 0x6052, 0x604e, 0xad05, 0x0005, 0x6803, 0x0000, 0x6084, 0xa00d, + 0x0120, 0x2d00, 0x200a, 0x6086, 0x0005, 0x2d00, 0x6086, 0x6082, + 0x0cd8, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6200, 0xa005, 0x0110, 0xc285, 0x0008, 0xc284, 0x6202, 0x002e, + 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, + 0x2260, 0x6204, 0xa294, 0xff00, 0xa215, 0x6206, 0x00ce, 0x012e, + 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, + 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, + 0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, + 0x936e, 0x2204, 0xa065, 0x1180, 0x0016, 0x00d6, 0x080c, 0x145f, + 0x2d60, 0x00de, 0x001e, 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, + 0x60ab, 0x0000, 0x080c, 0x41e0, 0xa006, 0x002e, 0x0005, 0x0026, + 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0060, 0x00d6, 0xa190, + 0x936e, 0x2204, 0xa06d, 0x0120, 0x2013, 0x0000, 0x080c, 0x1493, + 0x00de, 0xa006, 0x002e, 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, + 0xa085, 0x0001, 0x0030, 0xa188, 0x936e, 0x2104, 0xa065, 0x0dc0, + 0xa006, 0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, + 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x080c, 0x4dc5, + 0x1520, 0x60a0, 0xa086, 0x007e, 0x2069, 0x9790, 0x0130, 0x2001, + 0x9232, 0x2004, 0xd0ac, 0x11c8, 0x0098, 0x2d04, 0xd0e4, 0x01a8, + 0x00d6, 0x2069, 0x978e, 0x00c6, 0x2061, 0x94d9, 0x6810, 0x2062, + 0x6814, 0x6006, 0x6818, 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, + 0x8d69, 0x2d04, 0x2069, 0x0140, 0x6886, 0x2069, 0x978e, 0x6808, + 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0208, 0x603a, 0x6814, + 0x6066, 0x2099, 0x9796, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2099, 0x979a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2069, 0x97ae, 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, + 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, 0x1218, 0x2009, 0x0008, + 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0xa182, + 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, 0x1218, + 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, 0x0004, + 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, + 0x0002, 0x6192, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x00e6, + 0x2071, 0x978d, 0x2e04, 0x6896, 0x2071, 0x978e, 0x7004, 0x689a, + 0x701c, 0x689e, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff, 0x1540, 0x6a04, 0xa282, + 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, + 0xffff, 0x0128, 0x8108, 0x1f04, 0x44e6, 0x080c, 0x13fe, 0x260a, + 0x8210, 0x6a06, 0x0098, 0x080c, 0x145f, 0x01a8, 0x2d00, 0x60a6, + 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, + 0x8108, 0x1f04, 0x44fe, 0x6807, 0x0001, 0x6e12, 0xa085, 0x0001, + 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, + 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168, 0x6800, 0xa005, 0x1160, + 0x080c, 0x4630, 0x1168, 0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, + 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, 0x1493, 0x60a7, 0x0000, + 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x468d, + 0x0010, 0x080c, 0x4373, 0x080c, 0x45af, 0x1dd8, 0x080c, 0x4578, + 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a8, 0xa06d, + 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54, 0xa282, 0x0010, 0x1670, + 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0128, + 0x8108, 0x1f04, 0x454c, 0x080c, 0x13fe, 0x260a, 0x8210, 0x6a56, + 0x0098, 0x080c, 0x145f, 0x01d0, 0x2d00, 0x60aa, 0x6853, 0x0000, + 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, + 0x4564, 0x6857, 0x0001, 0x6e62, 0x0010, 0x080c, 0x43c4, 0x0089, + 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6015, 0x012e, 0x0005, 0xa01e, + 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126, 0x2091, 0x8000, 0x604c, + 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff, 0x01e8, 0x83ff, 0x0120, + 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, + 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x604c, + 0xad06, 0x1110, 0x624e, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, + 0x1110, 0x6152, 0x8dff, 0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, + 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x01e8, 0x83ff, 0x0120, + 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, + 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x6080, + 0xad06, 0x1110, 0x6282, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, + 0x1110, 0x6186, 0x8dff, 0x0005, 0xa016, 0x080c, 0x462a, 0x1110, + 0x2011, 0x0001, 0x080c, 0x4674, 0x1110, 0xa295, 0x0002, 0x0005, + 0x080c, 0x46a5, 0x0118, 0x080c, 0x83ab, 0x0010, 0xa085, 0x0001, + 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x8338, 0x0010, 0xa085, + 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x837e, 0x0010, + 0xa085, 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x8352, + 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, + 0x83d8, 0x0010, 0xa085, 0x0001, 0x0005, 0x0126, 0x0006, 0x00d6, + 0x2091, 0x8000, 0x6080, 0xa06d, 0x0168, 0x6800, 0x0006, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, + 0x000e, 0x0c88, 0x6083, 0x0000, 0x6087, 0x0000, 0x00de, 0x000e, + 0x012e, 0x0005, 0x60a4, 0xa00d, 0x1118, 0xa085, 0x0001, 0x0005, + 0x00e6, 0x2170, 0x7000, 0xa005, 0x1160, 0x20a9, 0x0010, 0xae88, + 0x0004, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x4639, 0xa085, + 0x0001, 0xa006, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x1128, 0x080c, 0x145f, 0x01a0, 0x2d00, 0x60a6, + 0x6803, 0x0001, 0x6807, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, + 0x200b, 0xffff, 0x8108, 0x1f04, 0x4658, 0xa085, 0x0001, 0x012e, + 0x00de, 0x0005, 0xa006, 0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x0130, 0x60a7, 0x0000, 0x080c, 0x1493, 0xa085, + 0x0001, 0x012e, 0x00de, 0x0005, 0x60a8, 0xa00d, 0x1118, 0xa085, + 0x0001, 0x0005, 0x00e6, 0x2170, 0x7050, 0xa005, 0x1160, 0x20a9, + 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, + 0x4683, 0xa085, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, + 0x0c19, 0x1188, 0x200b, 0xffff, 0x00d6, 0x60a8, 0x2068, 0x6854, + 0xa08a, 0x0002, 0x0218, 0x8001, 0x6856, 0x0020, 0x080c, 0x1493, + 0x60ab, 0x0000, 0x00de, 0x012e, 0x0005, 0x609c, 0xd0a4, 0x0005, + 0x00f6, 0x2079, 0x9251, 0x7804, 0xd0a4, 0x0518, 0x0156, 0x00c6, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1168, + 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, 0x0118, 0xa086, + 0x0006, 0x1118, 0x6000, 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, + 0x46b4, 0x00ce, 0x015e, 0x2009, 0x07d0, 0x2011, 0x46d3, 0x080c, + 0x57b3, 0x00fe, 0x0005, 0x2011, 0x46d3, 0x080c, 0x5731, 0x0156, + 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, + 0x1530, 0x6000, 0xd0ec, 0x0518, 0x0046, 0x62a0, 0xa294, 0x00ff, + 0x8227, 0xa006, 0x2009, 0x0029, 0x080c, 0x90d7, 0x6000, 0xc0e5, + 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, 0x6006, + 0x2019, 0x0029, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, + 0x606d, 0x2009, 0x0000, 0x080c, 0x8ee4, 0x008e, 0x004e, 0x001e, + 0x8108, 0x1f04, 0x46dd, 0x00ce, 0x015e, 0x0005, 0x00c6, 0x6018, + 0x2060, 0x6000, 0xc0ec, 0x6002, 0x00ce, 0x0005, 0x00c6, 0x00d6, + 0x080c, 0x145f, 0x2d60, 0x090c, 0x13fe, 0x2009, 0x00ff, 0x080c, + 0x41e0, 0x6007, 0x0006, 0x6013, 0x00ff, 0x6017, 0xffff, 0x606f, + 0x0200, 0x606c, 0x6093, 0x0002, 0x60bb, 0x0520, 0x60a3, 0x00ff, + 0x60b7, 0x0000, 0x60af, 0x0000, 0x2c08, 0x2001, 0x94c6, 0x2102, + 0x00de, 0x00ce, 0x0005, 0x0156, 0x00e6, 0x00d6, 0x00c6, 0x20a9, + 0x00ff, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1138, 0x2c70, + 0x70ac, 0xa005, 0x0118, 0x2060, 0x080c, 0x5cf4, 0x001e, 0x8108, + 0x1f04, 0x4743, 0x00ce, 0x00de, 0x00ee, 0x015e, 0x0005, 0x2071, + 0x9328, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, + 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x704b, 0x0001, 0x704f, + 0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, + 0x94b6, 0x7003, 0x9328, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, + 0x9496, 0x7013, 0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x0005, + 0x0016, 0x00e6, 0x2071, 0x946e, 0xa00e, 0x7186, 0x718a, 0x7097, + 0x0001, 0x2001, 0x9252, 0x2004, 0xd0fc, 0x1148, 0x2001, 0x9252, + 0x2004, 0xa00e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x04f0, 0x2001, + 0x9271, 0x200c, 0xa184, 0x000f, 0x2009, 0x9272, 0x210c, 0x0002, + 0x478e, 0x47b0, 0x47b7, 0x47c1, 0x47c6, 0x478e, 0x478e, 0x478e, + 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, + 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, 0x0030, 0x708f, + 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, 0x7097, 0x0001, + 0x0088, 0x7007, 0x0122, 0x2001, 0x0002, 0x0020, 0x7007, 0x0121, + 0x2001, 0x0003, 0x7002, 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, + 0x8007, 0x709a, 0xa184, 0x00ff, 0x7092, 0x00ee, 0x001e, 0x0005, + 0x00e6, 0x2071, 0x9328, 0x684c, 0xa005, 0x1130, 0x7028, 0xc085, + 0x702a, 0xa085, 0x0001, 0x0418, 0x6a60, 0x7236, 0x6b64, 0x733a, + 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, + 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x8007, 0x8006, 0x8006, + 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, + 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, 0x00ee, + 0x0005, 0x0156, 0x00e6, 0x0026, 0x6838, 0xd0fc, 0x1904, 0x4861, + 0x6804, 0xa00d, 0x0188, 0x00d6, 0x2071, 0x9200, 0xa016, 0x702c, + 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, + 0x70ac, 0xa200, 0x70ae, 0x00de, 0x2071, 0x9328, 0x701c, 0xa005, + 0x1904, 0x4871, 0x20a9, 0x0032, 0x0f04, 0x486f, 0x0e04, 0x482c, + 0x2071, 0x946e, 0x7200, 0x82ff, 0x05d0, 0x6934, 0xa186, 0x0103, + 0x1904, 0x487f, 0x6948, 0x6844, 0xa105, 0x1538, 0x2009, 0x8020, + 0x2200, 0x0002, 0x486f, 0x4846, 0x48e6, 0x48f3, 0x2071, 0x0000, + 0x20a9, 0x0032, 0x0f04, 0x486f, 0x7018, 0xd084, 0x1dd8, 0x7122, + 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, + 0x2071, 0x9200, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, + 0x70ae, 0x002e, 0x00ee, 0x015e, 0x0005, 0x6844, 0xa086, 0x0100, + 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, 0x0888, 0x2071, + 0x9328, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, 0x7018, + 0xa06d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x0c10, 0xa18c, + 0x00ff, 0xa186, 0x0013, 0x01e0, 0xa186, 0x001b, 0x01c8, 0xa186, + 0x0023, 0x01e8, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, + 0xa18e, 0x001f, 0x19e0, 0x684c, 0xd0cc, 0x09c8, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x1998, 0x2009, 0x8021, 0x0804, 0x4840, + 0x6848, 0xa005, 0x1960, 0x2009, 0x8022, 0x0804, 0x4840, 0x2071, + 0x0000, 0x7018, 0xd084, 0x1918, 0x00e6, 0x2071, 0x9281, 0x7140, + 0x00ee, 0x6838, 0xa102, 0x0a04, 0x486f, 0x684c, 0xa005, 0x1158, + 0x00e6, 0x2071, 0x9281, 0x7004, 0x00ee, 0xd08c, 0x1904, 0x486f, + 0x2001, 0x8024, 0x0040, 0x6848, 0xd084, 0x1118, 0x2001, 0x8023, + 0x0010, 0x2001, 0x8027, 0x7022, 0x6840, 0x7026, 0x683c, 0x702a, + 0x6850, 0x702e, 0x0026, 0x0036, 0x6b38, 0x2e10, 0xa290, 0x0072, + 0x2d00, 0xa080, 0x0015, 0x200c, 0x2112, 0x8000, 0x200c, 0x8210, + 0x8319, 0x1dd0, 0x003e, 0x002e, 0x0804, 0x4854, 0x7084, 0x8008, + 0xa092, 0x001e, 0x1a04, 0x486f, 0x7186, 0xae90, 0x0003, 0xa210, + 0x683c, 0x2012, 0x0080, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, + 0x486f, 0x7186, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, + 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, 0x0a04, 0x4858, 0x718c, + 0x7084, 0xa10a, 0x0a04, 0x4858, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x4858, 0x2071, 0x946e, 0x7000, 0xa086, 0x0002, 0x1150, + 0x080c, 0x4b12, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, + 0x0804, 0x4858, 0x080c, 0x4b3c, 0x2071, 0x0000, 0x701b, 0x0001, + 0x2091, 0x4080, 0x0804, 0x4858, 0x0006, 0x6837, 0x0103, 0x20a9, + 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x000e, + 0x684a, 0x6952, 0x0005, 0x2071, 0x9328, 0x7004, 0x0002, 0x4948, + 0x4958, 0x4afd, 0x4afe, 0x4b0b, 0x4b11, 0x4949, 0x4aee, 0x4a9a, + 0x0005, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4956, 0x2009, 0x000d, + 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x012e, 0x0005, + 0x2069, 0x94f8, 0x683c, 0xa005, 0x03f8, 0x11f0, 0x0126, 0x2091, + 0x8000, 0x2069, 0x0000, 0x6934, 0x2001, 0x9334, 0x2004, 0xa10a, + 0x0170, 0x0e04, 0x497c, 0x2069, 0x0000, 0x6818, 0xd084, 0x1158, + 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x2069, + 0x94f8, 0x683f, 0xffff, 0x012e, 0x2069, 0x9200, 0x6844, 0x6964, + 0xa102, 0x2069, 0x946e, 0x688a, 0x6984, 0x701c, 0xa06d, 0x0120, + 0x81ff, 0x0904, 0x49d1, 0x00a0, 0x81ff, 0x0904, 0x4a6f, 0x2071, + 0x946e, 0x7184, 0x7088, 0xa10a, 0x1258, 0x7190, 0x2071, 0x94f8, + 0x7038, 0xa005, 0x0128, 0x1b04, 0x4a6f, 0x713a, 0x0804, 0x4a6f, + 0x2071, 0x946e, 0x718c, 0x0126, 0x2091, 0x8000, 0x7084, 0xa10a, + 0x0a04, 0x4a70, 0x0e04, 0x4a2d, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x4a2d, 0x2001, 0xffff, 0x2071, 0x94f8, 0x703a, 0x2071, + 0x946e, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x4b12, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x4a2d, 0x080c, + 0x4b3c, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, + 0x4a2d, 0x2071, 0x946e, 0x7000, 0xa005, 0x0904, 0x4a51, 0x6934, + 0xa186, 0x0103, 0x1904, 0x4a30, 0x6948, 0x6844, 0xa105, 0x1904, + 0x4a47, 0x2071, 0x946e, 0x7000, 0x0002, 0x4a51, 0x4a11, 0x49e9, + 0x49fb, 0x7084, 0x8008, 0xa092, 0x001e, 0x1a04, 0x4a6f, 0xae90, + 0x0003, 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0x9328, 0x080c, + 0x4b95, 0x0804, 0x4a6f, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, + 0x4a6f, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, + 0x6840, 0x2012, 0x7186, 0x2071, 0x9328, 0x080c, 0x4b95, 0x0804, + 0x4a6f, 0x2009, 0x8020, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4a2d, + 0x2071, 0x0000, 0x7018, 0xd084, 0x1180, 0x7122, 0x683c, 0x7026, + 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x012e, 0x2071, + 0x9328, 0x080c, 0x4b95, 0x0804, 0x4a6f, 0x012e, 0x0804, 0x4a6f, + 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, + 0xa18e, 0x001f, 0x11b0, 0x684c, 0xd0cc, 0x0198, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x1168, 0x2009, 0x8021, 0x0860, 0x6844, + 0xa086, 0x0100, 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, + 0x0810, 0x2071, 0x9328, 0x080c, 0x4ba7, 0x01c8, 0x2071, 0x9328, + 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x1130, + 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x7007, 0x0003, + 0x080c, 0x4bc0, 0x7050, 0xa086, 0x0100, 0x0904, 0x4afe, 0x0005, + 0x2071, 0x9328, 0x080c, 0x4ba7, 0x0518, 0x2071, 0x946e, 0x7084, + 0x700a, 0x20a9, 0x0020, 0x2099, 0x946f, 0x20a1, 0x9496, 0x53a3, + 0x7087, 0x0000, 0x2071, 0x9328, 0x2069, 0x94b6, 0x706c, 0x6826, + 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x080c, + 0x14c7, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0x94f8, 0x703a, + 0x012e, 0x08a8, 0x2069, 0x94b6, 0x6808, 0xa08e, 0x0000, 0x0904, + 0x4aed, 0xa08e, 0x0200, 0x0904, 0x4aeb, 0xa08e, 0x0100, 0x1904, + 0x4aed, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4ae9, 0x2069, 0x0000, + 0x6818, 0xd084, 0x15b0, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, + 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, + 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, + 0x6936, 0x2001, 0x9493, 0x2004, 0xa005, 0x1190, 0x6934, 0x2069, + 0x946e, 0x689c, 0x699e, 0x2069, 0x94f8, 0xa102, 0x1118, 0x683c, + 0xa005, 0x1368, 0x2001, 0x9494, 0x200c, 0x810d, 0x693e, 0x0038, + 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x7007, + 0x0001, 0x012e, 0x0010, 0x7007, 0x0005, 0x0005, 0x701c, 0xa06d, + 0x0158, 0x080c, 0x4ba7, 0x0140, 0x7007, 0x0003, 0x080c, 0x4bc0, + 0x7050, 0xa086, 0x0100, 0x0110, 0x0005, 0x0005, 0x7050, 0xa09e, + 0x0100, 0x1118, 0x7007, 0x0004, 0x0030, 0xa086, 0x0200, 0x1110, + 0x7007, 0x0005, 0x0005, 0x080c, 0x4b61, 0x7006, 0x080c, 0x4b95, + 0x0005, 0x0005, 0x00e6, 0x0156, 0x2071, 0x946e, 0x7184, 0x81ff, + 0x0500, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, + 0x2014, 0x7226, 0x8000, 0x0f04, 0x4b36, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x4b36, 0x2014, 0x722e, 0x8000, 0x0f04, 0x4b36, 0x2014, + 0x723a, 0x8000, 0x0f04, 0x4b36, 0x2014, 0x723e, 0xa180, 0x8030, + 0x7022, 0x015e, 0x00ee, 0x0005, 0x00e6, 0x0156, 0x2071, 0x946e, + 0x7184, 0x81ff, 0x01d8, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, + 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x4b58, 0x2014, 0x723a, 0x8000, 0x2014, 0x723e, 0x0018, + 0x2001, 0x8020, 0x0010, 0xa180, 0x8042, 0x7022, 0x015e, 0x00ee, + 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, + 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e, + 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, + 0x700e, 0x11a0, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4b91, 0x2001, + 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x012e, 0x0005, + 0x2001, 0x000d, 0x2102, 0x2001, 0x0001, 0x0005, 0x2001, 0x0007, + 0x0005, 0x2001, 0x0006, 0x012e, 0x0005, 0x701c, 0xa06d, 0x0170, + 0x0126, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, + 0xa005, 0x1108, 0x701a, 0x012e, 0x080c, 0x1493, 0x0005, 0x2019, + 0x000d, 0x2304, 0x230c, 0xa10e, 0x0130, 0x2304, 0x230c, 0xa10e, + 0x0110, 0xa006, 0x0060, 0x732c, 0x8319, 0x7130, 0xa102, 0x1118, + 0x2300, 0xa005, 0x0020, 0x0210, 0xa302, 0x0008, 0x8002, 0x0005, + 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x0126, + 0x2091, 0x8000, 0x2009, 0x9508, 0x2104, 0xc08d, 0x200a, 0x012e, + 0x080c, 0x14df, 0x0005, 0x7088, 0xa08a, 0x0027, 0x1220, 0xa082, + 0x001d, 0x0033, 0x0010, 0x080c, 0x13fe, 0x6027, 0x1e00, 0x0005, + 0x4c57, 0x4be9, 0x4bff, 0x4c27, 0x4c4a, 0x4c7c, 0x4c8e, 0x4bff, + 0x4c68, 0x6803, 0x0010, 0x6124, 0xd1e4, 0x1180, 0x080c, 0x4cd7, + 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140, 0x708b, 0x0020, + 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, + 0x0008, 0x6124, 0xd1cc, 0x11e8, 0xd1dc, 0x11c0, 0xd1e4, 0x1198, + 0xa184, 0x1e00, 0x11d8, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x4df5, 0x6803, 0x0000, 0x708b, 0x0026, 0x2001, 0x9225, + 0x2003, 0x0000, 0x0058, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, + 0x0028, 0x708b, 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x60e3, + 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x4df5, 0x6803, 0x0000, + 0x6124, 0xd1d4, 0x11a0, 0xd1dc, 0x1178, 0xd1e4, 0x1150, 0xa184, + 0x1e00, 0x1178, 0x708b, 0x0026, 0x2001, 0x9225, 0x2003, 0x0000, + 0x0040, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, + 0x001f, 0x0005, 0x6803, 0x0020, 0x6124, 0xd1dc, 0x1128, 0xd1e4, + 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001d, 0x0005, 0x080c, + 0x4d03, 0x6124, 0xd1dc, 0x1158, 0x080c, 0x4cd7, 0xd1d4, 0x1128, + 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001f, 0x0005, + 0x6803, 0x0020, 0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, + 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, + 0x0010, 0x708b, 0x0021, 0x0005, 0x080c, 0x4d03, 0x6124, 0xd1d4, + 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, + 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x0010, + 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, + 0x0158, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, + 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x00c6, 0x00d6, 0x00e6, + 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x9200, 0x2091, + 0x8000, 0x080c, 0x4de1, 0x0150, 0x080c, 0x4dd7, 0x1138, 0x2001, + 0x0001, 0x080c, 0x23ba, 0x080c, 0x4d9a, 0x00a0, 0x080c, 0x4d00, + 0x0178, 0x2001, 0x0001, 0x080c, 0x23ba, 0x7088, 0xa086, 0x001e, + 0x0120, 0x7088, 0xa086, 0x0022, 0x1118, 0x708b, 0x0025, 0x0010, + 0x708b, 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0016, + 0x0026, 0x2009, 0x0064, 0x2011, 0x4ce2, 0x080c, 0x57b3, 0x002e, + 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, 0x6f1e, 0x2071, + 0x9200, 0x080c, 0x4ca5, 0x001e, 0x00fe, 0x00ee, 0x0005, 0x0026, + 0x00e6, 0x2011, 0x4ce2, 0x2071, 0x94f8, 0x701c, 0xa206, 0x1118, + 0x7018, 0xa005, 0x0110, 0xa085, 0x0001, 0x00ee, 0x002e, 0x0005, + 0x6020, 0xd09c, 0x0005, 0x6803, 0x0040, 0x0156, 0x20a9, 0x002d, + 0x1d04, 0x4d08, 0x2091, 0x6000, 0x1f04, 0x4d08, 0x015e, 0x0005, + 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, + 0x9200, 0x2001, 0x94d8, 0x200c, 0xa186, 0x0000, 0x0158, 0xa186, + 0x0001, 0x0158, 0xa186, 0x0002, 0x0158, 0xa186, 0x0003, 0x0158, + 0x0804, 0x4d88, 0x708b, 0x0022, 0x0048, 0x708b, 0x0021, 0x0030, + 0x708b, 0x0023, 0x0038, 0x708b, 0x0024, 0x0020, 0xa085, 0x0001, + 0x080c, 0x4e05, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, + 0x080c, 0x2460, 0x0026, 0x2011, 0x0003, 0x080c, 0x718f, 0x002e, + 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b, + 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024, + 0xd0ac, 0x0118, 0x012e, 0x015e, 0x04c8, 0x6803, 0x0080, 0x6803, + 0x0000, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100, 0x1f04, 0x4d57, + 0x080c, 0x4e12, 0x012e, 0x015e, 0x080c, 0x4dd7, 0x01a8, 0x6044, + 0xa005, 0x0168, 0x6050, 0x0006, 0xa085, 0x0020, 0x6052, 0x080c, + 0x4e12, 0xa006, 0x8001, 0x1df0, 0x000e, 0x6052, 0x0028, 0x6804, + 0xd0d4, 0x1110, 0x080c, 0x4e12, 0x2001, 0x94d8, 0x2003, 0x0004, + 0x080c, 0x4bd3, 0x080c, 0x4dd7, 0x0148, 0x6804, 0xd0d4, 0x1130, + 0xd0dc, 0x1100, 0x2001, 0x94d8, 0x2003, 0x0000, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0x9200, 0x2001, 0x94d7, 0x2003, 0x0000, 0x2001, + 0x94c8, 0x2003, 0x0000, 0x708b, 0x0000, 0x60e3, 0x0000, 0x6887, + 0x0000, 0x2001, 0x0000, 0x080c, 0x2460, 0x6803, 0x0000, 0x6043, + 0x0090, 0x6027, 0xffff, 0x602b, 0x002f, 0x2001, 0x9225, 0x2003, + 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0x94d7, + 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x2001, 0x9271, + 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e, 0x0005, 0x0006, + 0x2001, 0x9271, 0x2004, 0xa084, 0x0030, 0xa086, 0x0030, 0x000e, + 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xa084, 0x0030, 0xa086, + 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xa084, + 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001, 0x920c, 0x2004, + 0xd0a4, 0x0150, 0x080c, 0x2480, 0x0036, 0x2019, 0x0028, 0x080c, + 0x264b, 0x003e, 0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0x920c, + 0x2e04, 0x0118, 0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, + 0x00ee, 0x0005, 0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, + 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, + 0x602f, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x000e, 0x602a, + 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, + 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2460, + 0x6803, 0x0080, 0x6803, 0x0000, 0x6803, 0x0020, 0x000e, 0x6052, + 0x6050, 0x0005, 0x2071, 0x92f6, 0x7003, 0x0000, 0x7007, 0x0000, + 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, + 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, + 0x708f, 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0x92f6, + 0x6848, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, + 0x0428, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, + 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, + 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, + 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, + 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005, + 0x2b78, 0x2071, 0x92f6, 0x7004, 0x0043, 0x700c, 0x0002, 0x4e9c, + 0x4e93, 0x4e93, 0x4e93, 0x4e93, 0x0005, 0x4ef2, 0x4ef3, 0x4f25, + 0x4f26, 0x4ef0, 0x4f5a, 0x4f5f, 0x4f90, 0x4f91, 0x4fac, 0x4fad, + 0x4fae, 0x4faf, 0x4fb0, 0x4fb1, 0x502d, 0x5054, 0x700c, 0x0002, + 0x4eb5, 0x4ef0, 0x4ef0, 0x4ef1, 0x4ef1, 0x7830, 0x7930, 0xa106, + 0x0120, 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8, + 0x1210, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x145f, + 0x01b0, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, + 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0x9508, 0x2104, + 0xc085, 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x14df, 0x0005, + 0x080c, 0x145f, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x145f, 0x1108, + 0x0c10, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8, + 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, 0x4efa, 0x4efd, 0x4f0b, + 0x4f24, 0x4f24, 0x080c, 0x4eae, 0x0005, 0x0126, 0x8001, 0x700e, + 0x7058, 0x0006, 0x080c, 0x5311, 0x0120, 0x2091, 0x8000, 0x080c, + 0x4eae, 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x5311, + 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, + 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, 0x1218, 0x00db, 0x012e, + 0x0005, 0x012e, 0x080c, 0x4fb2, 0x0005, 0x0005, 0x0005, 0x00e6, + 0x2071, 0x92f6, 0x700c, 0x0002, 0x4f31, 0x4f31, 0x4f31, 0x4f33, + 0x4f36, 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002, + 0x00ee, 0x0005, 0x4fb2, 0x4fb2, 0x4fce, 0x4fb2, 0x50e0, 0x4fb2, + 0x4fb2, 0x4fb2, 0x4fb2, 0x4fb2, 0x4fce, 0x5119, 0x515c, 0x51a5, + 0x51b9, 0x4fb2, 0x4fb2, 0x4fea, 0x4fce, 0x4ffe, 0x4fb2, 0x5013, + 0x5243, 0x525e, 0x4fb2, 0x4fea, 0x4fb2, 0x4ffe, 0x4fb2, 0x4fb2, + 0x5013, 0x525e, 0x7020, 0x2068, 0x080c, 0x1493, 0x0005, 0x700c, + 0x0002, 0x4f66, 0x4f69, 0x4f77, 0x4f8f, 0x4f8f, 0x080c, 0x4eae, + 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006, 0x080c, 0x5311, + 0x0120, 0x2091, 0x8000, 0x080c, 0x4eae, 0x00de, 0x0048, 0x0126, + 0x8001, 0x700e, 0x080c, 0x5311, 0x7058, 0x2068, 0x7084, 0x705a, + 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, + 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e, 0x0419, 0x0005, + 0x0005, 0x0005, 0x4fb2, 0x4fce, 0x50cc, 0x4fb2, 0x4fce, 0x4fb2, + 0x4fce, 0x4fce, 0x4fb2, 0x4fce, 0x50cc, 0x4fce, 0x4fce, 0x4fce, + 0x4fce, 0x4fce, 0x4fb2, 0x4fce, 0x50cc, 0x4fb2, 0x4fb2, 0x4fce, + 0x4fb2, 0x4fb2, 0x4fb2, 0x4fce, 0x0005, 0x0005, 0x0005, 0x0005, + 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, + 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, 0x7007, 0x0001, + 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126, 0x2091, 0x8000, + 0x080c, 0x4809, 0x012e, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x4809, + 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0988, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0804, 0x508d, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x508d, 0x0005, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x0904, 0x4fc0, 0x8001, 0x1120, 0x7007, 0x0001, + 0x0804, 0x50ac, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, + 0x704b, 0x50ac, 0x0005, 0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, + 0xa080, 0x0024, 0x2098, 0x20a1, 0x9321, 0x53a3, 0x6858, 0x7012, + 0xa082, 0x0401, 0x1a04, 0x4fdc, 0x6884, 0xa08a, 0x0003, 0x1a04, + 0x4fdc, 0xa080, 0x507e, 0x2005, 0x70c6, 0x7010, 0xa015, 0x0904, + 0x5072, 0x080c, 0x145f, 0x1118, 0x7007, 0x000f, 0x0005, 0x2d00, + 0x7022, 0x70c4, 0x2060, 0x2c05, 0x6836, 0xe004, 0xad00, 0x7096, + 0xe008, 0xa20a, 0x1210, 0xa00e, 0x2200, 0x7112, 0xe20c, 0x8003, + 0x800b, 0xa296, 0x0004, 0x0108, 0xa108, 0x719a, 0x810b, 0x719e, + 0xae90, 0x0022, 0x080c, 0x14c7, 0x7090, 0xa08e, 0x0100, 0x0170, + 0xa086, 0x0200, 0x0118, 0x7007, 0x0010, 0x0005, 0x7020, 0x2068, + 0x080c, 0x1493, 0x7014, 0x2068, 0x0804, 0x4fdc, 0x7020, 0x2068, + 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, + 0x0804, 0x502d, 0x7014, 0x2068, 0x7007, 0x0001, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x0904, 0x5276, 0x0078, 0x5081, 0x5085, + 0x5089, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, + 0x0006, 0x0012, 0x000f, 0x0005, 0x0006, 0x2009, 0x922f, 0x210c, + 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a, 0x6853, 0x0000, + 0x080c, 0x423e, 0x1108, 0x0005, 0x080c, 0x492c, 0x0126, 0x2091, + 0x8000, 0x080c, 0x8527, 0x080c, 0x4809, 0x012e, 0x0ca0, 0x2001, + 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0x922f, 0x210c, 0x81ff, + 0x11a8, 0x6858, 0xa005, 0x01a8, 0x6838, 0xa084, 0x00ff, 0x683a, + 0x6853, 0x0000, 0x080c, 0x42db, 0x1108, 0x0005, 0x684a, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0cb8, 0x2001, 0x0028, + 0x0ca8, 0x2001, 0x0000, 0x0c90, 0x7018, 0x6802, 0x2d08, 0x2068, + 0x6906, 0x711a, 0x7010, 0x8001, 0x7012, 0x0118, 0x7007, 0x0006, + 0x0030, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x080f, 0x0005, + 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, + 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x01b0, 0x2009, 0x0000, + 0x20a9, 0x007e, 0xa096, 0x0002, 0x0178, 0xa005, 0x11f8, 0x6944, + 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4434, 0x11c0, 0x0066, 0x6e50, + 0x080c, 0x450d, 0x006e, 0x0090, 0x0046, 0x2011, 0x920c, 0x2224, + 0xc484, 0xc48c, 0x2412, 0x004e, 0x00c6, 0x080c, 0x4434, 0x1110, + 0x080c, 0x4664, 0x8108, 0x1f04, 0x510d, 0x00ce, 0x080c, 0x1493, + 0x0005, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x9252, + 0x2004, 0xd0a4, 0x0580, 0x2061, 0x9566, 0x6100, 0xd184, 0x0178, + 0x6858, 0xa084, 0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, + 0xa005, 0x1538, 0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, + 0x0001, 0x6860, 0xa005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, + 0x6858, 0xa084, 0x00ff, 0x0178, 0x6006, 0x6858, 0x8007, 0xa084, + 0x00ff, 0x0148, 0x600a, 0x6858, 0x8000, 0x1108, 0xc28d, 0x6202, + 0x012e, 0x0804, 0x5300, 0x012e, 0x0804, 0x52fa, 0x012e, 0x0804, + 0x52f4, 0x012e, 0x0804, 0x52f7, 0x0126, 0x2091, 0x8000, 0x7007, + 0x0001, 0x2001, 0x9252, 0x2004, 0xd0a4, 0x05e0, 0x2061, 0x9566, + 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c48, + 0xa484, 0x0003, 0x0170, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x1120, + 0x2100, 0xa210, 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0xa212, + 0x02f0, 0xa484, 0x000c, 0x0188, 0x6958, 0x810f, 0xa18c, 0x00ff, + 0xa082, 0x0004, 0x1120, 0x2100, 0xa318, 0x0288, 0x0030, 0xa082, + 0x0004, 0x1168, 0x2100, 0xa31a, 0x0250, 0x6860, 0xa005, 0x0110, + 0x8000, 0x6016, 0x6206, 0x630a, 0x012e, 0x0804, 0x5300, 0x012e, + 0x0804, 0x52fd, 0x012e, 0x0804, 0x52fa, 0x0126, 0x2091, 0x8000, + 0x7007, 0x0001, 0x2061, 0x9566, 0x6300, 0xd38c, 0x1120, 0x6308, + 0x8318, 0x0220, 0x630a, 0x012e, 0x0804, 0x530e, 0x012e, 0x0804, + 0x52fd, 0x0126, 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, + 0xd0ac, 0x0148, 0x00c6, 0x2061, 0x9566, 0x6000, 0xa084, 0xfcff, + 0x6002, 0x00ce, 0x04d8, 0x6858, 0xa005, 0x0904, 0x521a, 0x685c, + 0xa065, 0x0904, 0x5216, 0x2001, 0x922f, 0x2004, 0xa005, 0x0118, + 0x080c, 0x849b, 0x0030, 0x6013, 0x0400, 0x2009, 0x0041, 0x080c, + 0x7518, 0x6958, 0xa18c, 0xf600, 0xa186, 0x2000, 0x01b8, 0xa186, + 0x0400, 0x01a0, 0xa186, 0x1000, 0x0140, 0xa186, 0x4000, 0x01b0, + 0x6118, 0x2104, 0xc0fc, 0x200a, 0x0088, 0x00c6, 0x2061, 0x9566, + 0x6000, 0xa084, 0xfdff, 0x6002, 0x00ce, 0x0040, 0x0026, 0x2009, + 0x0000, 0x2011, 0xfdff, 0x080c, 0x585b, 0x002e, 0x684c, 0xd0c4, + 0x0148, 0x2061, 0x9566, 0x6000, 0xd08c, 0x1120, 0x6008, 0x8000, + 0x0208, 0x600a, 0x00ce, 0x012e, 0x0804, 0x5300, 0x00ce, 0x012e, + 0x0804, 0x52fa, 0x6954, 0xa186, 0x002e, 0x0d40, 0xa186, 0x002d, + 0x0d28, 0xa186, 0x002a, 0x1130, 0x2001, 0x920c, 0x200c, 0xc194, + 0x2102, 0x08e0, 0xa186, 0x0020, 0x0170, 0xa186, 0x0029, 0x1d30, + 0x6944, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4434, 0x1978, 0x6000, + 0xc0e4, 0x6002, 0x0858, 0x685c, 0xa065, 0x09c0, 0x2001, 0x94dd, + 0x2004, 0x6016, 0x0818, 0x2061, 0x9566, 0x6000, 0xd084, 0x0190, + 0xd08c, 0x1904, 0x530e, 0x0126, 0x2091, 0x8000, 0x6204, 0x8210, + 0x0220, 0x6206, 0x012e, 0x0804, 0x530e, 0x012e, 0x6853, 0x0016, + 0x0804, 0x5307, 0x6853, 0x0007, 0x0804, 0x5307, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x1118, 0x080c, 0x4fc0, 0x0078, 0x2030, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x5276, 0x0005, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2009, 0x922f, 0x210c, 0x81ff, 0x1904, 0x52e9, + 0x2009, 0x920c, 0x210c, 0xd194, 0x1904, 0x52f1, 0x6848, 0x2070, + 0xae82, 0x9900, 0x0a04, 0x52dd, 0x2001, 0x9216, 0x2004, 0xae02, + 0x1a04, 0x52dd, 0x2061, 0x9566, 0x6100, 0xa184, 0x0001, 0x0578, + 0xa184, 0x0100, 0x1904, 0x52e0, 0xa184, 0x0200, 0x1904, 0x52e3, + 0x601c, 0xa005, 0x1904, 0x52e6, 0x711c, 0xa186, 0x0006, 0x1520, + 0x7018, 0xa005, 0x05f0, 0x2004, 0xd0e4, 0x15f0, 0xd0fc, 0x1598, + 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x1138, + 0x7112, 0x2e60, 0x080c, 0x57ca, 0x012e, 0x00ee, 0x0005, 0x2068, + 0x6800, 0xa005, 0x1de0, 0x6902, 0x012e, 0x00ee, 0x0005, 0x012e, + 0x00ee, 0x6853, 0x0006, 0x04d8, 0x6944, 0xa18c, 0xff00, 0x810f, + 0x080c, 0x4434, 0x11c8, 0x6000, 0xd0e4, 0x11b0, 0x711c, 0xa186, + 0x0007, 0x1118, 0x6853, 0x0002, 0x0088, 0x6853, 0x0008, 0x0070, + 0x6853, 0x000e, 0x0058, 0x6853, 0x0017, 0x0040, 0x6853, 0x0035, + 0x0028, 0x6853, 0x0028, 0x0010, 0x6853, 0x0029, 0x012e, 0x00ee, + 0x00b0, 0x6853, 0x002a, 0x0cd0, 0x2009, 0x003e, 0x0058, 0x2009, + 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, + 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, 0x080c, 0x1493, + 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, + 0x7072, 0x7038, 0x7076, 0x0058, 0x7070, 0xa080, 0x0040, 0x7072, + 0x1230, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, + 0x7132, 0x0005, 0x00d6, 0x080c, 0x57c1, 0x00de, 0x0005, 0x00d6, + 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x00de, 0x0005, + 0x20e1, 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, + 0x0118, 0xa086, 0x1000, 0x1520, 0x20e1, 0x0004, 0x3d60, 0xd1bc, + 0x1170, 0x2100, 0xa084, 0xff00, 0xa086, 0x0500, 0x1140, 0x0026, + 0x2c10, 0x080c, 0x566e, 0x002e, 0x0198, 0x0070, 0x3e60, 0xac84, + 0x0003, 0x1170, 0xac82, 0x9900, 0x0258, 0x6858, 0xac02, 0x1240, + 0x2009, 0x0047, 0x080c, 0x7518, 0x7a1c, 0xd284, 0x1988, 0x0005, + 0xa016, 0x080c, 0x16c6, 0x0cc0, 0x0156, 0x0136, 0x0146, 0x20e1, + 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x1528, 0xa484, 0x7000, + 0xa086, 0x1000, 0x11a0, 0x04a1, 0x01f0, 0x20e1, 0x3000, 0x7828, + 0x7828, 0x080c, 0x53cc, 0x014e, 0x013e, 0x015e, 0x2009, 0x94ed, + 0x2104, 0xa005, 0x1108, 0x0005, 0x080c, 0x6462, 0x0ce0, 0xa484, + 0x7000, 0x1148, 0x00e9, 0x0190, 0x7000, 0xa084, 0xff00, 0xa086, + 0x8100, 0x0d18, 0x0058, 0xd5a4, 0x0140, 0x080c, 0x1c26, 0x20e1, + 0x9010, 0x2001, 0x0138, 0x2202, 0x0038, 0x0051, 0x080c, 0x9157, + 0x20e1, 0x3000, 0x7828, 0x7828, 0x014e, 0x013e, 0x015e, 0x08d8, + 0xa484, 0x01ff, 0x6882, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, + 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, + 0x0005, 0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, + 0x53a5, 0xa085, 0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, + 0xf000, 0x8007, 0xa196, 0x0000, 0x1118, 0x0804, 0x5571, 0x0005, + 0xa196, 0x2000, 0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, + 0x3a6a, 0x0ca8, 0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, + 0x55f9, 0x0c68, 0x00c6, 0x6a80, 0x82ff, 0x0904, 0x5506, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, + 0x1904, 0x5506, 0xa08e, 0x0023, 0x1558, 0x080c, 0x565c, 0x0904, + 0x5506, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, + 0xa005, 0x1904, 0x5506, 0x2009, 0x0015, 0x080c, 0x7518, 0x0804, + 0x5506, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, 0x7518, + 0x0804, 0x5506, 0xa08e, 0x0100, 0x1904, 0x5506, 0x7034, 0xa005, + 0x1904, 0x5506, 0x2009, 0x0016, 0x080c, 0x7518, 0x0804, 0x5506, + 0xa08e, 0x0022, 0x1904, 0x5506, 0x7030, 0xa08e, 0x0300, 0x1568, + 0x68c8, 0xd0a4, 0x0510, 0xc0b5, 0x68ca, 0x7100, 0xa18c, 0x00ff, + 0x696e, 0x7004, 0x6872, 0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, + 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x2435, 0x7932, + 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x240b, 0x694e, 0x703c, + 0x00e6, 0x2071, 0x0140, 0x7086, 0x00ee, 0x7034, 0xa005, 0x1904, + 0x5506, 0x2009, 0x0017, 0x0804, 0x54d9, 0xa08e, 0x0400, 0x1158, + 0x7034, 0xa005, 0x1904, 0x5506, 0x68c8, 0xc0a5, 0x68ca, 0x2009, + 0x0030, 0x0804, 0x54d9, 0xa08e, 0x0500, 0x1140, 0x7034, 0xa005, + 0x1904, 0x5506, 0x2009, 0x0018, 0x0804, 0x54d9, 0xa08e, 0x2010, + 0x1120, 0x2009, 0x0019, 0x0804, 0x54d9, 0xa08e, 0x2110, 0x1120, + 0x2009, 0x001a, 0x0804, 0x54d9, 0xa08e, 0x5200, 0x1140, 0x7034, + 0xa005, 0x1904, 0x5506, 0x2009, 0x001b, 0x0804, 0x54d9, 0xa08e, + 0x5000, 0x1140, 0x7034, 0xa005, 0x1904, 0x5506, 0x2009, 0x001c, + 0x0804, 0x54d9, 0xa08e, 0x1200, 0x1138, 0x7034, 0xa005, 0x1904, + 0x5506, 0x2009, 0x0024, 0x04a8, 0xa08c, 0xff00, 0xa18e, 0x2400, + 0x1118, 0x2009, 0x002d, 0x0468, 0xa08c, 0xff00, 0xa18e, 0x5300, + 0x1118, 0x2009, 0x002a, 0x0428, 0xa08e, 0x0f00, 0x1118, 0x2009, + 0x0020, 0x00f8, 0xa08e, 0x5300, 0x1108, 0x00c8, 0xa08e, 0x6104, + 0x11b0, 0x2011, 0x978d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, + 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x2124, 0x080c, + 0x3698, 0x8108, 0x1f04, 0x54ca, 0x2009, 0x0023, 0x0010, 0x2009, + 0x001d, 0x0016, 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, + 0x240b, 0x1530, 0x080c, 0x4400, 0x1518, 0x6612, 0x6516, 0x86ff, + 0x0180, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158, 0x686c, 0xa606, + 0x1140, 0x6870, 0xa506, 0xa084, 0xff00, 0x1118, 0x6000, 0xc0f5, + 0x6002, 0x00c6, 0x080c, 0x749c, 0x0168, 0x001e, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x7518, 0x00ce, 0x0005, + 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x00e6, 0x00d6, 0x2028, 0x2130, + 0xa696, 0x00ff, 0x1518, 0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, + 0x0804, 0x556d, 0xa596, 0xfffe, 0x1120, 0x2009, 0x007e, 0x0804, + 0x556d, 0xa596, 0xfffc, 0x1120, 0x2009, 0x0080, 0x0804, 0x556d, + 0xa594, 0xff00, 0xa296, 0xfc00, 0x1148, 0x2011, 0x0000, 0x2021, + 0x0081, 0x20a9, 0x007e, 0x2071, 0x93ef, 0x00a0, 0x2011, 0x0000, + 0x2019, 0x9232, 0x231c, 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, + 0x00ff, 0x2071, 0x936e, 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, + 0x2071, 0x93ef, 0x2e1c, 0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, + 0xc2fd, 0x0080, 0x2368, 0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, + 0x6b14, 0x1120, 0xa346, 0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, + 0x83ff, 0x0d58, 0x8420, 0x8e70, 0x1f04, 0x554a, 0x82ff, 0x1118, + 0xa085, 0x0001, 0x0018, 0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, + 0x0005, 0xa084, 0x0007, 0x000a, 0x0005, 0x557d, 0x557d, 0x557d, + 0x557d, 0x557d, 0x557e, 0x5593, 0x55e6, 0x0005, 0x7110, 0xd1bc, + 0x0188, 0x7120, 0x2160, 0xac8c, 0x0003, 0x1160, 0xac8a, 0x9900, + 0x0248, 0x6858, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, + 0x080c, 0x7518, 0x0005, 0x00c6, 0x7110, 0xd1bc, 0x1904, 0x55e4, + 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, 0x240b, 0x1904, + 0x55e4, 0x080c, 0x4434, 0x1904, 0x55e4, 0x6000, 0xd0ec, 0x15e0, + 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0160, 0x080c, + 0x4dc5, 0x11d0, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x11a0, + 0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0520, + 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6122, 0x2009, + 0x0044, 0x080c, 0x7518, 0x00c0, 0x00c6, 0x080c, 0x749c, 0x001e, + 0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, + 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, + 0x080c, 0x603e, 0x080c, 0x6462, 0x00ce, 0x0005, 0x7110, 0xd1bc, + 0x0178, 0x7020, 0x2060, 0xac84, 0x0003, 0x1150, 0xac82, 0x9900, + 0x0238, 0x6858, 0xac02, 0x1220, 0x2009, 0x0045, 0x080c, 0x7518, + 0x0005, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x1138, + 0xa084, 0x000f, 0xa08a, 0x0006, 0x1a0c, 0x13fe, 0x000b, 0x0005, + 0x560e, 0x560f, 0x560e, 0x560e, 0x5644, 0x5650, 0x0005, 0x7110, + 0xd1bc, 0x1588, 0x700c, 0x7108, 0x080c, 0x240b, 0x1560, 0x080c, + 0x4400, 0x1548, 0x6612, 0x6516, 0x6204, 0xa294, 0xff00, 0x8217, + 0xa286, 0x0004, 0x0118, 0xa286, 0x0006, 0x1178, 0x00c6, 0x080c, + 0x749c, 0x001e, 0x01c0, 0x611a, 0x601f, 0x0005, 0x7120, 0x610a, + 0x2009, 0x0088, 0x080c, 0x7518, 0x0070, 0x00c6, 0x080c, 0x749c, + 0x001e, 0x0148, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009, + 0x0001, 0x080c, 0x7518, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x00a1, + 0x0130, 0x7124, 0x610a, 0x2009, 0x0089, 0x080c, 0x7518, 0x0005, + 0x7110, 0xd1bc, 0x0140, 0x0041, 0x0130, 0x7124, 0x610a, 0x2009, + 0x008a, 0x080c, 0x7518, 0x0005, 0x7020, 0x2060, 0xac84, 0x0003, + 0x1158, 0xac82, 0x9900, 0x0240, 0x2001, 0x9216, 0x2004, 0xac02, + 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x00c6, 0x00d6, + 0x00e6, 0x20e1, 0x0000, 0x3d08, 0xa18c, 0x00ff, 0xa18e, 0x00ff, + 0x1150, 0x3e00, 0xa086, 0xffff, 0x1130, 0x2001, 0x94c6, 0x2064, + 0x2009, 0x00ff, 0x0060, 0x20e1, 0x0001, 0x3d08, 0x3e00, 0x0156, + 0x080c, 0x240b, 0x015e, 0x1578, 0x080c, 0x4434, 0x1560, 0x2138, + 0x873f, 0x2c00, 0x2070, 0x20e1, 0x0003, 0x3d18, 0x831f, 0xa39c, + 0x00ff, 0x0036, 0x0036, 0x003e, 0x003e, 0x20e1, 0x2000, 0x3d00, + 0xa084, 0x7000, 0xa086, 0x1000, 0x0120, 0x080c, 0x5cc0, 0x1198, + 0x0040, 0x080c, 0x749c, 0x0178, 0x2e00, 0x601a, 0x620a, 0x601f, + 0x0009, 0x2009, 0x0101, 0x080c, 0x7518, 0xa085, 0x0001, 0x00ee, + 0x00de, 0x00ce, 0x0005, 0xa006, 0x00ee, 0x00de, 0x00ce, 0x0005, + 0x2071, 0x94f8, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, + 0x7012, 0x7017, 0x9900, 0x7007, 0x0000, 0x7026, 0x702b, 0x6f2b, + 0x7032, 0x7037, 0x6f69, 0x703b, 0xffff, 0x703f, 0xffff, 0x0005, + 0x2071, 0x94f8, 0x1d04, 0x5720, 0x2091, 0x6000, 0x700c, 0x8001, + 0x700e, 0x1120, 0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, + 0x8000, 0x7024, 0xa00d, 0x0158, 0x7020, 0x8001, 0x7022, 0x1138, + 0x7023, 0x0009, 0x8109, 0x7126, 0x1110, 0x7028, 0x080f, 0x7030, + 0xa00d, 0x0158, 0x702c, 0x8001, 0x702e, 0x1138, 0x702f, 0x0009, + 0x8109, 0x7132, 0x1110, 0x7034, 0x080f, 0x7038, 0xa005, 0x0118, + 0x0310, 0x8001, 0x703a, 0x703c, 0xa005, 0x0118, 0x0310, 0x8001, + 0x703e, 0x7018, 0xa00d, 0x0158, 0x7008, 0x8001, 0x700a, 0x1138, + 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, 0x012e, + 0x7004, 0x0002, 0x5746, 0x5747, 0x575f, 0x00e6, 0x2071, 0x94f8, + 0x7018, 0xa005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee, + 0x0005, 0x00e6, 0x0006, 0x2071, 0x94f8, 0x701c, 0xa206, 0x1110, + 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x94f8, + 0x6088, 0xa102, 0x0208, 0x618a, 0x00ee, 0x0005, 0x0005, 0x7110, + 0x080c, 0x4434, 0x1158, 0x6088, 0x8001, 0x0240, 0x608a, 0x1130, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x8108, 0xa182, + 0x00ff, 0x0218, 0xa00e, 0x7007, 0x0002, 0x7112, 0x0005, 0x7014, + 0x2060, 0x0126, 0x2091, 0x8000, 0x6014, 0xa005, 0x0518, 0x8001, + 0x6016, 0x1500, 0x611c, 0xa186, 0x0003, 0x0130, 0xa186, 0x0006, + 0x0118, 0xa186, 0x0009, 0x11a0, 0x6010, 0x2068, 0x6854, 0xa08a, + 0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0210, + 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0010, + 0x080c, 0x8185, 0x012e, 0xac88, 0x000c, 0x7116, 0x2001, 0x9217, + 0x2004, 0xa102, 0x0220, 0x7017, 0x9900, 0x7007, 0x0000, 0x0005, + 0x00e6, 0x2071, 0x94f8, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, + 0x0005, 0x2001, 0x9501, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, + 0x94f8, 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0x9504, + 0x2013, 0x0000, 0x0005, 0x00e6, 0x2071, 0x94f8, 0x711a, 0x721e, + 0x700b, 0x0009, 0x00ee, 0x0005, 0x00c6, 0x2061, 0x9566, 0x00ce, + 0x0005, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x9566, + 0x2060, 0x0005, 0x6854, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, + 0xa005, 0x1150, 0x00c6, 0x2061, 0x9566, 0x6014, 0x00ce, 0xa005, + 0x1138, 0x2001, 0x001e, 0x0020, 0xa08e, 0xffff, 0x1108, 0xa006, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, 0x00c0, + 0xa18e, 0x00c0, 0x0588, 0xd0b4, 0x1138, 0xd0bc, 0x11f0, 0x2009, + 0x0006, 0x080c, 0x5838, 0x0005, 0xd0fc, 0x0140, 0xa084, 0x0003, + 0xa08e, 0x0003, 0x05b8, 0xa08e, 0x0000, 0x15a0, 0x2009, 0x9273, + 0x2104, 0xd084, 0x0128, 0x2009, 0x0042, 0x080c, 0x7518, 0x0005, + 0x2009, 0x0043, 0x080c, 0x7518, 0x0005, 0xd0fc, 0x0140, 0xa084, + 0x0003, 0xa08e, 0x0003, 0x01f0, 0xa08e, 0x0000, 0x11d8, 0x2009, + 0x0042, 0x080c, 0x7518, 0x0005, 0xd0fc, 0x0168, 0xa084, 0x0003, + 0xa08e, 0x0003, 0x0178, 0xa08e, 0x0002, 0x0138, 0x2009, 0x0041, + 0x080c, 0x7518, 0x0005, 0x0051, 0x0ce8, 0x2009, 0x0043, 0x080c, + 0x7518, 0x0cc0, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001, + 0x6010, 0xa0ec, 0xf000, 0x01f0, 0x2068, 0x6952, 0x6800, 0x6012, + 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, + 0x1158, 0x00c6, 0x2061, 0x9566, 0x6200, 0xd28c, 0x1120, 0x6204, + 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x4809, 0x6010, 0xa06d, + 0x190c, 0x57ca, 0x0005, 0x0156, 0x00c6, 0x2061, 0x9566, 0x6000, + 0x81ff, 0x0110, 0xa205, 0x0008, 0xa204, 0x6002, 0x00ce, 0x015e, + 0x0005, 0x6800, 0xd08c, 0x1138, 0x6808, 0xa005, 0x0120, 0x8001, + 0x680a, 0xa085, 0x0001, 0x0005, 0x2071, 0x9349, 0x7003, 0x0006, + 0x7007, 0x0000, 0x700f, 0x0000, 0x7013, 0x0001, 0x702f, 0x0006, + 0x7033, 0x0001, 0x7063, 0x0000, 0x0005, 0x00e6, 0x2071, 0x9349, + 0x6a2c, 0x721e, 0x6b30, 0x7322, 0x6834, 0x7026, 0x705a, 0x6838, + 0x702a, 0x705e, 0x6824, 0x7016, 0x683c, 0x701a, 0x2009, 0x0070, + 0x200a, 0xa005, 0x0150, 0x2009, 0x0000, 0xa188, 0x000c, 0x8001, + 0x1de0, 0x2100, 0xa210, 0x1208, 0x8318, 0x7252, 0x7356, 0x7010, + 0xc084, 0x7012, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, + 0x0005, 0x2b78, 0x2071, 0x9349, 0x7004, 0x004b, 0x700c, 0x0002, + 0x58bb, 0x58b4, 0x58b4, 0x0005, 0x58c5, 0x5913, 0x5914, 0x5915, + 0x5916, 0x5929, 0x592a, 0x700c, 0x0cba, 0x2f00, 0xa080, 0x0070, + 0x2004, 0x2f08, 0xa188, 0x0070, 0x210c, 0xa106, 0x0150, 0x2f00, + 0xa080, 0x0070, 0x2004, 0x2f08, 0xa188, 0x0070, 0x210c, 0xa106, + 0x15c8, 0x7018, 0xa10a, 0x05b0, 0x1210, 0x7114, 0xa10a, 0xa192, + 0x000a, 0x0210, 0x2009, 0x000a, 0x00d6, 0x0016, 0x2001, 0x9281, + 0xa080, 0x0011, 0x2014, 0x2001, 0x9363, 0xa080, 0x0005, 0x2004, + 0xa100, 0xa202, 0x001e, 0x00de, 0x02e8, 0x080c, 0x5976, 0x2200, + 0xa102, 0x0208, 0x2208, 0x713a, 0x080c, 0x5a67, 0x2100, 0x7042, + 0x2001, 0x0002, 0x7037, 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, + 0x2009, 0x9508, 0x2104, 0xc095, 0x200a, 0x000e, 0x700e, 0x012e, + 0x080c, 0x14df, 0x0005, 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, + 0x591b, 0x591e, 0x5928, 0x080c, 0x58c3, 0x0005, 0x0126, 0x8001, + 0x700e, 0x7138, 0x0041, 0x2091, 0x8000, 0x080c, 0x58c3, 0x012e, + 0x0005, 0x0005, 0x0005, 0x7018, 0xa100, 0x7214, 0xa21a, 0x1130, + 0x701c, 0x7052, 0x7020, 0x7056, 0xa006, 0x0068, 0x0006, 0x080c, + 0x5a67, 0x2100, 0x7250, 0xa210, 0x7252, 0x1220, 0x7054, 0xa081, + 0x0000, 0x7056, 0x000e, 0x2f08, 0xa188, 0x0070, 0x200a, 0x701a, + 0x0005, 0x00e6, 0x2071, 0x9349, 0x700c, 0x0002, 0x5951, 0x5951, + 0x5953, 0x00ee, 0x0005, 0x700f, 0x0001, 0x00ee, 0x0005, 0x00d6, + 0x00e6, 0x2071, 0x9363, 0xa006, 0x7006, 0x700e, 0x701a, 0x701e, + 0x7022, 0x702a, 0x7026, 0x080c, 0x5b1b, 0x0170, 0x080c, 0x5b4d, + 0x0158, 0x2d00, 0x7002, 0x700a, 0x701a, 0x7013, 0x0001, 0x701f, + 0x0007, 0x00ee, 0x00de, 0x0005, 0xa00e, 0x0cd8, 0x00e6, 0x00d6, + 0x00c6, 0x2071, 0x9363, 0x721c, 0x2100, 0xa202, 0x1618, 0x080c, + 0x5b4d, 0x090c, 0x13fe, 0x7018, 0xa005, 0x1160, 0x2d00, 0x7002, + 0x700a, 0x701a, 0xa006, 0x7006, 0x700e, 0x6806, 0x6802, 0x7012, + 0x701e, 0x0038, 0x2060, 0x6806, 0x2d00, 0x6002, 0x701a, 0x6803, + 0x0000, 0x7010, 0x8000, 0x7012, 0x701c, 0xa080, 0x0007, 0x701e, + 0x721c, 0x08d0, 0x721c, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x0156, + 0x0136, 0x0146, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x9363, + 0x7300, 0xa398, 0x0003, 0x7104, 0x080c, 0x5a67, 0x810c, 0x2100, + 0xa318, 0x8003, 0x2228, 0x2021, 0x0054, 0xa402, 0xa532, 0x0208, + 0x2028, 0x2500, 0x8004, 0x20a8, 0x23a0, 0xe000, 0xe000, 0xe000, + 0x53a5, 0x2508, 0x080c, 0x5a70, 0x2130, 0x7014, 0xa600, 0x7016, + 0x2600, 0x711c, 0xa102, 0x701e, 0x7004, 0xa600, 0x2008, 0xa082, + 0x0007, 0x1180, 0x7000, 0x2004, 0xa005, 0x1140, 0x2009, 0x0001, + 0x0026, 0x080c, 0x5976, 0x002e, 0x7000, 0x2004, 0x7002, 0x7007, + 0x0000, 0x0008, 0x7106, 0x2500, 0xa212, 0x1910, 0x012e, 0x00ee, + 0x014e, 0x013e, 0x015e, 0x0005, 0x0016, 0x0026, 0x00e6, 0x00d6, + 0x04e9, 0x15c8, 0x2170, 0x2805, 0xac68, 0x2900, 0x0002, 0x5a0f, + 0x5a0f, 0x5a13, 0x5a0f, 0x5a13, 0x5a0f, 0x5a0f, 0x5a0f, 0x5a0f, + 0x5a0f, 0x5a1c, 0x5a0f, 0x5a1c, 0x5a0f, 0x5a0f, 0x5a0f, 0x080c, + 0x13fe, 0xa005, 0x00d8, 0x7000, 0x6802, 0x7004, 0x6806, 0x7010, + 0x680a, 0x680f, 0x0000, 0x0060, 0x7010, 0x6812, 0x6817, 0x0000, + 0x7000, 0x6802, 0x7004, 0x6806, 0x7008, 0x680a, 0x700c, 0x680e, + 0x00de, 0x685c, 0x8000, 0x685e, 0x00d6, 0xa006, 0x00de, 0x00ee, + 0x002e, 0x001e, 0x0005, 0xa085, 0x0001, 0x0cc0, 0x00e6, 0x0036, + 0x2071, 0x9363, 0x7014, 0xa005, 0x0538, 0x8001, 0x7016, 0x7008, + 0xa080, 0x0003, 0x710c, 0x2110, 0x0411, 0x810c, 0xa118, 0x8210, + 0xa282, 0x0007, 0x11b0, 0x7008, 0x2004, 0xa005, 0x0178, 0x00d6, + 0x0006, 0x7008, 0x2068, 0x080c, 0x5b5c, 0x000e, 0x2068, 0x6807, + 0x0000, 0x700a, 0x00de, 0x7010, 0x8001, 0x7012, 0x700f, 0x0000, + 0x0008, 0x720e, 0x2308, 0xa006, 0x003e, 0x00ee, 0x0005, 0x0006, + 0x810b, 0x810b, 0x2100, 0x810b, 0xa100, 0x2008, 0x000e, 0x0005, + 0x0006, 0x0026, 0x2100, 0xa005, 0x0160, 0xa092, 0x000c, 0x0248, + 0x2009, 0x0000, 0x8108, 0xa082, 0x000c, 0x1de0, 0x002e, 0x000e, + 0x0005, 0x2009, 0x0000, 0x0cd0, 0x2d00, 0xa0b8, 0x0008, 0x690c, + 0x6810, 0x2019, 0x0001, 0x2031, 0x5ab2, 0xa112, 0x0220, 0x0118, + 0x8318, 0x2208, 0x0cd0, 0x6808, 0xa005, 0x0108, 0x8318, 0x233a, + 0x6804, 0xd084, 0x2300, 0x2021, 0x0001, 0x1150, 0xa082, 0x0003, + 0x0967, 0x0a67, 0x8420, 0xa082, 0x0007, 0x0967, 0x0a67, 0x0cd0, + 0xa082, 0x0002, 0x0967, 0x0a67, 0x8420, 0xa082, 0x0005, 0x0967, + 0x0a67, 0x0cd0, 0x6c1a, 0x2d00, 0xa0b8, 0x0007, 0x00e6, 0x2071, + 0x9200, 0x7128, 0x6810, 0x2019, 0x0001, 0xa10a, 0x0118, 0x0210, + 0x8318, 0x0cd8, 0x2031, 0x5ac5, 0x0870, 0x6c16, 0x00ee, 0x0005, + 0x00e6, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2e00, 0x2060, 0x2071, + 0x9363, 0x2009, 0x0001, 0x0026, 0x080c, 0x5976, 0x002e, 0x7300, + 0xa398, 0x0003, 0x7104, 0x080c, 0x5a67, 0x810c, 0x2100, 0xa318, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, 0x00d6, 0x2368, 0x1138, + 0x6000, 0x6802, 0x6004, 0x6806, 0x6008, 0x6812, 0x0050, 0x6000, + 0x6802, 0x6004, 0x6806, 0x6008, 0x680a, 0x600c, 0x680e, 0x6010, + 0x6812, 0x00de, 0x7014, 0x8000, 0x7016, 0x711c, 0x8109, 0x711e, + 0x7004, 0x8000, 0x2008, 0xa082, 0x0007, 0x1180, 0x7000, 0x2004, + 0xa005, 0x1140, 0x2009, 0x0001, 0x0026, 0x080c, 0x5976, 0x002e, + 0x7000, 0x2004, 0x7002, 0x7007, 0x0000, 0x0008, 0x7106, 0x012e, + 0x00ce, 0x00ee, 0x0005, 0x00d6, 0x0046, 0x0126, 0x2091, 0x8000, + 0x2001, 0x9281, 0xa080, 0x0011, 0x2004, 0x8003, 0x2020, 0x080c, + 0x145f, 0x01d0, 0x2d00, 0x7026, 0x6803, 0x0000, 0x6807, 0x0000, + 0x080c, 0x145f, 0x0188, 0x7024, 0x6802, 0x6807, 0x0000, 0x2d00, + 0x7026, 0xa4a2, 0x0007, 0x0110, 0x0208, 0x0c90, 0xa085, 0x0001, + 0x012e, 0x004e, 0x00de, 0x0005, 0x7024, 0xa005, 0x0dc8, 0x2068, + 0x2024, 0x080c, 0x1493, 0x2400, 0x0cc0, 0x0126, 0x2091, 0x8000, + 0x7024, 0x2068, 0xa005, 0x0130, 0x2004, 0x7026, 0x6803, 0x0000, + 0x6807, 0x0000, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7024, + 0x6802, 0x2d00, 0x7026, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0086, 0x0046, 0x0056, 0x0026, 0x2031, 0x0000, 0x2001, + 0x934a, 0x2004, 0xa005, 0x0904, 0x5bee, 0x2071, 0x9281, 0x20e1, + 0x0002, 0x3d08, 0xd19c, 0x0140, 0x2069, 0x9200, 0x6a28, 0x761c, + 0x7114, 0x2041, 0x0000, 0x0028, 0x7118, 0x720c, 0x7620, 0x7008, + 0x2040, 0x080c, 0x5d03, 0x0904, 0x5bee, 0x7004, 0xd084, 0x1128, + 0x2021, 0x0024, 0x2029, 0x0002, 0x0020, 0x2021, 0x002c, 0x2029, + 0x000a, 0x080c, 0x147c, 0x0904, 0x5bee, 0x2d00, 0x2060, 0x6436, + 0x0016, 0x20e1, 0x0001, 0x3d08, 0x3e00, 0xa18c, 0x00ff, 0x6142, + 0x603e, 0x001e, 0x6746, 0x2700, 0xa086, 0xff00, 0x1118, 0x6063, + 0x0000, 0x0010, 0x6063, 0x0003, 0xa006, 0x6002, 0x602a, 0x602e, + 0x6006, 0x603a, 0x604a, 0x6052, 0x6056, 0x605e, 0x6066, 0x604e, + 0x2800, 0x606a, 0x604c, 0xc0ad, 0x604e, 0x665a, 0x2c00, 0x2078, + 0x0479, 0x607f, 0xffff, 0x6083, 0x0000, 0x8109, 0x0180, 0x080c, + 0x147c, 0x01c0, 0x2d00, 0x7806, 0x2f00, 0x6802, 0x6d36, 0xa006, + 0x2d00, 0x2520, 0x00e9, 0x2d00, 0x2078, 0x8109, 0x1d80, 0x2c00, + 0xa005, 0x002e, 0x005e, 0x004e, 0x008e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x0005, 0x2c00, 0x2068, 0x080c, 0x14a3, 0x2600, 0x2071, + 0x9363, 0x7120, 0xa102, 0x0a0c, 0x13fe, 0x7022, 0xa006, 0x0c48, + 0x00d6, 0x00c6, 0x0136, 0x0146, 0x0156, 0x0016, 0x2068, 0x2400, + 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, 0x2005, 0xad60, 0x2c00, + 0x2d08, 0xa188, 0x0030, 0xa102, 0x20a8, 0x2c00, 0x20a0, 0x2001, + 0xffff, 0x40a4, 0x001e, 0x015e, 0x014e, 0x013e, 0x00ce, 0x00de, + 0x0005, 0x00c6, 0x00e6, 0x00f6, 0x6858, 0x2071, 0x9363, 0x7120, + 0xa102, 0x0a0c, 0x13fe, 0x7022, 0x6960, 0x694e, 0x697c, 0x2009, + 0xffff, 0x7818, 0xa102, 0xe000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x6852, 0x684b, + 0x0000, 0x6868, 0xa005, 0x0118, 0x6848, 0xc085, 0x684a, 0x2d00, + 0xa080, 0x0015, 0x2038, 0x2031, 0x0018, 0x6864, 0x2020, 0x683a, + 0x685c, 0xa08a, 0x00ff, 0x1a0c, 0x13fe, 0x2028, 0x2d00, 0x2060, + 0x2078, 0x6934, 0xa18c, 0x000f, 0xa188, 0x1f59, 0x2145, 0x685c, + 0x2050, 0xa005, 0x0530, 0x2805, 0xac70, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x0024, 0x1110, 0x7008, 0x0040, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x190c, 0x13fe, 0x7010, 0x0006, 0x2400, 0xa005, + 0x000e, 0x0168, 0x203a, 0x8738, 0x8631, 0x090c, 0x13fe, 0x8421, + 0x8529, 0x0138, 0x080c, 0x1f1b, 0x090c, 0x13fe, 0x08e0, 0x080c, + 0x5ac8, 0x6837, 0x0023, 0x00fe, 0x00ee, 0x00ce, 0x0005, 0x00e6, + 0x00c6, 0x00a6, 0x0086, 0x0056, 0x6858, 0x2071, 0x9363, 0x7120, + 0xa102, 0x0a0c, 0x13fe, 0x7022, 0x2d00, 0x2060, 0x6934, 0xa18c, + 0x000f, 0xa188, 0x1f59, 0x2145, 0x685c, 0x2050, 0xa005, 0x01d0, + 0x2028, 0x2805, 0xac70, 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, + 0x1110, 0x7008, 0x0008, 0x7010, 0x0006, 0xa086, 0xffff, 0x000e, + 0x0110, 0x080c, 0x5ac8, 0x8529, 0x0128, 0x080c, 0x1f1b, 0x090c, + 0x13fe, 0x0c38, 0x005e, 0x008e, 0x00ae, 0x00ce, 0x00ee, 0x0005, + 0x70ac, 0xa005, 0x0138, 0x2060, 0x6008, 0xa306, 0x0110, 0x600c, + 0x0cc0, 0x0005, 0xa085, 0x0001, 0x0ce0, 0x70ac, 0x600e, 0x2c00, + 0x70ae, 0x0005, 0x00f6, 0x00d6, 0x0036, 0x70ac, 0xa005, 0x090c, + 0x13fe, 0x2068, 0x2079, 0x0000, 0x2c08, 0xa11e, 0x1118, 0x680c, + 0x70ae, 0x0060, 0xa106, 0x0140, 0x2d00, 0x2078, 0x680c, 0xa005, + 0x090c, 0x13fe, 0x2068, 0x0cb0, 0x6b0c, 0x7b0e, 0x600f, 0x0000, + 0x003e, 0x00de, 0x00fe, 0x0005, 0x00e6, 0x080c, 0x5c87, 0x6018, + 0x2070, 0xa006, 0x70b2, 0x70b6, 0x080c, 0x14a3, 0x0899, 0x080c, + 0x74f2, 0x00ee, 0x0005, 0x00d6, 0x0026, 0x0016, 0x2061, 0x9363, + 0x6020, 0x6414, 0xa600, 0xa42a, 0x02c8, 0x6022, 0x2069, 0x9281, + 0x6828, 0x6114, 0xa102, 0x1260, 0x2011, 0x8025, 0x080c, 0x3698, + 0xa080, 0x0013, 0x2004, 0xa080, 0x0000, 0x200c, 0x8108, 0x2102, + 0xa085, 0x0001, 0x001e, 0x002e, 0x00de, 0x0005, 0x2069, 0x9281, + 0x6804, 0xd09c, 0x0120, 0x2011, 0x8026, 0x080c, 0x3698, 0x2001, + 0x9281, 0xa080, 0x0013, 0x2004, 0xa080, 0x0001, 0x200c, 0x8108, + 0x2102, 0xa006, 0x2031, 0x0000, 0x0c28, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x5d56, 0x5d56, + 0x5d56, 0x5d58, 0x5db1, 0x5d56, 0x5d56, 0x5d56, 0x5de6, 0x5d56, + 0x5e34, 0x5d56, 0x5d56, 0x5d56, 0x5d56, 0x5d56, 0x080c, 0x13fe, + 0xa182, 0x0100, 0x0002, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6c, 0x5d85, + 0x5d9d, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, + 0x5d6a, 0x5d6a, 0x080c, 0x13fe, 0x00d6, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x684b, 0x0000, 0x00d6, 0x6018, 0x2068, + 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x080c, 0x641b, 0x00f6, + 0x00d6, 0x6110, 0x2178, 0x080c, 0x82ee, 0x0140, 0x784b, 0x0006, + 0xa006, 0x70b2, 0x70b6, 0x2f68, 0x080c, 0x4809, 0x00de, 0x00fe, + 0x080c, 0x74f2, 0x080c, 0x651c, 0x0005, 0x080c, 0x641b, 0x080c, + 0x266c, 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0120, 0x684b, + 0x0029, 0x080c, 0x4809, 0x00de, 0x080c, 0x74f2, 0x080c, 0x651c, + 0x0005, 0xa182, 0x0100, 0x0002, 0x5dc3, 0x5dc5, 0x5dcd, 0x5dc3, + 0x5dc3, 0x5dc3, 0x5de1, 0x5dc3, 0x5dc3, 0x5dc3, 0x5dc3, 0x5dc3, + 0x5dc3, 0x5dc3, 0x5dc3, 0x080c, 0x13fe, 0x20e1, 0x0005, 0x3d18, + 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00d6, 0x00e6, 0x6110, + 0x2168, 0x080c, 0x5c19, 0x080c, 0x4809, 0x6018, 0x2070, 0xa006, + 0x70b2, 0x70b6, 0x080c, 0x5cd2, 0x00ee, 0x00de, 0x080c, 0x74f2, + 0x0005, 0x080c, 0x5cf4, 0x080c, 0x473b, 0x0005, 0xa182, 0x0100, + 0x0002, 0x5dfb, 0x5e16, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, + 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, + 0x5df9, 0x080c, 0x13fe, 0x00d6, 0x6003, 0x0003, 0x6106, 0x6010, + 0x2068, 0x687c, 0x680a, 0x6880, 0x680e, 0x6813, 0x0000, 0x6817, + 0x0000, 0x00de, 0x2c10, 0x080c, 0x1c88, 0x080c, 0x605b, 0x0126, + 0x2091, 0x8000, 0x080c, 0x651c, 0x012e, 0x0005, 0x6003, 0x0004, + 0x630a, 0x080c, 0x5b65, 0x0168, 0x6012, 0x600f, 0x0000, 0x080c, + 0x5ccd, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, + 0x0005, 0x2011, 0x0000, 0x080c, 0x16c6, 0x70b3, 0x0000, 0x70b7, + 0x0000, 0x080c, 0x74f2, 0x0005, 0x00d6, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x684b, 0x0000, 0x00d6, 0x6018, 0x2068, + 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x6000, 0xa08a, 0x0010, + 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x5e64, 0x5e64, 0x5e64, 0x5e66, + 0x5e7f, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, + 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x080c, 0x13fe, 0x080c, 0x7366, + 0x190c, 0x13fe, 0x6110, 0x2168, 0x684b, 0x0006, 0x00d6, 0x6018, + 0x2068, 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, + 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x0005, 0x0005, + 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x5e97, + 0x5e97, 0x5e97, 0x5e99, 0x5e9b, 0x5e97, 0x5e97, 0x5e97, 0x5e97, + 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x080c, + 0x13fe, 0x080c, 0x13fe, 0x00d6, 0x6010, 0x2068, 0x080c, 0x5cf4, + 0x00de, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x1208, 0xa200, 0x1f04, 0x5ea6, 0x8086, 0x818e, 0x0005, 0x0156, + 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, + 0x0228, 0xa11a, 0x1220, 0x1f04, 0x5eb6, 0x0028, 0xa11a, 0x2308, + 0x8210, 0x1f04, 0x5eb6, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, + 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, + 0x0126, 0x2091, 0x2400, 0x2079, 0x94e5, 0x012e, 0x00d6, 0x2069, + 0x94e5, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, + 0x206a, 0x00de, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, 0xa084, + 0x0007, 0x0002, 0x5ef4, 0x5f15, 0x5f68, 0x5efa, 0x5f15, 0x5ef4, + 0x5ef2, 0x5ef2, 0x080c, 0x13fe, 0x080c, 0x57a1, 0x080c, 0x6462, + 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, 0x2011, + 0x40af, 0x080c, 0x5731, 0x7828, 0xa092, 0x0002, 0x1228, 0x8000, + 0x782a, 0x080c, 0x40fc, 0x0c88, 0x080c, 0x40af, 0x7807, 0x0003, + 0x7827, 0x0000, 0x782b, 0x0000, 0x0c40, 0x080c, 0x57a1, 0x3c00, + 0x0006, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x000e, 0x20e0, + 0x82ff, 0x0178, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, + 0xa065, 0x090c, 0x13fe, 0x2009, 0x0013, 0x080c, 0x7518, 0x00ce, + 0x0005, 0x3900, 0xa082, 0x9606, 0x1210, 0x080c, 0x7432, 0x00c6, + 0x7824, 0xa065, 0x090c, 0x13fe, 0x7804, 0xa086, 0x0004, 0x0904, + 0x5fa8, 0x7828, 0xa092, 0x2710, 0x1230, 0x8000, 0x782a, 0x00ce, + 0x080c, 0x6f11, 0x0c20, 0x6104, 0xa186, 0x0003, 0x1188, 0x00e6, + 0x2071, 0x9200, 0x70d4, 0x00ee, 0xd08c, 0x0150, 0x00c6, 0x00e6, + 0x2061, 0x0100, 0x2071, 0x9200, 0x080c, 0x4105, 0x00ee, 0x00ce, + 0x080c, 0x91a0, 0x2009, 0x0014, 0x080c, 0x7518, 0x00ce, 0x0838, + 0x2001, 0x9501, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, + 0x0000, 0x7824, 0xa065, 0x090c, 0x13fe, 0x2009, 0x0013, 0x080c, + 0x7563, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082, 0x9606, + 0x1210, 0x080c, 0x7432, 0x7824, 0xa005, 0x090c, 0x13fe, 0x781c, + 0xa06d, 0x090c, 0x13fe, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, + 0x080c, 0x74f2, 0x693c, 0x81ff, 0x090c, 0x13fe, 0x8109, 0x693e, + 0x6854, 0xa015, 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, 0x7807, + 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, 0x080c, 0x6462, 0x0888, + 0x6104, 0xa186, 0x0002, 0x0128, 0xa186, 0x0004, 0x0110, 0x0804, + 0x5f41, 0x7808, 0xac06, 0x0904, 0x5f41, 0x080c, 0x6389, 0x080c, + 0x603e, 0x00ce, 0x080c, 0x6462, 0x0804, 0x5f2f, 0x00c6, 0x6027, + 0x0002, 0x62c8, 0x60c4, 0xa205, 0x11a0, 0x793c, 0xa1e5, 0x0000, + 0x0150, 0x2009, 0x0049, 0x601c, 0xa086, 0x0009, 0x1110, 0x2009, + 0x0103, 0x080c, 0x7518, 0x2011, 0x9504, 0x2013, 0x0000, 0x00ce, + 0x0005, 0x3908, 0xa192, 0x9606, 0x1210, 0x080c, 0x7432, 0x6017, + 0x0010, 0x793c, 0x81ff, 0x0d78, 0x793c, 0xa188, 0x0007, 0x210c, + 0xa18e, 0x0006, 0x1118, 0x6017, 0x0012, 0x0c48, 0x793c, 0xa188, + 0x0007, 0x210c, 0xa18e, 0x0009, 0x0db0, 0x6017, 0x0016, 0x08f8, + 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, + 0x2c08, 0x2061, 0x94e5, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, + 0x0148, 0xa080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, + 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0x94e5, + 0x6000, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, + 0x1110, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0804, 0x646f, + 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0158, 0x6056, 0x605b, 0x0000, + 0x0006, 0x2c00, 0x681a, 0x00de, 0x685a, 0x2069, 0x94e5, 0x0c18, + 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x94e5, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0148, 0xa080, + 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, + 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x94e5, 0x6034, 0xa005, 0x0130, 0xa080, 0x0003, 0x2102, 0x6136, + 0x00ce, 0x0005, 0x613a, 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, 0x2071, 0x94e5, + 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, 0x60cb, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x60c6, 0x88ff, + 0x0118, 0x6020, 0xa106, 0x15d0, 0x703c, 0xac06, 0x1120, 0x6003, + 0x000a, 0x630a, 0x0498, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, + 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, + 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x82ee, 0x0188, + 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x00ce, 0x0804, 0x607d, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x607d, 0x012e, 0x000e, 0x001e, 0x002e, 0x006e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, + 0x19e8, 0x080c, 0x9097, 0x0c28, 0x0006, 0x0066, 0x00c6, 0x00d6, + 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, 0x94e5, + 0x7838, 0xa065, 0x0510, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, + 0xac06, 0x1128, 0x6003, 0x000a, 0x630a, 0x2c30, 0x00a0, 0x080c, + 0x82ee, 0x0178, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x11b0, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x000e, 0x08e0, 0x7e3a, 0x7e36, 0x012e, + 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, 0xa086, + 0x0006, 0x0150, 0x601c, 0xa086, 0x0009, 0x1d10, 0x6b4a, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x0c38, 0x080c, 0x9097, 0x0c10, 0x0016, + 0x0026, 0x0086, 0x2041, 0x0000, 0x0099, 0x080c, 0x61d3, 0x008e, + 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, 0x2079, 0x94e5, 0x2091, + 0x8000, 0x080c, 0x625e, 0x080c, 0x62be, 0x012e, 0x00fe, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0x94e5, 0x7614, 0x2660, 0x2678, 0x8cff, + 0x0904, 0x61c3, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, + 0x61be, 0x88ff, 0x0120, 0x6020, 0xa106, 0x1904, 0x61be, 0x7024, + 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, + 0x57a1, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, 0x7027, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, + 0x04a8, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, + 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, + 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0178, + 0x601c, 0xa086, 0x0003, 0x1500, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, 0x848f, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x0804, 0x614f, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x614f, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19e0, + 0x080c, 0x9097, 0x0c20, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, + 0xa280, 0x936e, 0x2004, 0xa065, 0x0904, 0x625a, 0x00f6, 0x00e6, + 0x00d6, 0x0066, 0x2071, 0x94e5, 0x6654, 0x7018, 0xac06, 0x1108, + 0x761a, 0x701c, 0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, + 0x0008, 0x761e, 0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000, + 0x0110, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, + 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x43ba, 0x0904, 0x6256, 0x7624, + 0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x57a1, 0x080c, + 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, 0x7027, 0x0000, 0x0036, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, + 0x603e, 0x2660, 0x080c, 0x849b, 0x00ce, 0x0048, 0x00de, 0x00c6, + 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6203, 0x8dff, + 0x0148, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, + 0x080c, 0x4809, 0x080c, 0x7238, 0x0804, 0x6203, 0x006e, 0x00de, + 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005, 0x0006, 0x0066, + 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065, 0x0904, 0x62b0, + 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06, 0x1540, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x57a1, 0x080c, 0x6f1e, + 0x68c3, 0x0000, 0x080c, 0x7356, 0x7827, 0x0000, 0x0036, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, + 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00b0, 0x6010, + 0x2068, 0x080c, 0x82ee, 0x0168, 0x601c, 0xa086, 0x0003, 0x11b8, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x080c, 0x7238, 0x000e, 0x0804, 0x6265, + 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, + 0xa086, 0x0006, 0x1d28, 0x080c, 0x9097, 0x0c58, 0x0006, 0x0066, + 0x00c6, 0x00d6, 0x7818, 0xa065, 0x0904, 0x6324, 0x6054, 0x0006, + 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, + 0x080c, 0x43ba, 0x0904, 0x6321, 0x7e24, 0x86ff, 0x05e8, 0xa680, + 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x0548, 0x080c, 0x57a1, 0x080c, 0x6f1e, 0x68c3, 0x0000, + 0x080c, 0x7356, 0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, + 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, + 0x849b, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x0804, 0x62d0, 0x8dff, 0x0138, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x7238, 0x0804, + 0x62d0, 0x000e, 0x0804, 0x62c3, 0x781e, 0x781a, 0x00de, 0x00ce, + 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6, 0x0066, 0x6000, 0xd0dc, + 0x0188, 0x604c, 0xa06d, 0x0170, 0x6848, 0xa606, 0x1158, 0x2071, + 0x94e5, 0x7024, 0xa035, 0x0130, 0xa080, 0x0004, 0x2004, 0xad06, + 0x1108, 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, + 0x0100, 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x04a0, 0x080c, 0x6f1e, 0x78c3, 0x0000, 0x080c, + 0x7356, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0xa384, + 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, + 0x7824, 0xd084, 0x0110, 0x7827, 0x0001, 0x080c, 0x7356, 0x003e, + 0x080c, 0x43ba, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, + 0x2660, 0x080c, 0x74f2, 0x00ce, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, 0x7238, 0x00fe, + 0x0005, 0x00e6, 0x00c6, 0x2071, 0x94e5, 0x7004, 0xa084, 0x0007, + 0x0002, 0x639b, 0x639e, 0x63b4, 0x63cd, 0x6406, 0x639b, 0x6399, + 0x6399, 0x080c, 0x13fe, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0150, 0x7216, + 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, 0x080c, 0x43ba, + 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0120, 0x6054, + 0xa015, 0x0140, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, + 0x00ee, 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, 0xa065, 0x0598, + 0x700c, 0xac06, 0x1160, 0x080c, 0x7238, 0x600c, 0xa015, 0x0120, + 0x720e, 0x600f, 0x0000, 0x0428, 0x720e, 0x720a, 0x0410, 0x7014, + 0xac06, 0x1160, 0x080c, 0x7238, 0x600c, 0xa015, 0x0120, 0x7216, + 0x600f, 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098, 0x6018, 0x2060, + 0x080c, 0x43ba, 0x6000, 0xc0dc, 0x6002, 0x080c, 0x7238, 0x701c, + 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, 0x721e, 0x0010, 0x7218, + 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0140, 0x080c, 0x7238, 0x600c, 0xa015, 0x0150, 0x720e, 0x600f, + 0x0000, 0x080c, 0x7356, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, + 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, 0x94e5, 0x6830, 0xa084, + 0x0003, 0x0002, 0x6428, 0x642a, 0x644a, 0x6426, 0x080c, 0x13fe, + 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, 0x0001, 0x0198, 0x683c, + 0xa065, 0x0130, 0x600c, 0xa015, 0x0150, 0x6a3a, 0x600f, 0x0000, + 0x6833, 0x0000, 0x683f, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, + 0x6836, 0x0cb0, 0x6843, 0x0000, 0x6838, 0xa065, 0x0d88, 0x6003, + 0x0003, 0x0c70, 0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, + 0xa065, 0x0168, 0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f, 0x0000, + 0x683f, 0x0000, 0x0020, 0x683f, 0x0000, 0x683a, 0x6836, 0x00ce, + 0x00de, 0x0005, 0x00d6, 0x2001, 0x9295, 0x2004, 0xd084, 0x0110, + 0x00de, 0x0005, 0x2069, 0x94e5, 0x6804, 0xa084, 0x0007, 0x0002, + 0x647a, 0x650c, 0x650c, 0x650c, 0x650c, 0x650e, 0x6478, 0x6478, + 0x080c, 0x13fe, 0x6820, 0xa005, 0x1110, 0x00de, 0x0005, 0x00c6, + 0x680c, 0xa065, 0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, + 0x080c, 0x656d, 0x00ce, 0x00de, 0x0005, 0x6814, 0xa065, 0x0150, + 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x656d, 0x00ce, + 0x00de, 0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5, 0x0000, 0x0904, + 0x6508, 0x704c, 0xa00d, 0x0118, 0x7088, 0xa005, 0x01a0, 0x7054, + 0xa075, 0x0120, 0xa20e, 0x0904, 0x6508, 0x0028, 0x6818, 0xa20e, + 0x0904, 0x6508, 0x2070, 0x704c, 0xa00d, 0x0d88, 0x7088, 0xa005, + 0x1d70, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, 0x1e40, 0x080c, + 0x74c9, 0x0904, 0x6508, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, + 0xa180, 0x0015, 0x2004, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, + 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x00f6, 0x2c78, + 0x71a0, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1110, 0xd1bc, 0x0150, + 0x7100, 0xd1f4, 0x0120, 0x7114, 0xa18c, 0x00ff, 0x0040, 0x2009, + 0x0000, 0x0028, 0xa1e0, 0x2719, 0x2c0d, 0xa18c, 0x00ff, 0x2061, + 0x0100, 0x619a, 0x080c, 0x6a46, 0x7300, 0xc3dd, 0x7302, 0x6807, + 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, + 0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00ce, 0x00de, 0x0005, + 0x003e, 0x00ee, 0x00ce, 0x0cd0, 0x00de, 0x0005, 0x00c6, 0x680c, + 0xa065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, + 0x656d, 0x00ce, 0x00de, 0x0005, 0x00f6, 0x00d6, 0x2069, 0x94e5, + 0x6830, 0xa086, 0x0000, 0x1590, 0x6838, 0xa07d, 0x0578, 0x781c, + 0xa086, 0x0009, 0x1140, 0x7808, 0xd0fc, 0x0128, 0x2001, 0x94e6, + 0x2004, 0xa005, 0x1518, 0x2f00, 0x6833, 0x0001, 0x683e, 0x6847, + 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1d0f, + 0x11c0, 0x012e, 0xe000, 0xe000, 0xe000, 0x6a3c, 0x2278, 0x781c, + 0xa086, 0x0009, 0x1148, 0x7808, 0xd0fc, 0x0118, 0x080c, 0x6cf9, + 0x0028, 0x080c, 0x6d75, 0x0010, 0x080c, 0x6dec, 0x00de, 0x00fe, + 0x0005, 0x012e, 0xe000, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, + 0xa015, 0x0140, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, + 0x0000, 0x0c60, 0x683a, 0x6836, 0x0cc0, 0x601c, 0xa084, 0x000f, + 0x000b, 0x0005, 0x657b, 0x6580, 0x68f8, 0x6a03, 0x6580, 0x68f8, + 0x6a03, 0x657b, 0x6580, 0x080c, 0x6389, 0x080c, 0x6462, 0x0005, + 0x0156, 0x0136, 0x0146, 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x003e, + 0x1a0c, 0x13fe, 0x6118, 0x2178, 0x79a0, 0x2011, 0x9232, 0x2214, + 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, + 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, 0x2719, + 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0x0033, + 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x65f5, 0x662d, + 0x6647, 0x66fa, 0x6725, 0x672d, 0x674e, 0x675f, 0x6770, 0x6778, + 0x6789, 0x6778, 0x67ce, 0x675f, 0x67ef, 0x67f7, 0x6770, 0x67f7, + 0x6808, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, + 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x6fda, 0x6fef, 0x7012, + 0x7036, 0x674e, 0x65ec, 0x674e, 0x6778, 0x65ec, 0x6647, 0x66fa, + 0x65ec, 0x744f, 0x6778, 0x65ec, 0x746f, 0x6778, 0x65ec, 0x6770, + 0x65ee, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, + 0x65ec, 0x65ec, 0x65ec, 0x704b, 0x080c, 0x13fe, 0x2001, 0x9214, + 0x2004, 0x609a, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x00d6, 0x2069, 0x9251, + 0x6804, 0xd084, 0x0150, 0x6828, 0x20a3, 0x0000, 0x0016, 0x080c, + 0x241f, 0x21a2, 0x001e, 0x00de, 0x0028, 0x00de, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x9205, 0x53a6, 0x20a9, + 0x0004, 0x2099, 0x9201, 0x53a6, 0x20a3, 0x0000, 0x2001, 0x9214, + 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x001c, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x2001, 0x921b, 0x2004, + 0x20a2, 0x2001, 0x921c, 0x2004, 0x20a2, 0x20a9, 0x0004, 0x2099, + 0x9205, 0x53a6, 0x60c3, 0x0010, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x681d, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, + 0x007e, 0x1130, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0010, + 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x1904, 0x66bc, 0x2001, 0x9232, 0x2004, 0xd0a4, + 0x01c8, 0x2099, 0x94c7, 0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, + 0x3304, 0xa084, 0x2000, 0x20a2, 0x9398, 0x33a6, 0x9398, 0x20a3, + 0x0000, 0x9398, 0x2001, 0x2710, 0x20a2, 0x9398, 0x33a6, 0x9398, + 0x33a6, 0x00d0, 0x2099, 0x94c7, 0x33a6, 0x9398, 0x33a6, 0x9398, + 0x3304, 0x080c, 0x4dc5, 0x1118, 0xa084, 0x37ff, 0x0010, 0xa084, + 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x9205, + 0x53a6, 0x20a9, 0x0004, 0x2099, 0x9201, 0x53a6, 0x20a9, 0x0008, + 0x20a3, 0x0000, 0x1f04, 0x66a8, 0x20a9, 0x0008, 0x20a3, 0x0000, + 0x1f04, 0x66ae, 0x2099, 0x94cf, 0x33a6, 0x20a9, 0x0007, 0x20a3, + 0x0000, 0x1f04, 0x66b7, 0x0468, 0x2001, 0x9232, 0x2004, 0xd0a4, + 0x0140, 0x2001, 0x94c8, 0x2004, 0x60e3, 0x0000, 0x080c, 0x2460, + 0x60e2, 0x2099, 0x94c7, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, + 0x2099, 0x9205, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x9201, 0x53a6, + 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x66da, 0x20a9, 0x0008, + 0x20a3, 0x0000, 0x1f04, 0x66e0, 0x2099, 0x94cf, 0x20a9, 0x0008, + 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x66eb, 0x20a9, + 0x000a, 0x20a3, 0x0000, 0x1f04, 0x66f1, 0x60c3, 0x0074, 0x080c, + 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, 0x681d, 0x20a3, 0x2010, + 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0x9251, 0x7904, + 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, + 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x5000, 0x0804, 0x665a, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x0804, 0x665a, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x6f0b, + 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0210, + 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, 0x2068, 0x6894, 0xa086, + 0x0014, 0x1178, 0x6998, 0xa184, 0xc000, 0x1140, 0xd1ec, 0x0118, + 0x20a3, 0x2100, 0x0040, 0x20a3, 0x0100, 0x0028, 0x20a3, 0x0400, + 0x0010, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x00f6, 0x2079, 0x9251, 0x7904, 0x00fe, 0xd1ac, 0x1110, + 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0x2009, 0x9273, + 0x210c, 0xd184, 0x1110, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, + 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x00de, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x68a0, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x0804, 0x65fb, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x080c, 0x68a0, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, + 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, + 0x1198, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x2001, 0x94d7, 0x2004, 0xa005, 0x0118, 0x2011, + 0x921c, 0x2214, 0x22a2, 0x0498, 0xa286, 0x007f, 0x1130, 0x00d6, + 0x20a3, 0x22ff, 0x20a3, 0xfffd, 0x00c8, 0x2001, 0x9232, 0x2004, + 0xd0ac, 0x1110, 0xd2bc, 0x01c8, 0xa286, 0x0080, 0x00d6, 0x1128, + 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0048, 0xa2e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x2200, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x2200, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, + 0x0129, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, + 0x2011, 0xfffc, 0x22a2, 0x00d6, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x08e0, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x0005, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, + 0x02e0, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x2300, + 0x20a2, 0x6814, 0x20a2, 0x6810, 0xa005, 0x1140, 0x6814, 0xa005, + 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x2300, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, + 0x0198, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, + 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x13fe, 0xa08a, + 0x008c, 0x1a0c, 0x13fe, 0x6118, 0x2178, 0x79a0, 0x2011, 0x9232, + 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, + 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, + 0x2719, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, + 0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x692f, 0x6939, + 0x6954, 0x692d, 0x692d, 0x692d, 0x692f, 0x080c, 0x13fe, 0x0146, + 0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000, 0x080c, 0x6f0b, 0x014e, + 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6999, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, + 0x080c, 0x6f0b, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x69d1, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0004, 0x080c, 0x6f0b, 0x014e, 0x0005, 0x0026, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, + 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, + 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0050, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0804, + 0x6873, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, + 0x007e, 0x0288, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, + 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0050, 0x20a3, 0x8400, 0x6298, 0x22a2, 0x20a3, + 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x080c, 0x4dc5, 0x1118, + 0x20a3, 0x0099, 0x0010, 0x20a3, 0x00d1, 0x20a3, 0x0000, 0x0804, + 0x68e9, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, + 0x007e, 0x0288, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, + 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0050, 0x20a3, 0x8500, 0x6298, 0x22a2, 0x20a3, + 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0099, 0x20a3, + 0x0000, 0x0804, 0x68e9, 0x00c6, 0x00f6, 0x2c78, 0x7804, 0xa08a, + 0x0040, 0x0a0c, 0x13fe, 0xa08a, 0x0053, 0x1a0c, 0x13fe, 0x7918, + 0x2160, 0x61a0, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1110, 0xd1bc, + 0x0150, 0x6100, 0xd1f4, 0x0120, 0x6114, 0xa18c, 0x00ff, 0x0040, + 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2719, 0x2c0d, 0xa18c, 0x00ff, + 0x2061, 0x0100, 0x619a, 0xa082, 0x0040, 0x001b, 0x00fe, 0x00ce, + 0x0005, 0x6a46, 0x6b3a, 0x6ade, 0x6c75, 0x6a44, 0x6a44, 0x6a44, + 0x6a44, 0x6a44, 0x6a44, 0x6a44, 0x71f1, 0x7201, 0x7211, 0x7221, + 0x6a44, 0x6a44, 0x6a44, 0x71e0, 0x080c, 0x13fe, 0x00d6, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7910, 0x2168, 0x6948, + 0x7922, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, + 0x000f, 0x1118, 0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0018, 0xa084, 0x0006, 0x8004, 0x20a2, 0xd1ac, 0x0118, + 0x20a3, 0x0002, 0x0048, 0xd1b4, 0x0118, 0x20a3, 0x0001, 0x0020, + 0x20a3, 0x0000, 0x2230, 0x0010, 0x6a80, 0x6e7c, 0x20a9, 0x0008, + 0x0136, 0xad88, 0x0017, 0x2198, 0x20a1, 0x021b, 0x53a6, 0x013e, + 0x20a1, 0x020b, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, + 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0x9501, + 0x2003, 0x07d0, 0x2001, 0x9500, 0x2003, 0x0009, 0x080c, 0x165a, + 0x014e, 0x015e, 0x00de, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, + 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0x2019, 0x9232, 0x231c, + 0xd3ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0600, 0x6198, + 0x21a2, 0x20a3, 0x0000, 0x2009, 0x9214, 0x210c, 0x21a2, 0x20a3, + 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, + 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, 0x00d6, 0x0156, + 0x0136, 0x0146, 0x20a1, 0x020b, 0x00c1, 0x7810, 0x2068, 0x6860, + 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, 0x080c, 0x6f0b, + 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0x9232, + 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, + 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0500, + 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, + 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x6c38, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x1130, 0x7810, 0xa084, + 0x0700, 0x8007, 0x0043, 0x0010, 0xa006, 0x002b, 0x014e, 0x013e, + 0x015e, 0x00de, 0x0005, 0x6b65, 0x6bde, 0x6be1, 0x6c04, 0x6c11, + 0x6c23, 0x6c26, 0x6b63, 0x080c, 0x13fe, 0x0016, 0x0036, 0x694c, + 0xa18c, 0x0003, 0xa186, 0x0000, 0x1150, 0x6b78, 0x23a2, 0x6868, + 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, 0x6c08, 0xa186, + 0x0001, 0x1904, 0x6bd9, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, + 0x20a2, 0x22a2, 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, + 0x0018, 0xa384, 0x0300, 0x0904, 0x6bd8, 0xd3c4, 0x0110, 0x687c, + 0xa108, 0xd3cc, 0x0110, 0x6874, 0xa108, 0x0156, 0x20a9, 0x000d, + 0xad80, 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x1f04, 0x6b9a, + 0x015e, 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0588, 0x20a1, + 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, + 0x0028, 0x2004, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0700, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x000e, + 0x20a3, 0x0898, 0x20a2, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x61c2, 0x003e, 0x001e, 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0008, + 0x0428, 0x20a3, 0x0302, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, + 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, + 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, + 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, + 0x0032, 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0028, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x080c, 0x6f0b, + 0x0005, 0x20a3, 0x0100, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, + 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0008, 0x0c00, 0x0036, 0x7b10, + 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x1118, 0x22a2, + 0x003e, 0x08a0, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x003e, 0x0880, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, + 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0050, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0898, 0x20a3, 0x0000, 0x080c, + 0x6efa, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, + 0x0146, 0x0016, 0x0036, 0x7810, 0xa084, 0x0700, 0x8007, 0x003b, + 0x003e, 0x001e, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x6c8f, + 0x6c8f, 0x6c91, 0x6c8f, 0x6c8f, 0x6c8f, 0x6cb3, 0x6c8f, 0x080c, + 0x13fe, 0x7910, 0xa18c, 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, + 0x020b, 0x2009, 0x0003, 0x00f9, 0x00d6, 0x2069, 0x9251, 0x6804, + 0xd0bc, 0x0130, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0010, + 0x20a3, 0x3f00, 0x00de, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, + 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x2009, 0x0003, 0x0019, + 0x20a3, 0x7f00, 0x0c80, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, + 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, + 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, + 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0888, + 0xa18d, 0x0008, 0x21a2, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, 0x0046, 0x0036, + 0x2061, 0x0100, 0x2071, 0x9200, 0x2009, 0x9214, 0x210c, 0x7818, + 0x2068, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x0110, 0x736c, + 0x7470, 0x2500, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x0140, + 0x2001, 0x04ff, 0x6062, 0x6067, 0xffff, 0x636a, 0x646e, 0x0050, + 0x2001, 0x00ff, 0xa085, 0x0400, 0x6062, 0x6067, 0xffff, 0x606b, + 0x0000, 0x616e, 0x68b8, 0x6072, 0x6077, 0x0008, 0x688c, 0x8000, + 0xa084, 0x00ff, 0x688e, 0x8007, 0xa085, 0x0020, 0x607a, 0x68b4, + 0x607f, 0x0000, 0x2d00, 0x6082, 0x6087, 0xffff, 0x7810, 0x2070, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0x2001, 0x9232, 0x2004, 0xd09c, 0x0128, 0x609f, 0x0000, 0x2001, + 0x0012, 0x0048, 0x6028, 0xc0bd, 0x602a, 0x609f, 0x00ff, 0x6027, + 0xffff, 0x2001, 0x0032, 0x6016, 0x2009, 0x07d0, 0x080c, 0x57a6, + 0x2001, 0x9295, 0x200c, 0xc185, 0x2102, 0x003e, 0x004e, 0x005e, + 0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, + 0x0066, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x9200, + 0x2009, 0x9214, 0x210c, 0x7818, 0x2068, 0x68a0, 0x2028, 0x2031, + 0x9232, 0x2634, 0xd6ac, 0x1140, 0xd0bc, 0x1130, 0xa080, 0x2719, + 0x2015, 0xa294, 0x00ff, 0x0020, 0x6910, 0x6a14, 0x736c, 0x7470, + 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, + 0x0400, 0x6062, 0x6266, 0x636a, 0x646e, 0x0030, 0x6063, 0x0400, + 0x6266, 0x606b, 0x0000, 0x616e, 0x68b8, 0x6072, 0x6077, 0x0008, + 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0xa085, 0x0020, + 0x607a, 0x68b4, 0x607f, 0x0000, 0x2d00, 0x6082, 0x6087, 0xffff, + 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0xa582, 0x0080, 0x0210, 0x2011, 0x0000, 0x629e, + 0x00f6, 0x2079, 0x0140, 0x7803, 0x0000, 0x00fe, 0x6017, 0x0012, + 0x2009, 0x07d0, 0x080c, 0x57a6, 0x003e, 0x004e, 0x005e, 0x006e, + 0x00ce, 0x00de, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0056, + 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x9200, 0x7150, 0x7818, + 0x2068, 0x68a0, 0x2028, 0x76c8, 0xd6ac, 0x1140, 0xd0bc, 0x1130, + 0xa080, 0x2719, 0x2015, 0xa294, 0x00ff, 0x0020, 0x6910, 0x6a14, + 0x736c, 0x7470, 0x781c, 0xa086, 0x0006, 0x0904, 0x6e65, 0x70c8, + 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0030, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, + 0x616e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, + 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, + 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, + 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, + 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, + 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, + 0x629e, 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, + 0xa005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x57a6, 0x003e, 0x004e, + 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x7810, 0x2070, 0x704c, + 0xa084, 0x0003, 0xa086, 0x0002, 0x0904, 0x6eb4, 0x2001, 0x9232, + 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, + 0x6266, 0x636a, 0x646e, 0x0030, 0x6063, 0x0100, 0x6266, 0x606b, + 0x0000, 0x616e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, + 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, + 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, + 0x60c6, 0x707c, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, + 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, + 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, + 0x6017, 0x0012, 0x0804, 0x6e53, 0x2001, 0x9232, 0x2004, 0xd0ac, + 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, + 0x646e, 0x0030, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, + 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, + 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, + 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, + 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, + 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, + 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, + 0x0804, 0x6e53, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, + 0x00ff, 0x2202, 0x8217, 0x0005, 0x00d6, 0x2069, 0x94e5, 0x6843, + 0x0001, 0x00de, 0x0005, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, + 0x9575, 0x0019, 0x080c, 0x5798, 0x0005, 0x0006, 0x6014, 0xa084, + 0x0004, 0xa085, 0x0009, 0x6016, 0x000e, 0x0005, 0x0006, 0x00c6, + 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, + 0x00ce, 0x000e, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x080c, + 0x57a1, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, 0x4000, + 0x0538, 0x0c21, 0x6803, 0x1000, 0x6803, 0x0000, 0x00c6, 0x2061, + 0x94e5, 0x6128, 0xa192, 0x0002, 0x1250, 0x8108, 0x612a, 0x6124, + 0x00ce, 0x81ff, 0x0180, 0x080c, 0x5798, 0x0839, 0x0060, 0x6124, + 0xa1e5, 0x0000, 0x0130, 0x080c, 0x91a0, 0x2009, 0x0014, 0x080c, + 0x7518, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, + 0x080c, 0x4dc5, 0x1118, 0x080c, 0x6f1e, 0x08c0, 0x080c, 0x4105, + 0x0c90, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x57ae, + 0x2071, 0x94e5, 0x713c, 0x81ff, 0x0578, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0568, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, 0x003e, 0x713c, + 0x2160, 0x080c, 0x91a0, 0x2009, 0x004a, 0x621c, 0xa296, 0x0009, + 0x1110, 0x2009, 0x0104, 0x080c, 0x7518, 0x080c, 0x4dc5, 0x1160, + 0x0006, 0x2001, 0x94d8, 0x2003, 0x0002, 0x2001, 0x9200, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x000e, 0x002e, 0x001e, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x08b0, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, + 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, + 0x2071, 0x94e5, 0x7018, 0x2068, 0x8dff, 0x0198, 0x68a0, 0xa406, + 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6010, 0x2060, 0x643c, 0x6540, + 0x6e48, 0x2d60, 0x080c, 0x457f, 0x0120, 0x080c, 0x7238, 0xa085, + 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x681d, + 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, + 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x014e, 0x015e, 0x0005, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a9, 0x0006, 0x2011, 0x9240, 0x2019, 0x9241, 0x23a6, + 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x6fff, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x6f0b, 0x014e, + 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, + 0x080c, 0x6881, 0x080c, 0x6897, 0x7810, 0x0006, 0xa080, 0x0015, + 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, + 0x8003, 0x60c2, 0x000e, 0xa080, 0x0001, 0x2004, 0x7812, 0x080c, + 0x6f0b, 0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, + 0x20a1, 0x020b, 0x080c, 0x681d, 0x20a3, 0x6200, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x6f0b, + 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, + 0x020b, 0x080c, 0x681d, 0x7810, 0x0006, 0xa080, 0x0017, 0x2098, + 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x000e, + 0xa080, 0x0001, 0x2004, 0x7812, 0x080c, 0x6f0b, 0x002e, 0x001e, + 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x2071, 0x94e5, 0x700c, 0x2060, 0x8cff, 0x0168, 0x080c, + 0x84c8, 0x1110, 0x080c, 0x7776, 0x600c, 0x0006, 0x080c, 0x74f2, + 0x080c, 0x7238, 0x00ce, 0x0c88, 0x700f, 0x0000, 0x700b, 0x0000, + 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0156, 0x00f6, + 0x00e6, 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, + 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x94e5, 0x7024, 0x2060, + 0x8cff, 0x05a0, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x57a1, + 0x2009, 0x0013, 0x080c, 0x7518, 0x20a9, 0x01f4, 0x6824, 0xd094, + 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, + 0x1000, 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, + 0x0010, 0x1f04, 0x70ae, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, + 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x2001, 0x9200, + 0x2004, 0xa096, 0x0001, 0x0550, 0xa096, 0x0004, 0x0538, 0x6817, + 0x0008, 0x68c3, 0x0000, 0x2011, 0x40af, 0x080c, 0x5731, 0x20a9, + 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, + 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd084, + 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x70e9, 0x7804, 0xa084, + 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x000e, 0x001e, + 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, + 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, 0x0016, + 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, + 0x94e5, 0x703c, 0x2060, 0x8cff, 0x0904, 0x7185, 0x6817, 0x0010, + 0x68c7, 0x0000, 0x68cb, 0x0000, 0x080c, 0x57ae, 0x080c, 0x1ef8, + 0x0046, 0x0056, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, 0x2021, + 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x11b0, 0x68c7, + 0x0000, 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0020, 0x2071, + 0x953b, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, 0x6816, 0x7803, + 0x0008, 0x7003, 0x0000, 0x00fe, 0x00ee, 0x250a, 0x005e, 0x004e, + 0xa39d, 0x0000, 0x1150, 0x2009, 0x0049, 0x601c, 0xa086, 0x0009, + 0x1110, 0x2009, 0x0103, 0x080c, 0x7518, 0x20a9, 0x03e8, 0x6824, + 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, + 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd094, 0x0118, 0x6827, + 0x0002, 0x0010, 0x1f04, 0x7167, 0x7804, 0xa084, 0x1000, 0x0120, + 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x2069, 0x94e5, 0x6a06, 0x012e, 0x00de, + 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0x94e5, 0x6a32, + 0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006, + 0x0126, 0x2071, 0x94e5, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000, + 0x8cff, 0x0538, 0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110, + 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060, + 0x08b8, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, + 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, 0x20a2, + 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804, + 0x7230, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, + 0x0478, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, + 0x00f8, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, + 0x0078, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, + 0x0089, 0x60c3, 0x0020, 0x080c, 0x6f0b, 0x014e, 0x015e, 0x0005, + 0x00e6, 0x2071, 0x94e5, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022, + 0x00ee, 0x0005, 0x20a9, 0x0008, 0x20a2, 0x1f04, 0x7244, 0x20a2, + 0x20a2, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x7614, 0x2660, + 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0x72d2, 0x8cff, 0x0904, + 0x72d2, 0x601c, 0xa086, 0x0006, 0x1904, 0x72cd, 0x88ff, 0x0138, + 0x2800, 0xac06, 0x1904, 0x72cd, 0x2039, 0x0000, 0x0050, 0x6018, + 0xa206, 0x1904, 0x72cd, 0x85ff, 0x0120, 0x6020, 0xa106, 0x1904, + 0x72cd, 0x7024, 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x01f0, 0x080c, 0x57a1, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, + 0x7356, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, + 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, + 0x0009, 0x630a, 0x0450, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, + 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, + 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0110, 0x080c, 0x9097, 0x080c, 0x849b, 0x080c, 0x7238, + 0x88ff, 0x1190, 0x00ce, 0x0804, 0x725b, 0x2c78, 0x600c, 0x2060, + 0x0804, 0x725b, 0xa006, 0x012e, 0x000e, 0x006e, 0x007e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, 0x0000, 0x00ce, 0xa8c5, + 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x7638, 0x2660, + 0x2678, 0x8cff, 0x0904, 0x7346, 0x601c, 0xa086, 0x0006, 0x1904, + 0x7341, 0x88ff, 0x0128, 0x2800, 0xac06, 0x1904, 0x7341, 0x0040, + 0x6018, 0xa206, 0x15f0, 0x85ff, 0x0118, 0x6020, 0xa106, 0x15c8, + 0x703c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, + 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, + 0x003e, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, + 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, + 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0110, + 0x080c, 0x9097, 0x080c, 0x849b, 0x88ff, 0x1190, 0x00ce, 0x0804, + 0x72f1, 0x2c78, 0x600c, 0x2060, 0x0804, 0x72f1, 0xa006, 0x012e, + 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, + 0x6017, 0x0000, 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00e6, 0x2071, + 0x94e5, 0x2001, 0x9200, 0x2004, 0xa086, 0x0002, 0x1118, 0x7007, + 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x94e5, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, + 0xac06, 0x11e0, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, + 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, + 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0xa085, 0x0001, 0x0020, 0x2c78, 0x600c, + 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x760c, 0x2660, 0x2678, + 0x8cff, 0x0904, 0x7423, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, + 0x1904, 0x741e, 0x7024, 0xac06, 0x1500, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x01d8, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, + 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, + 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0xac36, 0x1110, + 0x660c, 0x760e, 0x7008, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x84b7, 0x1118, 0x080c, 0x2692, 0x00c0, 0x080c, 0x84c8, 0x1118, + 0x080c, 0x7776, 0x0090, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0168, + 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x6003, 0x0000, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x0804, 0x73b0, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x73b0, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19e8, 0x080c, + 0x9097, 0x0c18, 0x0036, 0x0156, 0x0136, 0x0146, 0x3908, 0xa006, + 0xa190, 0x0020, 0x221c, 0xa39e, 0x251b, 0x1118, 0x8210, 0x8000, + 0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, + 0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e, 0x003e, 0x0005, 0x00d6, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, 0x0014, + 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2099, 0x94df, + 0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x080c, 0x6f0b, 0x00de, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, + 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, + 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0018, 0x080c, 0x6f0b, 0x0005, 0x2061, 0x9900, 0x2a70, 0x7064, + 0x7046, 0x704b, 0x9900, 0x0005, 0x00e6, 0x0126, 0x2071, 0x9200, + 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0608, 0x7048, 0x2060, + 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x000c, 0x7058, 0xac02, + 0x1208, 0x0cb0, 0x2061, 0x9900, 0x0c98, 0x6003, 0x0008, 0x8529, + 0x7546, 0xaca8, 0x000c, 0x7058, 0xa502, 0x1230, 0x754a, 0xa085, + 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, 0x9900, 0x0cc0, 0xa006, + 0x0cc0, 0x00e6, 0x2071, 0x9200, 0x7544, 0xa582, 0x0001, 0x0600, + 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x000c, + 0x7058, 0xac02, 0x1208, 0x0cb0, 0x2061, 0x9900, 0x0c98, 0x6003, + 0x0008, 0x8529, 0x7546, 0xaca8, 0x000c, 0x7058, 0xa502, 0x1228, + 0x754a, 0xa085, 0x0001, 0x00ee, 0x0005, 0x704b, 0x9900, 0x0cc8, + 0xa006, 0x0cc8, 0xac82, 0x9900, 0x0a0c, 0x13fe, 0x2001, 0x9216, + 0x2004, 0xac02, 0x1a0c, 0x13fe, 0xa006, 0x6006, 0x600a, 0x600e, + 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x6022, + 0x2061, 0x9200, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0108, + 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0cc0, + 0x601c, 0xa084, 0x000f, 0x0002, 0x7526, 0x752d, 0x7548, 0x7563, + 0x8555, 0x8570, 0x858b, 0x7526, 0x752d, 0x5d3d, 0xa18e, 0x0047, + 0x1118, 0xa016, 0x080c, 0x16c6, 0x0005, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x7546, 0x7654, + 0x779c, 0x7546, 0x77eb, 0x7546, 0x7546, 0x7546, 0x75f6, 0x7b03, + 0x7546, 0x7546, 0x7546, 0x7546, 0x7546, 0x7546, 0x080c, 0x13fe, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, + 0x0005, 0x7561, 0x7fa1, 0x7561, 0x7561, 0x7561, 0x7561, 0x7561, + 0x7561, 0x7f89, 0x8078, 0x7561, 0x7fce, 0x8023, 0x7fce, 0x8023, + 0x7561, 0x080c, 0x13fe, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x13fe, 0x0013, 0x006e, 0x0005, 0x757c, 0x7b3f, 0x7bf0, 0x7cb4, + 0x7df4, 0x757c, 0x757c, 0x757c, 0x7b1b, 0x7f40, 0x7f43, 0x757c, + 0x757c, 0x757c, 0x757c, 0x7f66, 0x080c, 0x13fe, 0x20a9, 0x000e, + 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, + 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x758c, + 0x00e6, 0x080c, 0x82ee, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000, + 0x7037, 0x0103, 0x00ee, 0x080c, 0x74f2, 0x0005, 0x00d6, 0x0036, + 0x7330, 0xa386, 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff, + 0x6817, 0xfffd, 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000, + 0x6837, 0x0103, 0x6b32, 0x080c, 0x74f2, 0x003e, 0x00de, 0x0005, + 0x0016, 0x20a9, 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, + 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001, + 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004, + 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x74f2, 0x001e, 0x0005, + 0x00d6, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0xa1b6, + 0x0015, 0x1148, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, + 0x6800, 0xc08d, 0x6802, 0x00de, 0x0804, 0x7598, 0x2100, 0xa1b2, + 0x003e, 0x1a0c, 0x13fe, 0x0002, 0x763c, 0x7648, 0x763c, 0x763c, + 0x763c, 0x763c, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, 0x763c, 0x763c, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763c, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, + 0x603e, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, + 0x6003, 0x0001, 0x6106, 0x080c, 0x603e, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6462, 0x012e, 0x0005, 0x6004, 0xa0b2, 0x003e, 0x1a0c, + 0x13fe, 0xa1b6, 0x0013, 0x0904, 0x76f0, 0xa1b6, 0x0027, 0x1904, + 0x76b6, 0x080c, 0x6389, 0x6004, 0x080c, 0x84b7, 0x0178, 0x080c, + 0x84c8, 0x0904, 0x76b0, 0xa08e, 0x0021, 0x0904, 0x76b3, 0xa08e, + 0x0022, 0x05f0, 0xa08e, 0x003d, 0x05f0, 0x04a8, 0x080c, 0x2692, + 0x2001, 0x0007, 0x080c, 0x43e3, 0x6018, 0xa080, 0x0028, 0x200c, + 0x080c, 0x7776, 0xa186, 0x007e, 0x1148, 0x2001, 0x9232, 0x2014, + 0xc285, 0x080c, 0x4dc5, 0x1108, 0xc2ad, 0x2202, 0x0016, 0x0026, + 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x00c6, 0x6018, 0xa065, 0x0110, 0x080c, + 0x460d, 0x00ce, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x003e, 0x002e, + 0x001e, 0x080c, 0x441f, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x080c, 0x7776, 0x0cc0, 0x080c, 0x7790, 0x0ca8, 0xa186, 0x0014, + 0x1db0, 0x080c, 0x6389, 0x080c, 0x266c, 0x080c, 0x84b7, 0x1188, + 0x080c, 0x2692, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x7776, + 0xa186, 0x007e, 0x1128, 0x2001, 0x9232, 0x200c, 0xc185, 0x2102, + 0x08d0, 0x080c, 0x84c8, 0x1118, 0x080c, 0x7776, 0x08a0, 0x6004, + 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, 0x9296, 0x2079, + 0x0000, 0x080c, 0x2924, 0x00fe, 0x00ee, 0x0828, 0x6004, 0xa08e, + 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, 0x7790, 0x0804, 0x76ab, + 0x2008, 0x0002, 0x7732, 0x7733, 0x7736, 0x7739, 0x773c, 0x773f, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7742, 0x7747, 0x7730, 0x7750, 0x7747, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7747, 0x7747, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7747, + 0x080c, 0x13fe, 0x00a0, 0x2001, 0x000b, 0x0418, 0x2001, 0x0003, + 0x0400, 0x2001, 0x0005, 0x00e8, 0x2001, 0x0001, 0x00d0, 0x2001, + 0x0009, 0x00b8, 0x080c, 0x13fe, 0x0098, 0x080c, 0x43e3, 0x080c, + 0x6389, 0x6003, 0x0002, 0x6017, 0x0028, 0x080c, 0x6462, 0x0040, + 0x080c, 0x6389, 0x6003, 0x0004, 0x6017, 0x0028, 0x080c, 0x6462, + 0x0005, 0x080c, 0x43e3, 0x080c, 0x6389, 0x6003, 0x0002, 0x0036, + 0x2019, 0x925c, 0x2304, 0xa084, 0xff00, 0x1118, 0x2019, 0x0028, + 0x0040, 0x8007, 0xa09a, 0x0004, 0x0ec8, 0x8003, 0x801b, 0x831b, + 0xa318, 0x6316, 0x003e, 0x080c, 0x6462, 0x0c10, 0x00e6, 0x080c, + 0x82ee, 0x0188, 0x6010, 0x2070, 0x7007, 0x0000, 0x0016, 0x6004, + 0xa08e, 0x0021, 0x0150, 0xa08e, 0x003d, 0x0138, 0x001e, 0x7037, + 0x0103, 0x7033, 0x0100, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cd8, + 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, + 0x7023, 0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, + 0xa084, 0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x13fe, 0x6604, + 0xa6b6, 0x0028, 0x1118, 0x080c, 0x84f2, 0x0468, 0x6604, 0xa6b6, + 0x0029, 0x1118, 0x080c, 0x8509, 0x0430, 0x6604, 0xa6b6, 0x001f, + 0x1118, 0x080c, 0x757e, 0x00f8, 0x6604, 0xa6b6, 0x0000, 0x1118, + 0x080c, 0x75e0, 0x00c0, 0x6604, 0xa6b6, 0x0022, 0x1118, 0x080c, + 0x75a6, 0x0088, 0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x75c0, + 0x0050, 0xa1b6, 0x0015, 0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, + 0x1118, 0x0804, 0x7983, 0x0005, 0x080c, 0x7526, 0x0ce0, 0x7805, + 0x7808, 0x7805, 0x7844, 0x7805, 0x7923, 0x7805, 0x7805, 0x7805, + 0x795b, 0x7805, 0x7971, 0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, + 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00e6, 0xacf0, + 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, + 0x74f2, 0x0005, 0x080c, 0x74f2, 0x0005, 0xe000, 0xe000, 0x0005, + 0x00e6, 0x2071, 0x9200, 0x7080, 0xa086, 0x0074, 0x11f0, 0x080c, + 0x8ebb, 0x1170, 0x00d6, 0x6018, 0x2068, 0x00e9, 0x00de, 0x2001, + 0x0006, 0x080c, 0x43e3, 0x080c, 0x2692, 0x080c, 0x74f2, 0x0088, + 0x2001, 0x000a, 0x080c, 0x43e3, 0x080c, 0x2692, 0x6003, 0x0001, + 0x6007, 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, + 0x7910, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000, + 0x080c, 0x43d1, 0x2069, 0x9251, 0x6804, 0xd0a4, 0x0120, 0x2001, + 0x0006, 0x080c, 0x43f1, 0x0005, 0x00d6, 0x2011, 0x9220, 0x2204, + 0xa086, 0x0074, 0x1904, 0x790b, 0x080c, 0x7a64, 0x6018, 0x2068, + 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x0198, 0xa286, 0x0080, + 0x1904, 0x789c, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, + 0x0588, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, + 0x0448, 0x00d6, 0x00e6, 0x00f6, 0x6813, 0x00ff, 0x6817, 0xfffe, + 0x2071, 0x9232, 0x2e04, 0xa085, 0x0003, 0x2072, 0x2071, 0x9780, + 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0x921b, 0x206a, + 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x921c, 0x206a, 0x78ea, 0x7832, + 0x7836, 0xa084, 0x00ff, 0x2008, 0x080c, 0x2435, 0x00fe, 0x00ee, + 0x00de, 0x00f8, 0x2001, 0x0006, 0x080c, 0x43e3, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0804, 0x790e, 0x6010, 0xa005, 0x0130, 0x2068, + 0x6838, 0xd0f4, 0x0110, 0x0804, 0x7862, 0x2001, 0x0004, 0x080c, + 0x43e3, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x603e, 0x0804, + 0x790e, 0x685c, 0xd0e4, 0x01c8, 0x080c, 0x8531, 0x080c, 0x4dc5, + 0x0110, 0xd0dc, 0x19b8, 0x2011, 0x9232, 0x2204, 0xc0ad, 0x2012, + 0x2001, 0x94c8, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, + 0x080c, 0x2460, 0x78e2, 0x00fe, 0x0828, 0x080c, 0x854a, 0x2011, + 0x9232, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0x8fa4, 0x000e, + 0x1904, 0x7892, 0xc0b5, 0x2012, 0x2001, 0x0000, 0x080c, 0x43d1, + 0x00c6, 0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, + 0x7936, 0x00fe, 0x080c, 0x2435, 0x2001, 0x9214, 0x2004, 0x2009, + 0x0000, 0x080c, 0x240b, 0x2001, 0x9213, 0x2102, 0x8108, 0x080c, + 0x4400, 0x2c00, 0x00ce, 0x1904, 0x7892, 0x601a, 0x2001, 0x0002, + 0x080c, 0x43e3, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x603e, 0x0018, 0x2001, 0x0001, 0x0011, 0x00de, 0x0005, + 0x0006, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, 0x000e, 0x0130, + 0xa005, 0x0120, 0x2001, 0x0007, 0x080c, 0x43e3, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0005, 0x00e6, 0x2071, 0x9200, 0x7080, 0xa086, + 0x0014, 0x1548, 0x7000, 0xa086, 0x0003, 0x1128, 0x6010, 0xa005, + 0x1110, 0x080c, 0x370a, 0x00d6, 0x6018, 0x2068, 0x080c, 0x44c7, + 0x080c, 0x7833, 0x00de, 0x080c, 0x7a6e, 0x11a8, 0x2001, 0x0006, + 0x080c, 0x43e3, 0x00e6, 0x6010, 0xa005, 0x0138, 0x2070, 0x7007, + 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x00ee, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0030, 0x080c, 0x7776, 0x2001, 0x0000, 0x080c, + 0x7910, 0x00ee, 0x0005, 0x2011, 0x9220, 0x2204, 0xa086, 0x0014, + 0x1158, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, 0x7910, + 0x0005, 0x2011, 0x9220, 0x2204, 0xa086, 0x0004, 0x1138, 0x2001, + 0x0007, 0x080c, 0x43e3, 0x080c, 0x74f2, 0x0020, 0x2001, 0x0001, + 0x080c, 0x7910, 0x0005, 0x000b, 0x0005, 0x7805, 0x7991, 0x7805, + 0x79b5, 0x7805, 0x7a1a, 0x7805, 0x7802, 0x7805, 0x7a2f, 0x7805, + 0x7a41, 0x00c6, 0x080c, 0x7a53, 0x1178, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0002, 0x080c, 0x603e, 0x0078, 0x2009, 0x978f, 0x2104, 0xa084, + 0xff00, 0xa086, 0x1900, 0x1118, 0x080c, 0x74f2, 0x0020, 0x2001, + 0x0001, 0x080c, 0x7910, 0x00ce, 0x0005, 0x080c, 0x7a61, 0x00d6, + 0x2069, 0x94d7, 0x2d04, 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, + 0xa086, 0x007e, 0x1138, 0x2069, 0x921c, 0x2d04, 0x8000, 0x206a, + 0x00de, 0x0010, 0x00de, 0x0078, 0x2001, 0x0000, 0x080c, 0x43d1, + 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x603e, 0x0400, 0x080c, 0x7776, 0x2009, 0x978e, 0x2134, + 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x01b8, 0x2009, 0x978f, 0x2104, + 0xa084, 0xff00, 0xa086, 0x1900, 0x1150, 0xa686, 0x0009, 0x0160, + 0x2001, 0x0004, 0x080c, 0x43e3, 0x080c, 0x74f2, 0x0020, 0x2001, + 0x0001, 0x080c, 0x7910, 0x0005, 0x00d6, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0128, 0x6838, 0xd0fc, 0x0110, 0x00de, 0x0c80, 0x6018, + 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0140, 0x8001, 0x6842, + 0x6017, 0x000a, 0x6007, 0x0016, 0x00de, 0x0c28, 0x080c, 0x266c, + 0x00de, 0x08e8, 0x080c, 0x7a61, 0x1158, 0x2001, 0x0004, 0x080c, + 0x43e3, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x603e, 0x0030, + 0x080c, 0x7776, 0x2001, 0x0000, 0x080c, 0x7910, 0x0005, 0x0489, + 0x1158, 0x2001, 0x0008, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0005, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, 0x7910, + 0x0005, 0x00f9, 0x1158, 0x2001, 0x000a, 0x080c, 0x43e3, 0x6003, + 0x0001, 0x6007, 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, + 0x080c, 0x7910, 0x0005, 0x2009, 0x978e, 0x2104, 0xa086, 0x0003, + 0x1138, 0x2009, 0x978f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, + 0x0005, 0xa085, 0x0001, 0x0005, 0x00c6, 0x0016, 0xac88, 0x0006, + 0x2164, 0x080c, 0x4443, 0x001e, 0x00ce, 0x0005, 0x00e6, 0x2071, + 0x978c, 0x7004, 0xa086, 0x0014, 0x11a8, 0x7008, 0xa086, 0x0800, + 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, 0x0f00, 0xa086, 0x0100, + 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0xa006, 0x0010, + 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076, + 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, + 0x94ee, 0x252c, 0x2021, 0x94f4, 0x2424, 0x2061, 0x9900, 0x2071, + 0x9200, 0x7244, 0x7064, 0xa202, 0x1688, 0x080c, 0x90ee, 0x0540, + 0x671c, 0xa786, 0x0001, 0x0520, 0xa786, 0x0007, 0x0508, 0x2500, + 0xac06, 0x01f0, 0x2400, 0xac06, 0x01d8, 0x00c6, 0x6000, 0xa086, + 0x0004, 0x1110, 0x080c, 0x1788, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0160, 0xa786, 0x0003, 0x11e0, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x080c, 0x849b, 0x00ce, + 0xace0, 0x000c, 0x7058, 0xac02, 0x1208, 0x0858, 0x012e, 0x000e, + 0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, + 0xa786, 0x0006, 0x1118, 0x080c, 0x9097, 0x0c38, 0xa786, 0x0009, + 0x19d8, 0x2009, 0x0106, 0x080c, 0x7518, 0x0c08, 0x220c, 0x2304, + 0xa106, 0x1130, 0x8210, 0x8318, 0x1f04, 0x7aee, 0xa006, 0x0005, + 0x2304, 0xa102, 0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, + 0xa18d, 0x0001, 0x0005, 0x6004, 0xa08a, 0x003e, 0x1a0c, 0x13fe, + 0x080c, 0x84b7, 0x0120, 0x080c, 0x84c8, 0x0150, 0x0010, 0x080c, + 0x2692, 0x080c, 0x6389, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x080c, 0x7776, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x7b31, 0x7b31, + 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, + 0x7b31, 0x7b33, 0x7b33, 0x7b33, 0x7b33, 0x7b31, 0x7b31, 0x7b31, + 0x7b33, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, 0x5ff8, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, 0xa186, + 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, 0x0804, 0x7bc5, 0xa186, + 0x0027, 0x11d0, 0x080c, 0x6389, 0x080c, 0x266c, 0x00d6, 0x6110, + 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, + 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, + 0x74f2, 0x080c, 0x6462, 0x0005, 0xa186, 0x0014, 0x1120, 0x6004, + 0xa082, 0x0040, 0x0428, 0xa186, 0x0046, 0x0138, 0xa186, 0x0045, + 0x0120, 0xa186, 0x0047, 0x190c, 0x13fe, 0x2001, 0x0109, 0x2004, + 0xd084, 0x0198, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, + 0x080c, 0x5ee3, 0x002e, 0x001e, 0x000e, 0x012e, 0xe000, 0x6000, + 0xa086, 0x0002, 0x1110, 0x0804, 0x7bf0, 0x080c, 0x7526, 0x0005, + 0x0002, 0x7ba6, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, + 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7bbe, 0x7bbe, 0x7bbe, 0x7bbe, + 0x7ba4, 0x7ba4, 0x7ba4, 0x7bbe, 0x080c, 0x13fe, 0x080c, 0x6389, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, + 0x684b, 0x0006, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, + 0x00de, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, + 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x0002, 0x7bdb, 0x7bd9, + 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, + 0x7bd9, 0x7be9, 0x7be9, 0x7be9, 0x7be9, 0x7bd9, 0x7bd9, 0x7bd9, + 0x7be9, 0x080c, 0x13fe, 0x080c, 0x6389, 0x6003, 0x0002, 0x080c, + 0x6462, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, + 0x0005, 0x080c, 0x6389, 0x6003, 0x000f, 0x080c, 0x6462, 0x0005, + 0xa182, 0x0040, 0x0002, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, + 0x7c08, 0x7c8a, 0x7ca9, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, + 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x080c, 0x13fe, + 0x00e6, 0x00d6, 0x2071, 0x978c, 0x6110, 0x2168, 0x7614, 0xa6b4, + 0x0fff, 0x86ff, 0x0904, 0x7c70, 0xa68c, 0x0c00, 0x0120, 0x7318, + 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0190, + 0xa186, 0x0028, 0x1128, 0x080c, 0x84a6, 0x684b, 0x001c, 0x0060, + 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, + 0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, + 0xd6c4, 0x01b0, 0xa686, 0x0100, 0x1138, 0x2001, 0x9799, 0x2004, + 0xa005, 0x1110, 0xc6c4, 0x0868, 0x7328, 0x732c, 0x6b56, 0x0036, + 0x2308, 0x2019, 0x9798, 0xad90, 0x0019, 0x080c, 0x80e6, 0x003e, + 0xd6cc, 0x0560, 0x7124, 0x695a, 0xa192, 0x0021, 0x1250, 0x2071, + 0x9798, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x80e6, + 0x00e8, 0x6838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x00f6, 0x2d78, 0x080c, 0x808b, 0x00fe, 0x080c, 0x80d6, 0x0080, + 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0130, + 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x7de6, 0x080c, 0x4809, + 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x00de, 0x00ee, 0x080c, + 0x74f2, 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, 0x978c, 0x7c04, + 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0120, + 0x6003, 0x0002, 0x00fe, 0x0005, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, + 0x00fe, 0x2c10, 0x080c, 0x1c88, 0x080c, 0x605b, 0x080c, 0x651c, + 0x0005, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x16c6, 0x0005, 0xa182, 0x0040, 0x0002, 0x7cca, + 0x7cca, 0x7cca, 0x7cca, 0x7cca, 0x7ccc, 0x7d54, 0x7cca, 0x7cca, + 0x7d6a, 0x7dc1, 0x7cca, 0x7cca, 0x7cca, 0x7cca, 0x7dcc, 0x7cca, + 0x7cca, 0x7cca, 0x080c, 0x13fe, 0x0076, 0x00f6, 0x00e6, 0x00d6, + 0x2071, 0x978c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0904, 0x7d4f, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, + 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x7d4f, + 0x080c, 0x147c, 0x090c, 0x13fe, 0x2d00, 0x784a, 0x7f4c, 0xc7cd, + 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, + 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318, 0x6b62, 0x731c, + 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180, 0xa186, 0x0028, + 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0x684b, 0x0015, + 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, 0x0000, + 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0160, + 0x7328, 0x732c, 0x6b56, 0x0036, 0x2308, 0x2019, 0x9798, 0xad90, + 0x0019, 0x080c, 0x80e6, 0x003e, 0xd6cc, 0x01c8, 0x7124, 0x695a, + 0xa192, 0x0021, 0x1250, 0x2071, 0x9798, 0x831c, 0x2300, 0xae18, + 0xad90, 0x001d, 0x080c, 0x80e6, 0x0050, 0x7838, 0xd0fc, 0x0120, + 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78, 0x080c, 0x808b, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, + 0x978c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, + 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x2c10, 0x080c, 0x1c88, 0x080c, + 0x6f04, 0x0005, 0x00d6, 0x6003, 0x0002, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0904, 0x7dbf, 0xd1cc, + 0x0540, 0x6948, 0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, + 0x6850, 0x0006, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0023, + 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x7d8a, + 0x015e, 0x000e, 0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, + 0x14a3, 0x0418, 0x0016, 0x080c, 0x14a3, 0x00de, 0x080c, 0x80d6, + 0x00e0, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, + 0x0180, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, + 0x0118, 0x684b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, + 0x0010, 0x684b, 0x0000, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, + 0x0005, 0x2019, 0x0001, 0x080c, 0x7110, 0x6003, 0x0002, 0x080c, + 0x641b, 0x080c, 0x651c, 0x0005, 0x080c, 0x641b, 0x080c, 0x266c, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, + 0x684b, 0x0029, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, + 0x00de, 0x080c, 0x74f2, 0x080c, 0x651c, 0x0005, 0x684b, 0x0015, + 0xd1fc, 0x0138, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, + 0x0000, 0x6962, 0x685e, 0x0005, 0xa182, 0x0040, 0x0002, 0x7e0a, + 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0c, 0x7e0a, 0x7eac, 0x7eb4, + 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, + 0x7e0a, 0x7e0a, 0x080c, 0x13fe, 0x0076, 0x00f6, 0x00e6, 0x00d6, + 0x2071, 0x978c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0904, 0x7e9d, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, + 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x7e9b, + 0xa686, 0x0100, 0x1140, 0x2001, 0x9799, 0x2004, 0xa005, 0x1118, + 0xc6c4, 0x7e46, 0x0c28, 0x080c, 0x147c, 0x090c, 0x13fe, 0x2d00, + 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, + 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, + 0x0120, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, + 0x0002, 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, + 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, + 0x0007, 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, + 0x6856, 0xa01e, 0xd6c4, 0x0160, 0x7328, 0x732c, 0x6b56, 0x0036, + 0x2308, 0x2019, 0x9798, 0xad90, 0x0019, 0x080c, 0x80e6, 0x003e, + 0xd6cc, 0x01c8, 0x7124, 0x695a, 0xa192, 0x0021, 0x1250, 0x2071, + 0x9798, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x80e6, + 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x2d78, 0x080c, 0x808b, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001, + 0x0001, 0x2071, 0x978c, 0x7218, 0x731c, 0x080c, 0x1700, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00d6, 0x6003, 0x0002, 0x6110, + 0x2168, 0x694c, 0xd1e4, 0x0904, 0x7f3e, 0xd1cc, 0x0904, 0x7f17, + 0x6948, 0x6838, 0xd0fc, 0x0590, 0x0016, 0x684c, 0x0006, 0x6850, + 0x0006, 0x684c, 0xd0ac, 0x0180, 0x6810, 0x6914, 0xa115, 0x0160, + 0x080c, 0x7de6, 0x00f6, 0x6948, 0x2178, 0x6848, 0x784a, 0x6860, + 0x7862, 0x685c, 0x785e, 0x00fe, 0x6948, 0xad90, 0x000d, 0xa198, + 0x000d, 0x2009, 0x0023, 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, + 0x8210, 0x1f04, 0x7ee5, 0x015e, 0x000e, 0x6852, 0x000e, 0x684e, + 0x001e, 0x2168, 0x080c, 0x14a3, 0x0804, 0x7f3c, 0x0016, 0x684c, + 0xd0ac, 0x0190, 0x6810, 0x6914, 0xa115, 0x0170, 0x080c, 0x7de6, + 0x00f6, 0x6948, 0x2178, 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, + 0x785e, 0x684c, 0x784e, 0x00fe, 0x6948, 0xa188, 0x0013, 0x684c, + 0x200a, 0x080c, 0x14a3, 0x00de, 0x080c, 0x80d6, 0x0428, 0x6837, + 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, 0xa086, + 0x0028, 0x1118, 0x684b, 0x001c, 0x00a8, 0xd1dc, 0x0118, 0x684b, + 0x0015, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0058, 0x684b, + 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, + 0x080c, 0x7de6, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, + 0x080c, 0x6389, 0x0010, 0x080c, 0x641b, 0x080c, 0x82ee, 0x0198, + 0x00d6, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0x920c, 0x210c, + 0xd18c, 0x1188, 0xd184, 0x1160, 0x6108, 0x694a, 0x6847, 0x0000, + 0x080c, 0x4809, 0x00de, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x684b, 0x0004, 0x0c98, 0x684b, 0x0004, 0x0c80, 0xa182, 0x0040, + 0x0002, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7e, 0x7f7c, + 0x7f81, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, + 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x080c, 0x13fe, 0x080c, 0x74f2, + 0x0005, 0x0006, 0x0026, 0xa016, 0x080c, 0x16c6, 0x002e, 0x000e, + 0x0005, 0xa182, 0x0085, 0x0002, 0x7f95, 0x7f93, 0x7f93, 0x7f93, + 0x7f93, 0x7f93, 0x7f93, 0x080c, 0x13fe, 0x6003, 0x000b, 0x6106, + 0x080c, 0x5ff8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, + 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, + 0x13fe, 0xa08a, 0x008c, 0x1a0c, 0x13fe, 0xa082, 0x0085, 0x0072, + 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x13fe, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0x7fc5, 0x7fc7, + 0x7fc7, 0x7fc5, 0x7fc5, 0x7fc5, 0x7fc5, 0x080c, 0x13fe, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa186, 0x0013, + 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x0492, 0xa186, 0x0027, + 0x11e8, 0x080c, 0x6389, 0x080c, 0x266c, 0x00d6, 0x6010, 0x2068, + 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, + 0x0029, 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, 0x74f2, + 0x080c, 0x6462, 0x0005, 0x080c, 0x7526, 0x0ce0, 0xa186, 0x0014, + 0x1dd0, 0x080c, 0x6389, 0x00d6, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006, 0x0c08, + 0x8011, 0x800f, 0x800f, 0x800f, 0x800f, 0x800f, 0x801a, 0x080c, + 0x13fe, 0x080c, 0x6389, 0x6017, 0x0014, 0x6003, 0x000c, 0x080c, + 0x6462, 0x0005, 0x080c, 0x6389, 0x6017, 0x0014, 0x6003, 0x000e, + 0x080c, 0x6462, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, 0x0085, + 0x0208, 0x001a, 0x080c, 0x7526, 0x0005, 0x8034, 0x8034, 0x8034, + 0x8034, 0x8036, 0x8057, 0x8034, 0x080c, 0x13fe, 0x00d6, 0x080c, + 0x848f, 0x080c, 0x82ee, 0x01b8, 0x6010, 0x2068, 0x6837, 0x0103, + 0x6850, 0xd0b4, 0x0118, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, + 0x684b, 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x852d, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x01b8, 0x6837, 0x0103, 0x6850, + 0xd0b4, 0x0118, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, + 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x852d, 0x6847, 0x0000, + 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, 0x74f2, 0x0005, + 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, + 0x0118, 0x080c, 0x7526, 0x0030, 0x080c, 0x6389, 0x080c, 0x849b, + 0x080c, 0x6462, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, 0x2029, + 0x0001, 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, + 0x2069, 0x9798, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, + 0x001d, 0x080c, 0x80e6, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0110, + 0x080c, 0x14a3, 0x080c, 0x147c, 0x0500, 0x8528, 0x6837, 0x0110, + 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, 0x2608, + 0xad90, 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, 0x003c, + 0x2d78, 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, 0x8dff, + 0x0158, 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, 0x4809, + 0x2f68, 0x0cb8, 0x080c, 0x4809, 0x00fe, 0x0005, 0x0156, 0xa184, + 0x0001, 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, + 0x8318, 0x8210, 0x1f04, 0x80ed, 0x015e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x601c, 0xa084, 0x000f, 0x0013, 0x012e, 0x0005, 0x8117, + 0x8109, 0x8112, 0x812e, 0x8109, 0x8112, 0x810b, 0x8112, 0x8109, + 0x5e80, 0x080c, 0x13fe, 0x0036, 0x2019, 0x0010, 0x080c, 0x8d4e, + 0x003e, 0x0005, 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x0178, 0xa00e, 0x2001, 0x0005, + 0x080c, 0x492c, 0x080c, 0x852d, 0x080c, 0x4809, 0x080c, 0x74f2, + 0xa085, 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a, + 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x8145, 0x8160, 0x8147, + 0x816f, 0x815d, 0x8145, 0x8112, 0x8117, 0x8117, 0x8112, 0x8112, + 0x8112, 0x8112, 0x8112, 0x8112, 0x8112, 0x080c, 0x13fe, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x0110, 0x080c, 0x852d, 0x00de, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x5ff8, + 0x080c, 0x6462, 0xa085, 0x0001, 0x0005, 0x080c, 0x1788, 0x0c38, + 0x00e6, 0x2071, 0x94e5, 0x7024, 0xac06, 0x1110, 0x080c, 0x708d, + 0x080c, 0x6fab, 0x00ee, 0x19d8, 0x080c, 0x8112, 0x0005, 0x0036, + 0x00e6, 0x2071, 0x94e5, 0x703c, 0xac06, 0x1138, 0x2019, 0x0000, + 0x080c, 0x7110, 0x00ee, 0x003e, 0x0850, 0x080c, 0x7366, 0x00ee, + 0x003e, 0x1928, 0x080c, 0x8112, 0x0005, 0x00c6, 0x601c, 0xa084, + 0x000f, 0x0013, 0x00ce, 0x0005, 0x819a, 0x81f7, 0x829a, 0x819e, + 0x819a, 0x819a, 0x8d44, 0x74f2, 0x81f7, 0x080c, 0x84c8, 0x1110, + 0x080c, 0x7776, 0x0005, 0x6017, 0x0001, 0x0005, 0x6000, 0xa08a, + 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x81b5, 0x81b7, 0x81d5, + 0x81e7, 0x81f4, 0x81b5, 0x819a, 0x819a, 0x819a, 0x81e7, 0x81e7, + 0x81b5, 0x81b5, 0x81b5, 0x81b5, 0x81f1, 0x080c, 0x13fe, 0x00e6, + 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x94e5, 0x7024, + 0xac06, 0x0180, 0x080c, 0x6fab, 0x6007, 0x0085, 0x6003, 0x000b, + 0x601f, 0x0002, 0x6017, 0x0014, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x00ee, 0x0005, 0x6017, 0x0001, 0x0cd8, 0x00d6, 0x6010, 0x2068, + 0x6850, 0xc0b5, 0x6852, 0x00de, 0x6007, 0x0085, 0x6003, 0x000b, + 0x601f, 0x0002, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0005, 0x00d6, + 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de, + 0x0005, 0x080c, 0x74f2, 0x0005, 0x080c, 0x1788, 0x08f0, 0x6000, + 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x820e, 0x819b, + 0x8210, 0x820e, 0x8210, 0x820e, 0x820e, 0x820e, 0x8195, 0x8195, + 0x820e, 0x820e, 0x820e, 0x820e, 0x820e, 0x820e, 0x080c, 0x13fe, + 0x00d6, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x00de, 0xa08a, + 0x000c, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x8229, 0x824a, 0x8229, + 0x824a, 0x8229, 0x824a, 0x822b, 0x8232, 0x8229, 0x824a, 0x8229, + 0x8243, 0x080c, 0x13fe, 0x6004, 0xa08e, 0x0004, 0x01b0, 0xa08e, + 0x0002, 0x0198, 0x6004, 0x080c, 0x84c8, 0x0904, 0x8292, 0xa08e, + 0x0021, 0x0904, 0x8296, 0xa08e, 0x0022, 0x0904, 0x8292, 0xa08e, + 0x003d, 0x0904, 0x8296, 0x080c, 0x266c, 0x080c, 0x7776, 0x080c, + 0x74f2, 0x0005, 0x00c6, 0x00d6, 0x6104, 0xa186, 0x0016, 0x0598, + 0xa186, 0x0002, 0x11f8, 0x6018, 0x2068, 0x2001, 0x9232, 0x2004, + 0xd0ac, 0x11c0, 0x68a0, 0xd0bc, 0x11a8, 0x6840, 0xa084, 0x00ff, + 0xa005, 0x0180, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, + 0x6017, 0x0398, 0x080c, 0x749c, 0x0128, 0x2d00, 0x601a, 0x601f, + 0x0001, 0x0088, 0x00de, 0x00ce, 0x080c, 0x7776, 0x080c, 0x266c, + 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2692, 0x012e, 0x00ee, + 0x080c, 0x74f2, 0x0005, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x603e, 0x080c, 0x6462, 0x00de, + 0x00ce, 0x0c80, 0x080c, 0x7776, 0x0804, 0x8247, 0x080c, 0x7790, + 0x0804, 0x8247, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, + 0x0005, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, + 0x82b1, 0x82b1, 0x819a, 0x82b1, 0x819b, 0x82b3, 0x819b, 0x82bc, + 0x82b1, 0x080c, 0x13fe, 0x6007, 0x008b, 0x6003, 0x000d, 0x080c, + 0x5ff8, 0x080c, 0x6462, 0x0005, 0x080c, 0x848f, 0x0479, 0x01d8, + 0x080c, 0x266c, 0x00d6, 0x0451, 0x0150, 0x6010, 0x2068, 0x6837, + 0x0103, 0x684b, 0x0006, 0x6847, 0x0000, 0x080c, 0x4809, 0x00de, + 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x603e, + 0x080c, 0x6462, 0x0010, 0x080c, 0x74f2, 0x0005, 0xa284, 0x0003, + 0x1158, 0xa282, 0x9900, 0x0240, 0x2001, 0x9216, 0x2004, 0xa202, + 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x0026, 0x6210, + 0x82ff, 0x002e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2061, 0x9900, 0x2071, 0x9200, 0x7344, 0x7064, + 0xa302, 0x1290, 0x601c, 0xa206, 0x1148, 0x080c, 0x84c8, 0x1110, + 0x080c, 0x7776, 0x00c6, 0x080c, 0x74f2, 0x00ce, 0xace0, 0x000c, + 0x7058, 0xac02, 0x1208, 0x0c50, 0x012e, 0x000e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0xa188, 0x936e, 0x210c, + 0x81ff, 0x0170, 0x2061, 0x9900, 0x2071, 0x9200, 0x0016, 0x080c, + 0x749c, 0x001e, 0x0138, 0x611a, 0x080c, 0x266c, 0x080c, 0x74f2, + 0xa006, 0x0010, 0xa085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, + 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, + 0x005e, 0x0170, 0x6612, 0x651a, 0x601f, 0x0003, 0x2009, 0x004b, + 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, + 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, + 0x00c6, 0x080c, 0x749c, 0x005e, 0x01f8, 0x6013, 0x0000, 0x651a, + 0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x460d, 0x00ce, 0x080c, + 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, + 0x8ee4, 0x008e, 0x2009, 0x004c, 0x080c, 0x7518, 0xa085, 0x0001, + 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, + 0x0126, 0x2091, 0x8000, 0x62a0, 0x00c6, 0x080c, 0x749c, 0x005e, + 0x0500, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, 0x00c6, + 0x2560, 0x080c, 0x460d, 0x00ce, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x2009, + 0x004d, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, + 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, + 0x62a0, 0x00c6, 0x080c, 0x749c, 0x005e, 0x0500, 0x6612, 0x651a, + 0x601f, 0x0003, 0x2019, 0x0005, 0x00c6, 0x2560, 0x080c, 0x460d, + 0x00ce, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, + 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x2009, 0x004e, 0x080c, 0x7518, + 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, + 0x00c6, 0x0096, 0x0086, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, + 0x00c6, 0x080c, 0x749c, 0x005e, 0x0904, 0x8426, 0x6612, 0x651a, + 0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x45af, 0x0118, 0x2001, + 0x83ec, 0x0028, 0x080c, 0x4581, 0x0160, 0x2001, 0x83f2, 0x0006, + 0xa00e, 0x2001, 0x0004, 0x080c, 0x492c, 0x080c, 0x4809, 0x000e, + 0x0807, 0x2019, 0x0004, 0x080c, 0x632b, 0x0036, 0x003e, 0x00ce, + 0x2041, 0x0001, 0x2608, 0x080c, 0x6140, 0x080c, 0x606d, 0x2c08, + 0x2648, 0x080c, 0x8ee4, 0x6018, 0xa080, 0x000f, 0x200c, 0x81ff, + 0x090c, 0x61d3, 0x2009, 0x0052, 0x080c, 0x7518, 0xa085, 0x0001, + 0x012e, 0x005e, 0x008e, 0x009e, 0x00ce, 0x0005, 0xa006, 0x0cc0, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, + 0x0178, 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x001f, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, + 0x749c, 0x001e, 0x0178, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, + 0x6012, 0x2009, 0x0021, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, + 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x749c, 0x001e, 0x0178, 0x660a, 0x611a, 0x601f, + 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x080c, 0x7518, 0xa085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0170, 0x611a, + 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x7518, + 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x0026, + 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, + 0x00de, 0x002e, 0x0005, 0x0006, 0x6013, 0x0000, 0x601f, 0x0007, + 0x2001, 0x94dd, 0x2004, 0x6016, 0x000e, 0x0005, 0x0066, 0x00c6, + 0x00d6, 0x2031, 0x9252, 0x2634, 0xd6e4, 0x0128, 0x6618, 0x2660, + 0x6e48, 0x080c, 0x453a, 0x00de, 0x00ce, 0x006e, 0x0005, 0x0006, + 0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, 0x0128, + 0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005, + 0x0006, 0x00d6, 0x6010, 0xa06d, 0x0128, 0x6838, 0xd0fc, 0x0110, + 0xa006, 0x0010, 0xa085, 0x0001, 0x00de, 0x000e, 0x0005, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0180, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x080c, 0x266c, 0x2009, + 0x0028, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0xa186, 0x0015, 0x1178, 0x2011, 0x9220, 0x2204, + 0xa086, 0x0074, 0x1148, 0x080c, 0x7a64, 0x6003, 0x0001, 0x6007, + 0x0029, 0x080c, 0x603e, 0x0020, 0x080c, 0x7776, 0x080c, 0x74f2, + 0x0005, 0xa186, 0x0015, 0x11b0, 0x2011, 0x9220, 0x2204, 0xa086, + 0x0014, 0x1180, 0x00d6, 0x6018, 0x2068, 0x080c, 0x44c7, 0x00de, + 0x080c, 0x7a6e, 0x1138, 0x2001, 0x0006, 0x080c, 0x43e3, 0x080c, + 0x7598, 0x0020, 0x080c, 0x7776, 0x080c, 0x74f2, 0x0005, 0x6848, + 0xa086, 0x0005, 0x1108, 0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, + 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x2001, 0x94d9, 0x200c, + 0x8000, 0x2014, 0x2001, 0x0064, 0x080c, 0x5eaf, 0x2001, 0x94dd, + 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202, 0x003e, 0x002e, 0x001e, + 0x000e, 0x0005, 0x0006, 0x2001, 0x94dd, 0x2003, 0x0028, 0x2001, + 0x94de, 0x2003, 0x07d0, 0x000e, 0x0005, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x856e, 0x881c, + 0x8907, 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x85a6, 0x8973, + 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x080c, 0x13fe, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, + 0x0005, 0x8589, 0x8ce9, 0x8589, 0x8589, 0x8589, 0x8589, 0x8589, + 0x8589, 0x8cad, 0x8d31, 0x8589, 0x9105, 0x9135, 0x9105, 0x9135, + 0x8589, 0x080c, 0x13fe, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x13fe, 0x0013, 0x006e, 0x0005, 0x85a4, 0x8ab9, 0x8b64, 0x8b88, + 0x8bd3, 0x85a4, 0x85a4, 0x8c44, 0x897f, 0x8c87, 0x8c9a, 0x85a4, + 0x85a4, 0x85a4, 0x85a4, 0x85a4, 0x080c, 0x13fe, 0xa1b2, 0x003e, + 0x1a0c, 0x13fe, 0x2100, 0x0002, 0x85df, 0x86f0, 0x85df, 0x85df, + 0x85df, 0x86f7, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, + 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, + 0x85df, 0x85df, 0x85df, 0x85e1, 0x860b, 0x8616, 0x865a, 0x8674, + 0x86aa, 0x86dd, 0x85df, 0x85df, 0x86fa, 0x85df, 0x85df, 0x8709, + 0x8710, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x87ab, 0x85df, + 0x85df, 0x87b5, 0x85df, 0x85df, 0x875d, 0x85df, 0x85df, 0x080c, + 0x13fe, 0x080c, 0x470e, 0x6618, 0x00c6, 0x2660, 0x080c, 0x4443, + 0x00ce, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, + 0x0278, 0x080c, 0x8e28, 0x1904, 0x8654, 0x080c, 0x8dd3, 0x1120, + 0x6007, 0x0008, 0x0804, 0x86eb, 0x6007, 0x0009, 0x0804, 0x86eb, + 0x080c, 0x8fa4, 0x0128, 0x080c, 0x8e28, 0x0d78, 0x0804, 0x8654, + 0x6013, 0x1900, 0x0c88, 0x6106, 0x080c, 0x8d83, 0x6007, 0x0006, + 0x0804, 0x86eb, 0x6007, 0x0007, 0x0804, 0x86eb, 0x080c, 0x9150, + 0x1904, 0x87c6, 0x00d6, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x01a0, 0xa686, 0x0004, 0x0188, 0x080c, + 0x4dc5, 0x1160, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0140, + 0xa686, 0x0004, 0x0128, 0xa686, 0x0005, 0x0110, 0x00de, 0x00e0, + 0x080c, 0x8e86, 0x11a0, 0xa686, 0x0006, 0x1150, 0x0026, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x26b1, 0x002e, + 0x080c, 0x44c7, 0x6007, 0x000a, 0x00de, 0x0804, 0x86eb, 0x6007, + 0x000b, 0x00de, 0x0804, 0x86eb, 0x080c, 0x266c, 0x6007, 0x0001, + 0x0804, 0x86eb, 0x080c, 0x9150, 0x1904, 0x87c6, 0x6618, 0x00d6, + 0x2668, 0x6e04, 0x00de, 0xa686, 0x0707, 0x0d70, 0x0026, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x26b1, 0x002e, + 0x6007, 0x000c, 0x0804, 0x86eb, 0x080c, 0x470e, 0x6618, 0xa6b0, + 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x02b0, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0004, 0x0118, 0xa686, 0x0006, 0x1960, + 0x080c, 0x8e93, 0x1120, 0x6007, 0x000e, 0x0804, 0x86eb, 0x080c, + 0x266c, 0x6007, 0x000f, 0x0804, 0x86eb, 0x080c, 0x8fa4, 0x0160, + 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004, 0x0a04, 0x8654, 0xa682, + 0x0007, 0x0e30, 0x0804, 0x8654, 0x6013, 0x1900, 0x6007, 0x0009, + 0x0804, 0x86eb, 0x080c, 0x470e, 0x6618, 0xa6b0, 0x0001, 0x2634, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x02c0, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0x8654, 0x080c, + 0x8ebb, 0x1130, 0x080c, 0x8dd3, 0x1118, 0x6007, 0x0010, 0x0418, + 0x080c, 0x266c, 0x6007, 0x0011, 0x00f0, 0x080c, 0x8fa4, 0x0140, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0d48, 0x0804, 0x8654, + 0x6013, 0x1900, 0x6007, 0x0009, 0x0070, 0x7030, 0xa086, 0x6000, + 0x0140, 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, 0x1904, + 0x8654, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x603e, 0x0005, + 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x603e, 0x0cc0, 0x6007, + 0x0005, 0x0cc0, 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, + 0x1904, 0x8654, 0x6007, 0x0020, 0x6003, 0x0001, 0x080c, 0x603e, + 0x0005, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x603e, 0x0005, + 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, 0x1904, 0x8654, + 0x0016, 0x0026, 0x2011, 0x9791, 0x2214, 0xa286, 0xffff, 0x0190, + 0x2c08, 0x080c, 0x82de, 0x01d8, 0x2260, 0x2011, 0x9790, 0x2214, + 0x6008, 0xa206, 0x11a0, 0x6018, 0xa190, 0x0006, 0x2214, 0xa206, + 0x01e0, 0x0068, 0x2011, 0x9790, 0x2214, 0x2c08, 0x080c, 0x90ab, + 0x11a0, 0x2011, 0x9791, 0x2214, 0xa286, 0xffff, 0x01a0, 0x2160, + 0x6007, 0x0026, 0x6013, 0x1700, 0x2011, 0x9789, 0x2214, 0xa296, + 0xffff, 0x1160, 0x6007, 0x0025, 0x0048, 0x601c, 0xa086, 0x0007, + 0x1d70, 0x080c, 0x74f2, 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, + 0x080c, 0x603e, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, + 0x43d1, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, + 0x9205, 0x2011, 0x9796, 0x080c, 0x7aee, 0x003e, 0x002e, 0x001e, + 0x015e, 0x0120, 0x6007, 0x0031, 0x0804, 0x86eb, 0x080c, 0x7910, + 0x080c, 0x4dc5, 0x1578, 0x0006, 0x0026, 0x0036, 0x2011, 0x9223, + 0x2204, 0x8000, 0x2012, 0xa084, 0x0007, 0x0190, 0x2001, 0x94d7, + 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x003e, 0x002e, 0x000e, 0x0005, + 0x2001, 0x0001, 0x080c, 0x23ba, 0x080c, 0x4dd7, 0x1110, 0x080c, + 0x4d9a, 0x2011, 0x8036, 0x2019, 0x0005, 0x080c, 0x3698, 0x003e, + 0x002e, 0x000e, 0x0005, 0x6106, 0x0479, 0x6007, 0x002b, 0x0804, + 0x86eb, 0x6007, 0x002c, 0x0804, 0x86eb, 0x080c, 0x9150, 0x1170, + 0x0081, 0x1904, 0x8654, 0x6106, 0x0419, 0x1120, 0x6007, 0x002e, + 0x0804, 0x86eb, 0x6007, 0x002f, 0x0804, 0x86eb, 0x080c, 0x74f2, + 0x0005, 0x00d6, 0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, + 0x0001, 0x006e, 0x00de, 0x0005, 0x00d6, 0x0439, 0x00de, 0x0005, + 0x00d6, 0x0481, 0x11e0, 0x680c, 0xa08c, 0xff00, 0x6824, 0xa084, + 0x00ff, 0xa115, 0x6212, 0xd1e4, 0x0118, 0x2009, 0x0001, 0x0060, + 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x080c, 0x240b, + 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x26b1, 0x0018, 0xa085, + 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, 0x978d, 0x6800, + 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, 0x0001, 0x0008, + 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0x978c, 0x6808, 0xa084, + 0xff00, 0xa086, 0x0800, 0x0005, 0x6004, 0xa0b2, 0x003e, 0x1a0c, + 0x13fe, 0xa1b6, 0x0013, 0x1110, 0x2008, 0x0092, 0xa1b6, 0x0027, + 0x0120, 0xa1b6, 0x0014, 0x190c, 0x13fe, 0x2001, 0x0007, 0x080c, + 0x43f1, 0x080c, 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, + 0x8875, 0x8877, 0x8875, 0x8875, 0x8875, 0x8877, 0x8885, 0x88e7, + 0x88b2, 0x88e7, 0x88c3, 0x88e7, 0x8885, 0x88e7, 0x88df, 0x88e7, + 0x88df, 0x88e7, 0x88e7, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x88e7, 0x8875, 0x8875, 0x88e7, 0x8875, 0x88e7, 0x88e7, 0x8875, + 0x8875, 0x8875, 0x8875, 0x88e7, 0x88e7, 0x8875, 0x88e7, 0x88e7, + 0x8875, 0x887f, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x080c, 0x13fe, 0x080c, + 0x6389, 0x6003, 0x0002, 0x080c, 0x6462, 0x0804, 0x88ed, 0x2001, + 0x0000, 0x080c, 0x43d1, 0x0804, 0x88e7, 0x00f6, 0x2079, 0x9251, + 0x7804, 0x00fe, 0xd0ac, 0x1904, 0x88e7, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0904, + 0x88e7, 0x2001, 0x0002, 0x080c, 0x43e3, 0x080c, 0x6389, 0x601f, + 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x603e, 0x080c, + 0x6462, 0x00c6, 0x6118, 0x2160, 0x2009, 0x0001, 0x080c, 0x573d, + 0x00ce, 0x04d8, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0006, 0x0550, 0xa686, 0x0004, 0x0538, + 0x2001, 0x0004, 0x0410, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1110, 0x080c, 0x370a, 0x2001, 0x0006, 0x0401, 0x6618, 0x00d6, + 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, + 0x0170, 0x2001, 0x0006, 0x0048, 0x2001, 0x0004, 0x0030, 0x2001, + 0x0006, 0x0061, 0x0020, 0x0018, 0x0010, 0x080c, 0x43f1, 0x080c, + 0x6389, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x0016, 0x00d6, + 0x6118, 0x2168, 0x6900, 0xd184, 0x0178, 0x6104, 0xa18e, 0x000a, + 0x1128, 0x699c, 0xd1a4, 0x1110, 0x2001, 0x0007, 0x2001, 0x0000, + 0x080c, 0x43d1, 0x080c, 0x2692, 0x00de, 0x001e, 0x0005, 0x00d6, + 0x6618, 0x2668, 0x6804, 0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2, + 0x000c, 0x1a0c, 0x13fe, 0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028, + 0xa1b6, 0x0016, 0x190c, 0x13fe, 0x04eb, 0x0005, 0x7805, 0x7805, + 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, 0x892a, 0x7805, 0x7805, + 0x7805, 0x7805, 0x00f6, 0x2079, 0x9251, 0x7804, 0x00fe, 0xd0ac, + 0x1198, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, 0x080c, + 0x43e3, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x603e, 0x080c, 0x6462, 0x00a8, 0x2011, 0x9783, 0x2204, 0x8211, + 0x220c, 0x080c, 0x240b, 0x1168, 0x00c6, 0x080c, 0x4434, 0x0120, + 0x00ce, 0x080c, 0x74f2, 0x0028, 0x080c, 0x41e0, 0x00ce, 0x080c, + 0x74f2, 0x0005, 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, + 0x7805, 0x8966, 0x7805, 0x7805, 0x7805, 0x7805, 0x080c, 0x7a61, + 0x1138, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x603e, 0x0010, + 0x080c, 0x74f2, 0x0005, 0x6004, 0xa08a, 0x003e, 0x1a0c, 0x13fe, + 0x080c, 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa182, + 0x0040, 0x0002, 0x8995, 0x8995, 0x8995, 0x8995, 0x8997, 0x8995, + 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, + 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x080c, 0x13fe, 0x00d6, + 0x00e6, 0x00f6, 0x0156, 0x0046, 0x0026, 0x6106, 0x2071, 0x9780, + 0x7444, 0xa4a4, 0xf600, 0x0904, 0x8a0d, 0xa486, 0x2000, 0x01f0, + 0xa486, 0x0400, 0x01d8, 0xa486, 0x1000, 0x0178, 0xa486, 0x4000, + 0x01d8, 0xa486, 0x0200, 0x0120, 0x080c, 0x74f2, 0x0804, 0x8a67, + 0x6118, 0x2104, 0xc0fd, 0x200a, 0x0078, 0x2069, 0x9566, 0x6a00, + 0xd284, 0x0904, 0x8a79, 0xc2cd, 0x6a02, 0x0030, 0x2009, 0x0001, + 0x2011, 0x0200, 0x080c, 0x585b, 0x080c, 0x147c, 0x090c, 0x13fe, + 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, + 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, 0x6018, 0x2078, + 0x78a0, 0x8007, 0x7130, 0x694a, 0x0016, 0xa084, 0xff00, 0x6846, + 0x684f, 0x0000, 0x6857, 0x0036, 0x080c, 0x4809, 0x001e, 0xa486, + 0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0x9071, 0x0804, 0x8a67, + 0xa486, 0x0400, 0x1130, 0x2019, 0x0002, 0x080c, 0x9033, 0x0804, + 0x8a67, 0xa486, 0x0200, 0x1110, 0x080c, 0x9020, 0xa486, 0x1000, + 0x1110, 0x080c, 0x905e, 0x0804, 0x8a67, 0x2069, 0x9566, 0x6a00, + 0xd284, 0x0904, 0x8ab6, 0xa284, 0x0300, 0x1904, 0x8ab0, 0x6804, + 0xa005, 0x0904, 0x8aa1, 0x2d78, 0x6003, 0x0007, 0x6018, 0x2004, + 0xd0fc, 0x1904, 0x8ab0, 0x080c, 0x145f, 0x0904, 0x8a6e, 0x7800, + 0xd08c, 0x1118, 0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, + 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, + 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, + 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, + 0x684f, 0x0040, 0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, + 0x0010, 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0x9790, 0xad90, + 0x0015, 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0x8a59, + 0x200c, 0x6982, 0x8000, 0x200c, 0x697e, 0x080c, 0x4809, 0x002e, + 0x004e, 0x015e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x6013, 0x0100, + 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x0c70, 0x2069, 0x9792, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, + 0x11a8, 0x2069, 0x9780, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, + 0xa18c, 0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, + 0x0043, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0888, 0x6013, 0x0200, + 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x0830, 0x6013, 0x0300, 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, + 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0804, 0x8a67, + 0x6013, 0x0500, 0x0c98, 0x6013, 0x0600, 0x0818, 0x6013, 0x0200, + 0x0800, 0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, + 0x13fe, 0xa08a, 0x0053, 0x1a0c, 0x13fe, 0xa082, 0x0040, 0x2008, + 0x0804, 0x8b24, 0xa186, 0x0047, 0x11b8, 0x2001, 0x0109, 0x2004, + 0xd084, 0x01f0, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, + 0x080c, 0x5ee3, 0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, + 0x0002, 0x1170, 0x0804, 0x8b64, 0xa186, 0x0027, 0x0120, 0xa186, + 0x0014, 0x190c, 0x13fe, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, + 0x080c, 0x7526, 0x0005, 0x8b06, 0x8b08, 0x8b08, 0x8b06, 0x8b06, + 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, + 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x080c, 0x13fe, + 0x080c, 0x6389, 0x080c, 0x6462, 0x0036, 0x00d6, 0x6010, 0xa06d, + 0x0180, 0xad84, 0xf000, 0x0168, 0x2019, 0x0004, 0x080c, 0x9097, + 0x6013, 0x0000, 0x6014, 0xa005, 0x1110, 0x6017, 0x0014, 0x6003, + 0x0007, 0x00de, 0x003e, 0x0005, 0x0002, 0x8b38, 0x8b55, 0x8b41, + 0x8b5e, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, + 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, + 0x080c, 0x13fe, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, + 0x200a, 0x080c, 0x6389, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, + 0x0138, 0x6003, 0x0007, 0x2009, 0x0043, 0x080c, 0x7518, 0x0010, + 0x6003, 0x0002, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, 0x080c, + 0x5836, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, + 0x2009, 0x0041, 0x0804, 0x8c44, 0xa182, 0x0040, 0x0002, 0x8b7a, + 0x8b7c, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7d, 0x8b7a, + 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, + 0x8b7a, 0x8b7a, 0x080c, 0x13fe, 0x0005, 0x6003, 0x0004, 0x6110, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, + 0xa182, 0x0040, 0x0002, 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, + 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, 0x8ba0, 0x8bc0, 0x8b9e, 0x8b9e, + 0x8b9e, 0x8b9e, 0x8bc0, 0x8b9e, 0x8b9e, 0x8b9e, 0x080c, 0x13fe, + 0x080c, 0x641b, 0x080c, 0x651c, 0x6010, 0x00d6, 0x2068, 0x684c, + 0xd0fc, 0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0158, 0x2009, + 0x0041, 0x00de, 0x0804, 0x8c44, 0x6003, 0x0007, 0x080c, 0x5836, + 0x00de, 0x0005, 0x080c, 0x5836, 0x080c, 0x74f2, 0x00de, 0x0cc8, + 0x0036, 0x080c, 0x641b, 0x080c, 0x651c, 0x6010, 0x00d6, 0x2068, + 0x2019, 0x0004, 0x080c, 0x9097, 0x080c, 0x849b, 0x6017, 0x0028, + 0x00de, 0x003e, 0x0005, 0xa186, 0x0013, 0x1150, 0x6004, 0xa086, + 0x0042, 0x190c, 0x13fe, 0x080c, 0x6389, 0x080c, 0x6462, 0x0005, + 0xa186, 0x0027, 0x0118, 0xa186, 0x0014, 0x1180, 0x6004, 0xa086, + 0x0042, 0x190c, 0x13fe, 0x2001, 0x0007, 0x080c, 0x43f1, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa182, 0x0040, + 0x0002, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, + 0x8c0e, 0x8c1a, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, + 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x080c, 0x13fe, 0x0036, 0x0046, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x004e, + 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068, 0x6810, 0x6a14, 0xa20d, + 0x1168, 0x684c, 0xd0fc, 0x0120, 0x2009, 0x0041, 0x00de, 0x00e0, + 0x6003, 0x0007, 0x080c, 0x5836, 0x00de, 0x0005, 0x6003, 0x0007, + 0x0021, 0x080c, 0x5838, 0x00de, 0x0005, 0xd2fc, 0x0140, 0x8002, + 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, 0x0010, 0x2009, + 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040, 0x0002, 0x8c5a, + 0x8c5c, 0x8c68, 0x8c74, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c83, 0x8c5a, + 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, + 0x8c5a, 0x8c5a, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, + 0x5ff8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, + 0x6003, 0x0001, 0x6106, 0x080c, 0x5ff8, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6462, 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10, + 0x080c, 0x1c88, 0x0126, 0x2091, 0x8000, 0x080c, 0x605b, 0x080c, + 0x651c, 0x012e, 0x0005, 0xa016, 0x080c, 0x16c6, 0x0005, 0x080c, + 0x6389, 0x6110, 0x81ff, 0x0148, 0x00d6, 0x2168, 0x0036, 0x2019, + 0x0029, 0x080c, 0x9097, 0x003e, 0x00de, 0x080c, 0x849b, 0x080c, + 0x6462, 0x0005, 0x080c, 0x641b, 0x6110, 0x81ff, 0x0148, 0x00d6, + 0x2168, 0x0036, 0x2019, 0x0029, 0x080c, 0x9097, 0x003e, 0x00de, + 0x080c, 0x849b, 0x080c, 0x651c, 0x0005, 0xa182, 0x0085, 0x0002, + 0x8cb9, 0x8cb7, 0x8cb7, 0x8cc5, 0x8cb7, 0x8cb7, 0x8cb7, 0x080c, + 0x13fe, 0x6003, 0x000b, 0x6106, 0x080c, 0x5ff8, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, 0x0026, 0x00e6, 0x080c, + 0x9150, 0x0118, 0x080c, 0x74f2, 0x00c8, 0x2071, 0x9780, 0x7224, + 0x6212, 0x7220, 0x080c, 0x8f71, 0x0118, 0x6007, 0x0086, 0x0040, + 0x6007, 0x0087, 0x7224, 0xa296, 0xffff, 0x1110, 0x6007, 0x0086, + 0x6003, 0x0001, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x00ee, 0x002e, + 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, + 0x13fe, 0xa08a, 0x008c, 0x1a0c, 0x13fe, 0xa082, 0x0085, 0x00a2, + 0xa186, 0x0027, 0x0130, 0xa186, 0x0014, 0x0118, 0x080c, 0x7526, + 0x0050, 0x2001, 0x0007, 0x080c, 0x43f1, 0x080c, 0x6389, 0x080c, + 0x849b, 0x080c, 0x6462, 0x0005, 0x8d13, 0x8d15, 0x8d15, 0x8d13, + 0x8d13, 0x8d13, 0x8d13, 0x080c, 0x13fe, 0x080c, 0x6389, 0x080c, + 0x74f2, 0x080c, 0x6462, 0x0005, 0xa182, 0x0085, 0x0a0c, 0x13fe, + 0xa182, 0x008c, 0x1a0c, 0x13fe, 0xa182, 0x0085, 0x0002, 0x8d2e, + 0x8d2e, 0x8d2e, 0x8d30, 0x8d2e, 0x8d2e, 0x8d2e, 0x080c, 0x13fe, + 0x0005, 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, + 0x0027, 0x0118, 0x080c, 0x7526, 0x0030, 0x080c, 0x6389, 0x080c, + 0x849b, 0x080c, 0x6462, 0x0005, 0x0036, 0x2019, 0x000b, 0x0031, + 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036, + 0x0086, 0x2091, 0x8000, 0x2c40, 0x080c, 0x724a, 0x1540, 0x080c, + 0x72e2, 0x1528, 0x6000, 0xa086, 0x0000, 0x0508, 0x601c, 0xa086, + 0x0007, 0x01e8, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1140, 0x601f, + 0x0007, 0x2001, 0x94dd, 0x2004, 0x6016, 0x080c, 0x1788, 0x6010, + 0x2068, 0x080c, 0x82ee, 0x0110, 0x080c, 0x9097, 0x00de, 0x6013, + 0x0000, 0x601f, 0x0007, 0x2001, 0x94dd, 0x2004, 0x6016, 0x008e, + 0x003e, 0x012e, 0x0005, 0x00f6, 0x00c6, 0x0036, 0x0156, 0x2079, + 0x9780, 0x7938, 0x783c, 0x080c, 0x240b, 0x1904, 0x8dce, 0x0016, + 0x00c6, 0x080c, 0x4434, 0x15c0, 0x2011, 0x9790, 0xac98, 0x000a, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1578, 0x001e, 0x002e, 0x0026, + 0x0016, 0x2019, 0x0029, 0x080c, 0x73a2, 0x080c, 0x6127, 0x0086, + 0x2041, 0x0000, 0x080c, 0x606d, 0x008e, 0x001e, 0x0086, 0x2041, + 0x0000, 0x080c, 0x8ee4, 0x008e, 0x080c, 0x460d, 0x0026, 0x6204, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0118, 0xa286, 0x0004, + 0x1118, 0x62a0, 0x080c, 0x2704, 0x002e, 0x001e, 0x080c, 0x41e0, + 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce, 0x001e, 0x015e, 0x003e, + 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x2009, 0x9220, + 0x2104, 0xa086, 0x0074, 0x1904, 0x8e1e, 0x2069, 0x978e, 0x690c, + 0xa182, 0x0100, 0x0678, 0x6908, 0xa184, 0x8000, 0x05a0, 0x2001, + 0x94d7, 0x2004, 0xa005, 0x1118, 0xa184, 0x0800, 0x0560, 0x6910, + 0xa18a, 0x0001, 0x0610, 0x6914, 0x2069, 0x97ae, 0x6904, 0x81ff, + 0x1198, 0x690c, 0xa182, 0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, + 0x6910, 0xa18a, 0x0001, 0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, + 0x00d0, 0x6013, 0x0100, 0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, + 0x0500, 0x0070, 0x6013, 0x0700, 0x0058, 0x6013, 0x0900, 0x0040, + 0x6013, 0x0b00, 0x0028, 0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, + 0xa085, 0x0001, 0x0008, 0xa006, 0x001e, 0x00de, 0x00ce, 0x0005, + 0x00c6, 0x00d6, 0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, + 0xa394, 0x00ff, 0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, + 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, + 0x0130, 0x00c6, 0x2d60, 0x080c, 0x4443, 0x00ce, 0x04c0, 0x2011, + 0x9796, 0xad98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1580, + 0x2011, 0x979a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x7aee, + 0x1538, 0x0046, 0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, + 0x2009, 0x9252, 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, + 0x90d7, 0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x6127, + 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, + 0x008e, 0x2001, 0x0007, 0x080c, 0x43f1, 0x001e, 0x004e, 0xa006, + 0x015e, 0x003e, 0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, + 0x978e, 0x6800, 0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, + 0xa006, 0x00de, 0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, + 0x0156, 0x2079, 0x978c, 0x7930, 0x7834, 0x080c, 0x240b, 0x11a0, + 0x080c, 0x4434, 0x1188, 0x2011, 0x9790, 0xac98, 0x000a, 0x20a9, + 0x0004, 0x080c, 0x7aee, 0x1140, 0x2011, 0x9794, 0xac98, 0x0006, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x015e, 0x003e, 0x002e, 0x001e, + 0x00fe, 0x00ce, 0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, + 0x0156, 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, 0x240b, + 0x11a0, 0x080c, 0x4434, 0x1188, 0x2011, 0x9796, 0xac98, 0x000a, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1140, 0x2011, 0x979a, 0xac98, + 0x0006, 0x20a9, 0x0004, 0x080c, 0x7aee, 0x015e, 0x003e, 0x002e, + 0x001e, 0x000e, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0076, 0x0066, + 0x0056, 0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2029, 0x94ee, + 0x252c, 0x2021, 0x94f4, 0x2424, 0x2061, 0x9900, 0x2071, 0x9200, + 0x7644, 0x7064, 0x8001, 0xa602, 0x1a04, 0x8f44, 0x2100, 0xac06, + 0x05d0, 0x080c, 0x90ee, 0x05b8, 0x671c, 0xa786, 0x0001, 0x0904, + 0x8f56, 0xa786, 0x0007, 0x0578, 0x2500, 0xac06, 0x0560, 0x2400, + 0xac06, 0x0548, 0x080c, 0x90fe, 0x1530, 0x88ff, 0x0118, 0x6020, + 0xa906, 0x1508, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016, + 0x080c, 0x1788, 0x001e, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0180, + 0xa786, 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x0016, 0x080c, 0x8527, 0x080c, 0x4809, 0x001e, 0x080c, 0x848f, + 0x00de, 0x080c, 0x849b, 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, + 0xac02, 0x1210, 0x0804, 0x8ef6, 0x012e, 0x002e, 0x004e, 0x005e, + 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0xa786, 0x0006, 0x19d8, + 0xa386, 0x0005, 0x0d40, 0x080c, 0x9097, 0x0c10, 0x080c, 0x90fe, + 0x1d10, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x19e0, 0x6000, + 0xa086, 0x0002, 0x19c0, 0x080c, 0x84b7, 0x0130, 0x080c, 0x84c8, + 0x1990, 0x080c, 0x7776, 0x0010, 0x080c, 0x2692, 0x080c, 0x849b, + 0x0850, 0x00c6, 0x00e6, 0x0016, 0x2c08, 0x2170, 0x080c, 0x90ab, + 0x001e, 0x0120, 0x601c, 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, + 0x0005, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f8b, + 0x8f89, 0xa006, 0x0005, 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, + 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, + 0x90d7, 0x001e, 0x004e, 0x0036, 0x2019, 0x0002, 0x080c, 0x8d4e, + 0x003e, 0xa085, 0x0001, 0x0005, 0x2001, 0x0001, 0x080c, 0x43d1, + 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x9205, + 0x2011, 0x9796, 0x080c, 0x7aee, 0x003e, 0x002e, 0x001e, 0x015e, + 0xa005, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x0026, + 0x0126, 0x2091, 0x8000, 0x2061, 0x9900, 0x2079, 0x0001, 0x8fff, + 0x0904, 0x9014, 0x2071, 0x9200, 0x7644, 0x7064, 0x8001, 0xa602, + 0x1a04, 0x9014, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15a0, 0x2079, + 0x0000, 0x080c, 0x90ee, 0x0578, 0x2400, 0xac06, 0x0560, 0x671c, + 0xa786, 0x0006, 0x1540, 0xa786, 0x0007, 0x0528, 0x88ff, 0x1140, + 0x6018, 0xa206, 0x1500, 0x85ff, 0x0118, 0x6020, 0xa106, 0x11d8, + 0x00d6, 0x6000, 0xa086, 0x0004, 0x1140, 0x601f, 0x0007, 0x2001, + 0x94dd, 0x2004, 0x6016, 0x080c, 0x1788, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0120, 0x0046, 0x080c, 0x9097, 0x004e, 0x00de, 0x080c, + 0x849b, 0x88ff, 0x1190, 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, + 0xac02, 0x1210, 0x0804, 0x8fc7, 0xa006, 0x012e, 0x002e, 0x006e, + 0x007e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0xa8c5, 0x0001, 0x0ca8, + 0x0086, 0x0056, 0x2041, 0x0000, 0x2029, 0x0001, 0x2c20, 0x2019, + 0x0002, 0x6218, 0x080c, 0x724a, 0x080c, 0x72e2, 0x080c, 0x8fba, + 0x005e, 0x008e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0086, 0x00c6, + 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, + 0x0036, 0x080c, 0x4434, 0x1170, 0x2c10, 0x2041, 0x0000, 0x2508, + 0x0056, 0x2029, 0x0001, 0x080c, 0x724a, 0x080c, 0x72e2, 0x080c, + 0x8fba, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, 0x903f, 0x015e, + 0x00ce, 0x008e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0086, 0x0056, + 0x6218, 0x2041, 0x0000, 0x2029, 0x0001, 0x2019, 0x0048, 0x080c, + 0x724a, 0x080c, 0x72e2, 0x2c20, 0x080c, 0x8fba, 0x005e, 0x008e, + 0x0005, 0x0026, 0x0046, 0x0056, 0x0086, 0x00c6, 0x0156, 0x2c20, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, 0x080c, 0x4434, + 0x1150, 0x2c10, 0x2041, 0x0000, 0x2828, 0x080c, 0x724a, 0x080c, + 0x72e2, 0x080c, 0x8fba, 0x003e, 0x001e, 0x8108, 0x1f04, 0x907c, + 0x015e, 0x00ce, 0x008e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0016, + 0x00f6, 0x8dff, 0x0168, 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, + 0x6b52, 0x080c, 0x4809, 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x4809, + 0x00fe, 0x001e, 0x0005, 0x00e6, 0x0046, 0x0036, 0x2061, 0x9900, + 0x2071, 0x9200, 0x7444, 0x7064, 0x8001, 0xa402, 0x12d8, 0x2100, + 0xac06, 0x0168, 0x6000, 0xa086, 0x0000, 0x0148, 0x6008, 0xa206, + 0x1130, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, 0x0140, 0xace0, + 0x000c, 0x2001, 0x9216, 0x2004, 0xac02, 0x1220, 0x0c08, 0xa085, + 0x0001, 0x0008, 0xa006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x00d6, + 0x0006, 0x080c, 0x147c, 0x000e, 0x090c, 0x13fe, 0x6837, 0x010d, + 0x685e, 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, 0x68b2, 0x6802, + 0x683a, 0x685a, 0x080c, 0x4809, 0x00de, 0x0005, 0x6700, 0xa786, + 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786, 0x000a, 0x0128, + 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005, 0x00e6, 0x6018, + 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0xa186, 0x0013, 0x1128, + 0x6004, 0xa082, 0x0085, 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, + 0x080c, 0x6389, 0x0036, 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, + 0x080c, 0x9097, 0x00de, 0x003e, 0x080c, 0x6462, 0x0005, 0xa186, + 0x0014, 0x0d70, 0x080c, 0x7526, 0x0005, 0x912e, 0x912c, 0x912c, + 0x912c, 0x912c, 0x912c, 0x912e, 0x080c, 0x13fe, 0x080c, 0x6389, + 0x6003, 0x000c, 0x080c, 0x6462, 0x0005, 0xa182, 0x008c, 0x1220, + 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x7526, 0x0005, 0x9146, + 0x9146, 0x9146, 0x9146, 0x9148, 0x914d, 0x9146, 0x080c, 0x13fe, + 0x00d6, 0x080c, 0x74f2, 0x00de, 0x0005, 0x080c, 0x74f2, 0x0005, + 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0x9240, 0xd5a4, 0x0118, + 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, + 0xd5ac, 0x0118, 0x2071, 0x924a, 0x0451, 0x00ee, 0x000e, 0x012e, + 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0x9240, + 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, + 0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0x924a, 0x0081, 0x00ee, + 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, + 0x2071, 0x9242, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04, + 0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005, + 0x00e6, 0x2071, 0x9240, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x9244, 0x0c69, 0x00ee, 0x0005, 0x0001, 0x0002, 0x0004, 0x0008, + 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, + 0x1000, 0x2000, 0x4000, 0x8000, 0x448c }; -unsigned short risc_code_length01 = 0x65e6; diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.14/linux/drivers/scsi/sd.c Tue Jul 6 19:08:33 1999 +++ linux/drivers/scsi/sd.c Mon Aug 23 10:14:44 1999 @@ -74,7 +74,7 @@ * Time out in seconds for disks and Magneto-opticals (which are slower). */ -#define SD_TIMEOUT (15 * HZ) +#define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \ diff -u --recursive --new-file v2.3.14/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.3.14/linux/drivers/sgi/char/shmiq.c Fri Jul 16 09:27:46 1999 +++ linux/drivers/sgi/char/shmiq.c Mon Aug 23 11:15:53 1999 @@ -241,7 +241,7 @@ return -EBADF; } -extern int sys_munmap(unsigned long addr, size_t len); +extern long sys_munmap(unsigned long addr, size_t len); static int qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg, int minor) diff -u --recursive --new-file v2.3.14/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.3.14/linux/drivers/sound/Config.in Mon Aug 9 12:13:39 1999 +++ linux/drivers/sound/Config.in Mon Aug 23 10:14:44 1999 @@ -14,6 +14,9 @@ dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate 'ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND +if [ "$CONFIG_VISWS" = "y" ]; then + dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND +fi dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then diff -u --recursive --new-file v2.3.14/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.14/linux/drivers/sound/Makefile Thu Aug 12 12:18:32 1999 +++ linux/drivers/sound/Makefile Mon Aug 23 10:14:44 1999 @@ -72,6 +72,7 @@ obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o +obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o diff -u --recursive --new-file v2.3.14/linux/drivers/sound/ac97.h linux/drivers/sound/ac97.h --- v2.3.14/linux/drivers/sound/ac97.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/ac97.h Mon Aug 23 11:15:27 1999 @@ -0,0 +1,101 @@ +/* + * ac97.h + * + * definitions for the AC97, Intel's Audio Codec 97 Spec + */ + +#ifndef _AC97_H_ +#define _AC97_H_ + + // conections on concert 97 */ +#define AC97_RESET 0x0000 // */ +#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out +#define AC97_HEADPHONE_VOL 0x0004 // +#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output +#define AC97_MASTER_TONE 0x0008 // +#define AC97_PCBEEP_VOL 0x000a // none +#define AC97_PHONE_VOL 0x000c // TAD Input (mono) +#define AC97_MIC_VOL 0x000e // MIC Input (mono) +#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo) +#define AC97_CD_VOL 0x0012 // CD Input (stereo) +#define AC97_VIDEO_VOL 0x0014 // none +#define AC97_AUX_VOL 0x0016 // Aux Input (stereo) +#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo) +#define AC97_RECORD_SELECT 0x001a // +#define AC97_RECORD_GAIN 0x001c +#define AC97_RECORD_GAIN_MIC 0x001e +#define AC97_GENERAL_PURPOSE 0x0020 +#define AC97_3D_CONTROL 0x0022 +#define AC97_MODEM_RATE 0x0024 +#define AC97_POWER_CONTROL 0x0026 + +/* registers 0x0028 - 0x0058 are reserved */ + +/* registers 0x005a - 0x007a are vendor reserved */ + +#define AC97_VENDOR_ID1 0x007c +#define AC97_VENDOR_ID2 0x007e + + +/* volume control bit defines */ + +#define AC97_MUTE 0x8000 +#define AC97_MICBOOST 0x0040 +#define AC97_LEFTVOL 0x3f00 +#define AC97_RIGHTVOL 0x003f + +/* record mux defines */ + +#define AC97_RECMUX_MIC 0x0000 +#define AC97_RECMUX_CD 0x0101 +#define AC97_RECMUX_VIDEO 0x0202 /* not used */ +#define AC97_RECMUX_AUX 0x0303 +#define AC97_RECMUX_LINE 0x0404 +#define AC97_RECMUX_STEREO_MIX 0x0505 +#define AC97_RECMUX_MONO_MIX 0x0606 +#define AC97_RECMUX_PHONE 0x0707 + + +/* general purpose register bit defines */ + +#define AC97_GP_LPBK 0x0080 /* Loopback mode */ +#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */ +#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */ +#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */ +#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */ +#define AC97_GP_LD 0x1000 /* Loudness 1=on */ +#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */ +#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */ +#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ + + +/* powerdown control and status bit defines */ + +/* status */ +#define AC97_PWR_MDM 0x0010 /* Modem section ready */ +#define AC97_PWR_REF 0x0008 /* Vref nominal */ +#define AC97_PWR_ANL 0x0004 /* Analog section ready */ +#define AC97_PWR_DAC 0x0002 /* DAC section ready */ +#define AC97_PWR_ADC 0x0001 /* ADC section ready */ + +/* control */ +#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */ +#define AC97_PWR_PR1 0x0200 /* DAC powerdown */ +#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */ +#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */ +#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */ +#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */ +#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */ +#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */ + +/* useful power states */ +#define AC97_PWR_D0 0x0000 /* everything on */ +#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4 +#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 +#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 +#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */ + +#endif /* _AC97_H_ */ + + + diff -u --recursive --new-file v2.3.14/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.3.14/linux/drivers/sound/dmasound.c Wed Aug 18 10:01:36 1999 +++ linux/drivers/sound/dmasound.c Mon Aug 23 10:14:44 1999 @@ -5161,7 +5161,7 @@ if (nbufs < 2 || nbufs > numBufs) nbufs = numBufs; size &= 0xffff; - if (size >= 8 && size <= 30) { + if (size >= 8 && size <= 29) { size = 1 << size; size *= sound.hard.size * (sound.hard.stereo + 1); size /= sound.soft.size * (sound.soft.stereo + 1); diff -u --recursive --new-file v2.3.14/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.14/linux/drivers/sound/es1370.c Thu Aug 12 12:21:47 1999 +++ linux/drivers/sound/es1370.c Mon Aug 23 11:15:27 1999 @@ -107,6 +107,7 @@ * added kernel command line option "es1370=joystick[,lineout[,micbias]]" * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge * 12.08.99 0.27 module_init/__setup fixes + * 19.08.99 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca * * some important things missing in Ensoniq documentation: * @@ -793,10 +794,36 @@ [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */ }; +static void set_recsrc(struct es1370_state *s, unsigned int val) +{ + unsigned int i, j; + + for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!(val & (1 << i))) + continue; + if (!mixtable[i].recmask) { + val &= ~(1 << i); + continue; + } + j |= mixtable[i].recmask; + } + s->mix.recsrc = val; + wrcodec(s, 0x12, j & 0xd5); + wrcodec(s, 0x13, j & 0xaa); + wrcodec(s, 0x14, (j >> 8) & 0x17); + wrcodec(s, 0x15, (j >> 8) & 0x0f); + i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60; + if (!s->mix.imix) { + i &= 0xff60; /* mute record and line monitor */ + } + wrcodec(s, 0x10, i); + wrcodec(s, 0x11, i >> 8); +} + static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg) { unsigned long flags; - int i, val, j; + int i, val; unsigned char l, r, rl, rr; VALIDATE_STATE(s); @@ -901,34 +928,13 @@ switch (_IOC_NR(cmd)) { case SOUND_MIXER_IMIX: - if (arg == 0) - return -EFAULT; - get_user_ret(s->mix.imix,(int *)arg, -EFAULT); - val = s->mix.recsrc; - /* fall through */ + get_user_ret(s->mix.imix, (int *)arg, -EFAULT); + set_recsrc(s, s->mix.recsrc); + return 0; case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ get_user_ret(val, (int *)arg, -EFAULT); - for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!(val & (1 << i))) - continue; - if (!mixtable[i].recmask) { - val &= ~(1 << i); - continue; - } - j |= mixtable[i].recmask; - } - s->mix.recsrc = val; - wrcodec(s, 0x12, j & 0xd5); - wrcodec(s, 0x13, j & 0xaa); - wrcodec(s, 0x14, (j >> 8) & 0x17); - wrcodec(s, 0x15, (j >> 8) & 0x0f); - i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60; - if (!s->mix.imix) { - i &= 0xff60; /* mute record and line monitor */ - } - wrcodec(s, 0x10, i); - wrcodec(s, 0x11, i >> 8); + set_recsrc(s, val); return 0; default: @@ -2340,7 +2346,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.27 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.28 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->resource[0].flags == 0 || diff -u --recursive --new-file v2.3.14/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.14/linux/drivers/sound/es1371.c Thu Aug 12 12:21:48 1999 +++ linux/drivers/sound/es1371.c Mon Aug 23 11:15:27 1999 @@ -74,6 +74,13 @@ * 10.08.99 0.15 (Re)added S/PDIF module option for cards revision >= 4. * Initial version by Dave Platt . * module_init/__setup fixes + * 08.16.99 0.16 Joe Cotellese + * Added detection for ES1371 revision ID so that we can + * detect the ES1373 and later parts. + * added AC97 #defines for readability + * added a /proc file system for dumping hardware state + * updated SRC and CODEC w/r functions to accomodate bugs + * in some versions of the ES137x chips. * */ @@ -89,17 +96,21 @@ #include #include #include -#include -#include #include #include +#include +#include +#include +#include #include #include #include +#include "ac97.h" /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS +#define ES1371_DEBUG /* --------------------------------------------------------------------- */ @@ -110,6 +121,18 @@ #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 #endif +/* ES1371 chip ID */ +/* This is a little confusing because all ES1371 compatible chips have the + same DEVICE_ID, the only thing differentiating them is the REV_ID field. + This is only significant if you want to enable features on the later parts. + Yes, I know it's stupid and why didn't we use the sub IDs? +*/ +#define ES1371REV_ES1373_A 0x04 +#define ES1371REV_ES1373_B 0x06 +#define ES1371REV_CT5880_A 0x07 +#define ES1371REV_ES1371_B 0x09 + + #define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371) #define ES1371_EXTENT 0x40 @@ -209,14 +232,22 @@ #define UCTRL_CNTRL_SWR 0x03 /* software reset command */ /* sample rate converter */ +#define SRC_OKSTATE 1 + #define SRC_RAMADDR_MASK 0xfe000000 #define SRC_RAMADDR_SHIFT 25 +#define SRC_DAC1FREEZE (1UL << 21) +#define SRC_DAC2FREEZE (1UL << 20) +#define SRC_ADCFREEZE (1UL << 19) + + #define SRC_WE 0x01000000 /* read/write control for SRC RAM */ #define SRC_BUSY 0x00800000 /* SRC busy */ #define SRC_DIS 0x00400000 /* 1 = disable SRC */ #define SRC_DDAC1 0x00200000 /* 1 = disable accum update for DAC1 */ #define SRC_DDAC2 0x00100000 /* 1 = disable accum update for DAC2 */ #define SRC_DADC 0x00080000 /* 1 = disable accum update for ADC2 */ +#define SRC_CTLMASK 0x00780000 #define SRC_RAMDATA_MASK 0x0000ffff #define SRC_RAMDATA_SHIFT 0 @@ -296,7 +327,7 @@ /* misc stuff */ - +#define POLL_COUNT 0x1000 #define FMODE_DAC 4 /* slight misuse of mode_t */ /* MIDI buffer sizes */ @@ -355,8 +386,13 @@ /* hardware resources */ unsigned long io; /* long for SPARC */ unsigned int irq; - - /* mixer registers; there is no HW readback */ + u8 rev; /* the chip revision */ + +#ifdef ES1371_DEBUG + /* debug /proc entry */ + struct proc_dir_entry *ps; +#endif /* ES1371_DEBUG */ + /* mixer registers; there is no HW readback */ struct { unsigned short codec_id; unsigned int modcnt; @@ -441,31 +477,12 @@ } /* --------------------------------------------------------------------- */ -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ - -#ifdef hweight32 -#undef hweight32 -#endif - -extern __inline__ unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - -/* --------------------------------------------------------------------- */ static unsigned wait_src_ready(struct es1371_state *s) { unsigned int t, r; - for (t = 0; t < 1000; t++) { + for (t = 0; t < POLL_COUNT; t++) { if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY)) return r; udelay(1); @@ -476,29 +493,53 @@ static unsigned src_read(struct es1371_state *s, unsigned reg) { - unsigned int r; + unsigned int temp,i,orig; - r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC); - r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK; - outl(r, s->io + ES1371_REG_SRCONV); - return (wait_src_ready(s) & SRC_RAMDATA_MASK) >> SRC_RAMDATA_SHIFT; -} + /* wait for ready */ + temp = wait_src_ready (s); + /* we can only access the SRC at certain times, make sure + we're allowed to before we read */ + + orig = temp; + /* expose the SRC state bits */ + outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL, + s->io + ES1371_REG_SRCONV); + + /* now, wait for busy and the correct time to read */ + temp = wait_src_ready (s); + + if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){ + /* wait for the right state */ + for (i=0; iio + ES1371_REG_SRCONV); + if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 )) + break; + } + } + + /* hide the state bits */ + outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV); + return temp; + + +} static void src_write(struct es1371_state *s, unsigned reg, unsigned data) { + unsigned int r; r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC); r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK; r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK; outl(r | SRC_WE, s->io + ES1371_REG_SRCONV); + } /* --------------------------------------------------------------------- */ /* most of the following here is black magic */ - static void set_adc_rate(struct es1371_state *s, unsigned rate) { unsigned long flags; @@ -535,6 +576,7 @@ spin_unlock_irqrestore(&s->lock, flags); } + static void set_dac1_rate(struct es1371_state *s, unsigned rate) { unsigned long flags; @@ -569,6 +611,7 @@ rate = 4000; freq = (rate << 15) / 3000; s->dac2rate = (freq * 3000) >> 15; + printk (KERN_DEBUG "dac2 freq: %d\n", freq); spin_lock_irqsave(&s->lock, flags); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2; outl(r, s->io + ES1371_REG_SRCONV); @@ -583,26 +626,80 @@ /* --------------------------------------------------------------------- */ +static void __init src_init(struct es1371_state *s) +{ + unsigned int i; + + /* before we enable or disable the SRC we need + to wait for it to become ready */ + wait_src_ready(s); + + outl(SRC_DIS, s->io + ES1371_REG_SRCONV); + + for (i = 0; i < 0x80; i++) + src_write(s, i, 0); + + src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4); + src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10); + src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4); + src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10); + src_write(s, SRCREG_VOL_ADC, 1 << 12); + src_write(s, SRCREG_VOL_ADC+1, 1 << 12); + src_write(s, SRCREG_VOL_DAC1, 1 << 12); + src_write(s, SRCREG_VOL_DAC1+1, 1 << 12); + src_write(s, SRCREG_VOL_DAC2, 1 << 12); + src_write(s, SRCREG_VOL_DAC2+1, 1 << 12); + set_adc_rate(s, 22050); + set_dac1_rate(s, 22050); + set_dac2_rate(s, 22050); + + /* WARNING: + * enabling the sample rate converter without properly programming + * its parameters causes the chip to lock up (the SRC busy bit will + * be stuck high, and I've found no way to rectify this other than + * power cycle) + */ + wait_src_ready(s); + outl(0, s->io+ES1371_REG_SRCONV); +} + +/* --------------------------------------------------------------------- */ + static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data) { unsigned long flags; unsigned t, x; - - for (t = 0; t < 0x1000; t++) + + for (t = 0; t < POLL_COUNT; t++) if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) break; spin_lock_irqsave(&s->lock, flags); - /* save the current state for later */ - x = inl(s->io+ES1371_REG_SRCONV); - /* enable SRC state data in SRC mux */ - outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, + + /* save the current state for later */ + x = wait_src_ready(s); + + /* enable SRC state data in SRC mux */ + outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, s->io+ES1371_REG_SRCONV); - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t = 0; t < 0x1000; t++) - if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000) - break; + + /* wait for not busy (state 0) first to avoid + transition states */ + for (t=0; tio+ES1371_REG_SRCONV) & 0x00870000) ==0 ) + break; + udelay(1); + } + + /* wait for a SAFE time to write addr/data and then do it, dammit */ + for (t=0; tio+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) + break; + udelay(1); + } + outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC); + /* restore SRC reg */ wait_src_ready(s); outl(x, s->io+ES1371_REG_SRCONV); @@ -614,28 +711,50 @@ unsigned long flags; unsigned t, x; + /* wait for WIP to go away */ for (t = 0; t < 0x1000; t++) if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) break; spin_lock_irqsave(&s->lock, flags); + /* save the current state for later */ - x = inl(s->io+ES1371_REG_SRCONV); + x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)); + /* enable SRC state data in SRC mux */ - outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, - s->io+ES1371_REG_SRCONV); - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t = 0; t < 0x1000; t++) - if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000) - break; + outl( x | 0x00010000, + s->io+ES1371_REG_SRCONV); + + /* wait for not busy (state 0) first to avoid + transition states */ + for (t=0; tio+ES1371_REG_SRCONV) & 0x00870000) ==0 ) + break; + udelay(1); + } + + /* wait for a SAFE time to write addr/data and then do it, dammit */ + for (t=0; tio+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) + break; + udelay(1); + } + outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC); /* restore SRC reg */ wait_src_ready(s); outl(x, s->io+ES1371_REG_SRCONV); spin_unlock_irqrestore(&s->lock, flags); - /* now wait for the stinkin' data (RDY) */ + + /* wait for WIP again */ for (t = 0; t < 0x1000; t++) + if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) + break; + + /* now wait for the stinkin' data (RDY) */ + for (t = 0; t < POLL_COUNT; t++) if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY) break; + return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT); } @@ -996,6 +1115,21 @@ /* --------------------------------------------------------------------- */ +/* + * AC97 Mixer Register to Connections mapping of the Concert 97 board + * + * AC97_MASTER_VOL_STEREO Line Out + * AC97_MASTER_VOL_MONO TAD Output + * AC97_PCBEEP_VOL none + * AC97_PHONE_VOL TAD Input (mono) + * AC97_MIC_VOL MIC Input (mono) + * AC97_LINEIN_VOL Line Input (stereo) + * AC97_CD_VOL CD Input (stereo) + * AC97_VIDEO_VOL none + * AC97_AUX_VOL Aux Input (stereo) + * AC97_PCMOUT_VOL Wave Output (stereo) + */ + #define AC97_PESSIMISTIC /* @@ -1021,25 +1155,25 @@ static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { /* 5 bit stereo */ - [SOUND_MIXER_LINE] = 0x10, - [SOUND_MIXER_CD] = 0x12, - [SOUND_MIXER_VIDEO] = 0x14, - [SOUND_MIXER_LINE1] = 0x16, - [SOUND_MIXER_PCM] = 0x18, + [SOUND_MIXER_LINE] = AC97_LINEIN_VOL, + [SOUND_MIXER_CD] = AC97_CD_VOL, + [SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL, + [SOUND_MIXER_LINE1] = AC97_AUX_VOL, + [SOUND_MIXER_PCM] = AC97_PCMOUT_VOL, /* 6 bit stereo */ - [SOUND_MIXER_VOLUME] = 0x02, - [SOUND_MIXER_PHONEOUT] = 0x04, + [SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO, + [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL, /* 6 bit mono */ - [SOUND_MIXER_OGAIN] = 0x06, - [SOUND_MIXER_PHONEIN] = 0x0c, + [SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO, + [SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL, /* 4 bit mono but shifted by 1 */ - [SOUND_MIXER_SPEAKER] = 0x08, + [SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE, /* 6 bit mono + preamp */ - [SOUND_MIXER_MIC] = 0x0e, + [SOUND_MIXER_MIC] = AC97_MIC_VOL, /* 4 bit stereo */ - [SOUND_MIXER_RECLEV] = 0x1c, + [SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN, /* 4 bit mono */ - [SOUND_MIXER_IGAIN] = 0x1e + [SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC }; #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -1052,8 +1186,8 @@ switch (ch) { case SOUND_MIXER_MIC: - j = rdcodec(s, 0x0e); - if (j & 0x8000) + j = rdcodec(s, AC97_MIC_VOL); + if (j & AC97_MUTE) return put_user(0, (int *)arg); #ifdef AC97_PESSIMISTIC return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg); @@ -1064,7 +1198,7 @@ case SOUND_MIXER_OGAIN: case SOUND_MIXER_PHONEIN: j = rdcodec(s, volreg[ch]); - if (j & 0x8000) + if (j & AC97_MUTE) return put_user(0, (int *)arg); #ifdef AC97_PESSIMISTIC return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg); @@ -1078,7 +1212,7 @@ /* fall through */ case SOUND_MIXER_VOLUME: j = rdcodec(s, volreg[ch]); - if (j & 0x8000) + if (j & AC97_MUTE) return put_user(0, (int *)arg); #ifdef AC97_PESSIMISTIC return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg); @@ -1087,8 +1221,8 @@ #endif /* AC97_PESSIMISTIC */ case SOUND_MIXER_SPEAKER: - j = rdcodec(s, 0x0a); - if (j & 0x8000) + j = rdcodec(s, AC97_PCBEEP_VOL); + if (j & AC97_MUTE return put_user(0, (int *)arg); return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg); @@ -1098,7 +1232,7 @@ case SOUND_MIXER_LINE1: case SOUND_MIXER_PCM: j = rdcodec(s, volreg[ch]); - if (j & 0x8000) + if (j & AC97_MUTE) return put_user(0, (int *)arg); return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg); @@ -1106,23 +1240,23 @@ case SOUND_MIXER_TREBLE: if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE)) return -EINVAL; - j = rdcodec(s, 0x08); + j = rdcodec(s, AC97_MASTER_TONE); if (ch == SOUND_MIXER_BASS) j >>= 8; return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg); /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */ case SOUND_MIXER_RECLEV: - j = rdcodec(s, 0x1c); - if (j & 0x8000) + j = rdcodec(s, AC97_RECORD_GAIN); + if (j & AC97_MUTE) return put_user(0, (int *)arg); return put_user((swab(j) & 0xf0f) * 6 + 0xa0a, (int *)arg); case SOUND_MIXER_IGAIN: if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC)) return -EINVAL; - j = rdcodec(s, 0x1e); - if (j & 0x8000) + j = rdcodec(s, AC97_RECORD_GAIN_MIC); + if (j & AC97_MUTE) return put_user(0, (int *)arg); return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg); @@ -1177,7 +1311,7 @@ case SOUND_MIXER_LINE1: case SOUND_MIXER_PCM: if (l1 < 7 && r1 < 7) { - wrcodec(s, volreg[ch], 0x8000); + wrcodec(s, volreg[ch], AC97_MUTE); return 0; } if (l1 < 7) @@ -1194,7 +1328,7 @@ case SOUND_MIXER_VOLUME: #ifdef AC97_PESSIMISTIC if (l1 < 7 && r1 < 7) { - wrcodec(s, volreg[ch], 0x8000); + wrcodec(s, volreg[ch], AC97_MUTE); return 0; } if (l1 < 7) @@ -1205,7 +1339,7 @@ return 0; #else /* AC97_PESSIMISTIC */ if (l1 < 4 && r1 < 4) { - wrcodec(s, volreg[ch], 0x8000); + wrcodec(s, volreg[ch], AC97_MUTE); return 0; } if (l1 < 4) @@ -1219,21 +1353,21 @@ case SOUND_MIXER_OGAIN: case SOUND_MIXER_PHONEIN: #ifdef AC97_PESSIMISTIC - wrcodec(s, volreg[ch], (l1 < 7) ? 0x8000 : (100 - l1) / 3); + wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3); return 0; #else /* AC97_PESSIMISTIC */ - wrcodec(s, volreg[ch], (l1 < 4) ? 0x8000 : (2 * (100 - l1) / 3)); + wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3)); return 0; #endif /* AC97_PESSIMISTIC */ case SOUND_MIXER_SPEAKER: - wrcodec(s, 0x0a, (l1 < 10) ? 0x8000 : ((100 - l1) / 6) << 1); + wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1); return 0; case SOUND_MIXER_MIC: #ifdef AC97_PESSIMISTIC if (l1 < 11) { - wrcodec(s, 0x0e, 0x8000); + wrcodec(s, AC97_MIC_VOL, AC97_MUTE); return 0; } i = 0; @@ -1243,11 +1377,11 @@ } if (l1 < 11) l1 = 11; - wrcodec(s, 0x0e, ((73 - l1) / 2) | i); + wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i); return 0; #else /* AC97_PESSIMISTIC */ if (l1 < 9) { - wrcodec(s, 0x0e, 0x8000); + wrcodec(s, AC97_MIC_VOL, AC97_MUTE); return 0; } i = 0; @@ -1257,37 +1391,37 @@ } if (l1 < 9) l1 = 9; - wrcodec(s, 0x0e, (((87 - l1) * 4) / 5) | i); + wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i); return 0; #endif /* AC97_PESSIMISTIC */ case SOUND_MIXER_BASS: val = ((l1 * 15) / 100) & 0xf; - wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0x00ff) | (val << 8)); + wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8)); return 0; case SOUND_MIXER_TREBLE: val = ((l1 * 15) / 100) & 0xf; - wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0xff00) | val); + wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val); return 0; /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */ case SOUND_MIXER_RECLEV: if (l1 < 10 || r1 < 10) { - wrcodec(s, 0x1c, 0x8000); + wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE); return 0; } if (l1 < 10) l1 = 10; if (r1 < 10) r1 = 10; - wrcodec(s, 0x1c, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6)); + wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6)); return 0; case SOUND_MIXER_IGAIN: if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC)) return -EINVAL; - wrcodec(s, 0x1e, (l1 < 10) ? 0x8000 : ((l1 - 10) / 6) & 0xf); + wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf); return 0; default: @@ -1305,8 +1439,8 @@ return -EINVAL; get_user_ret(val, (int *)arg, -EFAULT); if (val & 1) - wrcodec(s, 0x22, ((val << 3) & 0xf00) | ((val >> 1) & 0xf)); - val = rdcodec(s, 0x22); + wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf)); + val = rdcodec(s, AC97_3D_CONTROL); return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg); } if (cmd == SOUND_MIXER_INFO) { @@ -1333,7 +1467,7 @@ if (_IOC_DIR(cmd) == _IOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - return put_user(recsrc[rdcodec(s, 0x1a) & 7], (int *)arg); + return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO | @@ -1380,10 +1514,10 @@ if (i == 0) return 0; /*val = mixer_recmask(s);*/ else if (i > 1) - val &= ~recsrc[rdcodec(s, 0x1a) & 7]; + val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7]; for (i = 0; i < 8; i++) { if (val & recsrc[i]) { - wrcodec(s, 0x1a, 0x101 * i); + wrcodec(s, AC97_RECORD_SELECT, 0x101 * i); return 0; } } @@ -1473,8 +1607,9 @@ if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; - current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac1.wait, &wait); + current->state = TASK_INTERRUPTIBLE; for (;;) { spin_lock_irqsave(&s->lock, flags); count = s->dma_dac1.count; @@ -1491,7 +1626,7 @@ tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "es1371: dma timed out??\n"); + printk(KERN_DEBUG "es1371: dac1 dma timed out??\n"); } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1508,8 +1643,9 @@ if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; - current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac2.wait, &wait); + current->state = TASK_UNINTERRUPTIBLE; for (;;) { spin_lock_irqsave(&s->lock, flags); count = s->dma_dac2.count; @@ -1526,7 +1662,7 @@ tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "es1371: dma timed out??\n"); + printk(KERN_DEBUG "es1371: dac2 dma timed out??\n"); } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -1753,6 +1889,7 @@ if (file->f_mode & FMODE_WRITE) { stop_dac2(s); s->dma_dac2.ready = 0; + printk (KERN_DEBUG "es137x: setting DAC2 rate: %d\n", val); set_dac2_rate(s, val); } } @@ -2700,6 +2837,44 @@ /* --------------------------------------------------------------------- */ +/* + * for debugging purposes, we'll create a proc device that dumps the + * CODEC chipstate + */ + +#ifdef ES1371_DEBUG +static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data) +{ + int len = 0; + + struct es1371_state *s = devs; + int cnt; + + /* print out header */ + len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n"); + + /* print out CODEC state */ + len += sprintf (buf + len, "AC97 CODEC state\n"); + + for (cnt=0; cnt <= 0x7e; cnt = cnt +2) + len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s , cnt)); + + if (fpos >=len){ + *start = buf; + *eof =1; + return 0; + } + *start = buf + fpos; + if ((len -= fpos) > length) + return length; + *eof =1; + return len; + +} +#endif /* ES1371_DEBUG */ + +/* --------------------------------------------------------------------- */ + /* maximum number of devices */ #define NR_DEVICE 5 @@ -2741,7 +2916,6 @@ struct pci_dev *pcidev = NULL; mm_segment_t fs; int i, val, val2, index = 0; - u8 revision; unsigned cssr; if (!pci_present()) /* No PCI bus in this machine! */ @@ -2769,6 +2943,7 @@ s->magic = ES1371_MAGIC; s->io = pcidev->resource[0].start; s->irq = pcidev->irq; + pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); if (check_region(s->io, ES1371_EXTENT)) { printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; @@ -2778,8 +2953,8 @@ printk(KERN_ERR "es1371: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "es1371: found adapter at io %#lx irq %u\n" - KERN_INFO "es1371: features: joystick 0x%x\n", s->io, s->irq, joystick[index]); + printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" + KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) goto err_dev1; @@ -2789,6 +2964,13 @@ goto err_dev3; if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0) goto err_dev4; +#ifdef ES1371_DEBUG + /* intialize the debug proc device */ + s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL); + if (s->ps) + s->ps->read_proc = proc_es1371_dump; +#endif /* ES1371_DEBUG */ + /* initialize codec registers */ s->ctrl = 0; if ((joystick[index] & ~0x18) == 0x200) { @@ -2801,14 +2983,13 @@ s->sctrl = 0; cssr = 0; /* check to see if s/pdif mode is being requested */ - pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision); if (spdif[index]) { - if (revision >= 4) { + if (s->rev >= 4) { printk(KERN_INFO "es1371: enabling S/PDIF output\n"); cssr |= STAT_EN_SPDIF; s->ctrl |= CTRL_SPDIFEN_B; } else { - printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", revision); + printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev); } } /* initialize the chips */ @@ -2821,35 +3002,12 @@ udelay(2); outl(s->ctrl, s->io+ES1371_REG_CONTROL); /* init the sample rate converter */ - outl(SRC_DIS, s->io + ES1371_REG_SRCONV); - for (val = 0; val < 0x80; val++) - src_write(s, val, 0); - src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_VOL_ADC, 1 << 12); - src_write(s, SRCREG_VOL_ADC+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC2, 1 << 12); - src_write(s, SRCREG_VOL_DAC2+1, 1 << 12); - set_adc_rate(s, 22050); - set_dac1_rate(s, 22050); - set_dac2_rate(s, 22050); - /* WARNING: - * enabling the sample rate converter without properly programming - * its parameters causes the chip to lock up (the SRC busy bit will - * be stuck high, and I've found no way to rectify this other than - * power cycle) - */ - wait_src_ready(s); - outl(0, s->io+ES1371_REG_SRCONV); + src_init(s); /* codec init */ - wrcodec(s, 0x00, 0); /* reset codec */ - s->mix.codec_id = rdcodec(s, 0x00); /* get codec ID */ - val = rdcodec(s, 0x7c); - val2 = rdcodec(s, 0x7e); + wrcodec(s, AC97_RESET, 0); /* reset codec */ + s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */ + val = rdcodec(s, AC97_VENDOR_ID1); + val2 = rdcodec(s, AC97_VENDOR_ID2); printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n", (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff); printk(KERN_INFO "es1371: codec features"); @@ -2876,6 +3034,7 @@ printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none"); val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK; printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown"); + fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE; @@ -2918,6 +3077,10 @@ while ((s = devs)) { devs = devs->next; +#ifdef ES1371_DEBUG + if (s->ps) + remove_proc_entry("es1371", NULL); +#endif /* ES1371_DEBUG */ outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */ outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ synchronize_irq(); diff -u --recursive --new-file v2.3.14/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.3.14/linux/drivers/sound/mad16.c Sun Mar 7 15:22:06 1999 +++ linux/drivers/sound/mad16.c Mon Aug 23 10:14:44 1999 @@ -668,7 +668,7 @@ * Set the IRQ and DMA addresses. */ - if (board_type == C930) + if (board_type == C930 || c924pnp) interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ bits = interrupt_bits[hw_config->irq]; @@ -889,7 +889,7 @@ int cdtype = 0; int cdirq = 0; int cdport = 0x340; -int cddma = 3; +int cddma = -1; int opl4 = 0; int joystick = 0; @@ -949,23 +949,28 @@ break; case 0x02: printk("Sony CDU31A"); - dmatype = 2; + dmatype = 1; + if(cddma == -1) cddma = 3; break; case 0x04: printk("Mitsumi"); - dmatype = 1; + dmatype = 0; + if(cddma == -1) cddma = 5; break; case 0x06: printk("Panasonic Lasermate"); - dmatype = 2; + dmatype = 1; + if(cddma == -1) cddma = 3; break; case 0x08: printk("Secondary IDE"); - dmatype = 1; + dmatype = 0; + if(cddma == -1) cddma = 5; break; case 0x0A: printk("Primary IDE"); - dmatype = 1; + dmatype = 0; + if(cddma == -1) cddma = 5; break; default: printk("\n"); @@ -973,8 +978,16 @@ return -EINVAL; } - if (dmatype) - { + /* + * Build the config words + */ + + mad16_conf = (joystick ^ 1) | cdtype; + mad16_cdsel = 0; + if (opl4) + mad16_cdsel |= 0x20; + + if(cdtype){ if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) { printk("\n"); @@ -985,58 +998,51 @@ printk(", DMA %d", cddma); else printk(", no DMA"); - } - if (cdtype && !cdirq) - printk(", no IRQ"); - else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) - { - printk(", invalid IRQ (disabling)"); - cdirq = 0; - } - else printk(", IRQ %d", cdirq); - printk(".\n"); - printk(KERN_INFO "Joystick port "); - if (joystick == 1) - printk("enabled.\n"); - else - { - joystick = 0; - printk("disabled.\n"); - } - - /* - * Build the config words - */ + if (!cdirq) + printk(", no IRQ"); + else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) + { + printk(", invalid IRQ (disabling)"); + cdirq = 0; + } + else printk(", IRQ %d", cdirq); - mad16_conf = (joystick ^ 1) | cdtype; - mad16_cdsel = 0; - if (opl4) - mad16_cdsel |= 0x20; - mad16_cdsel |= dma_map[dmatype][cddma]; + mad16_cdsel |= dma_map[dmatype][cddma]; - if (cdtype < 0x08) - { - switch (cdport) + if (cdtype < 0x08) { - case 0x340: - mad16_cdsel |= 0x00; - break; - case 0x330: - mad16_cdsel |= 0x40; - break; - case 0x360: - mad16_cdsel |= 0x80; - break; - case 0x320: - mad16_cdsel |= 0xC0; - break; - default: - printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport); - return -EINVAL; + switch (cdport) + { + case 0x340: + mad16_cdsel |= 0x00; + break; + case 0x330: + mad16_cdsel |= 0x40; + break; + case 0x360: + mad16_cdsel |= 0x80; + break; + case 0x320: + mad16_cdsel |= 0xC0; + break; + default: + printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport); + return -EINVAL; + } } + mad16_cdsel |= irq_map[cdirq]; } - mad16_cdsel |= irq_map[cdirq]; + + printk(".\n"); + printk(KERN_INFO "Joystick port "); + if (joystick == 1) + printk("enabled.\n"); + else + { + joystick = 0; + printk("disabled.\n"); + } config.io_base = io; config.irq = irq; diff -u --recursive --new-file v2.3.14/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.3.14/linux/drivers/sound/mpu401.c Thu May 14 10:33:17 1998 +++ linux/drivers/sound/mpu401.c Mon Aug 23 10:14:44 1999 @@ -437,6 +437,15 @@ devc->m_busy = 0; } +int intchk_mpu401(void *dev_id) +{ + struct mpu_config *devc; + int dev = (int) dev_id; + + devc = &dev_conf[dev]; + return input_avail(devc); +} + void mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { struct mpu_config *devc; @@ -1715,6 +1724,7 @@ EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); +EXPORT_SYMBOL(intchk_mpu401); EXPORT_SYMBOL(mpuintr); #ifdef MODULE diff -u --recursive --new-file v2.3.14/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.3.14/linux/drivers/sound/sb_common.c Wed Aug 4 15:48:00 1999 +++ linux/drivers/sound/sb_common.c Mon Aug 23 10:14:44 1999 @@ -116,7 +116,8 @@ #if defined(CONFIG_MIDI)&& defined(CONFIG_UART401) if (src & 4) /* MPU401 interrupt */ - uart401intr(devc->irq, devc->midi_irq_cookie, NULL); + if(devc->midi_irq_cookie) + uart401intr(devc->irq, devc->midi_irq_cookie, NULL); #endif if (!(src & 3)) @@ -897,7 +898,7 @@ } if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI)) { - if (devc->irq > 0); + if (devc->irq > 0) free_irq(devc->irq, devc); sound_unload_mixerdev(devc->my_mixerdev); diff -u --recursive --new-file v2.3.14/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c --- v2.3.14/linux/drivers/sound/sb_ess.c Tue Jul 6 10:11:40 1999 +++ linux/drivers/sound/sb_ess.c Mon Aug 23 10:14:44 1999 @@ -1200,6 +1200,17 @@ /* AAS: info stolen from ALSA: these boards have different clocks */ switch(devc->submodel) { +/* APPARENTLY NOT 1869 + case SUBMDL_ES1869: +*/ + case SUBMDL_ES1887: + case SUBMDL_ES1888: + devc->caps |= SB_CAP_ES18XX_RATE; + break; + } + + /* AAS: info stolen from ALSA: these boards have different clocks */ + switch(devc->submodel) { case SUBMDL_ES1869: case SUBMDL_ES1887: case SUBMDL_ES1888: diff -u --recursive --new-file v2.3.14/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.3.14/linux/drivers/sound/sound_calls.h Mon Jul 5 19:58:25 1999 +++ linux/drivers/sound/sound_calls.h Mon Aug 23 10:14:44 1999 @@ -157,6 +157,7 @@ /* From mpu401.c */ void attach_mpu401(struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +int intchk_mpu401(void *dev_id); void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); /* From uart6850.c */ diff -u --recursive --new-file v2.3.14/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.3.14/linux/drivers/sound/sound_core.c Wed Aug 4 09:27:54 1999 +++ linux/drivers/sound/sound_core.c Mon Aug 23 10:14:44 1999 @@ -395,5 +395,8 @@ #ifdef CONFIG_SOUND_MSNDPIN msnd_pinnacle_init(); #endif +#ifdef CONFIG_SOUND_VWSND + init_vwsnd(); +#endif return 0; } diff -u --recursive --new-file v2.3.14/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.3.14/linux/drivers/sound/vwsnd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vwsnd.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,3524 @@ +/* + * Sound driver for Silicon Graphics 320 and 540 Visual Workstations' + * onboard audio. See notes in ../../Documentation/sound/vwsnd . + * + * Copyright 1999 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#undef VWSND_DEBUG /* define for debugging */ + +/* + * XXX to do - + * + * External sync. + * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational. + * Bug - if select() called before read(), pcm_setup() not called. + * Bug - output doesn't stop soon enough if process killed. + */ + +/* + * Things to test - + * + * Will readv/writev work? Write a test. + * + * insmod/rmmod 100 million times. + * + * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT + * rate). + * + * Concurrent threads banging on mixer simultaneously, both UP + * and SMP kernels. Especially, watch for thread A changing + * OUTSRC while thread B changes gain -- both write to the same + * ad1843 register. + * + * What happens if a client opens /dev/audio then forks? + * Do two procs have /dev/audio open? Test. + * + * Pump audio through the CD, MIC and line inputs and verify that + * they mix/mute into the output. + * + * Apps: + * amp + * mpg123 + * x11amp + * mxv + * kmedia + * esound + * need more input apps + * + * Run tests while bombarding with signals. setitimer(2) will do it... */ + +/* + * This driver is organized in nine sections. + * The nine sections are: + * + * debug stuff + * low level lithium access + * high level lithium access + * AD1843 access + * PCM I/O + * audio driver + * mixer driver + * probe/attach/unload + * initialization and loadable kernel module interface + * + * That is roughly the order of increasing abstraction, so forward + * dependencies are minimal. + */ + +/* + * Locking Notes + * + * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of + * open descriptors to this driver. When the driver is compiled + * as a module, they call MOD_{INC,DEC}_USE_COUNT; otherwise they + * bump vwsnd_use_count. The global device list, vwsnd_dev_list, + * is immutable when the IN_USE is true. + * + * devc->open_lock is a semaphore that is used to enforce the + * single reader/single writer rule for /dev/audio. The rule is + * that each device may have at most one reader and one writer. + * Open will block until the previous client has closed the + * device, unless O_NONBLOCK is specified. + * + * The semaphore devc->io_sema serializes PCM I/O syscalls. This + * is unnecessary in Linux 2.2, because the kernel lock + * serializes read, write, and ioctl globally, but it's there, + * ready for the brave, new post-kernel-lock world. + * + * Locking between interrupt and baselevel is handled by the + * "lock" spinlock in vwsnd_port (one lock each for read and + * write). Each half holds the lock just long enough to see what + * area it owns and update its pointers. See pcm_output() and + * pcm_input() for most of the gory stuff. + * + * devc->mix_sema serializes all mixer ioctls. This is also + * redundant because of the kernel lock. + * + * The lowest level lock is lith->lithium_lock. It is a + * spinlock which is held during the two-register tango of + * reading/writing an AD1843 register. See + * li_{read,write}_ad1843_reg(). + */ + +/* + * Sample Format Notes + * + * Lithium's DMA engine has two formats: 16-bit 2's complement + * and 8-bit unsigned . 16-bit transfers the data unmodified, 2 + * bytes per sample. 8-bit unsigned transfers 1 byte per sample + * and XORs each byte with 0x80. Lithium can input or output + * either mono or stereo in either format. + * + * The AD1843 has four formats: 16-bit 2's complement, 8-bit + * unsigned, 8-bit mu-Law and 8-bit A-Law. + * + * This driver supports five formats: AFMT_S8, AFMT_U8, + * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE. + * + * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and + * rely on Lithium's XOR to translate between U8 and S8. + * + * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR + * the 0x80 bit in software to compensate for Lithium's XOR. + * This happens in pcm_copy_{in,out}(). + */ + +#include +#include +#include +#include +#include + +#include "sound_config.h" + +/*****************************************************************************/ +/* debug stuff */ + +#ifdef VWSND_DEBUG + +#include /* for in_interrupt() */ + +static int shut_up = 1; + +/* + * dbgassert - called when an assertion fails. + */ + +static void dbgassert(const char *fcn, int line, const char *expr) +{ + if (in_interrupt()) + panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n", + __FILE__, fcn, line, expr); + else { + int x; + printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n", + __FILE__, fcn, line, expr); + x = * (volatile int *) 0; /* force proc to exit */ + } +} + +/* + * Bunch of useful debug macros: + * + * ASSERT - print unless e nonzero (panic if in interrupt) + * DBGDO - include arbitrary code if debugging + * DBGX - debug print raw (w/o function name) + * DBGP - debug print w/ function name + * DBGE - debug print function entry + * DBGC - debug print function call + * DBGR - debug print function return + * DBGXV - debug print raw when verbose + * DBGPV - debug print when verbose + * DBGEV - debug print function entry when verbose + * DBGRV - debug print function return when verbose + */ + +#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e)) +#define DBGDO(x) x +#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args)) +#define DBGP(fmt, args...) (DBGX(__FUNCTION__ ": " fmt, ##args)) +#define DBGE(fmt, args...) (DBGX(__FUNCTION__ fmt, ##args)) +#define DBGC(rtn) (DBGP("calling %s\n", rtn)) +#define DBGR() (DBGP("returning\n")) +#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args)) +#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args)) +#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args)) +#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn)) +#define DBGRV() (shut_up ? 0 : DBGR()) + +#else /* !VWSND_DEBUG */ + +#define ASSERT(e) ((void) 0) +#define DBGDO(x) /* don't */ +#define DBGX(fmt, args...) ((void) 0) +#define DBGP(fmt, args...) ((void) 0) +#define DBGE(fmt, args...) ((void) 0) +#define DBGC(rtn) ((void) 0) +#define DBGR() ((void) 0) +#define DBGPV(fmt, args...) ((void) 0) +#define DBGXV(fmt, args...) ((void) 0) +#define DBGEV(fmt, args...) ((void) 0) +#define DBGCV(rtn) ((void) 0) +#define DBGRV() ((void) 0) + +#endif /* !VWSND_DEBUG */ + +/*****************************************************************************/ +/* low level lithium access */ + +/* + * We need to talk to Lithium registers on three pages. Here are + * the pages' offsets from the base address (0xFF001000). + */ + +enum { + LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */ + LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */ + LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */ +}; + +/* low-level lithium data */ + +typedef struct lithium { + caddr_t page0; /* virtual addresses */ + caddr_t page1; + caddr_t page2; + spinlock_t lock; /* protects codec and UST/MSC access */ +} lithium_t; + +/* + * li_create initializes the lithium_t structure and sets up vm mappings + * to access the registers. + * Returns 0 on success, -errno on failure. + */ + +static int li_create(lithium_t *lith, unsigned long baseaddr) +{ + static void li_destroy(lithium_t *); + + lith->lock = SPIN_LOCK_UNLOCKED; + lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE); + lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE); + lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE); + if (!lith->page0 || !lith->page1 || !lith->page2) { + li_destroy(lith); + return -ENOMEM; + } + return 0; +} + +/* + * li_destroy destroys the lithium_t structure and vm mappings. + */ + +static void li_destroy(lithium_t *lith) +{ + if (lith->page0) { + iounmap(lith->page0); + lith->page0 = NULL; + } + if (lith->page1) { + iounmap(lith->page1); + lith->page1 = NULL; + } + if (lith->page2) { + iounmap(lith->page2); + lith->page2 = NULL; + } +} + +/* + * basic register accessors - read/write long/byte + */ + +static __inline__ unsigned long li_readl(lithium_t *lith, int off) +{ + return * (volatile unsigned long *) (lith->page0 + off); +} + +static __inline__ unsigned char li_readb(lithium_t *lith, int off) +{ + return * (volatile unsigned char *) (lith->page0 + off); +} + +static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val) +{ + * (volatile unsigned long *) (lith->page0 + off) = val; +} + +static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val) +{ + * (volatile unsigned char *) (lith->page0 + off) = val; +} + +/*****************************************************************************/ +/* High Level Lithium Access */ + +/* + * Lithium DMA Notes + * + * Lithium has two dedicated DMA channels for audio. They are known + * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for + * input, and comm2 is for output. Each is controlled by three + * registers: BASE (base address), CFG (config) and CCTL + * (config/control). + * + * Each DMA channel points to a physically contiguous ring buffer in + * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.) + * There are three pointers into the ring buffer: read, write, and + * trigger. The pointers are 8 bits each. Each pointer points to + * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time, + * so there is no finer-granularity control. + * + * In comm1, the hardware updates the write ptr, and software updates + * the read ptr. In comm2, it's the opposite: hardware updates the + * read ptr, and software updates the write ptr. I designate the + * hardware-updated ptr as the hwptr, and the software-updated ptr as + * the swptr. + * + * The trigger ptr and trigger mask are used to trigger interrupts. + * From the Lithium spec, section 5.6.8, revision of 12/15/1998: + * + * Trigger Mask Value + * + * A three bit wide field that represents a power of two mask + * that is used whenever the trigger pointer is compared to its + * respective read or write pointer. A value of zero here + * implies a mask of 0xFF and a value of seven implies a mask + * 0x01. This value can be used to sub-divide the ring buffer + * into pie sections so that interrupts monitor the progress of + * hardware from section to section. + * + * My interpretation of that is, whenever the hw ptr is updated, it is + * compared with the trigger ptr, and the result is masked by the + * trigger mask. (Actually, by the complement of the trigger mask.) + * If the result is zero, an interrupt is triggered. I.e., interrupt + * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from + * the trigger register value as mask = (1 << (8 - tmreg)) - 1. + * + * In yet different words, setting tmreg to 0 causes an interrupt after + * every 256 DMA chunks (8192 bytes) or once per traversal of the + * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks + * (64 bytes) or 128 times per traversal of the ring buffer. + */ + +/* Lithium register offsets and bit definitions */ + +#define LI_HOST_CONTROLLER 0x000 +# define LI_HC_RESET 0x00008000 +# define LI_HC_LINK_ENABLE 0x00004000 +# define LI_HC_LINK_FAILURE 0x00000004 +# define LI_HC_LINK_CODEC 0x00000002 +# define LI_HC_LINK_READY 0x00000001 + +#define LI_INTR_STATUS 0x010 +#define LI_INTR_MASK 0x014 +# define LI_INTR_LINK_ERR 0x00008000 +# define LI_INTR_COMM2_TRIG 0x00000008 +# define LI_INTR_COMM2_UNDERFLOW 0x00000004 +# define LI_INTR_COMM1_TRIG 0x00000002 +# define LI_INTR_COMM1_OVERFLOW 0x00000001 + +#define LI_CODEC_COMMAND 0x018 +# define LI_CC_BUSY 0x00008000 +# define LI_CC_DIR 0x00000080 +# define LI_CC_DIR_RD LI_CC_DIR +# define LI_CC_DIR_WR (!LI_CC_DIR) +# define LI_CC_ADDR_MASK 0x0000007F + +#define LI_CODEC_DATA 0x01C + +#define LI_COMM1_BASE 0x100 +#define LI_COMM1_CTL 0x104 +# define LI_CCTL_RESET 0x80000000 +# define LI_CCTL_SIZE 0x70000000 +# define LI_CCTL_DMA_ENABLE 0x08000000 +# define LI_CCTL_TMASK 0x07000000 /* trigger mask */ +# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */ +# define LI_CCTL_RPTR 0x0000FF00 +# define LI_CCTL_WPTR 0x000000FF +#define LI_COMM1_CFG 0x108 +# define LI_CCFG_LOCK 0x00008000 +# define LI_CCFG_SLOT 0x00000070 +# define LI_CCFG_DIRECTION 0x00000008 +# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION) +# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION +# define LI_CCFG_MODE 0x00000004 +# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE) +# define LI_CCFG_MODE_STEREO LI_CCFG_MODE +# define LI_CCFG_FORMAT 0x00000003 +# define LI_CCFG_FMT_8BIT 0x00000000 +# define LI_CCFG_FMT_16BIT 0x00000001 +#define LI_COMM2_BASE 0x10C +#define LI_COMM2_CTL 0x110 + /* bit definitions are the same as LI_COMM1_CTL */ +#define LI_COMM2_CFG 0x114 + /* bit definitions are the same as LI_COMM1_CFG */ + +#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */ +#define LI_UST_HIGH 0x204 /* microseconds since boot */ + +#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */ +#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */ +#define LI_AUDIO2_UST 0x308 /* counts samples actually */ +#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */ + +/* + * Lithium's DMA engine operates on chunks of 32 bytes. We call that + * a DMACHUNK. + */ + +#define DMACHUNK_SHIFT 5 +#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT) +#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT) +#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT) + +/* + * Two convenient macros to shift bitfields into/out of position. + * + * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)). + * As long as mask is constant, we trust the compiler will change the + * multipy and divide into shifts. + */ + +#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask)) +#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask))) + +/* + * dma_chan_desc is invariant information about a Lithium + * DMA channel. There are two instances, li_comm1 and li_comm2. + * + * Note that the CCTL register fields are write ptr and read ptr, but what + * we care about are which pointer is updated by software and which by + * hardware. + */ + +typedef struct dma_chan_desc { + int basereg; + int cfgreg; + int ctlreg; + int hwptrreg; + int swptrreg; + int ustreg; + int mscreg; + unsigned long swptrmask; + int ad1843_slot; + int direction; /* LI_CCTL_DIR_IN/OUT */ +} dma_chan_desc_t; + +static const dma_chan_desc_t li_comm1 = { + LI_COMM1_BASE, /* base register offset */ + LI_COMM1_CFG, /* config register offset */ + LI_COMM1_CTL, /* control register offset */ + LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */ + LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */ + LI_AUDIO1_UST, /* ust reg offset */ + LI_AUDIO1_MSC, /* msc reg offset */ + LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */ + 2, /* ad1843 serial slot */ + LI_CCFG_DIR_IN /* direction */ +}; + +static const dma_chan_desc_t li_comm2 = { + LI_COMM2_BASE, /* base register offset */ + LI_COMM2_CFG, /* config register offset */ + LI_COMM2_CTL, /* control register offset */ + LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */ + LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */ + LI_AUDIO2_UST, /* ust reg offset */ + LI_AUDIO2_MSC, /* msc reg offset */ + LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */ + 2, /* ad1843 serial slot */ + LI_CCFG_DIR_OUT /* direction */ +}; + +/* + * dma_chan is variable information about a Lithium DMA channel. + * + * The desc field points to invariant information. + * The lith field points to a lithium_t which is passed + * to li_read* and li_write* to access the registers. + * The *val fields shadow the lithium registers' contents. + */ + +typedef struct dma_chan { + const dma_chan_desc_t *desc; + lithium_t *lith; + unsigned long baseval; + unsigned long cfgval; + unsigned long ctlval; +} dma_chan_t; + +/* + * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter). + * UST is time in microseconds since the system booted, and MSC is a + * counter that increments with every audio sample. + */ + +typedef struct ustmsc { + unsigned long long ust; + unsigned long msc; +} ustmsc_t; + +/* + * li_ad1843_wait waits until lithium says the AD1843 register + * exchange is not busy. Returns 0 on success, -EBUSY on timeout. + * + * Locking: must be called with lithium_lock held. + */ + +static int li_ad1843_wait(lithium_t *lith) +{ + unsigned long later = jiffies + 2; + while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY) + if (jiffies >= later) + return -EBUSY; + return 0; +} + +/* + * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register. + * + * Returns unsigned register value on success, -errno on failure. + */ + +static int li_read_ad1843_reg(lithium_t *lith, int reg) +{ + int val; + + ASSERT(!in_interrupt()); + spin_lock(&lith->lock); + { + val = li_ad1843_wait(lith); + if (val == 0) { + li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg); + val = li_ad1843_wait(lith); + } + if (val == 0) + val = li_readl(lith, LI_CODEC_DATA); + } + spin_unlock(&lith->lock); + + DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n", + lith, reg, val); + + return val; +} + +/* + * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register. + */ + +static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval) +{ + spin_lock(&lith->lock); + { + if (li_ad1843_wait(lith) == 0) { + li_writel(lith, LI_CODEC_DATA, newval); + li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg); + } + } + spin_unlock(&lith->lock); +} + +/* + * li_setup_dma calculates all the register settings for DMA in a particular + * mode. It takes too many arguments. + */ + +static void li_setup_dma(dma_chan_t *chan, + const dma_chan_desc_t *desc, + lithium_t *lith, + unsigned long buffer_paddr, + int bufshift, + int fragshift, + int channels, + int sampsize) +{ + unsigned long mode, format; + unsigned long size, tmask; + + DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, " + "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n", + chan, desc, lith, buffer_paddr, + bufshift, fragshift, channels, sampsize); + + /* Reset the channel first. */ + + li_writel(lith, desc->ctlreg, LI_CCTL_RESET); + + ASSERT(channels == 1 || channels == 2); + if (channels == 2) + mode = LI_CCFG_MODE_STEREO; + else + mode = LI_CCFG_MODE_MONO; + ASSERT(sampsize == 1 || sampsize == 2); + if (sampsize == 2) + format = LI_CCFG_FMT_16BIT; + else + format = LI_CCFG_FMT_8BIT; + chan->desc = desc; + chan->lith = lith; + + /* + * Lithium DMA address register takes a 40-bit physical + * address, right-shifted by 8 so it fits in 32 bits. Bit 37 + * must be set -- it enables cache coherence. + */ + + ASSERT(!(buffer_paddr & 0xFF)); + chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8); + + chan->cfgval = (!LI_CCFG_LOCK | + SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) | + desc->direction | + mode | + format); + + size = bufshift - 6; + tmask = 13 - fragshift; /* See Lithium DMA Notes above. */ + ASSERT(size >= 2 && size <= 7); + ASSERT(tmask >= 1 && tmask <= 7); + chan->ctlval = (!LI_CCTL_RESET | + SHIFT_FIELD(size, LI_CCTL_SIZE) | + !LI_CCTL_DMA_ENABLE | + SHIFT_FIELD(tmask, LI_CCTL_TMASK) | + SHIFT_FIELD(0, LI_CCTL_TPTR)); + + DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval); + DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval); + DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval); + + li_writel(lith, desc->basereg, chan->baseval); + li_writel(lith, desc->cfgreg, chan->cfgval); + li_writel(lith, desc->ctlreg, chan->ctlval); + + DBGRV(); +} + +static void li_shutdown_dma(dma_chan_t *chan) +{ + lithium_t *lith = chan->lith; + caddr_t lith1 = lith->page1; + + DBGEV("(chan=0x%p)\n", chan); + + chan->ctlval &= ~LI_CCTL_DMA_ENABLE; + DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); + li_writel(lith, chan->desc->ctlreg, chan->ctlval); + + /* + * Offset 0x500 on Lithium page 1 is an undocumented, + * unsupported register that holds the zero sample value. + * Lithium is supposed to output zero samples when DMA is + * inactive, and repeat the last sample when DMA underflows. + * But it has a bug, where, after underflow occurs, the zero + * sample is not reset. + * + * I expect this to break in a future rev of Lithium. + */ + + if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT) + * (volatile unsigned long *) (lith1 + 0x500) = 0; +} + +/* + * li_activate_dma always starts dma at the beginning of the buffer. + * + * N.B., these may be called from interrupt. + */ + +static __inline__ void li_activate_dma(dma_chan_t *chan) +{ + chan->ctlval |= LI_CCTL_DMA_ENABLE; + DBGPV("ctlval = 0x%lx\n", chan->ctlval); + li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval); +} + +static void li_deactivate_dma(dma_chan_t *chan) +{ + lithium_t *lith = chan->lith; + caddr_t lith2 = lith->page2; + + chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR); + DBGPV("ctlval = 0x%lx\n", chan->ctlval); + DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); + li_writel(lith, chan->desc->ctlreg, chan->ctlval); + + /* + * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented, + * unsupported registers that are internal copies of the DMA + * read and write pointers. Because of a Lithium bug, these + * registers aren't zeroed correctly when DMA is shut off. So + * we whack them directly. + * + * I expect this to break in a future rev of Lithium. + */ + + if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) { + * (volatile unsigned long *) (lith2 + 0x98) = 0; + * (volatile unsigned long *) (lith2 + 0x9C) = 0; + } +} + +/* + * read/write the ring buffer pointers. These routines' arguments and results + * are byte offsets from the beginning of the ring buffer. + */ + +static __inline__ int li_read_swptr(dma_chan_t *chan) +{ + const unsigned long mask = chan->desc->swptrmask; + + return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask)); +} + +static __inline__ int li_read_hwptr(dma_chan_t *chan) +{ + return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg)); +} + +static __inline__ void li_write_swptr(dma_chan_t *chan, int val) +{ + const unsigned long mask = chan->desc->swptrmask; + + ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF))); + val = BYTES_TO_CHUNKS(val); + chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask); + li_writeb(chan->lith, chan->desc->swptrreg, val); +} + +/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */ + +static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc) +{ + lithium_t *lith = chan->lith; + const dma_chan_desc_t *desc = chan->desc; + unsigned long now_low, now_high0, now_high1, chan_ust; + + spin_lock(&lith->lock); + { + /* + * retry until we do all five reads without the + * high word changing. (High word increments + * every 2^32 microseconds, i.e., not often) + */ + do { + now_high0 = li_readl(lith, LI_UST_HIGH); + now_low = li_readl(lith, LI_UST_LOW); + + /* + * Lithium guarantees these two reads will be + * atomic -- ust will not increment after msc + * is read. + */ + + ustmsc->msc = li_readl(lith, desc->mscreg); + chan_ust = li_readl(lith, desc->ustreg); + + now_high1 = li_readl(lith, LI_UST_HIGH); + } while (now_high0 != now_high1); + } + spin_unlock(&lith->lock); + ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust); +} + +static void li_enable_interrupts(lithium_t *lith, unsigned int mask) +{ + DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); + + /* clear any already-pending interrupts. */ + + li_writel(lith, LI_INTR_STATUS, mask); + + /* enable the interrupts. */ + + mask |= li_readl(lith, LI_INTR_MASK); + li_writel(lith, LI_INTR_MASK, mask); +} + +static void li_disable_interrupts(lithium_t *lith, unsigned int mask) +{ + unsigned int keepmask; + + DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); + + /* disable the interrupts */ + + keepmask = li_readl(lith, LI_INTR_MASK) & ~mask; + li_writel(lith, LI_INTR_MASK, keepmask); + + /* clear any pending interrupts. */ + + li_writel(lith, LI_INTR_STATUS, mask); +} + +/* Get the interrupt status and clear all pending interrupts. */ + +static unsigned int li_get_clear_intr_status(lithium_t *lith) +{ + unsigned int status; + + status = li_readl(lith, LI_INTR_STATUS); + li_writel(lith, LI_INTR_STATUS, ~0); + return status & li_readl(lith, LI_INTR_MASK); +} + +static int li_init(lithium_t *lith) +{ + /* 1. System power supplies stabilize. */ + + /* 2. Assert the ~RESET signal. */ + + li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET); + udelay(1); + + /* 3. Deassert the ~RESET signal and enter a wait period to allow + the AD1843 internal clocks and the external crystal oscillator + to stabilize. */ + + li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); + udelay(1); + + return 0; +} + +/*****************************************************************************/ +/* AD1843 access */ + +/* + * AD1843 bitfield definitions. All are named as in the AD1843 data + * sheet, with ad1843_ prepended and individual bit numbers removed. + * + * E.g., bits LSS0 through LSS2 become ad1843_LSS. + * + * Only the bitfields we need are defined. + */ + +typedef struct ad1843_bitfield { + char reg; + char lo_bit; + char nbits; +} ad1843_bitfield_t; + +static const ad1843_bitfield_t + ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ + ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ + ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ + ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ + ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ + ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ + ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ + ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ + ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ + ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ + ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ + ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ + ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ + ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ + ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ + ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ + ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ + ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ + ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ + ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ + ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ + ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ + ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ + ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ + ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ + ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ + ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ + ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ + ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ + ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ + ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ + ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ + ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */ + ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ + ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ + ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ + ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ + ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ + ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ + ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ + ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ + ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ + ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ + ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ + ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ + ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ + ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ + ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ + ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ + ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ + ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ + +/* + * The various registers of the AD1843 use three different formats for + * specifying gain. The ad1843_gain structure parameterizes the + * formats. + */ + +typedef struct ad1843_gain { + + int negative; /* nonzero if gain is negative. */ + const ad1843_bitfield_t *lfield; + const ad1843_bitfield_t *rfield; + +} ad1843_gain_t; + +static const ad1843_gain_t ad1843_gain_RECLEV + = { 0, &ad1843_LIG, &ad1843_RIG }; +static const ad1843_gain_t ad1843_gain_LINE + = { 1, &ad1843_LX1M, &ad1843_RX1M }; +static const ad1843_gain_t ad1843_gain_CD + = { 1, &ad1843_LX2M, &ad1843_RX2M }; +static const ad1843_gain_t ad1843_gain_MIC + = { 1, &ad1843_LMCM, &ad1843_RMCM }; +static const ad1843_gain_t ad1843_gain_PCM + = { 1, &ad1843_LDA1G, &ad1843_RDA1G }; + +/* read the current value of an AD1843 bitfield. */ + +static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field) +{ + int w = li_read_ad1843_reg(lith, field->reg); + int val = w >> field->lo_bit & ((1 << field->nbits) - 1); + + DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n", + lith, field->reg, field->lo_bit, field->nbits, val); + + return val; +} + +/* + * write a new value to an AD1843 bitfield and return the old value. + */ + +static int ad1843_write_bits(lithium_t *lith, + const ad1843_bitfield_t *field, + int newval) +{ + int w = li_read_ad1843_reg(lith, field->reg); + int mask = ((1 << field->nbits) - 1) << field->lo_bit; + int oldval = (w & mask) >> field->lo_bit; + int newbits = (newval << field->lo_bit) & mask; + w = (w & ~mask) | newbits; + (void) li_write_ad1843_reg(lith, field->reg, w); + + DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) " + "returns 0x%x\n", + lith, field->reg, field->lo_bit, field->nbits, newval, + oldval); + + return oldval; +} + +/* + * ad1843_read_multi reads multiple bitfields from the same AD1843 + * register. It uses a single read cycle to do it. (Reading the + * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 + * microseconds.) + * + * Called ike this. + * + * ad1843_read_multi(lith, nfields, + * &ad1843_FIELD1, &val1, + * &ad1843_FIELD2, &val2, ...); + */ + +static void ad1843_read_multi(lithium_t *lith, int argcount, ...) +{ + va_list ap; + const ad1843_bitfield_t *fp; + int w = 0, mask, *value, reg = -1; + + va_start(ap, argcount); + while (--argcount >= 0) { + fp = va_arg(ap, const ad1843_bitfield_t *); + value = va_arg(ap, int *); + if (reg == -1) { + reg = fp->reg; + w = li_read_ad1843_reg(lith, reg); + } + ASSERT(reg == fp->reg); + mask = (1 << fp->nbits) - 1; + *value = w >> fp->lo_bit & mask; + } + va_end(ap); +} + +/* + * ad1843_write_multi stores multiple bitfields into the same AD1843 + * register. It uses one read and one write cycle to do it. + * + * Called like this. + * + * ad1843_write_multi(lith, nfields, + * &ad1843_FIELD1, val1, + * &ad1843_FIELF2, val2, ...); + */ + +static void ad1843_write_multi(lithium_t *lith, int argcount, ...) +{ + va_list ap; + int reg; + const ad1843_bitfield_t *fp; + int value; + int w, m, mask, bits; + + mask = 0; + bits = 0; + reg = -1; + + va_start(ap, argcount); + while (--argcount >= 0) { + fp = va_arg(ap, const ad1843_bitfield_t *); + value = va_arg(ap, int); + if (reg == -1) + reg = fp->reg; + ASSERT(fp->reg == reg); + m = ((1 << fp->nbits) - 1) << fp->lo_bit; + mask |= m; + bits |= (value << fp->lo_bit) & m; + } + va_end(ap); + ASSERT(!(bits & ~mask)); + if (~mask & 0xFFFF) + w = li_read_ad1843_reg(lith, reg); + else + w = 0; + w = (w & ~mask) | bits; + (void) li_write_ad1843_reg(lith, reg, w); +} + +/* + * ad1843_get_gain reads the specified register and extracts the gain value + * using the supplied gain type. It returns the gain in OSS format. + */ + +static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp) +{ + int lg, rg; + unsigned short mask = (1 << gp->lfield->nbits) - 1; + + ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg); + if (gp->negative) { + lg = mask - lg; + rg = mask - rg; + } + lg = (lg * 100 + (mask >> 1)) / mask; + rg = (rg * 100 + (mask >> 1)) / mask; + return lg << 0 | rg << 8; +} + +/* + * Set an audio channel's gain. Converts from OSS format to AD1843's + * format. + * + * Returns the new gain, which may be lower than the old gain. + */ + +static int ad1843_set_gain(lithium_t *lith, + const ad1843_gain_t *gp, + int newval) +{ + unsigned short mask = (1 << gp->lfield->nbits) - 1; + + int lg = newval >> 0 & 0xFF; + int rg = newval >> 8; + if (lg < 0 || lg > 100 || rg < 0 || rg > 100) + return -EINVAL; + lg = (lg * mask + (mask >> 1)) / 100; + rg = (rg * mask + (mask >> 1)) / 100; + if (gp->negative) { + lg = mask - lg; + rg = mask - rg; + } + ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg); + return ad1843_get_gain(lith, gp); +} + +/* Returns the current recording source, in OSS format. */ + +static int ad1843_get_recsrc(lithium_t *lith) +{ + int ls = ad1843_read_bits(lith, &ad1843_LSS); + + switch (ls) { + case 1: + return SOUND_MASK_MIC; + case 2: + return SOUND_MASK_LINE; + case 3: + return SOUND_MASK_CD; + case 6: + return SOUND_MASK_PCM; + default: + ASSERT(0); + return -1; + } +} + +/* + * Enable/disable digital resample mode in the AD1843. + * + * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down + * while switching modes. So we save DA1's state (DA2's state is not + * interesting), power them down, switch into/out of resample mode, + * power them up, and restore state. + * + * This will cause audible glitches if D/A or A/D is going on, so the + * driver disallows that (in mixer_write_ioctl()). + * + * The open question is, is this worth doing? I'm leaving it in, + * because it's written, but... + */ + +static void ad1843_set_resample_mode(lithium_t *lith, int onoff) +{ + /* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */ + int save_da1 = li_read_ad1843_reg(lith, 9); + + /* Power down A/D and D/A. */ + ad1843_write_multi(lith, 4, + &ad1843_DA1EN, 0, + &ad1843_DA2EN, 0, + &ad1843_ADLEN, 0, + &ad1843_ADREN, 0); + + /* Switch mode */ + ASSERT(onoff == 0 || onoff == 1); + ad1843_write_bits(lith, &ad1843_DRSFLT, onoff); + + /* Power up A/D and D/A. */ + ad1843_write_multi(lith, 3, + &ad1843_DA1EN, 1, + &ad1843_ADLEN, 1, + &ad1843_ADREN, 1); + + /* Restore DA1 mute and gain. */ + li_write_ad1843_reg(lith, 9, save_da1); +} + +/* + * Set recording source. Arg newsrc specifies an OSS channel mask. + * + * The complication is that when we switch into/out of loopback mode + * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of + * digital resampling mode. + * + * Returns newsrc on success, -errno on failure. + */ + +static int ad1843_set_recsrc(lithium_t *lith, int newsrc) +{ + int bits; + int oldbits; + + switch (newsrc) { + case SOUND_MASK_PCM: + bits = 6; + break; + + case SOUND_MASK_MIC: + bits = 1; + break; + + case SOUND_MASK_LINE: + bits = 2; + break; + + case SOUND_MASK_CD: + bits = 3; + break; + + default: + return -EINVAL; + } + oldbits = ad1843_read_bits(lith, &ad1843_LSS); + if (newsrc == SOUND_MASK_PCM && oldbits != 6) { + DBGP("enabling digital resample mode\n"); + ad1843_set_resample_mode(lith, 1); + ad1843_write_multi(lith, 2, + &ad1843_DAADL, 2, + &ad1843_DAADR, 2); + } else if (newsrc != SOUND_MASK_PCM && oldbits == 6) { + DBGP("disabling digital resample mode\n"); + ad1843_set_resample_mode(lith, 0); + ad1843_write_multi(lith, 2, + &ad1843_DAADL, 0, + &ad1843_DAADR, 0); + } + ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits); + return newsrc; +} + +/* + * Return current output sources, in OSS format. + */ + +static int ad1843_get_outsrc(lithium_t *lith) +{ + int pcm, line, mic, cd; + + pcm = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM; + line = ad1843_read_bits(lith, &ad1843_LX1MM) ? 0 : SOUND_MASK_LINE; + cd = ad1843_read_bits(lith, &ad1843_LX2MM) ? 0 : SOUND_MASK_CD; + mic = ad1843_read_bits(lith, &ad1843_LMCMM) ? 0 : SOUND_MASK_MIC; + + return pcm | line | cd | mic; +} + +/* + * Set output sources. Arg is a mask of active sources in OSS format. + * + * Returns source mask on success, -errno on failure. + */ + +static int ad1843_set_outsrc(lithium_t *lith, int mask) +{ + int pcm, line, mic, cd; + + if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_CD | SOUND_MASK_MIC)) + return -EINVAL; + pcm = (mask & SOUND_MASK_PCM) ? 0 : 1; + line = (mask & SOUND_MASK_LINE) ? 0 : 1; + mic = (mask & SOUND_MASK_MIC) ? 0 : 1; + cd = (mask & SOUND_MASK_CD) ? 0 : 1; + + ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm); + ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line); + ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd, &ad1843_RX2MM, cd); + ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic, &ad1843_RMCMM, mic); + + return mask; +} + +/* Setup ad1843 for D/A conversion. */ + +static void ad1843_setup_dac(lithium_t *lith, + int framerate, + int fmt, + int channels) +{ + int ad_fmt = 0, ad_mode = 0; + + DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", + lith, framerate, fmt, channels); + + switch (fmt) { + case AFMT_S8: ad_fmt = 1; break; + case AFMT_U8: ad_fmt = 1; break; + case AFMT_S16_LE: ad_fmt = 1; break; + case AFMT_MU_LAW: ad_fmt = 2; break; + case AFMT_A_LAW: ad_fmt = 3; break; + default: ASSERT(0); + } + + switch (channels) { + case 2: ad_mode = 0; break; + case 1: ad_mode = 1; break; + default: ASSERT(0); + } + + DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt); + ASSERT(framerate >= 4000 && framerate <= 49000); + ad1843_write_bits(lith, &ad1843_C1C, framerate); + ad1843_write_multi(lith, 2, + &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt); +} + +static void ad1843_shutdown_dac(lithium_t *lith) +{ + ad1843_write_bits(lith, &ad1843_DA1F, 1); +} + +static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels) +{ + int da_fmt = 0; + + DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", + lith, framerate, fmt, channels); + + switch (fmt) { + case AFMT_S8: da_fmt = 1; break; + case AFMT_U8: da_fmt = 1; break; + case AFMT_S16_LE: da_fmt = 1; break; + case AFMT_MU_LAW: da_fmt = 2; break; + case AFMT_A_LAW: da_fmt = 3; break; + default: ASSERT(0); + } + + DBGPV("da_fmt = %d\n", da_fmt); + ASSERT(framerate >= 4000 && framerate <= 49000); + ad1843_write_bits(lith, &ad1843_C2C, framerate); + ad1843_write_multi(lith, 2, + &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); +} + +static void ad1843_shutdown_adc(lithium_t *lith) +{ + /* nothing to do */ +} + +/* + * Fully initialize the ad1843. As described in the AD1843 data + * sheet, section "START-UP SEQUENCE". The numbered comments are + * subsection headings from the data sheet. See the data sheet, pages + * 52-54, for more info. + * + * return 0 on success, -errno on failure. */ + +static int ad1843_init(lithium_t *lith) +{ + unsigned long later; + int err; + + err = li_init(lith); + if (err) + return err; + + if (ad1843_read_bits(lith, &ad1843_INIT) != 0) { + printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n"); + return -EIO; + } + + ad1843_write_bits(lith, &ad1843_SCF, 1); + + /* 4. Put the conversion resources into standby. */ + + ad1843_write_bits(lith, &ad1843_PDNI, 0); + later = jiffies + HZ / 2; /* roughly half a second */ + DBGDO(shut_up++); + while (ad1843_read_bits(lith, &ad1843_PDNO)) { + if (jiffies > later) { + printk(KERN_ERR + "vwsnd audio: AD1843 won't power up\n"); + return -EIO; + } + schedule(); + } + DBGDO(shut_up--); + + /* 5. Power up the clock generators and enable clock output pins. */ + + ad1843_write_multi(lith, 2, &ad1843_C1EN, 1, &ad1843_C2EN, 1); + + /* 6. Configure conversion resources while they are in standby. */ + + /* DAC1 uses clock 1 as source, ADC uses clock 2. Always. */ + + ad1843_write_multi(lith, 3, + &ad1843_DA1C, 1, + &ad1843_ADLC, 2, + &ad1843_ADRC, 2); + + /* 7. Enable conversion resources. */ + + ad1843_write_bits(lith, &ad1843_ADTLK, 1); + ad1843_write_multi(lith, 5, + &ad1843_ANAEN, 1, + &ad1843_AAMEN, 1, + &ad1843_DA1EN, 1, + &ad1843_ADLEN, 1, + &ad1843_ADREN, 1); + + /* 8. Configure conversion resources while they are enabled. */ + + ad1843_write_bits(lith, &ad1843_DA1C, 1); + + /* Unmute all channels. */ + + ad1843_set_outsrc(lith, + (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD)); + ad1843_write_multi(lith, 2, &ad1843_LDA1AM, 0, &ad1843_RDA1AM, 0); + + /* Set default recording source to Line In and set + * mic gain to +20 dB. + */ + + ad1843_set_recsrc(lith, SOUND_MASK_LINE); + ad1843_write_multi(lith, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); + + /* Set Speaker Out level to +/- 4V and unmute it. */ + + ad1843_write_multi(lith, 2, &ad1843_HPOS, 1, &ad1843_HPOM, 0); + + return 0; +} + +/*****************************************************************************/ +/* PCM I/O */ + +#define READ_INTR_MASK (LI_INTR_COMM1_TRIG | LI_INTR_COMM1_OVERFLOW) +#define WRITE_INTR_MASK (LI_INTR_COMM2_TRIG | LI_INTR_COMM2_UNDERFLOW) + +typedef enum vwsnd_port_swstate { /* software state */ + SW_OFF, + SW_INITIAL, + SW_RUN, + SW_DRAIN, +} vwsnd_port_swstate_t; + +typedef enum vwsnd_port_hwstate { /* hardware state */ + HW_STOPPED, + HW_RUNNING, +} vwsnd_port_hwstate_t; + +/* + * These flags are read by ISR, but only written at baseline. + */ + +typedef enum vwsnd_port_flags { + DISABLED = 1 << 0, + ERFLOWN = 1 << 1, /* overflown or underflown */ + HW_BUSY = 1 << 2, +} vwsnd_port_flags_t; + +/* + * vwsnd_port is the per-port data structure. Each device has two + * ports, one for input and one for output. + * + * Locking: + * + * port->lock protects: hwstate, flags, swb_[iu]_avail. + * + * devc->io_sema protects: swstate, sw_*, swb_[iu]_idx. + * + * everything else is only written by open/release or + * pcm_{setup,shutdown}(), which are serialized by a + * combination of devc->open_sema and devc->io_sema. + */ + +typedef struct vwsnd_port { + + spinlock_t lock; + wait_queue_head_t queue; + vwsnd_port_swstate_t swstate; + vwsnd_port_hwstate_t hwstate; + vwsnd_port_flags_t flags; + + int sw_channels; + int sw_samplefmt; + int sw_framerate; + int sample_size; + int frame_size; + unsigned int zero_word; /* zero for the sample format */ + + int sw_fragshift; + int sw_fragcount; + int sw_subdivshift; + + unsigned int hw_fragshift; + unsigned int hw_fragsize; + unsigned int hw_fragcount; + + int hwbuf_size; + unsigned long hwbuf_paddr; + unsigned long hwbuf_vaddr; + caddr_t hwbuf; /* hwbuf == hwbuf_vaddr */ + int hwbuf_max; /* max bytes to preload */ + + caddr_t swbuf; + unsigned int swbuf_size; /* size in bytes */ + unsigned int swb_u_idx; /* index of next user byte */ + unsigned int swb_i_idx; /* index of next intr byte */ + unsigned int swb_u_avail; /* # bytes avail to user */ + unsigned int swb_i_avail; /* # bytes avail to intr */ + + dma_chan_t chan; + + /* Accounting */ + + int byte_count; + int frag_count; + int MSC_offset; + +} vwsnd_port_t; + +/* vwsnd_dev is the per-device data structure. */ + +typedef struct vwsnd_dev { + struct vwsnd_dev *next_dev; + int audio_minor; /* minor number of audio device */ + int mixer_minor; /* minor number of mixer device */ + + struct semaphore open_sema; + struct semaphore io_sema; + struct semaphore mix_sema; + mode_t open_mode; + wait_queue_head_t open_wait; + + lithium_t lith; + + vwsnd_port_t rport; + vwsnd_port_t wport; +} vwsnd_dev_t; + +static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */ + +#ifdef MODULE + +# define INC_USE_COUNT MOD_INC_USE_COUNT +# define DEC_USE_COUNT MOD_DEC_USE_COUNT +# define IN_USE MOD_IN_USE + +#else + +static atomic_t vwsnd_use_count = ATOMIC_INIT(0); + +# define INC_USE_COUNT (atomic_inc(&vwsnd_use_count)) +# define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count)) +# define IN_USE (atomic_read(&vwsnd_use_count) != 0) + +#endif + +/* + * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may + * be up to 8 Kb. This driver always uses 8 Kb. + * + * Memory bug workaround -- I'm not sure what's going on here, but + * somehow pcm_copy_out() was triggering segv's going on to the next + * page of the hw buffer. So, I make the hw buffer one size bigger + * than we actually use. That way, the following page is allocated + * and mapped, and no error. I suspect that something is broken + * in Cobalt, but haven't really investigated. HBO is the actual + * size of the buffer, and HWBUF_ORDER is what we allocate. + */ + +#define HWBUF_SHIFT 13 +#define HWBUF_SIZE (1 << HWBUF_SHIFT) +# define HBO (HWBUF_SHIFT > PAGE_SHIFT ? HWBUF_SHIFT - PAGE_SHIFT : 0) +# define HWBUF_ORDER (HBO + 1) /* next size bigger */ +#define MIN_SPEED 4000 +#define MAX_SPEED 49000 + +#define MIN_FRAGSHIFT (DMACHUNK_SHIFT + 1) +#define MAX_FRAGSHIFT (PAGE_SHIFT) +#define MIN_FRAGSIZE (1 << MIN_FRAGSHIFT) +#define MAX_FRAGSIZE (1 << MAX_FRAGSHIFT) +#define MIN_FRAGCOUNT(fragsize) 3 +#define MAX_FRAGCOUNT(fragsize) (32 * PAGE_SIZE / (fragsize)) +#define DEFAULT_FRAGSHIFT 12 +#define DEFAULT_FRAGCOUNT 16 +#define DEFAULT_SUBDIVSHIFT 0 + +/* + * The software buffer (swbuf) is a ring buffer shared between user + * level and interrupt level. Each level owns some of the bytes in + * the buffer, and may give bytes away by calling swb_inc_{u,i}(). + * User level calls _u for user, and interrupt level calls _i for + * interrupt. + * + * port->swb_{u,i}_avail is the number of bytes available to that level. + * + * port->swb_{u,i}_idx is the index of the first available byte in the + * buffer. + * + * Each level calls swb_inc_{u,i}() to atomically increment its index, + * recalculate the number of bytes available for both sides, and + * return the number of bytes available. Since each side can only + * give away bytes, the other side can only increase the number of + * bytes available to this side. Each side updates its own index + * variable, swb_{u,i}_idx, so no lock is needed to read it. + * + * To query the number of bytes available, call swb_inc_{u,i} with an + * increment of zero. + */ + +static __inline__ unsigned int __swb_inc_u(vwsnd_port_t *port, int inc) +{ + if (inc) { + port->swb_u_idx += inc; + port->swb_u_idx %= port->swbuf_size; + port->swb_u_avail -= inc; + port->swb_i_avail += inc; + } + return port->swb_u_avail; +} + +static __inline__ unsigned int swb_inc_u(vwsnd_port_t *port, int inc) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + { + ret = __swb_inc_u(port, inc); + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static __inline__ unsigned int __swb_inc_i(vwsnd_port_t *port, int inc) +{ + if (inc) { + port->swb_i_idx += inc; + port->swb_i_idx %= port->swbuf_size; + port->swb_i_avail -= inc; + port->swb_u_avail += inc; + } + return port->swb_i_avail; +} + +static __inline__ unsigned int swb_inc_i(vwsnd_port_t *port, int inc) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + { + ret = __swb_inc_i(port, inc); + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +/* + * pcm_setup - this routine initializes all port state after + * mode-setting ioctls have been done, but before the first I/O is + * done. + * + * Locking: called with devc->io_sema held. + * + * Returns 0 on success, -errno on failure. + */ + +static int pcm_setup(vwsnd_dev_t *devc, + vwsnd_port_t *rport, + vwsnd_port_t *wport) +{ + vwsnd_port_t *aport = rport ? rport : wport; + int sample_size; + unsigned int zero_word; + + DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); + + ASSERT(aport != NULL); + if (aport->swbuf != NULL) + return 0; + switch (aport->sw_samplefmt) { + case AFMT_MU_LAW: + sample_size = 1; + zero_word = 0xFFFFFFFF ^ 0x80808080; + break; + + case AFMT_A_LAW: + sample_size = 1; + zero_word = 0xD5D5D5D5 ^ 0x80808080; + break; + + case AFMT_U8: + sample_size = 1; + zero_word = 0x80808080; + break; + + case AFMT_S8: + sample_size = 1; + zero_word = 0x00000000; + break; + + case AFMT_S16_LE: + sample_size = 2; + zero_word = 0x00000000; + break; + + default: + sample_size = 0; /* prevent compiler warning */ + zero_word = 0; + ASSERT(0); + } + aport->sample_size = sample_size; + aport->zero_word = zero_word; + aport->frame_size = aport->sw_channels * aport->sample_size; + aport->hw_fragshift = aport->sw_fragshift - aport->sw_subdivshift; + aport->hw_fragsize = 1 << aport->hw_fragshift; + aport->hw_fragcount = aport->sw_fragcount << aport->sw_subdivshift; + ASSERT(aport->hw_fragsize >= MIN_FRAGSIZE); + ASSERT(aport->hw_fragsize <= MAX_FRAGSIZE); + ASSERT(aport->hw_fragcount >= MIN_FRAGCOUNT(aport->hw_fragsize)); + ASSERT(aport->hw_fragcount <= MAX_FRAGCOUNT(aport->hw_fragsize)); + if (rport) { + int hwfrags, swfrags; + rport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE; + hwfrags = rport->hwbuf_max >> aport->hw_fragshift; + swfrags = aport->hw_fragcount - hwfrags; + if (swfrags < 2) + swfrags = 2; + rport->swbuf_size = swfrags * aport->hw_fragsize; + DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags); + DBGPV("read hwbuf_max = %d, swbuf_size = %d\n", + rport->hwbuf_max, rport->swbuf_size); + } + if (wport) { + int hwfrags, swfrags; + int total_bytes = aport->hw_fragcount * aport->hw_fragsize; + wport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE; + if (wport->hwbuf_max > total_bytes) + wport->hwbuf_max = total_bytes; + hwfrags = wport->hwbuf_max >> aport->hw_fragshift; + DBGPV("hwfrags = %d\n", hwfrags); + swfrags = aport->hw_fragcount - hwfrags; + if (swfrags < 2) + swfrags = 2; + wport->swbuf_size = swfrags * aport->hw_fragsize; + DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags); + DBGPV("write hwbuf_max = %d, swbuf_size = %d\n", + wport->hwbuf_max, wport->swbuf_size); + } + + aport->swb_u_idx = 0; + aport->swb_i_idx = 0; + aport->byte_count = 0; + + /* + * Is this a Cobalt bug? We need to make this buffer extend + * one page further than we actually use -- somehow memcpy + * causes an exceptoin otherwise. I suspect there's a bug in + * Cobalt (or somewhere) where it's generating a fault on a + * speculative load or something. Obviously, I haven't taken + * the time to track it down. + */ + + aport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); + if (!aport->swbuf) + return -ENOMEM; + if (rport && wport) { + ASSERT(aport == rport); + ASSERT(wport->swbuf == NULL); + /* One extra page - see comment above. */ + wport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); + if (!wport->swbuf) { + vfree(aport->swbuf); + aport->swbuf = NULL; + return -ENOMEM; + } + wport->sample_size = rport->sample_size; + wport->zero_word = rport->zero_word; + wport->frame_size = rport->frame_size; + wport->hw_fragshift = rport->hw_fragshift; + wport->hw_fragsize = rport->hw_fragsize; + wport->hw_fragcount = rport->hw_fragcount; + wport->swbuf_size = rport->swbuf_size; + wport->hwbuf_max = rport->hwbuf_max; + wport->swb_u_idx = rport->swb_u_idx; + wport->swb_i_idx = rport->swb_i_idx; + wport->byte_count = rport->byte_count; + } + if (rport) { + rport->swb_u_avail = 0; + rport->swb_i_avail = rport->swbuf_size; + rport->swstate = SW_RUN; + li_setup_dma(&rport->chan, + &li_comm1, + &devc->lith, + rport->hwbuf_paddr, + HWBUF_SHIFT, + rport->hw_fragshift, + rport->sw_channels, + rport->sample_size); + ad1843_setup_adc(&devc->lith, + rport->sw_framerate, + rport->sw_samplefmt, + rport->sw_channels); + li_enable_interrupts(&devc->lith, READ_INTR_MASK); + if (!(rport->flags & DISABLED)) { + ustmsc_t ustmsc; + rport->hwstate = HW_RUNNING; + li_activate_dma(&rport->chan); + li_read_USTMSC(&rport->chan, &ustmsc); + rport->MSC_offset = ustmsc.msc; + } + } + if (wport) { + if (wport->hwbuf_max > wport->swbuf_size) + wport->hwbuf_max = wport->swbuf_size; + wport->flags &= ~ERFLOWN; + wport->swb_u_avail = wport->swbuf_size; + wport->swb_i_avail = 0; + wport->swstate = SW_RUN; + li_setup_dma(&wport->chan, + &li_comm2, + &devc->lith, + wport->hwbuf_paddr, + HWBUF_SHIFT, + wport->hw_fragshift, + wport->sw_channels, + wport->sample_size); + ad1843_setup_dac(&devc->lith, + wport->sw_framerate, + wport->sw_samplefmt, + wport->sw_channels); + li_enable_interrupts(&devc->lith, WRITE_INTR_MASK); + } + DBGRV(); + return 0; +} + +/* + * pcm_shutdown_port - shut down one port (direction) for PCM I/O. + * Only called from pcm_shutdown. + */ + +static void pcm_shutdown_port(vwsnd_dev_t *devc, + vwsnd_port_t *aport, + unsigned int mask) +{ + unsigned long flags; + vwsnd_port_hwstate_t hwstate; + DECLARE_WAITQUEUE(wait, current); + + aport->swstate = SW_INITIAL; + add_wait_queue(&aport->queue, &wait); + current->state = TASK_UNINTERRUPTIBLE; + while (1) { + spin_lock_irqsave(&aport->lock, flags); + { + hwstate = aport->hwstate; + } + spin_unlock_irqrestore(&aport->lock, flags); + if (hwstate == HW_STOPPED) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&aport->queue, &wait); + li_disable_interrupts(&devc->lith, mask); + if (aport == &devc->rport) + ad1843_shutdown_adc(&devc->lith); + else /* aport == &devc->wport) */ + ad1843_shutdown_dac(&devc->lith); + li_shutdown_dma(&aport->chan); + vfree(aport->swbuf); + aport->swbuf = NULL; + aport->byte_count = 0; +} + +/* + * pcm_shutdown undoes what pcm_setup did. + * Also sets the ports' swstate to newstate. + */ + +static void pcm_shutdown(vwsnd_dev_t *devc, + vwsnd_port_t *rport, + vwsnd_port_t *wport) +{ + DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); + + if (rport && rport->swbuf) { + DBGPV("shutting down rport\n"); + pcm_shutdown_port(devc, rport, READ_INTR_MASK); + } + if (wport && wport->swbuf) { + DBGPV("shutting down wport\n"); + pcm_shutdown_port(devc, wport, WRITE_INTR_MASK); + } + DBGRV(); +} + +static void pcm_copy_in(vwsnd_port_t *rport, int swidx, int hwidx, int nb) +{ + char *src = rport->hwbuf + hwidx; + char *dst = rport->swbuf + swidx; + int fmt = rport->sw_samplefmt; + + DBGPV("swidx = %d, hwidx = %d\n", swidx, hwidx); + ASSERT(rport->hwbuf != NULL); + ASSERT(rport->swbuf != NULL); + ASSERT(nb > 0 && (nb % 32) == 0); + ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); + ASSERT(swidx >= 0 && swidx + nb <= rport->swbuf_size); + ASSERT(hwidx >= 0 && hwidx + nb <= rport->hwbuf_size); + + if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { + + /* See Sample Format Notes above. */ + + char *end = src + nb; + while (src < end) + *dst++ = *src++ ^ 0x80; + } else + memcpy(dst, src, nb); +} + +static void pcm_copy_out(vwsnd_port_t *wport, int swidx, int hwidx, int nb) +{ + char *src = wport->swbuf + swidx; + char *dst = wport->hwbuf + hwidx; + int fmt = wport->sw_samplefmt; + + ASSERT(nb > 0 && (nb % 32) == 0); + ASSERT(wport->hwbuf != NULL); + ASSERT(wport->swbuf != NULL); + ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); + ASSERT(swidx >= 0 && swidx + nb <= wport->swbuf_size); + ASSERT(hwidx >= 0 && hwidx + nb <= wport->hwbuf_size); + if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { + + /* See Sample Format Notes above. */ + + char *end = src + nb; + while (src < end) + *dst++ = *src++ ^ 0x80; + } else + memcpy(dst, src, nb); +} + +/* + * pcm_output() is called both from baselevel and from interrupt level. + * This is where audio frames are copied into the hardware-accessible + * ring buffer. + * + * Locking note: The part of this routine that figures out what to do + * holds wport->lock. The longer part releases wport->lock, but sets + * wport->flags & HW_BUSY. Afterward, it reacquires wport->lock, and + * checks for more work to do. + * + * If another thread calls pcm_output() while HW_BUSY is set, it + * returns immediately, knowing that the thread that set HW_BUSY will + * look for more work to do before returning. + * + * This has the advantage that port->lock is held for several short + * periods instead of one long period. Also, when pcm_output is + * called from base level, it reenables interrupts. + */ + +static void pcm_output(vwsnd_dev_t *devc, int erflown, int nb) +{ + vwsnd_port_t *wport = &devc->wport; + const int hwmax = wport->hwbuf_max; + const int hwsize = wport->hwbuf_size; + const int swsize = wport->swbuf_size; + const int fragsize = wport->hw_fragsize; + unsigned long iflags; + + DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); + spin_lock_irqsave(&wport->lock, iflags); + if (erflown) + wport->flags |= ERFLOWN; + (void) __swb_inc_u(wport, nb); + if (wport->flags & HW_BUSY) { + spin_unlock_irqrestore(&wport->lock, iflags); + DBGPV("returning: HW BUSY\n"); + return; + } + if (wport->flags & DISABLED) { + spin_unlock_irqrestore(&wport->lock, iflags); + DBGPV("returning: DISABLED\n"); + return; + } + wport->flags |= HW_BUSY; + while (1) { + int swptr, hwptr, hw_avail, sw_avail, swidx; + vwsnd_port_hwstate_t hwstate = wport->hwstate; + vwsnd_port_swstate_t swstate = wport->swstate; + int hw_unavail; + ustmsc_t ustmsc; + + hwptr = li_read_hwptr(&wport->chan); + swptr = li_read_swptr(&wport->chan); + hw_unavail = (swptr - hwptr + hwsize) % hwsize; + hw_avail = (hwmax - hw_unavail) & -fragsize; + sw_avail = wport->swb_i_avail & -fragsize; + if (sw_avail && swstate == SW_RUN) { + if (wport->flags & ERFLOWN) { + wport->flags &= ~ERFLOWN; + } + } else if (swstate == SW_INITIAL || + swstate == SW_OFF || + (swstate == SW_DRAIN && + !sw_avail && + (wport->flags & ERFLOWN))) { + DBGP("stopping. hwstate = %d\n", hwstate); + if (hwstate != HW_STOPPED) { + li_deactivate_dma(&wport->chan); + wport->hwstate = HW_STOPPED; + } + wake_up(&wport->queue); + break; + } + if (!sw_avail || !hw_avail) + break; + spin_unlock_irqrestore(&wport->lock, iflags); + + /* + * We gave up the port lock, but we have the HW_BUSY flag. + * Proceed without accessing any nonlocal state. + * Do not exit the loop -- must check for more work. + */ + + swidx = wport->swb_i_idx; + nb = hw_avail; + if (nb > sw_avail) + nb = sw_avail; + if (nb > hwsize - swptr) + nb = hwsize - swptr; /* don't overflow hwbuf */ + if (nb > swsize - swidx) + nb = swsize - swidx; /* don't overflow swbuf */ + ASSERT(nb > 0); + if (nb % fragsize) { + DBGP("nb = %d, fragsize = %d\n", nb, fragsize); + DBGP("hw_avail = %d\n", hw_avail); + DBGP("sw_avail = %d\n", sw_avail); + DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); + DBGP("swsize = %d, swidx = %d\n", swsize, swidx); + } + ASSERT(!(nb % fragsize)); + DBGPV("copying swb[%d..%d] to hwb[%d..%d]\n", + swidx, swidx + nb, swptr, swptr + nb); + pcm_copy_out(wport, swidx, swptr, nb); + li_write_swptr(&wport->chan, (swptr + nb) % hwsize); + spin_lock_irqsave(&wport->lock, iflags); + if (hwstate == HW_STOPPED) { + DBGPV("starting\n"); + li_activate_dma(&wport->chan); + wport->hwstate = HW_RUNNING; + li_read_USTMSC(&wport->chan, &ustmsc); + ASSERT(wport->byte_count % wport->frame_size == 0); + wport->MSC_offset = ustmsc.msc - wport->byte_count / wport->frame_size; + } + __swb_inc_i(wport, nb); + wport->byte_count += nb; + wport->frag_count += nb / fragsize; + ASSERT(nb % fragsize == 0); + wake_up(&wport->queue); + } + wport->flags &= ~HW_BUSY; + spin_unlock_irqrestore(&wport->lock, iflags); + DBGRV(); +} + +/* + * pcm_input() is called both from baselevel and from interrupt level. + * This is where audio frames are copied out of the hardware-accessible + * ring buffer. + * + * Locking note: The part of this routine that figures out what to do + * holds rport->lock. The longer part releases rport->lock, but sets + * rport->flags & HW_BUSY. Afterward, it reacquires rport->lock, and + * checks for more work to do. + * + * If another thread calls pcm_input() while HW_BUSY is set, it + * returns immediately, knowing that the thread that set HW_BUSY will + * look for more work to do before returning. + * + * This has the advantage that port->lock is held for several short + * periods instead of one long period. Also, when pcm_input is + * called from base level, it reenables interrupts. + */ + +static void pcm_input(vwsnd_dev_t *devc, int erflown, int nb) +{ + vwsnd_port_t *rport = &devc->rport; + const int hwmax = rport->hwbuf_max; + const int hwsize = rport->hwbuf_size; + const int swsize = rport->swbuf_size; + const int fragsize = rport->hw_fragsize; + unsigned long iflags; + + DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); + + spin_lock_irqsave(&rport->lock, iflags); + if (erflown) + rport->flags |= ERFLOWN; + (void) __swb_inc_u(rport, nb); + if (rport->flags & HW_BUSY || !rport->swbuf) { + spin_unlock_irqrestore(&rport->lock, iflags); + DBGPV("returning: HW BUSY or !swbuf\n"); + return; + } + if (rport->flags & DISABLED) { + spin_unlock_irqrestore(&rport->lock, iflags); + DBGPV("returning: DISABLED\n"); + return; + } + rport->flags |= HW_BUSY; + while (1) { + int swptr, hwptr, hw_avail, sw_avail, swidx; + vwsnd_port_hwstate_t hwstate = rport->hwstate; + vwsnd_port_swstate_t swstate = rport->swstate; + + hwptr = li_read_hwptr(&rport->chan); + swptr = li_read_swptr(&rport->chan); + hw_avail = (hwptr - swptr + hwsize) % hwsize & -fragsize; + if (hw_avail > hwmax) + hw_avail = hwmax; + sw_avail = rport->swb_i_avail & -fragsize; + if (swstate != SW_RUN) { + DBGP("stopping. hwstate = %d\n", hwstate); + if (hwstate != HW_STOPPED) { + li_deactivate_dma(&rport->chan); + rport->hwstate = HW_STOPPED; + } + wake_up(&rport->queue); + break; + } + if (!sw_avail || !hw_avail) + break; + spin_unlock_irqrestore(&rport->lock, iflags); + + /* + * We gave up the port lock, but we have the HW_BUSY flag. + * Proceed without accessing any nonlocal state. + * Do not exit the loop -- must check for more work. + */ + + swidx = rport->swb_i_idx; + nb = hw_avail; + if (nb > sw_avail) + nb = sw_avail; + if (nb > hwsize - swptr) + nb = hwsize - swptr; /* don't overflow hwbuf */ + if (nb > swsize - swidx) + nb = swsize - swidx; /* don't overflow swbuf */ + ASSERT(nb > 0); + if (nb % fragsize) { + DBGP("nb = %d, fragsize = %d\n", nb, fragsize); + DBGP("hw_avail = %d\n", hw_avail); + DBGP("sw_avail = %d\n", sw_avail); + DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); + DBGP("swsize = %d, swidx = %d\n", swsize, swidx); + } + ASSERT(!(nb % fragsize)); + DBGPV("copying hwb[%d..%d] to swb[%d..%d]\n", + swptr, swptr + nb, swidx, swidx + nb); + pcm_copy_in(rport, swidx, swptr, nb); + li_write_swptr(&rport->chan, (swptr + nb) % hwsize); + spin_lock_irqsave(&rport->lock, iflags); + __swb_inc_i(rport, nb); + rport->byte_count += nb; + rport->frag_count += nb / fragsize; + ASSERT(nb % fragsize == 0); + wake_up(&rport->queue); + } + rport->flags &= ~HW_BUSY; + spin_unlock_irqrestore(&rport->lock, iflags); + DBGRV(); +} + +/* + * pcm_flush_frag() writes zero samples to fill the current fragment, + * then flushes it to the hardware. + * + * It is only meaningful to flush output, not input. + */ + +static void pcm_flush_frag(vwsnd_dev_t *devc) +{ + vwsnd_port_t *wport = &devc->wport; + + DBGPV("swstate = %d\n", wport->swstate); + if (wport->swstate == SW_RUN) { + int idx = wport->swb_u_idx; + int end = (idx + wport->hw_fragsize - 1) + >> wport->hw_fragshift + << wport->hw_fragshift; + int nb = end - idx; + DBGPV("clearing %d bytes\n", nb); + if (nb) + memset(wport->swbuf + idx, + (char) wport->zero_word, + nb); + wport->swstate = SW_DRAIN; + pcm_output(devc, 0, nb); + } + DBGRV(); +} + +/* + * Wait for output to drain. This sleeps uninterruptibly because + * there is nothing intelligent we can do if interrupted. This + * means the process will be delayed in responding to the signal. + */ + +static void pcm_write_sync(vwsnd_dev_t *devc) +{ + vwsnd_port_t *wport = &devc->wport; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + vwsnd_port_hwstate_t hwstate; + + DBGEV("(devc=0x%p)\n", devc); + add_wait_queue(&wport->queue, &wait); + current->state = TASK_UNINTERRUPTIBLE; + while (1) { + spin_lock_irqsave(&wport->lock, flags); + { + hwstate = wport->hwstate; + } + spin_unlock_irqrestore(&wport->lock, flags); + if (hwstate == HW_STOPPED) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + DBGPV("swstate = %d, hwstate = %d\n", wport->swstate, wport->hwstate); + DBGRV(); +} + +/*****************************************************************************/ +/* audio driver */ + +/* + * seek on an audio device always fails. + */ + +static void vwsnd_audio_read_intr(vwsnd_dev_t *devc, unsigned int status) +{ + int overflown = status & LI_INTR_COMM1_OVERFLOW; + + if (status & READ_INTR_MASK) + pcm_input(devc, overflown, 0); +} + +static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status) +{ + int underflown = status & LI_INTR_COMM2_UNDERFLOW; + + if (status & WRITE_INTR_MASK) + pcm_output(devc, underflown, 0); +} + +static void vwsnd_audio_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id; + unsigned int status; + + DBGEV("(irq=%d, dev_id=0x%p, regs=0x%p)\n", irq, dev_id, regs); + + status = li_get_clear_intr_status(&devc->lith); + vwsnd_audio_read_intr(devc, status); + vwsnd_audio_write_intr(devc, status); +} + +static loff_t vwsnd_audio_llseek(struct file *file, loff_t offset, int whence) +{ + DBGEV("(file=0x%p, offset=%Ld, whence=%d)\n", file, offset, whence); + return -ESPIPE; +} + +static ssize_t vwsnd_audio_do_read(struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + vwsnd_port_t *rport = ((file->f_mode & FMODE_READ) ? + &devc->rport : NULL); + int ret, nb; + + DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", + file, buffer, count, ppos); + + if (!rport) + return -EINVAL; + + if (rport->swbuf == NULL) { + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + ret = pcm_setup(devc, rport, wport); + if (ret < 0) + return ret; + } + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count) { + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&rport->queue, &wait); + current->state = TASK_INTERRUPTIBLE; + while ((nb = swb_inc_u(rport, 0)) == 0) { + DBGPV("blocking\n"); + if (rport->flags & DISABLED || + file->f_flags & O_NONBLOCK) { + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + return ret ? ret : -EAGAIN; + } + schedule(); + if (signal_pending(current)) { + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + return ret ? ret : -ERESTARTSYS; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&rport->queue, &wait); + pcm_input(devc, 0, 0); + /* nb bytes are available in userbuf. */ + if (nb > count) + nb = count; + DBGPV("nb = %d\n", nb); + copy_to_user(buffer, rport->swbuf + rport->swb_u_idx, nb); + (void) swb_inc_u(rport, nb); + buffer += nb; + count -= nb; + ret += nb; + } + DBGPV("returning %d\n", ret); + return ret; +} + +static ssize_t vwsnd_audio_read(struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + ssize_t ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_read(file, buffer, count, ppos); + up(&devc->io_sema); + return ret; +} + +static ssize_t vwsnd_audio_do_write(struct file *file, + const char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + vwsnd_port_t *wport = ((file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL); + int ret, nb; + + DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", + file, buffer, count, ppos); + + if (!wport) + return -EINVAL; + + if (wport->swbuf == NULL) { + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + ret = pcm_setup(devc, rport, wport); + if (ret < 0) + return ret; + } + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + while (count) { + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&wport->queue, &wait); + current->state = TASK_INTERRUPTIBLE; + while ((nb = swb_inc_u(wport, 0)) == 0) { + if (wport->flags & DISABLED || + file->f_flags & O_NONBLOCK) { + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + return ret ? ret : -EAGAIN; + } + schedule(); + if (signal_pending(current)) { + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + return ret ? ret : -ERESTARTSYS; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&wport->queue, &wait); + /* nb bytes are available in userbuf. */ + if (nb > count) + nb = count; + DBGPV("nb = %d\n", nb); + copy_from_user(wport->swbuf + wport->swb_u_idx, buffer, nb); + pcm_output(devc, 0, nb); + buffer += nb; + count -= nb; + ret += nb; + } + DBGPV("returning %d\n", ret); + return ret; +} + +static ssize_t vwsnd_audio_write(struct file *file, + const char *buffer, + size_t count, + loff_t *ppos) +{ + vwsnd_dev_t *devc = file->private_data; + ssize_t ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_write(file, buffer, count, ppos); + up(&devc->io_sema); + return ret; +} + +static unsigned int vwsnd_audio_poll(struct file *file, + struct poll_table_struct *wait) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + unsigned int mask = 0; + + DBGEV("(file=0x%p, wait=0x%p)\n", file, wait); + + ASSERT(rport || wport); + if (rport) { + poll_wait(file, &rport->queue, wait); + if (swb_inc_u(rport, 0)) + mask |= (POLLIN | POLLRDNORM); + } + if (wport) { + poll_wait(file, &wport->queue, wait); + if (wport->swbuf == NULL || swb_inc_u(wport, 0)) + mask |= (POLLOUT | POLLWRNORM); + } + + DBGPV("returning 0x%x\n", mask); + return mask; +} + +static int vwsnd_audio_do_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? + &devc->rport : NULL; + vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? + &devc->wport : NULL; + vwsnd_port_t *aport = rport ? rport : wport; + struct audio_buf_info buf_info; + struct count_info info; + unsigned long flags; + int ival; + + + DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n", + inode, file, cmd, arg); + switch (cmd) { + case OSS_GETVERSION: /* _SIOR ('M', 118, int) */ + DBGX("OSS_GETVERSION\n"); + ival = SOUND_VERSION; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */ + DBGX("SNDCTL_DSP_GETCAPS\n"); + ival = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */ + DBGX("SNDCTL_DSP_GETFMTS\n"); + ival = (AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | + AFMT_U8 | AFMT_S8); + return put_user(ival, (int *) arg); + break; + + case SOUND_PCM_READ_RATE: /* _SIOR ('P', 2, int) */ + DBGX("SOUND_PCM_READ_RATE\n"); + ival = aport->sw_framerate; + return put_user(ival, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: /* _SIOR ('P', 6, int) */ + DBGX("SOUND_PCM_READ_CHANNELS\n"); + ival = aport->sw_channels; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SPEED %d\n", ival); + if (ival) { + if (aport->swstate != SW_INITIAL) { + DBGX("SNDCTL_DSP_SPEED failed: swstate = %d\n", + aport->swstate); + return -EINVAL; + } + if (ival < MIN_SPEED) + ival = MIN_SPEED; + if (ival > MAX_SPEED) + ival = MAX_SPEED; + if (rport) + rport->sw_framerate = ival; + if (wport) + wport->sw_framerate = ival; + } else + ival = aport->sw_framerate; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_STEREO %d\n", ival); + if (ival != 0 && ival != 1) + return -EINVAL; + if (aport->swstate != SW_INITIAL) + return -EINVAL; + if (rport) + rport->sw_channels = ival + 1; + if (wport) + wport->sw_channels = ival + 1; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_CHANNELS %d\n", ival); + if (ival != 1 && ival != 2) + return -EINVAL; + if (aport->swstate != SW_INITIAL) + return -EINVAL; + if (rport) + rport->sw_channels = ival; + if (wport) + wport->sw_channels = ival; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */ + ival = pcm_setup(devc, rport, wport); + if (ival < 0) { + DBGX("SNDCTL_DSP_GETBLKSIZE failed, errno %d\n", ival); + return ival; + } + ival = 1 << aport->sw_fragshift; + DBGX("SNDCTL_DSP_GETBLKSIZE returning %d\n", ival); + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n", + ival >> 16, ival & 0xFFFF); + if (aport->swstate != SW_INITIAL) + return -EINVAL; + { + int sw_fragshift = ival & 0xFFFF; + int sw_subdivshift = aport->sw_subdivshift; + int hw_fragshift = sw_fragshift - sw_subdivshift; + int sw_fragcount = (ival >> 16) & 0xFFFF; + int hw_fragsize; + if (hw_fragshift < MIN_FRAGSHIFT) + hw_fragshift = MIN_FRAGSHIFT; + if (hw_fragshift > MAX_FRAGSHIFT) + hw_fragshift = MAX_FRAGSHIFT; + sw_fragshift = hw_fragshift + aport->sw_subdivshift; + hw_fragsize = 1 << hw_fragshift; + if (sw_fragcount < MIN_FRAGCOUNT(hw_fragsize)) + sw_fragcount = MIN_FRAGCOUNT(hw_fragsize); + if (sw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) + sw_fragcount = MAX_FRAGCOUNT(hw_fragsize); + DBGPV("sw_fragshift = %d\n", sw_fragshift); + DBGPV("rport = 0x%p, wport = 0x%p\n", rport, wport); + if (rport) { + rport->sw_fragshift = sw_fragshift; + rport->sw_fragcount = sw_fragcount; + } + if (wport) { + wport->sw_fragshift = sw_fragshift; + wport->sw_fragcount = sw_fragcount; + } + ival = sw_fragcount << 16 | sw_fragshift; + } + DBGX("SNDCTL_DSP_SETFRAGMENT returns %d:%d\n", + ival >> 16, ival & 0xFFFF); + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SUBDIVIDE %d\n", ival); + if (aport->swstate != SW_INITIAL) + return -EINVAL; + { + int subdivshift; + int hw_fragshift, hw_fragsize, hw_fragcount; + switch (ival) { + case 1: subdivshift = 0; break; + case 2: subdivshift = 1; break; + case 4: subdivshift = 2; break; + default: return -EINVAL; + } + hw_fragshift = aport->sw_fragshift - subdivshift; + if (hw_fragshift < MIN_FRAGSHIFT || + hw_fragshift > MAX_FRAGSHIFT) + return -EINVAL; + hw_fragsize = 1 << hw_fragshift; + hw_fragcount = aport->sw_fragcount >> subdivshift; + if (hw_fragcount < MIN_FRAGCOUNT(hw_fragsize) || + hw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) + return -EINVAL; + if (rport) + rport->sw_subdivshift = subdivshift; + if (wport) + wport->sw_subdivshift = subdivshift; + } + return 0; + + case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SETFMT %d\n", ival); + if (ival != AFMT_QUERY) { + if (aport->swstate != SW_INITIAL) { + DBGP("SETFMT failed, swstate = %d\n", + aport->swstate); + return -EINVAL; + } + switch (ival) { + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + case AFMT_S16_LE: + if (rport) + rport->sw_samplefmt = ival; + if (wport) + wport->sw_samplefmt = ival; + break; + default: + return -EINVAL; + } + } + ival = aport->sw_samplefmt; + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */ + DBGXV("SNDCTL_DSP_GETOSPACE\n"); + if (!wport) + return -EINVAL; + ival = pcm_setup(devc, rport, wport); + if (ival < 0) + return ival; + ival = swb_inc_u(wport, 0); + buf_info.fragments = ival >> wport->sw_fragshift; + buf_info.fragstotal = wport->sw_fragcount; + buf_info.fragsize = 1 << wport->sw_fragshift; + buf_info.bytes = ival; + DBGXV("SNDCTL_DSP_GETOSPACE returns { %d %d %d %d }\n", + buf_info.fragments, buf_info.fragstotal, + buf_info.fragsize, buf_info.bytes); + return copy_to_user((void *) arg, &buf_info, sizeof buf_info); + + case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */ + DBGX("SNDCTL_DSP_GETISPACE\n"); + if (!rport) + return -EINVAL; + ival = pcm_setup(devc, rport, wport); + if (ival < 0) + return ival; + ival = swb_inc_u(rport, 0); + buf_info.fragments = ival >> rport->sw_fragshift; + buf_info.fragstotal = rport->sw_fragcount; + buf_info.fragsize = 1 << rport->sw_fragshift; + buf_info.bytes = ival; + DBGX("SNDCTL_DSP_GETISPACE returns { %d %d %d %d }\n", + buf_info.fragments, buf_info.fragstotal, + buf_info.fragsize, buf_info.bytes); + return copy_to_user((void *) arg, &buf_info, sizeof buf_info); + + case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ + DBGX("SNDCTL_DSP_NONBLOCK\n"); + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ + DBGX("SNDCTL_DSP_RESET\n"); + /* + * Nothing special needs to be done for input. Input + * samples sit in swbuf, but it will be reinitialized + * to empty when pcm_setup() is called. + */ + if (wport && wport->swbuf) { + wport->swstate = SW_INITIAL; + pcm_output(devc, 0, 0); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + return 0; + + case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */ + DBGX("SNDCTL_DSP_SYNC\n"); + if (wport) { + pcm_flush_frag(devc); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + return 0; + + case SNDCTL_DSP_POST: /* _SIO ('P', 8) */ + DBGX("SNDCTL_DSP_POST\n"); + if (!wport) + return -EINVAL; + pcm_flush_frag(devc); + return 0; + + case SNDCTL_DSP_GETIPTR: /* _SIOR ('P', 17, count_info) */ + DBGX("SNDCTL_DSP_GETIPTR\n"); + if (!rport) + return -EINVAL; + spin_lock_irqsave(&rport->lock, flags); + { + ustmsc_t ustmsc; + if (rport->hwstate == HW_RUNNING) { + ASSERT(rport->swstate == SW_RUN); + li_read_USTMSC(&rport->chan, &ustmsc); + info.bytes = ustmsc.msc - rport->MSC_offset; + info.bytes *= rport->frame_size; + } else { + info.bytes = rport->byte_count; + } + info.blocks = rport->frag_count; + info.ptr = 0; /* not implemented */ + rport->frag_count = 0; + } + spin_unlock_irqrestore(&rport->lock, flags); + return copy_to_user((void *) arg, &info, sizeof info); + + case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */ + DBGX("SNDCTL_DSP_GETOPTR\n"); + if (!wport) + return -EINVAL; + spin_lock_irqsave(&wport->lock, flags); + { + ustmsc_t ustmsc; + if (wport->hwstate == HW_RUNNING) { + ASSERT(wport->swstate == SW_RUN); + li_read_USTMSC(&wport->chan, &ustmsc); + info.bytes = ustmsc.msc - wport->MSC_offset; + info.bytes *= wport->frame_size; + } else { + info.bytes = wport->byte_count; + } + info.blocks = wport->frag_count; + info.ptr = 0; /* not implemented */ + wport->frag_count = 0; + } + spin_unlock_irqrestore(&wport->lock, flags); + return copy_to_user((void *) arg, &info, sizeof info); + + case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */ + DBGX("SNDCTL_DSP_GETODELAY\n"); + if (!wport) + return -EINVAL; + spin_lock_irqsave(&wport->lock, flags); + { + int fsize = wport->frame_size; + ival = wport->swb_i_avail / fsize; + if (wport->hwstate == HW_RUNNING) { + int swptr, hwptr, hwframes, hwbytes, hwsize; + int totalhwbytes; + ustmsc_t ustmsc; + + hwsize = wport->hwbuf_size; + swptr = li_read_swptr(&wport->chan); + li_read_USTMSC(&wport->chan, &ustmsc); + hwframes = ustmsc.msc - wport->MSC_offset; + totalhwbytes = hwframes * fsize; + hwptr = totalhwbytes % hwsize; + hwbytes = (swptr - hwptr + hwsize) % hwsize; + ival += hwbytes / fsize; + } + } + spin_unlock_irqrestore(&wport->lock, flags); + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_PROFILE: /* _SIOW ('P', 23, int) */ + DBGX("SNDCTL_DSP_PROFILE\n"); + + /* + * Thomas Sailer explains SNDCTL_DSP_PROFILE + * (private email, March 24, 1999): + * + * This gives the sound driver a hint on what it + * should do with partial fragments + * (i.e. fragments partially filled with write). + * This can direct the driver to zero them or + * leave them alone. But don't ask me what this + * is good for, my driver just zeroes the last + * fragment before the receiver stops, no idea + * what good for any other behaviour could + * be. Implementing it as NOP seems safe. + */ + + break; + + case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */ + DBGX("SNDCTL_DSP_GETTRIGGER\n"); + ival = 0; + if (rport) { + spin_lock_irqsave(&rport->lock, flags); + { + if (!(rport->flags & DISABLED)) + ival |= PCM_ENABLE_INPUT; + } + spin_unlock_irqrestore(&rport->lock, flags); + } + if (wport) { + spin_lock_irqsave(&wport->lock, flags); + { + if (!(wport->flags & DISABLED)) + ival |= PCM_ENABLE_OUTPUT; + } + spin_unlock_irqrestore(&wport->lock, flags); + } + return put_user(ival, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */ + get_user_ret(ival, (int *) arg, -EFAULT); + DBGX("SNDCTL_DSP_SETTRIGGER %d\n", ival); + + /* + * If user is disabling I/O and port is not in initial + * state, fail with EINVAL. + */ + + if (((rport && !(ival & PCM_ENABLE_INPUT)) || + (wport && !(ival & PCM_ENABLE_OUTPUT))) && + aport->swstate != SW_INITIAL) + return -EINVAL; + + if (rport) { + vwsnd_port_hwstate_t hwstate; + spin_lock_irqsave(&rport->lock, flags); + { + hwstate = rport->hwstate; + if (ival & PCM_ENABLE_INPUT) + rport->flags &= ~DISABLED; + else + rport->flags |= DISABLED; + } + spin_unlock_irqrestore(&rport->lock, flags); + if (hwstate != HW_RUNNING && ival & PCM_ENABLE_INPUT) { + + if (rport->swstate == SW_INITIAL) + pcm_setup(devc, rport, wport); + else + li_activate_dma(&rport->chan); + } + } + if (wport) { + vwsnd_port_flags_t pflags; + spin_lock_irqsave(&wport->lock, flags); + { + pflags = wport->flags; + if (ival & PCM_ENABLE_OUTPUT) + wport->flags &= ~DISABLED; + else + wport->flags |= DISABLED; + } + spin_unlock_irqrestore(&wport->lock, flags); + if (pflags & DISABLED && ival & PCM_ENABLE_OUTPUT) { + if (wport->swstate == SW_RUN) + pcm_output(devc, 0, 0); + } + } + return 0; + + default: + DBGP("unknown ioctl 0x%x\n", cmd); + return -EINVAL; + } + DBGP("unimplemented ioctl 0x%x\n", cmd); + return -EINVAL; +} + +static int vwsnd_audio_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + int ret; + + down(&devc->io_sema); + ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg); + up(&devc->io_sema); + return ret; +} + +/* No mmap. */ + +static int vwsnd_audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + DBGE("(file=0x%p, vma=0x%p)\n", file, vma); + return -ENODEV; +} + +/* + * Open the audio device for read and/or write. + * + * Returns 0 on success, -errno on failure. + */ + +static int vwsnd_audio_open(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc; + dev_t minor = MINOR(inode->i_rdev); + int sw_samplefmt; + + DBGE("(inode=0x%p, file=0x%p)\n", inode, file); + + INC_USE_COUNT; + for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) + if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) + break; + + if (devc == NULL) { + DEC_USE_COUNT; + return -ENODEV; + } + + down(&devc->open_sema); + while (devc->open_mode & file->f_mode) { + up(&devc->open_sema); + if (file->f_flags & O_NONBLOCK) { + DEC_USE_COUNT; + return -EBUSY; + } + interruptible_sleep_on(&devc->open_wait); + if (signal_pending(current)) { + DEC_USE_COUNT; + return -ERESTARTSYS; + } + down(&devc->open_sema); + } + devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&devc->open_sema); + + /* get default sample format from minor number. */ + + sw_samplefmt = 0; + if ((minor & 0xF) == SND_DEV_DSP) + sw_samplefmt = AFMT_U8; + else if ((minor & 0xF) == SND_DEV_AUDIO) + sw_samplefmt = AFMT_MU_LAW; + else if ((minor & 0xF) == SND_DEV_DSP16) + sw_samplefmt = AFMT_S16_LE; + else + ASSERT(0); + + /* Initialize vwsnd_ports. */ + + down(&devc->io_sema); + { + if (file->f_mode & FMODE_READ) { + devc->rport.swstate = SW_INITIAL; + devc->rport.flags = 0; + devc->rport.sw_channels = 1; + devc->rport.sw_samplefmt = sw_samplefmt; + devc->rport.sw_framerate = 8000; + devc->rport.sw_fragshift = DEFAULT_FRAGSHIFT; + devc->rport.sw_fragcount = DEFAULT_FRAGCOUNT; + devc->rport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; + devc->rport.byte_count = 0; + devc->rport.frag_count = 0; + } + if (file->f_mode & FMODE_WRITE) { + devc->wport.swstate = SW_INITIAL; + devc->wport.flags = 0; + devc->wport.sw_channels = 1; + devc->wport.sw_samplefmt = sw_samplefmt; + devc->wport.sw_framerate = 8000; + devc->wport.sw_fragshift = DEFAULT_FRAGSHIFT; + devc->wport.sw_fragcount = DEFAULT_FRAGCOUNT; + devc->wport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; + devc->wport.byte_count = 0; + devc->wport.frag_count = 0; + } + } + up(&devc->io_sema); + + file->private_data = devc; + DBGRV(); + return 0; +} + +/* + * Release (close) the audio device. + */ + +static int vwsnd_audio_release(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + vwsnd_port_t *wport = NULL, *rport = NULL; + int err = 0; + + down(&devc->io_sema); + { + DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); + + if (file->f_mode & FMODE_READ) + rport = &devc->rport; + if (file->f_mode & FMODE_WRITE) { + wport = &devc->wport; + pcm_flush_frag(devc); + pcm_write_sync(devc); + } + pcm_shutdown(devc, rport, wport); + if (rport) + rport->swstate = SW_OFF; + if (wport) + wport->swstate = SW_OFF; + } + up(&devc->io_sema); + + down(&devc->open_sema); + { + devc->open_mode &= ~file->f_mode; + } + up(&devc->open_sema); + wake_up(&devc->open_wait); + DBGDO(if (IN_USE)) /* see hack in vwsnd_mixer_release() */ + DEC_USE_COUNT; + DBGR(); + return err; +} + +static struct file_operations vwsnd_audio_fops = { + &vwsnd_audio_llseek, + &vwsnd_audio_read, + &vwsnd_audio_write, + NULL, /* readdir */ + &vwsnd_audio_poll, + &vwsnd_audio_ioctl, + &vwsnd_audio_mmap, + &vwsnd_audio_open, + NULL, /* flush */ + &vwsnd_audio_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/*****************************************************************************/ +/* mixer driver */ + +/* open the mixer device. */ + +static int vwsnd_mixer_open(struct inode *inode, struct file *file) +{ + vwsnd_dev_t *devc; + + DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); + + INC_USE_COUNT; + for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) + if (devc->mixer_minor == MINOR(inode->i_rdev)) + break; + + if (devc == NULL) { + DEC_USE_COUNT; + return -ENODEV; + } + file->private_data = devc; + return 0; +} + +/* release (close) the mixer device. */ + +static int vwsnd_mixer_release(struct inode *inode, struct file *file) +{ + DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); + + /* + * hack -- opening/closing the mixer device zeroes use count + * so driver can be unloaded. + * Use only while debugging module, and then use it carefully. + */ + + DBGDO(while (IN_USE)) + DEC_USE_COUNT; + return 0; +} + +/* seek is illegal on mixer. */ + +static loff_t vwsnd_mixer_llseek(struct file *file, loff_t offset, int whence) +{ + return -ESPIPE; +} + +/* mixer_read_ioctl handles all read ioctls on the mixer device. */ + +static int mixer_read_ioctl(vwsnd_dev_t *devc, unsigned int nr, caddr_t arg) +{ + int val = -1; + + DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); + + switch (nr) { + case SOUND_MIXER_CAPS: + val = SOUND_CAP_EXCL_INPUT; + break; + + case SOUND_MIXER_DEVMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); + break; + + case SOUND_MIXER_STEREODEVS: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); + break; + + case SOUND_MIXER_OUTMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD); + break; + + case SOUND_MIXER_RECMASK: + val = (SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_MIC | SOUND_MASK_CD); + break; + + case SOUND_MIXER_PCM: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_PCM); + break; + + case SOUND_MIXER_LINE: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_LINE); + break; + + case SOUND_MIXER_MIC: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_MIC); + break; + + case SOUND_MIXER_CD: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_CD); + break; + + case SOUND_MIXER_RECLEV: + val = ad1843_get_gain(&devc->lith, &ad1843_gain_RECLEV); + break; + + case SOUND_MIXER_RECSRC: + val = ad1843_get_recsrc(&devc->lith); + break; + + case SOUND_MIXER_OUTSRC: + val = ad1843_get_outsrc(&devc->lith); + break; + + default: + return -EINVAL; + } + return put_user(val, (int *) arg); +} + +/* mixer_write_ioctl handles all write ioctls on the mixer device. */ + +static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, caddr_t arg) +{ + int val; + int err; + + DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); + + err = get_user(val, (int *) arg); + if (err) + return -EFAULT; + switch (nr) { + case SOUND_MIXER_PCM: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_PCM, val); + break; + + case SOUND_MIXER_LINE: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_LINE, val); + break; + + case SOUND_MIXER_MIC: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_MIC, val); + break; + + case SOUND_MIXER_CD: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_CD, val); + break; + + case SOUND_MIXER_RECLEV: + val = ad1843_set_gain(&devc->lith, &ad1843_gain_RECLEV, val); + break; + + case SOUND_MIXER_RECSRC: + if (devc->rport.swbuf || devc->wport.swbuf) + return -EBUSY; /* can't change recsrc while running */ + val = ad1843_set_recsrc(&devc->lith, val); + break; + + case SOUND_MIXER_OUTSRC: + val = ad1843_set_outsrc(&devc->lith, val); + break; + + default: + return -EINVAL; + } + if (val < 0) + return val; + return put_user(val, (int *) arg); +} + +/* This is the ioctl entry to the mixer driver. */ + +static int vwsnd_mixer_ioctl(struct inode *ioctl, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; + const unsigned int nrmask = _IOC_NRMASK << _IOC_NRSHIFT; + const unsigned int nr = (cmd & nrmask) >> _IOC_NRSHIFT; + int retval; + + DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); + + down(&devc->mix_sema); + { + if ((cmd & ~nrmask) == MIXER_READ(0)) + retval = mixer_read_ioctl(devc, nr, (caddr_t) arg); + else if ((cmd & ~nrmask) == MIXER_WRITE(0)) + retval = mixer_write_ioctl(devc, nr, (caddr_t) arg); + else + retval = -EINVAL; + } + up(&devc->mix_sema); + return retval; +} + +static struct file_operations vwsnd_mixer_fops = { + &vwsnd_mixer_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &vwsnd_mixer_ioctl, + NULL, /* mmap */ + &vwsnd_mixer_open, + NULL, /* flush */ + &vwsnd_mixer_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/*****************************************************************************/ +/* probe/attach/unload */ + +/* driver probe routine. Return nonzero if hardware is found. */ + +static int probe_vwsnd(struct address_info *hw_config) +{ + lithium_t lith; + int w; + unsigned long later; + + DBGEV("(hw_config=0x%p)\n", hw_config); + + /* XXX verify lithium present (to prevent crash on non-vw) */ + + if (li_create(&lith, hw_config->io_base) != 0) { + printk(KERN_WARNING "probe_vwsnd: can't map lithium\n"); + return 0; + } + later = jiffies + 2; + li_writel(&lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); + do { + w = li_readl(&lith, LI_HOST_CONTROLLER); + } while (w == LI_HC_LINK_ENABLE && jiffies < later); + + li_destroy(&lith); + + DBGPV("HC = 0x%04x\n", w); + + if ((w == LI_HC_LINK_ENABLE) || (w & LI_HC_LINK_CODEC)) { + + /* This may indicate a beta machine with no audio, + * or a future machine with different audio. + * On beta-release 320 w/ no audio, HC == 0x4000 */ + + printk(KERN_WARNING "probe_vwsnd: audio codec not found\n"); + return 0; + } + + if (w & LI_HC_LINK_FAILURE) { + printk(KERN_WARNING "probe_vwsnd: can't init audio codec\n"); + return 0; + } + + printk(KERN_INFO "probe_vwsnd: lithium audio found\n"); + + return 1; +} + +/* + * driver attach routine. Initialize driver data structures and + * initialize hardware. A new vwsnd_dev_t is allocated and put + * onto the global list, vwsnd_dev_list. + * + * Return +minor_dev on success, -errno on failure. + */ + +static int attach_vwsnd(struct address_info *hw_config) +{ + vwsnd_dev_t *devc = NULL; + int err = -ENOMEM; + + DBGEV("(hw_config=0x%p)\n", hw_config); + + devc = kmalloc(sizeof (vwsnd_dev_t), GFP_KERNEL); + if (devc == NULL) + goto fail0; + + err = li_create(&devc->lith, hw_config->io_base); + if (err) + goto fail1; + + init_waitqueue(&devc->open_wait); + + devc->rport.hwbuf_size = HWBUF_SIZE; + devc->rport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); + if (!devc->rport.hwbuf_vaddr) + goto fail2; + devc->rport.hwbuf = (caddr_t) devc->rport.hwbuf_vaddr; + devc->rport.hwbuf_paddr = virt_to_phys(devc->rport.hwbuf); + + /* + * Quote from the NT driver: + * + * // WARNING!!! HACK to setup output dma!!! + * // This is required because even on output there is some data + * // trickling into the input DMA channel. This is a bug in the + * // Lithium microcode. + * // --sde + * + * We set the input side's DMA base address here. It will remain + * valid until the driver is unloaded. + */ + + li_writel(&devc->lith, LI_COMM1_BASE, + devc->rport.hwbuf_paddr >> 8 | 1 << (37 - 8)); + + devc->wport.hwbuf_size = HWBUF_SIZE; + devc->wport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); + if (!devc->wport.hwbuf_vaddr) + goto fail3; + devc->wport.hwbuf = (caddr_t) devc->wport.hwbuf_vaddr; + devc->wport.hwbuf_paddr = virt_to_phys(devc->wport.hwbuf); + DBGP("wport hwbuf = 0x%p\n", devc->wport.hwbuf); + + DBGDO(shut_up++); + err = ad1843_init(&devc->lith); + DBGDO(shut_up--); + if (err) + goto fail4; + + /* install interrupt handler */ + + err = request_irq(hw_config->irq, vwsnd_audio_intr, 0, "vwsnd", devc); + if (err) + goto fail5; + + /* register this device's drivers. */ + + devc->audio_minor = register_sound_dsp(&vwsnd_audio_fops, -1); + if ((err = devc->audio_minor) < 0) { + DBGDO(printk(KERN_WARNING + "attach_vwsnd: register_sound_dsp error %d\n", + err)); + goto fail6; + } + devc->mixer_minor = register_sound_mixer(&vwsnd_mixer_fops, + devc->audio_minor >> 4); + if ((err = devc->mixer_minor) < 0) { + DBGDO(printk(KERN_WARNING + "attach_vwsnd: register_sound_mixer error %d\n", + err)); + goto fail7; + } + + /* Squirrel away device indices for unload routine. */ + + hw_config->slots[0] = devc->audio_minor; + + /* Initialize as much of *devc as possible */ + + devc->open_sema = MUTEX; + devc->io_sema = MUTEX; + devc->mix_sema = MUTEX; + devc->open_mode = 0; + devc->rport.lock = SPIN_LOCK_UNLOCKED; + init_waitqueue(&devc->rport.queue); + devc->rport.swstate = SW_OFF; + devc->rport.hwstate = HW_STOPPED; + devc->rport.flags = 0; + devc->rport.swbuf = NULL; + devc->wport.lock = SPIN_LOCK_UNLOCKED; + init_waitqueue(&devc->wport.queue); + devc->wport.swstate = SW_OFF; + devc->wport.hwstate = HW_STOPPED; + devc->wport.flags = 0; + devc->wport.swbuf = NULL; + + /* Success. Link us onto the local device list. */ + + devc->next_dev = vwsnd_dev_list; + vwsnd_dev_list = devc; + return devc->audio_minor; + + /* So many ways to fail. Undo what we did. */ + + fail7: + unregister_sound_dsp(devc->audio_minor); + fail6: + free_irq(hw_config->irq, devc); + fail5: + fail4: + free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); + fail3: + free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); + fail2: + li_destroy(&devc->lith); + fail1: + kfree(devc); + fail0: + return err; +} + +static int unload_vwsnd(struct address_info *hw_config) +{ + vwsnd_dev_t *devc, **devcp; + + DBGE("()\n"); + + if (IN_USE) + return -EBUSY; + devcp = &vwsnd_dev_list; + while ((devc = *devcp)) { + if (devc->audio_minor == hw_config->slots[0]) { + *devcp = devc->next_dev; + break; + } + devcp = &devc->next_dev; + } + + if (!devc) + return -ENODEV; + + unregister_sound_mixer(devc->mixer_minor); + unregister_sound_dsp(devc->audio_minor); + free_irq(hw_config->irq, devc); + free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); + free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); + li_destroy(&devc->lith); + kfree(devc); + + return 0; +} + +/*****************************************************************************/ +/* initialization and loadable kernel module interface */ + +static struct address_info the_hw_config = { + 0xFF001000, /* lithium phys addr */ + CO_IRQ(CO_APIC_LI_AUDIO) /* irq */ +}; + +#ifdef MODULE + +MODULE_DESCRIPTION("SGI Visual Workstation sound module"); +MODULE_AUTHOR("Bob Miller "); + +extern int init_module(void) +{ + int err; + + DBGXV("\n"); + DBGXV("sound::vwsnd::init_module()\n"); + + if(!probe_vwsnd(&the_hw_config)) + return -ENODEV; + err = attach_vwsnd(&the_hw_config); + if (err < 0) + return err; + return 0; +} + +extern void cleanup_module(void) +{ + DBGX("sound::vwsnd::cleanup_module()\n"); + + unload_vwsnd(&the_hw_config); +} + +#else + +extern void init_vwsnd(void) +{ + DBGX("sound::vwsnd::init_vwsnd()\n"); + if (probe_vwsnd(&the_hw_config)) + (void) attach_vwsnd(&the_hw_config); +} + +#endif /* !MODULE */ + +/* + * Local variables: + * compile-command: "cd ../..; make modules SUBDIRS=drivers/sound" + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.3.14/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.14/linux/drivers/usb/Config.in Mon Aug 9 12:15:53 1999 +++ linux/drivers/usb/Config.in Wed Aug 25 15:03:54 1999 @@ -24,6 +24,8 @@ bool ' OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB fi + bool 'Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC + dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB diff -u --recursive --new-file v2.3.14/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.14/linux/drivers/usb/Makefile Fri Aug 13 11:54:47 1999 +++ linux/drivers/usb/Makefile Wed Aug 25 15:03:54 1999 @@ -18,11 +18,14 @@ MOD_LIST_NAME := USB_MODULES ifeq ($(CONFIG_USB),y) - L_OBJS +=usbcore.o + L_OBJS += usbcore.o + ifeq ($(CONFIG_USB_PROC),y) + L_OBJS += proc_usb.o + endif endif ifeq ($(CONFIG_USB),m) - M_OBJS +=usbcore.o - MIX_OBJS +=usb.o usb-debug.o usb-core.o + M_OBJS += usbcore.o + MIX_OBJS += usb.o usb-debug.o usb-core.o ifeq ($(CONFIG_USB_PROC),y) MIX_OBJS += proc_usb.o endif @@ -57,16 +60,16 @@ L_OBJS += mouse.o endif ifeq ($(CONFIG_USB_MOUSE),m) - M_OBJS +=mouse.o - MIX_OBJS +=mouse.o + M_OBJS += mouse.o + MIX_OBJS += mouse.o endif ifeq ($(CONFIG_USB_HUB),y) L_OBJS += hub.o endif ifeq ($(CONFIG_USB_HUB),m) - M_OBJS +=hub.o - MIX_OBJS +=hub.o + M_OBJS += hub.o + MIX_OBJS += hub.o endif ifeq ($(CONFIG_USB_ACM),y) @@ -74,7 +77,7 @@ endif ifeq ($(CONFIG_USB_ACM),m) M_OBJS += acm.o - MIX_OBJS +=acm.o + MIX_OBJS += acm.o endif ifeq ($(CONFIG_USB_PRINTER),y) @@ -86,15 +89,6 @@ MIX_OBJS += printer.o endif -ifeq ($(CONFIG_USB_CPIA),y) - L_OBJS += cpia.o -endif - -ifeq ($(CONFIG_USB_CPIA),m) - M_OBJS += cpia.o - MIX_OBJS += cpia.o -endif - ifeq ($(CONFIG_USB_KBD),y) L_OBJS += keyboard.o keymap.o endif @@ -187,10 +181,10 @@ usb-ohci.o: ohci.o ohci-debug.o $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o - + usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o - + ifeq ($(CONFIG_USB_PROC),y) usbcore.o: usb.o usb-debug.o usb-core.o proc_usb.o $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o proc_usb.o diff -u --recursive --new-file v2.3.14/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.14/linux/drivers/usb/acm.c Mon Aug 2 14:29:08 1999 +++ linux/drivers/usb/acm.c Wed Aug 25 15:03:54 1999 @@ -468,15 +468,15 @@ Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm); } -static int get_free_acm() +static int get_free_acm(void) { - int i; + int i; - for (i=0;idescriptor.bDeviceProtocol != 0) return -1; - /*Now scan all configs for a ACM configuration*/ + /* Now scan all configs for a ACM configuration */ for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { /* The first one should be Communications interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[0]; + interface = &dev->config[cfgnum].interface[0].altsetting[0]; if (interface->bInterfaceClass != 2 || interface->bInterfaceSubClass != 2 || interface->bInterfaceProtocol != 1 || @@ -517,7 +517,7 @@ continue; /* The second one should be a Data interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[1]; + interface = &dev->config[cfgnum].interface[1].altsetting[0]; if (interface->bInterfaceClass != 10 || interface->bInterfaceSubClass != 0 || interface->bInterfaceProtocol != 0 || @@ -542,18 +542,18 @@ acm->dev=dev; dev->private=acm; - acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress; + acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].bEndpointAddress; acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp); - acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].wMaxPacketSize,GFP_KERNEL); + acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].wMaxPacketSize,GFP_KERNEL); acm->reading=0; if (!acm->readbuffer) { printk("ACM: Couldn't allocate readbuffer\n"); return -1; } - acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress; + acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].bEndpointAddress; acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp); - acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].wMaxPacketSize, GFP_KERNEL); + acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].wMaxPacketSize, GFP_KERNEL); acm->writing=0; if (!acm->writebuffer) { printk("ACM: Couldn't allocate writebuffer\n"); @@ -561,11 +561,11 @@ return -1; } - acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress; + acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress; acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp); - acm->ctrlinterval=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval; + acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval; - acm->present=1; + acm->present=1; MOD_INC_USE_COUNT; return 0; } @@ -699,4 +699,4 @@ { usb_acm_cleanup(); } -#endif +#endif diff -u --recursive --new-file v2.3.14/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.3.14/linux/drivers/usb/audio.c Mon Aug 16 23:19:13 1999 +++ linux/drivers/usb/audio.c Wed Aug 25 15:03:54 1999 @@ -15,6 +15,8 @@ struct usb_audio { struct usb_device *dev; struct list_head list; + + void *irq_handle; }; static struct usb_driver usb_audio_driver = { @@ -25,42 +27,43 @@ }; +#if 0 static int usb_audio_irq(int state, void *buffer, int len, void *dev_id) { +#if 0 struct usb_audio *aud = (struct usb_audio *)dev_id; printk("irq on %p\n", aud); +#endif return 1; } +#endif static int usb_audio_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; - struct usb_endpoint_descriptor *endpoint; + struct usb_interface_descriptor *interface; struct usb_audio *aud; - int bEndpointAddress = 0; int i; int na=0; - for (i=0; iconfig[0].bNumInterfaces; i++) { - intf_desc = &dev->config->interface[i].altsetting[0]; + interface = &dev->config->interface[i].altsetting[0]; - if(intf_desc->bInterfaceClass != 1) + if (interface->bInterfaceClass != 1) continue; printk(KERN_INFO "USB audio device detected.\n"); - switch(intf_desc->bInterfaceSubClass) { + switch(interface->bInterfaceSubClass) { case 0x01: - printk(KERN_INFO "audio: Control device.\n"); + printk(KERN_INFO "audio: control device\n"); break; case 0x02: - printk(KERN_INFO "audio: streaming.\n"); + printk(KERN_INFO "audio: streaming\n"); break; case 0x03: - printk(KERN_INFO "audio: nonstreaming.\n"); + printk(KERN_INFO "audio: nonstreaming\n"); break; } na++; @@ -70,44 +73,49 @@ return -1; aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL); - if (aud) { - memset(aud, 0, sizeof(*aud)); - aud->dev = dev; - dev->private = aud; - -// if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { -// printk (KERN_INFO " Failed usb_set_configuration: Audio\n"); -// break; -// } -// usb_set_protocol(dev, 0); -// usb_set_idle(dev, 0, 0); + if (!aud) + return -1; + + memset(aud, 0, sizeof(*aud)); + aud->dev = dev; + dev->private = aud; + +/* + if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { + printk (KERN_INFO "Failed usb_set_configuration: Audio\n"); + break; + } + usb_set_protocol(dev, 0); + usb_set_idle(dev, 0, 0); +*/ -// usb_request_irq(dev, -// usb_rcvctrlpipe(dev, bEndpointAddress), -// usb_audio_irq, -// endpoint->bInterval, -// aud); +/* + aud->irq_handle = usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_audio_irq, + endpoint->bInterval, + aud); +*/ - list_add(&aud->list, &usb_audio_list); + list_add(&aud->list, &usb_audio_list); - return 0; - } - - if (aud) - kfree (aud); - return -1; + return 0; } static void usb_audio_disconnect(struct usb_device *dev) { struct usb_audio *aud = (struct usb_audio*) dev->private; - if (aud) { - dev->private = NULL; - list_del(&aud->list); - kfree(aud); - } - printk(KERN_INFO "USB audio driver removed.\n"); + if (!aud) + return; + + list_del(&aud->list); + + usb_release_irq(aud->dev, aud->irq_handle); + aud->irq_handle = NULL; + + kfree(aud); + dev->private = NULL; } int usb_audio_init(void) diff -u --recursive --new-file v2.3.14/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.14/linux/drivers/usb/cpia.c Fri Jul 30 12:31:45 1999 +++ linux/drivers/usb/cpia.c Wed Aug 25 15:03:54 1999 @@ -1,11 +1,12 @@ /* * USB CPiA Video Camera driver * - * Supports CPiA based Video Camera's. Many manufacturers use this chipset. + * Supports CPiA based Video Cameras. Many manufacturers use this chipset. * There's a good chance, if you have a USB video camera, it's a CPiA based - * one + * one. * * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap */ #include @@ -453,6 +454,31 @@ cpia->scratchlen = l; } +/* + * For the moment there is no actual data compression (making blocks + * of data contiguous). This just checks the "frames" array for errors. + */ +static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc) +{ + char *data = isodesc->data; + int i, totlen = 0; + + for (i = 0; i < isodesc->frame_count; i++) { + int n = isodesc->frames [i].frame_length; + int st = isodesc->frames [i].frame_status; + +#ifdef CPIA_DEBUG + /* Debugging */ + if (st) + printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", + i, n, st); +#endif + + } + + return totlen; +} + static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) { struct usb_cpia *cpia = dev_id; @@ -489,10 +515,10 @@ sbuf = &cpia->sbuf[cpia->receivesbuf]; - usb_unschedule_isochronous(dev, sbuf->isodesc); + usb_kill_isoc(sbuf->isodesc); /* Do something to it now */ - sbuf->len = usb_compress_isochronous(dev, sbuf->isodesc); + sbuf->len = cpia_compress_isochronous(sbuf->isodesc); #ifdef CPIA_DEBUG if (sbuf->len) @@ -511,7 +537,12 @@ } /* Reschedule this block of Isochronous desc */ + /* + usb_run_isoc(sbuf->isodesc, NULL); + */ +/* usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc); +*/ /* Move to the next one */ cpia->receivesbuf = (cpia->receivesbuf + 1) % 3; @@ -522,6 +553,8 @@ int cpia_init_isoc(struct usb_cpia *cpia) { struct usb_device *dev = cpia->dev; + struct usb_isoc_desc *id; + int fx, err; cpia->receivesbuf = 0; @@ -529,21 +562,66 @@ cpia->curline = 0; cpia->state = STATE_SCANNING; - /* Allocate all of the memory necessary */ + /* ALT_ISOC is only doing double-buffering, not triple. */ + err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia, + &cpia->sbuf[0].isodesc); + if (err) + printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err); + err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia, + &cpia->sbuf[1].isodesc); + if (err) + printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err); + + if (!cpia->sbuf[0].isodesc || !cpia->sbuf[1].isodesc) { + if (cpia->sbuf[0].isodesc) + usb_free_isoc (cpia->sbuf[0].isodesc); + if (cpia->sbuf[1].isodesc) + usb_free_isoc (cpia->sbuf[1].isodesc); + return -ENOMEM; + } +#if 0 cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); +#endif #ifdef CPIA_DEBUG printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc); printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc); +#if 0 printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc); #endif +#endif + + /* Set the Isoc. desc. parameters. */ + /* First for desc. [0] */ + id = cpia->sbuf [0].isodesc; + id->start_type = START_ASAP; + id->callback_frames = 1; /* on every frame */ + id->callback_fn = cpia_isoc_irq; + id->data = cpia->sbuf [0].data; + id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) + id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; + + /* and the desc. [1] */ + id = cpia->sbuf [1].isodesc; + id->start_type = 0; /* will follow the first desc. */ + id->callback_frames = 1; /* on every frame */ + id->callback_fn = cpia_isoc_irq; + id->data = cpia->sbuf [1].data; + id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) + id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; + + usb_run_isoc (cpia->sbuf [0].isodesc, NULL); + usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc); - /* Schedule the queues */ +#if 0 usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL); usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc); +#endif #ifdef CPIA_DEBUG printk("done scheduling\n"); @@ -582,19 +660,28 @@ } /* Unschedule all of the iso td's */ + usb_kill_isoc (cpia->sbuf[1].isodesc); + usb_kill_isoc (cpia->sbuf[0].isodesc); +#if 0 usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc); usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc); usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc); +#endif /* Delete them all */ + usb_free_isoc (cpia->sbuf[1].isodesc); + usb_free_isoc (cpia->sbuf[0].isodesc); +#if 0 usb_delete_isochronous(dev, cpia->sbuf[2].isodesc); usb_delete_isochronous(dev, cpia->sbuf[1].isodesc); usb_delete_isochronous(dev, cpia->sbuf[0].isodesc); +#endif } /* Video 4 Linux API */ static int cpia_open(struct video_device *dev, int flags) { + int err = -ENOMEM; struct usb_cpia *cpia = (struct usb_cpia *)dev; #ifdef CPIA_DEBUG @@ -615,6 +702,15 @@ printk("frame [1] @ %p\n", cpia->frame[1].data); #endif + cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cpia->sbuf[0].data) + goto open_err_on0; + + cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cpia->sbuf[1].data) + goto open_err_on1; + +#if 0 cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[0].data) goto open_err_on0; @@ -626,19 +722,24 @@ cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[2].data) goto open_err_on2; +#endif #ifdef CPIA_DEBUG printk("sbuf[0] @ %p\n", cpia->sbuf[0].data); printk("sbuf[1] @ %p\n", cpia->sbuf[1].data); +#if 0 printk("sbuf[2] @ %p\n", cpia->sbuf[2].data); #endif +#endif cpia->curframe = -1; cpia->receivesbuf = 0; usb_cpia_initstreamcap(cpia->dev, 0, 60); - cpia_init_isoc(cpia); + err = cpia_init_isoc(cpia); + if (err) + goto open_err_on2; return 0; @@ -649,7 +750,7 @@ open_err_on0: rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); open_err_ret: - return -ENOMEM; + return err; } static void cpia_close(struct video_device *dev) @@ -1083,7 +1184,7 @@ if (dev->descriptor.bNumConfigurations != 1) return -1; - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0].altsetting[0]; /* Is it a CPiA? */ if (dev->descriptor.idVendor != 0x0553) diff -u --recursive --new-file v2.3.14/linux/drivers/usb/cpia.h linux/drivers/usb/cpia.h --- v2.3.14/linux/drivers/usb/cpia.h Thu May 13 14:18:09 1999 +++ linux/drivers/usb/cpia.h Wed Aug 25 15:03:54 1999 @@ -82,6 +82,9 @@ #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) +#define FRAMES_PER_DESC 500 +#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ + enum { STATE_SCANNING, /* Scanning for start */ STATE_HEADER, /* Parsing header */ @@ -93,7 +96,10 @@ struct cpia_sbuf { char *data; int len; + struct usb_isoc_desc *isodesc; +#if 0 void *isodesc; +#endif }; enum { diff -u --recursive --new-file v2.3.14/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c --- v2.3.14/linux/drivers/usb/ezusb.c Wed Jul 28 10:45:39 1999 +++ linux/drivers/usb/ezusb.c Wed Aug 25 15:03:54 1999 @@ -22,6 +22,10 @@ * * History: * 0.1 26.05.99 Created + * 0.2 23.07.99 Removed EZUSB_INTERRUPT. Interrupt pipes may be polled with + * bulk reads. + * Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK. + * Preliminary ISO support * */ @@ -31,6 +35,9 @@ #include #include #include +#include +#include +#include #include "usb.h" #include "ezusb.h" @@ -42,23 +49,27 @@ static struct ezusb { struct semaphore mutex; struct usb_device *usbdev; - unsigned int irqep; - unsigned int intlen; - unsigned char intdata[64]; + struct list_head iso; } ezusb[NREZUSB]; -/* --------------------------------------------------------------------- */ +struct isodesc { + struct list_head isolist; + spinlock_t lock; + struct usb_device *usbdev; + unsigned int ep; + unsigned int pipe; + unsigned int pktsz; + unsigned int framesperint; + unsigned int rd, wr, buflen; + unsigned int flags; + unsigned int schedcnt, unschedcnt; + + void *hcbuf[2]; + void *hcisodesc[2]; + unsigned char *buf; +}; -static int ezusb_irq(int state, void *__buffer, int len, void *dev_id) -{ - struct ezusb *ez = (struct ezusb *)dev_id; - - if (len > sizeof(ez->intdata)) - len = sizeof(ez->intdata); - ez->intlen = len; - memcpy(ez->intdata, __buffer, len); - return 1; -} +#define ISOFLG_ACTIVE (1<<0) /* --------------------------------------------------------------------- */ @@ -214,16 +225,132 @@ return 0; } +static void iso_schedrcv(struct isodesc *isodesc) +{ + unsigned diff; + + if (!(isodesc->flags & ISOFLG_ACTIVE)) + return; + diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; + if (diff < isodesc->framesperint * isodesc->pktsz) + return; + for (;;) { + diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3; + if (diff >= 2) + return; + usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1], + diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL); + isodesc->schedcnt++; + } +} + +static void iso_schedsnd(struct isodesc *isodesc) +{ + unsigned diff, bcnt, x; + unsigned char *p1, *p2; + + if (!(isodesc->flags & ISOFLG_ACTIVE)) + return; + for (;;) { + diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3; + if (diff >= 2) + return; + bcnt = (isodesc->buflen - isodesc->rd + isodesc->wr) % isodesc->buflen; + if (bcnt < isodesc->framesperint * isodesc->pktsz) + return; + p2 = isodesc->hcbuf[isodesc->schedcnt & 1]; + for (bcnt = 0; bcnt < isodesc->framesperint; bcnt++) { + p1 = isodesc->buf + isodesc->rd; + if (isodesc->rd + isodesc->pktsz > isodesc->buflen) { + x = isodesc->buflen - isodesc->rd; + memcpy(p2, p1, x); + memcpy(p2+x, isodesc->buf, isodesc->pktsz - x); + } else + memcpy(p2, p1, isodesc->pktsz); + isodesc->rd = (isodesc->rd + isodesc->pktsz) % isodesc->buflen; + p2 += isodesc->pktsz; + if (((unsigned long)p2 ^ ((unsigned long)p2 + isodesc->pktsz - 1)) & (~(PAGE_SIZE - 1))) + p2 = (void *)(((unsigned long)p2 + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1))); + } + usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1], + diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL); + isodesc->schedcnt++; + } +} + +static int ezusb_isorcv_irq(int status, void *__buffer, int __len, void *dev_id) +{ + struct isodesc *isodesc = (struct isodesc *)dev_id; + unsigned int len, len2; + unsigned char *p1; + + spin_lock(&isodesc->lock); + usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); + len = usb_compress_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); + printk(KERN_DEBUG "ezusb_isorcv_irq: %u bytes recvd\n", len); + p1 = isodesc->hcbuf[isodesc->unschedcnt & 1]; + while (len > 0) { + len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; + if (!len2) + break; + if (isodesc->wr + len2 > isodesc->buflen) + len2 = isodesc->buflen - isodesc->wr; + if (len2 > len) + len2 = len; + memcpy(isodesc->buf + isodesc->wr, p1, len2); + isodesc->wr = (isodesc->wr + len2) % isodesc->buflen; + p1 += len2; + len -= len2; + } + isodesc->unschedcnt++; + iso_schedrcv(isodesc); + spin_unlock(&isodesc->lock); + return 1; +} + +static int ezusb_isosnd_irq(int status, void *__buffer, int len, void *dev_id) +{ + struct isodesc *isodesc = (struct isodesc *)dev_id; + + spin_lock(&isodesc->lock); + usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); + isodesc->unschedcnt++; + iso_schedsnd(isodesc); + spin_unlock(&isodesc->lock); + return 1; +} + +static struct isodesc *findiso(struct ezusb *ez, unsigned int ep) +{ + struct list_head *head = &ez->iso; + struct list_head *tmp = head->next; + struct isodesc *id; + + while (tmp != head) { + id = list_entry(tmp, struct isodesc, isolist); + if (id->ep == ep) + return id; + tmp = tmp->next; + } + return NULL; +} + static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ezusb *ez = (struct ezusb *)file->private_data; struct ezusb_ctrltransfer ctrl; struct ezusb_bulktransfer bulk; - unsigned int len1, ep; + struct ezusb_setinterface setintf; + unsigned int len1, ep, pipe, cnt; unsigned long len2; - unsigned int irqep; unsigned char tbuf[1024]; int i; + struct ezusb_isotransfer isot; + struct ezusb_isodata isod; + struct isodesc *isodesc; + usb_device_irq isocompl; + unsigned long flags; + unsigned char *p1, *p2; switch (cmd) { case EZUSB_CONTROL: @@ -264,23 +391,14 @@ } return 0; - case EZUSB_INTERRUPT: - get_user_ret(irqep, (unsigned int *)arg, -EFAULT); - if (irqep != ez->irqep) { - if (ez->irqep) - return -EIO; - ez->irqep = irqep; - usb_request_irq(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, ez->irqep), - ezusb_irq, 2 /* interval */, ez); - ez->intlen = 0; - return -EAGAIN; - } - copy_to_user_ret((&((struct ezusb_interrupttransfer *)0)->data) + arg, - ez->intdata, 64, -EFAULT); - return ez->intlen; - case EZUSB_BULK: copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); + if (bulk.ep & 0x80) + pipe = usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f); + else + pipe = usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f); + if (!usb_maxpacket(ez->usbdev, pipe, !(bulk.ep & 0x80))) + return -EINVAL; len1 = bulk.len; if (len1 > sizeof(tbuf)) len1 = sizeof(tbuf); @@ -292,8 +410,7 @@ up(&ez->mutex); return -EIO; } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f), - tbuf, len1, &len2); + i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2); up(&ez->mutex); if (!i && len2) { copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); @@ -307,8 +424,7 @@ up(&ez->mutex); return -EIO; } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f), - tbuf, len1, &len2); + i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2); up(&ez->mutex); } if (i) { @@ -324,6 +440,213 @@ return -EINVAL; usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0); return 0; + + case EZUSB_SETINTERFACE: + copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); + if (usb_set_interface(ez->usbdev, setintf.interface, setintf.altsetting)) + return -EINVAL; + return 0; + + case EZUSB_STARTISO: + copy_from_user_ret(&isot, (void *)arg, sizeof(isot), -EFAULT); + len1 = isot.framesperint * isot.pktsz; + if (len1 > PAGE_SIZE) { + len1 = PAGE_SIZE / isot.pktsz; + len1 = PAGE_SIZE * ((isot.framesperint + len1 - 1) / len1); + } + len2 = (isot.pktsz * 1000 + PAGE_SIZE - 1) & (PAGE_SIZE-1); + if (len2 > 32*PAGE_SIZE) + len2 = PAGE_SIZE; + if ((isot.ep & ~0x80) >= 16 || isot.pktsz < 1 || isot.pktsz > 1023 || + isot.framesperint < 1 || isot.framesperint > 1000 || + len1 > 4*PAGE_SIZE) + return -EINVAL; + down(&ez->mutex); + if (!ez->usbdev) { + up(&ez->mutex); + return -EIO; + } + if (findiso(ez, isod.ep)) { + up(&ez->mutex); + return -EBUSY; + } + if (isot.ep & 0x80) { + pipe = usb_rcvisocpipe(ez->usbdev, isot.ep & 15); + isocompl = ezusb_isorcv_irq; + } else { + pipe = usb_sndisocpipe(ez->usbdev, isot.ep & 15); + isocompl = ezusb_isosnd_irq; + } + if (!(isodesc = kmalloc(sizeof(struct isodesc), GFP_KERNEL))) { + up(&ez->mutex); + return -ENOMEM; + } + memset(isodesc, 0, sizeof(struct isodesc)); + INIT_LIST_HEAD(&isodesc->isolist); + spin_lock_init(&isodesc->lock); + isodesc->usbdev = ez->usbdev; + isodesc->ep = isot.ep; + isodesc->pktsz = isot.pktsz; + isodesc->framesperint = isot.framesperint; + isodesc->buflen = len2; + if (!(isodesc->hcbuf[0] = kmalloc(len1, GFP_KERNEL)) || + !(isodesc->hcbuf[1] = kmalloc(len1, GFP_KERNEL))) + goto startisomemerr; + if (!(isodesc->hcisodesc[0] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[0], + len1, isodesc->pktsz, isocompl, isodesc)) || + !(isodesc->hcisodesc[1] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[1], + len1, isodesc->pktsz, isocompl, isodesc))) + goto startisomemerr; + if (!(isodesc->buf = vmalloc(isodesc->buflen))) + goto startisomemerr; + up(&ez->mutex); + return 0; + + startisomemerr: + if (isodesc->hcisodesc[0]) + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); + if (isodesc->hcisodesc[1]) + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); + if (isodesc->hcbuf[0]) + kfree(isodesc->hcbuf[0]); + if (isodesc->hcbuf[1]) + kfree(isodesc->hcbuf[1]); + if (isodesc->buf) + vfree(isodesc->buf); + up(&ez->mutex); + return -ENOMEM; + + case EZUSB_STOPISO: + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + down(&ez->mutex); + if (!ez->usbdev) { + up(&ez->mutex); + return -EIO; + } + if (!(isodesc = findiso(ez, ep))) { + up(&ez->mutex); + return -EINVAL; + } + list_del(&isodesc->isolist); + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); + kfree(isodesc->hcbuf[0]); + kfree(isodesc->hcbuf[1]); + vfree(isodesc->buf); + up(&ez->mutex); + return 0; + + case EZUSB_ISODATA: + copy_from_user_ret(&isod, (void *)arg, sizeof(isod), -EFAULT); + if ((isod.ep & ~0x80) >= 16) + return -EINVAL; + if (isod.size) + if (!access_ok((isod.ep & 0x80) ? VERIFY_WRITE : VERIFY_READ, isod.data, isod.size)) + return -EFAULT; + down(&ez->mutex); + if (!ez->usbdev) { + up(&ez->mutex); + return -EIO; + } + if (!(isodesc = findiso(ez, ep))) { + up(&ez->mutex); + return -EINVAL; + } + if (isod.ep & 0x80) { + cnt = 0; + p1 = isod.data; + while (cnt < isod.size) { + spin_lock_irqsave(&isodesc->lock, flags); + p2 = isodesc->buf + isodesc->rd; + len2 = (isodesc->rd >= isodesc->wr) ? isodesc->buflen : isodesc->wr; + len2 -= isodesc->rd; + spin_unlock_irqrestore(&isodesc->lock, flags); + if (len2 <= 0) + break; + if (len2 >= isod.size - cnt) + len2 = isod.size - cnt; + if (__copy_to_user(p1, p2, len2)) { + up(&ez->mutex); + return -EFAULT; + } + p1 += len2; + cnt += len2; + spin_lock_irqsave(&isodesc->lock, flags); + isodesc->rd = (isodesc->rd + len2) % isodesc->buflen; + spin_unlock_irqrestore(&isodesc->lock, flags); + } + isod.size = cnt; + iso_schedrcv(isodesc); + } else { + cnt = 0; + p1 = isod.data; + while (cnt < isod.size) { + spin_lock_irqsave(&isodesc->lock, flags); + p2 = isodesc->buf + isodesc->wr; + len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; + if (isodesc->wr + len2 > isodesc->buflen) + len2 = isodesc->buflen - isodesc->wr; + spin_unlock_irqrestore(&isodesc->lock, flags); + if (len2 <= 0) + break; + if (len2 >= isod.size - cnt) + len2 = isod.size - cnt; + if (__copy_from_user(p2, p1, len2)) { + up(&ez->mutex); + return -EFAULT; + } + p1 += len2; + cnt += len2; + spin_lock_irqsave(&isodesc->lock, flags); + isodesc->wr = (isodesc->wr + len2) % isodesc->buflen; + spin_unlock_irqrestore(&isodesc->lock, flags); + } + isod.size = cnt; + iso_schedsnd(isodesc); + } + spin_lock_irqsave(&isodesc->lock, flags); + isod.bufqueued = (isodesc->buflen + isodesc->wr - isodesc->rd) % isodesc->buflen; + isod.buffree = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; + spin_unlock_irqrestore(&isodesc->lock, flags); + up(&ez->mutex); + copy_to_user_ret((void *)arg, &isod, sizeof(isod), -EFAULT); + return 0; + + case EZUSB_PAUSEISO: + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + if (!(isodesc = findiso(ez, ep))) + return -EINVAL; + spin_lock_irqsave(&isodesc->lock, flags); + isodesc->flags &= ~ISOFLG_ACTIVE; + spin_unlock_irqrestore(&isodesc->lock, flags); + return 0; + + case EZUSB_RESUMEISO: + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + down(&ez->mutex); + if (!ez->usbdev) { + up(&ez->mutex); + return -EIO; + } + if (!(isodesc = findiso(ez, ep))) { + up(&ez->mutex); + return -EINVAL; + } + spin_lock_irqsave(&isodesc->lock, flags); + isodesc->flags |= ISOFLG_ACTIVE; + if (isot.ep & 0x80) + iso_schedrcv(isodesc); + else + iso_schedsnd(isodesc); + spin_unlock_irqrestore(&isodesc->lock, flags); + up(&ez->mutex); + return 0; } return -ENOIOCTLCMD; } @@ -388,7 +711,7 @@ printk(KERN_ERR "ezusb: set_configuration failed\n"); goto err; } - interface = &usbdev->config[0].altsetting[1].interface[0]; + interface = &usbdev->config[0].interface[0].altsetting[1]; if (usb_set_interface(usbdev, 0, 1)) { printk(KERN_ERR "ezusb: set_interface failed\n"); goto err; @@ -407,8 +730,18 @@ static void ezusb_disconnect(struct usb_device *usbdev) { struct ezusb *ez = (struct ezusb *)usbdev->private; + struct isodesc *isodesc; down(&ez->mutex); + while (!list_empty(&ez->iso)) { + isodesc = list_entry(ez->iso.next, struct isodesc, isolist); + list_del(ez->iso.next); + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); + usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); + kfree(isodesc->hcbuf[0]); + kfree(isodesc->hcbuf[1]); + vfree(isodesc->buf); + } ez->usbdev = NULL; up(&ez->mutex); usbdev->private = NULL; @@ -432,7 +765,7 @@ for (u = 0; u < NREZUSB; u++) { init_MUTEX(&ezusb[u].mutex); ezusb[u].usbdev = NULL; - ezusb[u].irqep = 0; + INIT_LIST_HEAD(&ezusb[u].iso); } /* register misc device */ if (misc_register(&ezusb_misc)) { diff -u --recursive --new-file v2.3.14/linux/drivers/usb/ezusb.h linux/drivers/usb/ezusb.h --- v2.3.14/linux/drivers/usb/ezusb.h Wed Jul 14 10:30:36 1999 +++ linux/drivers/usb/ezusb.h Wed Aug 25 15:03:54 1999 @@ -45,13 +45,6 @@ #define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer) -struct ezusb_interrupttransfer { - unsigned int ep; - unsigned char data[64]; -}; - -#define EZUSB_INTERRUPT _IOWR('E', 1, struct ezusb_interrupttransfer) - struct ezusb_bulktransfer { unsigned int ep; unsigned int len; @@ -62,6 +55,33 @@ #define EZUSB_RESETEP _IOR('E', 3, unsigned int) +struct ezusb_setinterface { + unsigned int interface; + unsigned int altsetting; +}; + +#define EZUSB_SETINTERFACE _IOR('E', 4, struct ezusb_setinterface) + +struct ezusb_isotransfer { + unsigned int ep; + unsigned int pktsz; + unsigned int framesperint; +}; + +struct ezusb_isodata { + unsigned int ep; + unsigned int size; + unsigned int bufqueued; + unsigned int buffree; + void *data; +}; + +#define EZUSB_STARTISO _IOR('E', 8, struct ezusb_isotransfer) +#define EZUSB_STOPISO _IOR('E', 9, unsigned int) +#define EZUSB_ISODATA _IOWR('E', 10, struct ezusb_isodata) +#define EZUSB_PAUSEISO _IOR('E', 11, unsigned int) +#define EZUSB_RESUMEISO _IOR('E', 12, unsigned int) /* --------------------------------------------------------------------- */ #endif /* _LINUX_EZUSB_H */ + diff -u --recursive --new-file v2.3.14/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.3.14/linux/drivers/usb/hub.c Mon Aug 16 23:19:13 1999 +++ linux/drivers/usb/hub.c Wed Aug 25 15:03:54 1999 @@ -32,72 +32,35 @@ static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_HUB; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (USB_DT_HUB << 8); - dr.index = 0; - dr.length = size; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, size); + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, data, size); } static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) { - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_CLEAR_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, - NULL, 0); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0); } static int usb_set_port_feature(struct usb_device *dev, int port, int feature) { - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_SET_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, - NULL, 0); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0); } static int usb_get_hub_status(struct usb_device *dev, void *data) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_HUB; - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = 0; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, 4); + /* FIXME: Don't hardcode 4 */ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4); } static int usb_get_port_status(struct usb_device *dev, int port, void *data) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_PORT; - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = port; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, 4); + /* FIXME: Don't hardcode 4 */ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4); } /* @@ -110,37 +73,58 @@ struct usb_hub *hub = dev_id; unsigned long flags; - if (waitqueue_active(&khubd_wait)) { - /* Add the hub to the event queue */ - spin_lock_irqsave(&hub_event_lock, flags); - if (hub->event_list.next == &hub->event_list) { - list_add(&hub->event_list, &hub_event_list); - /* Wake up khubd */ - wake_up(&khubd_wait); + switch (status) { + case USB_ST_REMOVED: + /* Just ignore it */ + break; + case USB_ST_NOERROR: + /* Something happened, let khubd figure it out */ + if (waitqueue_active(&khubd_wait)) { + /* Add the hub to the event queue */ + spin_lock_irqsave(&hub_event_lock, flags); + if (hub->event_list.next == &hub->event_list) { + list_add(&hub->event_list, &hub_event_list); + /* Wake up khubd */ + wake_up(&khubd_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); } - spin_unlock_irqrestore(&hub_event_lock, flags); + break; } return 1; } -static void usb_hub_configure(struct usb_hub *hub) +static int usb_hub_configure(struct usb_hub *hub) { struct usb_device *dev = hub->dev; - unsigned char hubdescriptor[8], buf[4]; - int charac, i; + unsigned char buffer[4], *bitmap; + struct usb_hub_descriptor *descriptor; + struct usb_descriptor_header *header; + int i; + /* Set it to the first configuration */ usb_set_configuration(dev, dev->config[0].bConfigurationValue); - if (usb_get_hub_descriptor(dev, hubdescriptor, 8)) - return; + /* Get the length first */ + if (usb_get_hub_descriptor(dev, buffer, 4)) + return -1; - hub->nports = dev->maxchild = hubdescriptor[2]; + header = (struct usb_descriptor_header *)buffer; + bitmap = kmalloc(header->bLength, GFP_KERNEL); + if (!bitmap) + return -1; + + if (usb_get_hub_descriptor(dev, bitmap, header->bLength)) + return -1; + + descriptor = (struct usb_hub_descriptor *)bitmap; + + hub->nports = dev->maxchild = descriptor->bNbrPorts; printk(KERN_INFO "hub: %d-port%s detected\n", hub->nports, (hub->nports == 1) ? "" : "s"); - charac = (hubdescriptor[4] << 8) + hubdescriptor[3]; - switch (charac & HUB_CHAR_LPSM) { + switch (descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: printk(KERN_INFO "hub: ganged power switching\n"); break; @@ -153,12 +137,12 @@ break; } - if (charac & HUB_CHAR_COMPOUND) + if (descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) printk(KERN_INFO "hub: part of a compound device\n"); else printk(KERN_INFO "hub: standalone hub\n"); - switch (charac & HUB_CHAR_OCPM) { + switch (descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: printk(KERN_INFO "hub: global over current protection\n"); break; @@ -172,34 +156,38 @@ } printk(KERN_INFO "hub: power on to power good time: %dms\n", - hubdescriptor[5] * 2); + descriptor->bPwrOn2PwrGood * 2); printk(KERN_INFO "hub: hub controller current requirement: %dmA\n", - hubdescriptor[6]); + descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) printk(KERN_INFO "hub: port %d is%s removable\n", i + 1, - hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) + bitmap[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) ? " not" : ""); - if (usb_get_hub_status(dev, buf)) - return; + kfree(bitmap); + + if (usb_get_hub_status(dev, buffer)) + return -1; printk(KERN_INFO "hub: local power source is %s\n", - (buf[0] & 1) ? "lost (inactive)" : "good"); + (buffer[0] & 1) ? "lost (inactive)" : "good"); printk(KERN_INFO "hub: %sover current condition exists\n", - (buf[0] & 2) ? "" : "no "); + (buffer[0] & 2) ? "" : "no "); /* Enable power to the ports */ printk(KERN_INFO "hub: enabling power on all ports\n"); for (i = 0; i < hub->nports; i++) usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + + return 0; } static int hub_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; + struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_hub *hub; unsigned long flags; @@ -212,20 +200,23 @@ if (dev->config[0].bNumInterfaces != 1) return -1; - intf_desc = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->config[0].interface[0].altsetting[0]; /* Is it a hub? */ - if (intf_desc->bInterfaceClass != 9) + if (interface->bInterfaceClass != USB_CLASS_HUB) return -1; - if ((intf_desc->bInterfaceSubClass != 0) && - (intf_desc->bInterfaceSubClass != 1)) + + /* Some hubs have a subclass of 1, which AFAICT according to the */ + /* specs is not defined, but it works */ + if ((interface->bInterfaceSubClass != 0) && + (interface->bInterfaceSubClass != 1)) return -1; /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (intf_desc->bNumEndpoints != 1) + if (interface->bNumEndpoints != 1) return -1; - endpoint = &intf_desc->endpoint[0]; + endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) @@ -256,13 +247,13 @@ list_add(&hub->hub_list, &hub_list); spin_unlock_irqrestore(&hub_list_lock, flags); - usb_hub_configure(hub); - - hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, - endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); + if (usb_hub_configure(hub) >= 0) { + hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, + endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); - /* Wake up khubd */ - wake_up(&khubd_wait); + /* Wake up khubd */ + wake_up(&khubd_wait); + } return 0; } @@ -282,8 +273,10 @@ spin_unlock_irqrestore(&hub_event_lock, flags); - usb_release_irq(hub->dev, hub->irq_handle); - hub->irq_handle = NULL; + if (hub->irq_handle) { + usb_release_irq(hub->dev, hub->irq_handle); + hub->irq_handle = NULL; + } /* Free the memory */ kfree(hub); @@ -319,7 +312,7 @@ return; /* Allocate a new device struct for it */ - usb = hub->bus->op->allocate(hub); + usb = usb_alloc_dev(hub, hub->bus); if (!usb) { printk(KERN_ERR "couldn't allocate usb_device\n"); return; @@ -335,36 +328,47 @@ /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ - printk(KERN_DEBUG "hub: disabling malfunctioning port %d\n", + printk(KERN_DEBUG "hub: disabling port %d\n", port + 1); usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_POWER); } } static void usb_hub_events(void) { unsigned long flags; - unsigned char buf[4]; - unsigned short portstatus, portchange; int i; - struct list_head *next, *tmp, *head = &hub_event_list; + struct list_head *tmp; struct usb_device *dev; struct usb_hub *hub; - spin_lock_irqsave(&hub_event_lock, flags); + /* + * We restart the list everytime to avoid a deadlock with + * deleting hubs downstream from this one. This should be + * safe since we delete the hub from the event list. + * Not the most efficient, but avoids deadlocks. + */ + while (1) { + spin_lock_irqsave(&hub_event_lock, flags); + + if (list_empty(&hub_event_list)) + goto he_unlock; + + /* Grab the next entry from the beginning of the list */ + tmp = hub_event_list.next; - tmp = head->next; - while (tmp != head) { hub = list_entry(tmp, struct usb_hub, event_list); dev = hub->dev; - next = tmp->next; - list_del(tmp); INIT_LIST_HEAD(tmp); + spin_unlock_irqrestore(&hub_event_lock, flags); + for (i = 0; i < hub->nports; i++) { + unsigned char buf[4]; + unsigned short portstatus, portchange; + if (usb_get_port_status(dev, i + 1, buf)) { printk(KERN_ERR "get_port_status failed\n"); continue; @@ -406,9 +410,9 @@ } } - tmp = next; } +he_unlock: spin_unlock_irqrestore(&hub_event_lock, flags); } @@ -464,7 +468,6 @@ int pid; usb_register(&hub_driver); - printk(KERN_INFO "USB hub driver registered\n"); pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -482,15 +485,13 @@ void usb_hub_cleanup(void) { - struct list_head *next, *tmp, *head = &hub_list; - struct usb_hub *hub; - unsigned long flags, flags2; int ret; /* Kill the thread */ ret = kill_proc(khubd_pid, SIGTERM, 1); if (!ret) { - int count = 10; + /* Wait 10 seconds */ + int count = 10 * 100; while (khubd_running && --count) { current->state = TASK_INTERRUPTIBLE; diff -u --recursive --new-file v2.3.14/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.3.14/linux/drivers/usb/hub.h Tue Jul 13 10:09:01 1999 +++ linux/drivers/usb/hub.h Wed Aug 25 15:03:54 1999 @@ -46,6 +46,24 @@ #define HUB_CHAR_COMPOUND 0x0004 #define HUB_CHAR_OCPM 0x0018 +/* Hub descriptor */ +struct usb_hub_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bNbrPorts; + __u16 wHubCharacteristics; +#if 0 + __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */ +#endif + __u8 bPwrOn2PwrGood; + __u8 bHubContrCurrent; + /* DeviceRemovable and PortPwrCtrlMask want to be variable-length + bitmaps that hold max 256 entries, but for now they're ignored */ +#if 0 + __u8 filler; +#endif +} __attribute__ ((packed)); + struct usb_device; typedef enum { @@ -69,7 +87,7 @@ struct usb_device *dev; /* Reference to the hub's polling IRQ */ - void* irq_handle; + void *irq_handle; /* List of hubs */ struct list_head hub_list; diff -u --recursive --new-file v2.3.14/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c --- v2.3.14/linux/drivers/usb/keyboard.c Mon Jul 19 11:17:32 1999 +++ linux/drivers/usb/keyboard.c Thu Aug 19 13:08:16 1999 @@ -176,7 +176,7 @@ if (dev->descriptor.bNumConfigurations < 1) return -1; - interface = &dev->config[0].altsetting[0].interface[0]; + interface = &dev->config[0].interface[0].altsetting[0]; endpoint = &interface->endpoint[0]; if(interface->bInterfaceClass != 3 diff -u --recursive --new-file v2.3.14/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c --- v2.3.14/linux/drivers/usb/mouse.c Mon Aug 16 23:19:13 1999 +++ linux/drivers/usb/mouse.c Wed Aug 25 15:03:54 1999 @@ -256,7 +256,7 @@ static int mouse_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; + struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct mouse_state *mouse = &static_mouse_state; @@ -269,19 +269,19 @@ return -1; /* Is it a mouse interface? */ - intf_desc = &dev->config[0].interface[0].altsetting[0]; - if (intf_desc->bInterfaceClass != 3) + interface = &dev->config[0].interface[0].altsetting[0]; + if (interface->bInterfaceClass != 3) return -1; - if (intf_desc->bInterfaceSubClass != 1) + if (interface->bInterfaceSubClass != 1) return -1; - if (intf_desc->bInterfaceProtocol != 2) + if (interface->bInterfaceProtocol != 2) return -1; /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ - if (intf_desc->bNumEndpoints != 1) + if (interface->bNumEndpoints != 1) return -1; - endpoint = &intf_desc->endpoint[0]; + endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & 0x80)) diff -u --recursive --new-file v2.3.14/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c --- v2.3.14/linux/drivers/usb/ohci.c Wed Aug 18 16:22:23 1999 +++ linux/drivers/usb/ohci.c Mon Aug 23 11:16:42 1999 @@ -320,6 +320,11 @@ * Guarantee that an ED is safe to be modified by the HCD (us). * * This function can NOT be called from an interrupt. + * + * TODO: If we're waiting for the ED to be safe so that it can be + * destroyed, a similar "ohci_schedule_ed_free" function that just + * adds it to a list of EDs to destroy during the SOF interrupt + * processing would be useful (and be callable from an interrupt). */ void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type) { @@ -566,6 +571,7 @@ /* * Remove a TD from the given EDs TD list. The TD is freed as well. + * (so far this function hasn't been needed) */ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) { @@ -799,6 +805,9 @@ * Create a chain of Normal TDs to be used for a large data transfer * (bulk or control). * + * The next_td parameter should be OHCI byte order bus address of the + * next TD to follow this chain or 0 if there is none. + * * Returns the head TD in the chain. */ struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, @@ -877,7 +886,7 @@ noauto_free_td(head); /* link the given next_td to the end of this chain */ - cur_td->next_td = cpu_to_le32(next_td); + cur_td->next_td = next_td; if (next_td == 0) set_td_endofchain(cur_td); @@ -1044,9 +1053,189 @@ } /* ohci_release_irq() */ -/************************************ - * OHCI control transfer operations * - ************************************/ +/********************************************************************** + * Generic bulk/control/isochronous transfer processing + **********************************************************************/ + + +/* + * Queue a generic OHCI data transfer, specifying the type in ed_type. + * + * - data_td_toggle specifies the data toggle value to start with. + * - round specifies if the transfer should be allowed to fall short. + * - autofree determines if the data TDs are automatically freed. + * - setup_td and status_td will be prepended and appended to the TD + * chain respectively. Control transfers need these.. + * + * - handler will be called upon completion of every data TD it + * needs to check if the transfer is really done or not. + * + * A handle to the transfer is returned. + */ +static void * ohci_generic_trans(struct usb_device *usb_dev, int pipe, + int data_td_toggle, int round, int autofree, + void *dev_id, usb_device_irq handler, void *data, int len, + int ed_type, struct ohci_td *setup_td, struct ohci_td *status_td) +{ + struct ohci_device *dev = usb_to_ohci(usb_dev); + struct ohci_ed *trans_ed; + struct ohci_td *data_td, *head_td; + unsigned long flags; + +#ifdef OHCI_DEBUG + if (MegaDebug) + printk(KERN_DEBUG "ohci_request_trans()\n"); +#endif + + trans_ed = ohci_get_free_ed(dev); + if (!trans_ed) { + printk("usb-ohci: couldn't get ED for dev %p\n", dev); + return NULL; + } + + /* If this transfer has a data phase, allocate TDs for it */ + if (len > 0) { + __u32 next_td = status_td ? cpu_to_le32(virt_to_bus(status_td)) : 0; + /* allocate & fill in the TDs for this request */ + data_td = ohci_build_td_chain( dev, data, len, + usb_pipeout(pipe), + data_td_toggle, + round, autofree, + dev_id, + handler, + next_td ); + if (!data_td) { + /* out of TDs */ + printk(KERN_ERR "usb-ohci: build_td_chain failed for dev %p, pipe 0x%x\n", dev, pipe); + goto gt_free_and_exit; + } + } else { + data_td = status_td; + } + + /* start with the setup TD if there is one */ + if (setup_td) { + if (data_td) { + setup_td->next_td = cpu_to_le32(virt_to_bus(data_td)); + head_td = setup_td; + } else { +#ifdef OHCI_DEBUG + printk(KERN_ERR "usb-ohci: lonely setup_td detected\n"); +#endif + goto gt_free_and_exit; + } + } else { + head_td = data_td; + } + + if (!head_td) { +#ifdef OHCI_DEBUG + printk(KERN_ERR "usb-ohci: no TDs in transfer\n"); +#endif + goto gt_free_and_exit; /* nothing to do */ + } + + /* Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. */ + ohci_fill_ed(dev, trans_ed, + usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)), + usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), + (ed_type == HCD_ED_ISOC) ); + + /* initialize the toggle carry flag in the ED */ + if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) + ohci_ed_set_carry(trans_ed); + + /* + * Add the TDs to the ED, remove the skip flag + */ + spin_lock_irqsave(&ohci_edtd_lock, flags); + head_td = ohci_add_tds_to_ed(head_td, trans_ed); + trans_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); + /* ohci_unhalt_ed(trans_ed); */ + spin_unlock_irqrestore(&ohci_edtd_lock, flags); + +#ifdef OHCI_DEBUG + if (MegaDebug) { + /* complete transaction debugging output (before) */ + printk(KERN_DEBUG " Trans ED %lx:\n", virt_to_bus(trans_ed)); + show_ohci_ed(trans_ed); + printk(KERN_DEBUG " Trans TD chain:\n"); + show_ohci_td_chain(head_td); + } +#endif + + /* Give the ED to the HC on the appropriate list */ + switch (ed_type) { + case HCD_ED_ISOC: + /* Isochronous transfers have a 1ms period */ + ohci_add_periodic_ed(dev->ohci, trans_ed, 1); + break; + case HCD_ED_CONTROL: + ohci_add_control_ed(dev->ohci, trans_ed); + break; + case HCD_ED_BULK: + ohci_add_bulk_ed(dev->ohci, trans_ed); + break; + default: +#ifdef OHCI_DEBUG + printk(KERN_ERR "usb-ohci: bad ED type %d\n", ed_type); +#endif + goto gt_free_and_exit; + } + + /* ... */ + + return trans_ed; + +gt_free_and_exit: + ohci_free_ed(trans_ed); + return NULL; +} /* ohci_generic_trans() */ + + +/* + * Terminate a transfer initiated by ohci_generic_trans() + * + * This function is NOT safe to call from an interrupt. + */ +static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle, int ed_type) +{ + struct ohci_ed *req_ed = (struct ohci_ed *) handle; + struct ohci_device *dev = usb_to_ohci(usb_dev); + struct ohci_regs *regs = dev->ohci->regs; + + if (!handle) + return 0; + + /* stop the transfer & collect the number of bytes */ + /* (this is the non-interrupt safe function call) */ + ohci_wait_for_ed_safe(regs, req_ed, ed_type); + + /* Remove the ED from the appropriate HC list */ + switch (ed_type) { + case HCD_ED_ISOC: + ohci_remove_periodic_ed(dev->ohci, req_ed); + break; + case HCD_ED_CONTROL: + ohci_remove_control_ed(dev->ohci, req_ed); + break; + case HCD_ED_BULK: + ohci_remove_bulk_ed(dev->ohci, req_ed); + break; + } + + ohci_free_ed(req_ed); /* return it to the pool */ + + return 1; +} /* ohci_terminate_trans() */ + + +/********************************************************************** + * Control transfer processing + **********************************************************************/ + static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); @@ -1082,12 +1271,12 @@ * * This function can NOT be called from an interrupt. */ -static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, +static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len) { - struct ohci_device *dev = usb_to_ohci(usb); - struct ohci_ed *control_ed = ohci_get_free_ed(dev); - struct ohci_td *setup_td, *data_td, *status_td; + struct ohci_device *dev = usb_to_ohci(usb_dev); + void *trans_handle; + struct ohci_td *setup_td, *status_td; DECLARE_WAITQUEUE(wait, current); int completion_status = -1; devrequest our_cmd; @@ -1100,34 +1289,17 @@ #ifdef OHCI_DEBUG if (MegaDebug) - printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); + printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb_dev, dev, pipe, cmd, data, len); #endif - if (!control_ed) { - printk(KERN_ERR "usb-ohci: couldn't get ED for dev %p\n", dev); - return -1; - } /* get a TD to send this control message with */ setup_td = ohci_get_free_td(dev); if (!setup_td) { printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev); - ohci_free_ed(control_ed); - return -1; + return USB_ST_INTERNALERROR; } /* - * Set the max packet size, device speed, endpoint number, usb - * device number (function address), and type of TD. - * - */ - ohci_fill_ed(dev, control_ed, usb_maxpacket(usb, pipe, usb_pipeout(pipe)), - usb_pipeslow(pipe), usb_pipe_endpdev(pipe), 0 /* normal TDs */); - - /* - * Build the control TD - */ - - /* * Set the not accessed condition code, allow odd sized data, * and set the data transfer type to SETUP. Setup DATA always * uses a DATA0 packet. @@ -1145,8 +1317,7 @@ if (!status_td) { printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev); ohci_free_td(setup_td); - ohci_free_ed(control_ed); - return -1; + return USB_ST_INTERNALERROR; } /* The control status packet always uses a DATA1 @@ -1161,62 +1332,41 @@ set_td_endofchain(status_td); status_td->next_td = 0; /* end of TDs */ - /* If there is data to transfer, create the chain of data TDs - * followed by the status TD. */ - if (len > 0) { - data_td = ohci_build_td_chain( dev, data, len, - usb_pipeout(pipe), TOGGLE_DATA1, - 1 /* round */, 1 /* autofree */, - &completion_status, NULL /* no handler here */, - virt_to_bus(status_td) ); - if (!data_td) { - printk(KERN_ERR "usb-ohci: couldn't allocate control data TDs for dev %p\n", dev); - ohci_free_td(setup_td); - ohci_free_td(status_td); - ohci_free_ed(control_ed); - return -1; - } - - /* link the to the data & status TDs */ - setup_td->next_td = cpu_to_le32(virt_to_bus(data_td)); - } else { - /* no data TDs, link to the status TD */ - setup_td->next_td = cpu_to_le32(virt_to_bus(status_td)); - } - - /* - * Add the control TDs to the control ED (setup_td is the first) - */ - setup_td = ohci_add_tds_to_ed(setup_td, control_ed); - control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - /* ohci_unhalt_ed(control_ed); */ - -#ifdef OHCI_DEBUG - if (MegaDebug) { - /* complete transaction debugging output (before) */ - printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); - show_ohci_ed(control_ed); - printk(KERN_DEBUG " Control TD chain:\n"); - show_ohci_td_chain(setup_td); - printk(KERN_DEBUG " OHCI Controller Status:\n"); - show_ohci_status(dev->ohci); - } -#endif - /* * Start the control transaction.. + * XXX should this come so soon? or... XXX + * XXX should it be put into generic_trans? XXX */ current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(&control_wakeup, &wait); - /* Give the ED to the HC */ - ohci_add_control_ed(dev->ohci, control_ed); + trans_handle = ohci_generic_trans(usb_dev, pipe, + TOGGLE_DATA1, 1 /* round */, 1 /* autofree */, + &completion_status, NULL /* no data td handler */, + data, len, HCD_ED_CONTROL, + setup_td, status_td); + + /* did something go wrong? return an error */ + if (!trans_handle) { + remove_wait_queue(&control_wakeup, &wait); + ohci_free_td(setup_td); + ohci_free_td(status_td); + return USB_ST_INTERNALERROR; + } + /* wait a "reasonable" amount of time for it to complete */ schedule_timeout(HZ); remove_wait_queue(&control_wakeup, &wait); #ifdef OHCI_DEBUG + /* + * NOTE! this debug code blatently assumes that the handle returned + * by ohci_generic_trans is the pointer to this transfers ED. + * (which it is at the moment) + * Also, since the TDs were autofreed, there is no guarantee that + * they haven't been reclaimed by another transfer by now... + */ if (completion_status != 0) { const char *what = (completion_status < 0)? "timed out": cc_names[completion_status & 0xf]; @@ -1233,6 +1383,7 @@ } printk("\n"); if (MegaDebug && completion_status < 0) { + struct ohci_ed *control_ed = (struct ohci_ed *) trans_handle; printk(KERN_DEBUG "control_ed at %p:\n", control_ed); show_ohci_ed(control_ed); if (ed_head_td(control_ed) != ed_tail_td(control_ed)) @@ -1255,21 +1406,21 @@ } if (MegaDebug) { - /* complete transaction debugging output (after) */ - printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); - show_ohci_ed(control_ed); - printk(KERN_DEBUG " *after* Control TD chain:\n"); - show_ohci_td_chain(setup_td); - printk(KERN_DEBUG " *after* OHCI Controller Status:\n"); - show_ohci_status(dev->ohci); + struct ohci_ed *control_ed = (struct ohci_ed *) trans_handle; + /* complete transaction debugging output (after) */ + printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " *after* Control TD chain:\n"); + show_ohci_td_chain(setup_td); + printk(KERN_DEBUG " *after* OHCI Controller Status:\n"); + show_ohci_status(dev->ohci); } #endif /* no TD cleanup, the TDs were auto-freed as they finished */ - /* remove the control ED from the HC */ - ohci_remove_control_ed(dev->ohci, control_ed); - ohci_free_ed(control_ed); /* return it to the pool */ + /* remove the generic_trans ED from the HC and free it */ + ohci_terminate_trans(usb_dev, trans_handle, HCD_ED_CONTROL); if (completion_status < 0) completion_status = USB_ST_TIMEOUT; @@ -1281,10 +1432,51 @@ * Bulk transfer processing **********************************************************************/ + /* - * Internal state for an ohci_bulk_request + * Request to send or receive bulk data. The handler() function + * will be called as each OHCI TD in the transfer completes or is + * aborted due to an error. + * + * IMPORTANT NOTE: This means the handler may be called multiple + * times for a large (more than one 4096 byte page) request until + * the transfer is finished. + * + * Returns: a pointer to the ED being used for this request as the + * bulk request handle. */ -struct ohci_bulk_request_state { +static void * ohci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, void* data, int len, void* dev_id) +{ +#ifdef OHCI_DEBUG + struct ohci_device *dev = usb_to_ohci(usb_dev); + if (MegaDebug) + printk(KERN_DEBUG "ohci_request_bulk() ohci_dev %p, handler %p, pipe %x, data %p, len %d, dev_id %p\n", dev, handler, pipe, data, len, dev_id); +#endif + + return ohci_generic_trans(usb_dev, pipe, + TOGGLE_AUTO, + 1 /* round */, 1 /* autofree */, + dev_id, handler, data, len, + HCD_ED_BULK, + NULL /* no setup_td */, NULL /* no status_td */ ); +} /* ohci_request_bulk() */ + + +/* + * Terminate a bulk transfer requested using ohci_request_bulk. + * + * This function is NOT safe to call from an interrupt. + */ +static int ohci_terminate_bulk(struct usb_device *usb_dev, void * handle) +{ + return ohci_terminate_trans(usb_dev, handle, HCD_ED_CONTROL); +} /* ohci_terminate_bulk() */ + + +/* + * Internal state for an ohci_bulk_request_msg + */ +struct ohci_bulk_msg_request_state { struct usb_device *usb_dev; unsigned int pipe; /* usb "pipe" */ void *data; /* ptr to data */ @@ -1300,11 +1492,11 @@ * request. It keeps track of the total bytes transferred, calls the * final completion handler, etc. */ -static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id) +static int ohci_bulk_msg_td_handler(int stats, void *buffer, int len, void *dev_id) { - struct ohci_bulk_request_state *req; + struct ohci_bulk_msg_request_state *req; - req = (struct ohci_bulk_request_state *) dev_id; + req = (struct ohci_bulk_msg_request_state *) dev_id; #ifdef OHCI_DEBUG if (MegaDebug) @@ -1339,100 +1531,27 @@ } return 0; /* do not re-queue the TD */ -} /* ohci_bulk_td_handler() */ +} /* ohci_bulk_msg_td_handler() */ /* - * Request to send or receive bulk data. The completion() function - * will be called when the transfer has completed or been aborted due - * to an error. - * - * bytes_transferred_p is a pointer to an integer that will be - * set to the number of bytes that have been successfully - * transferred. The interrupt handler will update it after each - * internal TD completes successfully. + * Request to send or receive bulk data for a blocking bulk_msg call. * - * This function can NOT be called from an interrupt (?) - * (TODO: verify & fix this if needed). - * - * Returns: a pointer to the ED being used for this request. At the - * moment, removing & freeing it is the responsibilty of the caller. + * bulk_request->bytes_transferred_p is a pointer to an integer that + * will be set to the number of bytes that have been successfully + * transferred upon completion. The interrupt handler will update it + * after each internal TD completes successfully. */ -static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_request) +static struct ohci_ed* ohci_request_bulk_msg(struct ohci_bulk_msg_request_state *bulk_request) { - /* local names for the readonly fields */ - struct usb_device *usb_dev = bulk_request->usb_dev; - unsigned int pipe = bulk_request->pipe; - void *data = bulk_request->data; - int len = bulk_request->length; - - struct ohci_device *dev = usb_to_ohci(usb_dev); - struct ohci_ed *bulk_ed; - struct ohci_td *head_td; - unsigned long flags; - -#ifdef OHCI_DEBUG - if (MegaDebug) - printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len); -#endif - - bulk_ed = ohci_get_free_ed(dev); - if (!bulk_ed) { - printk("usb-ohci: couldn't get ED for dev %p\n", dev); - return NULL; - } - - /* allocate & fill in the TDs for this request */ - head_td = ohci_build_td_chain(dev, data, len, usb_pipeout(pipe), - TOGGLE_AUTO, - 0 /* round not required */, 1 /* autofree */, - bulk_request, /* dev_id: the bulk_request */ - ohci_bulk_td_handler, - 0 /* no additional TDs */); - if (!head_td) { - printk("usb-ohci: couldn't get TDs for dev %p\n", dev); - ohci_free_ed(bulk_ed); - return NULL; - } - - /* Set the max packet size, device speed, endpoint number, usb - * device number (function address), and type of TD. */ - ohci_fill_ed(dev, bulk_ed, - usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)), - usb_pipeslow(pipe), - usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */); - - /* initialize the toggle carry */ - if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) - ohci_ed_set_carry(bulk_ed); - /* initialize the internal counter */ bulk_request->_bytes_done = 0; - /* - * Add the TDs to the ED - */ - spin_lock_irqsave(&ohci_edtd_lock, flags); - head_td = ohci_add_tds_to_ed(head_td, bulk_ed); - bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); - /* ohci_unhalt_ed(bulk_ed); */ - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - -#ifdef OHCI_DEBUG - if (MegaDebug) { - /* complete request debugging output (before) */ - printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed)); - show_ohci_ed(bulk_ed); - printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td)); - show_ohci_td_chain(head_td); - } -#endif - - /* Give the ED to the HC */ - ohci_add_bulk_ed(dev->ohci, bulk_ed); - - return bulk_ed; -} /* ohci_request_bulk() */ + return ohci_request_bulk(bulk_request->usb_dev, bulk_request->pipe, + ohci_bulk_msg_td_handler, + bulk_request->data, bulk_request->length, + bulk_request); +} /* ohci_request_bulk_msg() */ static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); @@ -1457,7 +1576,7 @@ { DECLARE_WAITQUEUE(wait, current); int completion_status = USB_ST_INTERNALERROR; - struct ohci_bulk_request_state req; + struct ohci_bulk_msg_request_state req; struct ohci_ed *req_ed; #ifdef OHCI_DEBUG @@ -1490,7 +1609,7 @@ current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(&bulk_wakeup, &wait); - req_ed = ohci_request_bulk(&req); + req_ed = ohci_request_bulk_msg(&req); /* FIXME this should to wait for a caller specified time... */ schedule_timeout(HZ*5); @@ -1667,6 +1786,8 @@ ohci_bulk_msg, ohci_request_irq, ohci_release_irq, + ohci_request_bulk, + ohci_terminate_bulk, ohci_alloc_isochronous, ohci_delete_isochronous, ohci_sched_isochronous, @@ -2020,7 +2141,7 @@ struct ohci_ed *ed = td->ed; if (td_dummy(*td)) - printk(KERN_ERR "yikes! reaping a dummy TD\n"); + printk(KERN_ERR "usb-ohci: yikes! reaping dummy TD\n"); #ifdef OHCI_DEBUG if (cc != 0 && MegaDebug) { @@ -2054,14 +2175,14 @@ if (td_endofchain(*td)) break; - printk(KERN_DEBUG "skipping TD %p\n", td); + printk(KERN_DEBUG "usb-ohci: skipping TD %p\n", td); ohci_free_td(td); td = ntd; } /* Set the ED head past the ones we cleaned off, and clear the halted flag */ - printk(KERN_DEBUG "restarting ED %p at TD %p\n", ed, ntd); + printk(KERN_DEBUG "usb-ohci: restarting ED %p at TD %p\n", ed, ntd); set_ed_head_td(ed, virt_to_bus(ntd)); ohci_unhalt_ed(ed); /* If we didn't find an endofchain TD, give up */ @@ -2198,7 +2319,7 @@ context &= ~OHCI_INTR_RD; /* mark this as checked */ } if (context & OHCI_INTR_UE) { - /* FIXME: need to have the control thread reset the + /* TODO: need to have the control thread reset the * controller now and keep a count of unrecoverable * errors. If there are too many, it should just shut * the broken controller down entirely. */ diff -u --recursive --new-file v2.3.14/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.14/linux/drivers/usb/printer.c Wed Aug 18 16:22:23 1999 +++ linux/drivers/usb/printer.c Wed Aug 25 15:03:54 1999 @@ -161,7 +161,7 @@ unsigned long copy_size; unsigned long bytes_written = 0; unsigned long partial; - int result; + int result = USB_ST_NOERROR; int maxretry; do { diff -u --recursive --new-file v2.3.14/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c --- v2.3.14/linux/drivers/usb/proc_usb.c Mon Aug 16 23:19:13 1999 +++ linux/drivers/usb/proc_usb.c Wed Aug 25 15:03:54 1999 @@ -213,7 +213,7 @@ const int active, char *buf, int *len) { int i, j; - struct usb_interface *intf; + struct usb_interface *interface; if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */ *len += sprintf (buf + *len, "(null Cfg. desc.)\n"); @@ -224,12 +224,12 @@ return -1; for (i = 0; i < config->bNumInterfaces; i++) { - intf = config->interface + i; - if ((intf) == NULL) + interface = config->interface + i; + if (!interface) break; - for (j = 0; j < intf->num_altsetting; j++) - if (usb_dump_interface (intf->altsetting + j, buf, len) < 0) + for (j = 0; j < interface->num_altsetting; j++) + if (usb_dump_interface (interface->altsetting + j, buf, len) < 0) return -1; } @@ -432,6 +432,250 @@ len += sprintf (buf + len, "(none)\n"); return (len); } + +/* + * proc entry for every device + * sailer@ife.ee.ethz.ch + */ +#include +#include +#include +#include "ezusb.h" + +static long long usbdev_lseek(struct file * file, long long offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + + case 1: + file->f_pos += offset; + return file->f_pos; + + case 2: + return -EINVAL; + + default: + return -EINVAL; + } +} + +static ssize_t usbdev_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; + struct usb_device *dev = (struct usb_device *)dp->data; + ssize_t ret = 0; + unsigned len; + + if (*ppos < 0) + return -EINVAL; + if (*ppos < sizeof(struct usb_device_descriptor)) { + len = sizeof(struct usb_device_descriptor); + if (len > nbytes) + len = nbytes; + copy_to_user_ret(buf, ((char *)&dev->descriptor) + *ppos, len, -EFAULT); + *ppos += len; + buf += len; + nbytes -= len; + ret += len; + } + return ret; +} + +static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; + struct usb_device *dev = (struct usb_device *)dp->data; + struct ezusb_ctrltransfer ctrl; + struct ezusb_bulktransfer bulk; + struct ezusb_setinterface setintf; + unsigned int len1, ep, pipe; + unsigned long len2; + unsigned char *tbuf; + int i; + + switch (cmd) { + case EZUSB_CONTROL: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); + if (ctrl.dlen > PAGE_SIZE) + return -EINVAL; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (ctrl.requesttype & 0x80) { + if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen); + if (!i && ctrl.dlen) { + copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT); + } + } else { + if (ctrl.dlen) { + copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT); + } + i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "procusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", + ctrl.requesttype, ctrl.request, ctrl.length, i); + return -ENXIO; + } + return 0; + + case EZUSB_BULK: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); + if (bulk.ep & 0x80) + pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); + else + pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); + if (!usb_maxpacket(dev, pipe, !(bulk.ep & 0x80))) + return -EINVAL; + len1 = bulk.len; + if (len1 > PAGE_SIZE) + len1 = PAGE_SIZE; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (bulk.ep & 0x80) { + if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + if (!i && len2) { + copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); + } + } else { + if (len1) { + copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "procusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", + bulk.ep, bulk.len, i); + return -ENXIO; + } + return len2; + + case EZUSB_RESETEP: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + usb_settoggle(dev, ep & 0xf, !(ep & 0x80), 0); + return 0; + + case EZUSB_SETINTERFACE: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); + if (usb_set_interface(dev, setintf.interface, setintf.altsetting)) + return -EINVAL; + return 0; + } + return -ENOIOCTLCMD; +} + +static struct file_operations proc_usb_device_file_operations = { + usbdev_lseek, /* lseek */ + usbdev_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + usbdev_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations proc_usb_device_inode_operations = { + &proc_usb_device_file_operations, /* file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +#define PROCUSB_MAXBUSSES 64 + +static unsigned long busnumbermap[(PROCUSB_MAXBUSSES+8 * sizeof(unsigned long)-1) / (8 * sizeof(unsigned long))] = { 0, }; + +void proc_usb_add_bus(struct usb_bus *bus) +{ + int bnum; + char buf[16]; + + bus->proc_busnum = -1; + bus->proc_entry = NULL; + if (!usbdir) + return; + bnum = find_first_zero_bit(busnumbermap, PROCUSB_MAXBUSSES); + if (bnum >= PROCUSB_MAXBUSSES) + return; + sprintf(buf, "%03d", bnum); + if (!(bus->proc_entry = create_proc_entry(buf, S_IFDIR, usbdir))) + return; + set_bit(bnum, busnumbermap); + bus->proc_busnum = bnum; + bus->proc_entry->data = bus; +} + +/* devices need already be removed! */ +void proc_usb_remove_bus(struct usb_bus *bus) +{ + if (!bus->proc_entry) + return; + remove_proc_entry(bus->proc_entry->name, usbdir); + clear_bit(bus->proc_busnum, busnumbermap); +} + +void proc_usb_add_device(struct usb_device *dev) +{ + char buf[16]; + + dev->proc_entry = NULL; + if (!dev->bus->proc_entry) + return; + sprintf(buf, "%03d", dev->devnum); + if (!(dev->proc_entry = create_proc_entry(buf, 0, dev->bus->proc_entry))) + return; + dev->proc_entry->ops = &proc_usb_device_inode_operations; + dev->proc_entry->data = dev; +} + +void proc_usb_remove_device(struct usb_device *dev) +{ + if (dev->proc_entry) + remove_proc_entry(dev->proc_entry->name, dev->bus->proc_entry); +} + void proc_usb_cleanup (void) { diff -u --recursive --new-file v2.3.14/linux/drivers/usb/uhci-debug.c linux/drivers/usb/uhci-debug.c --- v2.3.14/linux/drivers/usb/uhci-debug.c Sat Aug 7 13:01:44 1999 +++ linux/drivers/usb/uhci-debug.c Wed Aug 25 15:03:54 1999 @@ -2,7 +2,11 @@ * UHCI-specific debugging code. Invaluable when something * goes wrong, but don't get in my face. * + * Kernel visible pointers are surrounded in []'s and bus + * visible pointers are surrounded in ()'s + * * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt */ #include @@ -10,65 +14,66 @@ #include "uhci.h" -void show_td(struct uhci_td * td) +void uhci_show_td(struct uhci_td * td) { char *spid; printk("%08x ", td->link); - printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ", - ((td->status >> 29) & 1) ? "SPD " : "", + printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", ((td->status >> 27) & 3), - ((td->status >> 26) & 1) ? "LS " : "", - ((td->status >> 25) & 1) ? "IOS " : "", - ((td->status >> 24) & 1) ? "IOC " : "", - ((td->status >> 23) & 1) ? "Active " : "", - ((td->status >> 22) & 1) ? "Stalled " : "", - ((td->status >> 21) & 1) ? "DataBufErr " : "", - ((td->status >> 20) & 1) ? "Babble " : "", - ((td->status >> 19) & 1) ? "NAK " : "", - ((td->status >> 18) & 1) ? "CRC/Timeo " : "", - ((td->status >> 17) & 1) ? "BitStuff " : "", + (td->status & TD_CTRL_SPD) ? "SPD " : "", + (td->status & TD_CTRL_LS) ? "LS " : "", + (td->status & TD_CTRL_IOC) ? "IOC " : "", + (td->status & TD_CTRL_ACTIVE) ? "Active " : "", + (td->status & TD_CTRL_STALLED) ? "Stalled " : "", + (td->status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", + (td->status & TD_CTRL_BABBLE) ? "Babble " : "", + (td->status & TD_CTRL_NAK) ? "NAK " : "", + (td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", + (td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", td->status & 0x7ff); + switch (td->info & 0xff) { - case 0x2d: - spid = "SETUP"; - break; - case 0xe1: - spid = "OUT"; - break; - case 0x69: - spid = "IN"; - break; - default: - spid = "?"; - break; + case USB_PID_SETUP: + spid = "SETUP"; + break; + case USB_PID_OUT: + spid = "OUT"; + break; + case USB_PID_IN: + spid = "IN"; + break; + default: + spid = "?"; + break; } + printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", td->info >> 21, - ((td->info >> 19) & 1), - (td->info >> 15) & 15, - (td->info >> 8) & 127, - (td->info & 0xff), - spid); + ((td->info >> 19) & 1), + (td->info >> 15) & 15, + (td->info >> 8) & 127, + (td->info & 0xff), + spid); printk("(buf=%08x)\n", td->buffer); } -static void show_sc(int port, unsigned short status) +static void uhci_show_sc(int port, unsigned short status) { printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", port, status, - (status & (1 << 12)) ? " PortSuspend" : "", - (status & (1 << 9)) ? " PortReset" : "", - (status & (1 << 8)) ? " LowSpeed" : "", - (status & 0x40) ? " ResumeDetect" : "", - (status & 0x08) ? " EnableChange" : "", - (status & 0x04) ? " PortEnabled" : "", - (status & 0x02) ? " ConnectChange" : "", - (status & 0x01) ? " PortConnected" : ""); + (status & USBPORTSC_SUSP) ? "PortSuspend " : "", + (status & USBPORTSC_PR) ? "PortReset " : "", + (status & USBPORTSC_LSDA) ? "LowSpeed " : "", + (status & USBPORTSC_RD) ? "ResumeDetect " : "", + (status & USBPORTSC_PEC) ? "EnableChange " : "", + (status & USBPORTSC_PE) ? "PortEnabled " : "", + (status & USBPORTSC_CSC) ? "ConnectChange " : "", + (status & USBPORTSC_CCS) ? "PortConnected " : ""); } -void show_status(struct uhci *uhci) +void uhci_show_status(struct uhci *uhci) { unsigned int io_addr = uhci->io_addr; unsigned short usbcmd, usbstat, usbint, usbfrnum; @@ -87,30 +92,31 @@ printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", usbcmd, - (usbcmd & 0x80) ? " Maxp64" : " Maxp32", - (usbcmd & 0x40) ? " CF" : "", - (usbcmd & 0x20) ? " SWDBG" : "", - (usbcmd & 0x10) ? " FGR" : "", - (usbcmd & 0x08) ? " EGSM" : "", - (usbcmd & 0x04) ? " GRESET" : "", - (usbcmd & 0x02) ? " HCRESET" : "", - (usbcmd & 0x01) ? " RS" : ""); + (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", + (usbcmd & USBCMD_CF) ? "CF " : "", + (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", + (usbcmd & USBCMD_FGR) ? "FGR " : "", + (usbcmd & USBCMD_EGSM) ? "EGSM " : "", + (usbcmd & USBCMD_GRESET) ? "GRESET " : "", + (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", + (usbcmd & USBCMD_RS) ? "RS " : ""); printk(" usbstat = %04x %s%s%s%s%s%s\n", usbstat, - (usbstat & 0x20) ? " HCHalted" : "", - (usbstat & 0x10) ? " HostControllerProcessError" : "", - (usbstat & 0x08) ? " HostSystemError" : "", - (usbstat & 0x04) ? " ResumeDetect" : "", - (usbstat & 0x02) ? " USBError" : "", - (usbstat & 0x01) ? " USBINT" : ""); + (usbstat & USBSTS_HCH) ? "HCHalted " : "", + (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", + (usbstat & USBSTS_HSE) ? "HostSystemError " : "", + (usbstat & USBSTS_RD) ? "ResumeDetect " : "", + (usbstat & USBSTS_ERROR) ? "USBError " : "", + (usbstat & USBSTS_USBINT) ? "USBINT " : ""); printk(" usbint = %04x\n", usbint); - printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum)); + printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, + 0xfff & (4*(unsigned int)usbfrnum)); printk(" flbaseadd = %08x\n", flbaseadd); printk(" sof = %02x\n", sof); - show_sc(1, portsc1); - show_sc(2, portsc2); + uhci_show_sc(1, portsc1); + uhci_show_sc(2, portsc2); } #define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) @@ -123,13 +129,13 @@ return bus_to_virt(link & ~UHCI_PTR_BITS); } -void show_queue(struct uhci_qh *qh) +void uhci_show_queue(struct uhci_qh *qh) { - struct uhci_td *td; - int i = 0; + struct uhci_td *td, *first; + int i = 0, count = 1000; if (qh->element & UHCI_PTR_QH) - printk(" Element points to QH?\n"); + printk(" Element points to QH (bug?)\n"); if (qh->element & UHCI_PTR_DEPTH) printk(" Depth traverse\n"); @@ -138,19 +144,30 @@ printk(" Terminate\n"); if (!(qh->element & ~UHCI_PTR_BITS)) { - printk(" td 0 = NULL\n"); + printk(" td 0: [NULL]\n"); return; } - for(td = uhci_link_to_td(qh->element); td; - td = uhci_link_to_td(td->link)) { - printk(" td %d = %p\n", i++, td); + if (qh->first) + first = qh->first; + else + first = uhci_link_to_td(qh->element); + + /* Make sure it doesn't runaway */ + for (td = first; td && count > 0; + td = uhci_link_to_td(td->link), --count) { + printk(" td %d: [%p]\n", i++, td); printk(" "); - show_td(td); + uhci_show_td(td); + + if (td == uhci_link_to_td(td->link)) { + printk(KERN_ERR "td links to itself!\n"); + break; + } } } -int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) +static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) { int j; @@ -166,7 +183,7 @@ "interrupt128", "interrupt256", "control", "bulk"}; -void show_queues(struct uhci *uhci) +void uhci_show_queues(struct uhci *uhci) { int i; struct uhci_qh *qh; @@ -178,13 +195,13 @@ qh = uhci_link_to_qh(uhci->skelqh[i].link); for (; qh; qh = uhci_link_to_qh(qh->link)) { - if (is_skeleton_qh(uhci, qh)) + if (uhci_is_skeleton_qh(uhci, qh)) break; printk(" [%p] (%08X) (%08x)\n", qh, qh->link, qh->element); - show_queue(qh); + uhci_show_queue(qh); } } } diff -u --recursive --new-file v2.3.14/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.14/linux/drivers/usb/uhci.c Wed Aug 18 16:22:23 1999 +++ linux/drivers/usb/uhci.c Wed Aug 25 15:03:54 1999 @@ -3,6 +3,7 @@ * * (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap * * Intel documents this fairly well, and as far as I know there * are no royalties or anything like that, but even so there are @@ -63,32 +64,51 @@ #define UHCI_DEBUG /* - * Map status to standard result codes. + * function prototypes + */ + +static int uhci_get_current_frame_number (struct usb_device *usb_dev); + +static int uhci_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc); + +static void uhci_free_isoc (struct usb_isoc_desc *isocdesc); + +static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc); + +static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc); + +/* + * Map status to standard result codes * - * is ((td->status >> 16) & 0xff) [a.k.a. uhci_status_bits(td->status)] + * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status) * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) { if (!status) return USB_ST_NOERROR; - if (status & 0x02) /* Bitstuff error*/ + if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ return USB_ST_BITSTUFF; - if (status & 0x04) { /* CRC/Timeout */ + if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ if (dir_out) - return USB_ST_NORESPONSE; + return USB_ST_NORESPONSE; else return USB_ST_CRC; } - if (status & 0x08) /* NAK */ + if (status & TD_CTRL_NAK) /* NAK */ return USB_ST_TIMEOUT; - if (status & 0x10) /* Babble */ + if (status & TD_CTRL_BABBLE) /* Babble */ return USB_ST_STALL; - if (status & 0x20) /* Buffer error */ + if (status & TD_CTRL_DBUFERR) /* Buffer error */ return USB_ST_BUFFERUNDERRUN; - if (status & 0x40) /* Stalled */ + if (status & TD_CTRL_STALLED) /* Stalled */ return USB_ST_STALL; - if (status & 0x80) /* Active */ + if (status & TD_CTRL_ACTIVE) /* Active */ return USB_ST_NOERROR; return USB_ST_INTERNALERROR; @@ -96,77 +116,83 @@ /* * Return the result of a TD.. */ -static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval) +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval, int debug) { unsigned int status; struct uhci_td *tmp; - - if (!td->qh) - tmp = td; - else - tmp = uhci_ptr_to_virt(td->qh->element); + int count = 1000; if (rval) *rval = 0; - /* locate the first failing td, if any */ + /* Start at the TD first in the chain, if possible */ + if (td->qh && td->qh->first) + tmp = td->qh->first; + else + tmp = td; + if (!tmp) + return USB_ST_INTERNALERROR; + + /* Locate the first failing td, if any */ do { status = uhci_status_bits(tmp->status); + if (status) { - /* must reset the toggle on first error */ - if (uhci_debug) { - printk(KERN_DEBUG "Set toggle from %x rval %ld\n", - (unsigned int)tmp, rval ? *rval : 0); + if (debug) { + /* Must reset the toggle on first error */ + if (uhci_debug) { + printk(KERN_DEBUG "Set toggle from %x rval %ld\n", + (unsigned int)tmp, rval ? *rval : 0); + } + + usb_settoggle(dev->usb, uhci_endpoint(tmp->info), + uhci_packetout(tmp->info) ^ 1, + uhci_toggle(tmp->info)); + break; } - usb_settoggle(dev->usb, uhci_endpoint(tmp->info), - uhci_packetout(tmp->info), uhci_toggle(tmp->info)); - break; } else { - if (rval) - *rval += uhci_actual_length(tmp->status); + if (rval && ((tmp->info & 0xFF) == USB_PID_IN)) + *rval += uhci_actual_length(tmp->status); } + if ((tmp->link & UHCI_PTR_TERM) || (tmp->link & UHCI_PTR_QH)) break; + tmp = uhci_ptr_to_virt(tmp->link); - } while (1); + } while (--count); - if (!status) + if (!count) { + printk(KERN_ERR "runaway td's in uhci_td_result!\n"); + /* Force debugging on */ + debug = 1; + } else if (!status) return USB_ST_NOERROR; /* Some debugging code */ - if (uhci_debug) { - int count = 10; - - if (!td->qh) - tmp = td; - else - tmp = uhci_ptr_to_virt(td->qh->element); + if (debug && uhci_debug) { printk(KERN_DEBUG "uhci_td_result() failed with status %x\n", status); - do { - show_td(tmp); - if ((tmp->link & UHCI_PTR_TERM) || - (tmp->link & UHCI_PTR_QH)) - break; - tmp = uhci_ptr_to_virt(tmp->link); - } while (--count); + + /* Print the chain for debugging purposes */ + if (td->qh) + uhci_show_queue(td->qh); + else + uhci_show_td(td); } - if (status & 0x40) { + if (status & TD_CTRL_STALLED) { /* endpoint has stalled - mark it halted */ usb_endpoint_halt(dev->usb, uhci_endpoint(tmp->info), uhci_packetout(tmp->info)); return USB_ST_STALL; } - if (status == 0x80) { - /* still active */ - if (!rval) - return USB_ST_DATAUNDERRUN; - } - return uhci_map_status(status, uhci_packetout(tmp->info)); + if ((status == TD_CTRL_ACTIVE) && (!rval)) + return USB_ST_DATAUNDERRUN; + + return uhci_map_status(status, usb_pipeout(tmp->info) ^ 1); } /* @@ -194,6 +220,7 @@ :"=q" (success), "=a" (link) :"m" (qh->element), "1" (link), "r" (new) :"memory"); + if (success) { /* Was there a successor entry? Fix it's backpointer */ if ((link & UHCI_PTR_TERM) == 0) { @@ -203,6 +230,10 @@ break; } } + + qh->first = first; + first->qh = qh; + last->qh = qh; } static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td) @@ -279,6 +310,54 @@ : :"r" (link), "m" (*backptr), "a" (me) :"memory"); + + /* Reset it just in case */ + td->link = UHCI_PTR_TERM; +} + +/* + * Only the USB core should call uhci_alloc_dev and uhci_free_dev + */ +static int uhci_alloc_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev; + + /* Allocate the UHCI device private data */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -1; + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + atomic_set(&dev->refcnt, 1); + + if (usb_dev->parent) + dev->uhci = usb_to_uhci(usb_dev->parent)->uhci; + + return 0; +} + +static int uhci_free_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + + if (atomic_dec_and_test(&dev->refcnt)) + kfree(dev); + + return 0; +} + +static void uhci_inc_dev_use(struct uhci_device *dev) +{ + atomic_inc(&dev->refcnt); +} + +static void uhci_dec_dev_use(struct uhci_device *dev) +{ + uhci_free_dev(dev->usb); } static struct uhci_td *uhci_td_alloc(struct uhci_device *dev) @@ -305,13 +384,19 @@ INIT_LIST_HEAD(&td->irq_list); atomic_set(&td->refcnt, 1); + uhci_inc_dev_use(dev); + return td; } static void uhci_td_free(struct uhci_td *td) { - if (atomic_dec_and_test(&td->refcnt)) + if (atomic_dec_and_test(&td->refcnt)) { kmem_cache_free(uhci_td_cachep, td); + + if (td->dev) + uhci_dec_dev_use(td->dev); + } } static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev) @@ -332,16 +417,23 @@ qh->dev = dev; qh->skel = NULL; + qh->first = NULL; init_waitqueue_head(&qh->wakeup); atomic_set(&qh->refcnt, 1); + uhci_inc_dev_use(dev); + return qh; } static void uhci_qh_free(struct uhci_qh *qh) { - if (atomic_dec_and_test(&qh->refcnt)) + if (atomic_dec_and_test(&qh->refcnt)) { kmem_cache_free(uhci_qh_cachep, qh); + + if (qh->dev) + uhci_dec_dev_use(qh->dev); + } } /* @@ -371,9 +463,9 @@ } /* - * This function removes and disallcoates all structures set up for an transfer. + * This function removes and disallocates all structures set up for a transfer. * It takes the qh out of the skeleton, removes the tq and the td's. - * It only removes the associated interrupt handler if removeirq ist set. + * It only removes the associated interrupt handler if removeirq is set. * The *td argument is any td in the list of td's. */ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) @@ -382,10 +474,10 @@ struct uhci_td *curtd; unsigned int nextlink; - if (!td->qh) - curtd = td; + if (td->qh && td->qh->first) + curtd = td->qh->first; else - curtd = uhci_ptr_to_virt(td->qh->element); + curtd = td; /* Remove it from the skeleton */ uhci_remove_qh(td->qh->skel, td->qh); @@ -436,7 +528,8 @@ td->link = UHCI_PTR_TERM; /* Terminate */ td->status = status; /* In */ td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) | - (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); + (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); + td->buffer = virt_to_bus(dev->data); td->qh = qh; td->dev = dev; @@ -471,10 +564,6 @@ struct uhci_td *td; struct uhci_qh *qh; -#ifdef UHCI_DEBUG - printk(KERN_DEBUG "usb-uhci: releasing irq handle %p\n", handle); -#endif - td = (struct uhci_td *)handle; if (!td) return USB_ST_INTERNALERROR; @@ -498,190 +587,327 @@ } /* uhci_release_irq() */ /* - * Isochronous operations + * uhci_get_current_frame_number() + * + * returns the current frame number for a USB bus/controller. */ -static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc) +static int uhci_get_current_frame_number(struct usb_device *usb_dev) { - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - char *data = isodesc->data; - int i, totlen = 0; + return inw (usb_to_uhci(usb_dev)->uhci->io_addr + USBFRNUM) & 0x3ff; +} - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; - char *cdata = uhci_ptr_to_virt(td->buffer); - int n = uhci_actual_length(td->status); - if ((cdata != data) && (n)) - memmove(data, cdata, n); +/* + * uhci_init_isoc() + * + * Checks bus bandwidth allocation for this USB bus. + * Allocates some data structures. + * Initializes parts of them from the function parameters. + * + * It does not associate any data/buffer pointers or + * driver (caller) callback functions with the allocated + * data structures. Such associations are left until + * uhci_run_isoc(). + * + * Returns 0 for success or negative value for error. + * Sets isocdesc before successful return. + */ +static int uhci_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, /* bandwidth % = 100 * this / 1000 */ + void *context, + struct usb_isoc_desc **isocdesc) +{ + struct usb_isoc_desc *id; -#ifdef UHCI_DEBUG - /* Debugging */ - if (uhci_status_bits(td->status)) - printk(KERN_DEBUG "error: %d %X\n", i, - (td->status >> 16)); +#ifdef BANDWIDTH_ALLOCATION + /* TBD: add bandwidth allocation/checking/management HERE. */ + /* TBD: some way to factor in frame_spacing ??? */ #endif - data += n; - totlen += n; - } - - return totlen; -} + *isocdesc = NULL; -static int uhci_unschedule_isochronous(struct usb_device *usb_dev, void *_isodesc) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - int i; - - if ((isodesc->frame < 0) || (isodesc->frame > 1023)) { - printk(KERN_ERR "illegal frame number %d\n", isodesc->frame); - return 1; + /* Check some parameters. */ + if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n", + frame_count); +#endif + return -EINVAL; } - /* FIXME: Use uhci_remove_td */ - - /* Remove from previous frames */ - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; - - /* Turn off Active and IOC bits */ - td->status &= ~(3 << 23); - td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); - - uhci->fl->frame[(isodesc->frame + i) % 1024] = td->link; + if (!usb_pipeisoc (pipe)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: NOT an Isoc. pipe\n"); +#endif + return -EINVAL; } - isodesc->frame = -1; - - return 0; -} - -/* td points to the one td we allocated for isochronous transfers */ -static int uhci_schedule_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc; - int frame, i; - - if (isodesc->frame != -1) { - printk(KERN_ERR "isoc queue not removed\n"); - uhci_unschedule_isochronous(usb_dev, isodesc); - } - - /* Insert TD into list */ - if (!pisodesc) { - /* It's not guaranteed to be 1-1024 */ - frame = inw(uhci->io_addr + USBFRNUM) % 1024; - - /* HACK: Start 2 frames from now */ - frame = (frame + 2) % 1024; - } else - frame = (pisodesc->endframe + 1) % 1024; - - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; + id = kmalloc (sizeof (*id) + + (sizeof (struct isoc_frame_desc) * frame_count), GFP_KERNEL); + if (!id) + return -ENOMEM; - /* Active */ - td->status |= TD_CTRL_ACTIVE; - td->backptr = &uhci->fl->frame[(frame + i) % 1024]; - td->link = uhci->fl->frame[(frame + i) % 1024]; - uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(td); + id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL); + if (!id->td) { + kfree (id); + return -ENOMEM; } - /* IOC on the last TD */ - isodesc->td[i - 1].status |= TD_CTRL_IOC; - - isodesc->frame = frame; - isodesc->endframe = (frame + isodesc->num - 1) % 1024; + memset (id, 0, sizeof (*id) + + (sizeof (struct isoc_frame_desc) * frame_count)); + memset (id->td, 0, sizeof (struct uhci_td) * frame_count); + + id->frame_count = frame_count; + id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe)); + /* TBD: or make this a parameter to allow for frame_size + that is less than maxpacketsize */ + id->start_frame = -1; + id->end_frame = -1; + id->usb_dev = usb_dev; + id->pipe = pipe; + id->context = context; + *isocdesc = id; return 0; -} +} /* end uhci_init_isoc */ /* - * Initialize isochronous queue + * uhci_run_isoc() + * + * Associates data/buffer pointers/lengths and + * driver (caller) callback functions with the + * allocated Isoc. data structures and TDs. + * + * Then inserts the TDs into the USB controller frame list + * for its processing. + * And inserts the callback function into its TD. + * + * pr_isocdesc (previous Isoc. desc.) may be NULL. + * It is used only for chaining one list of TDs onto the + * end of the previous list of TDs. + * + * Returns 0 (success) or error code (negative value). */ -static void *uhci_allocate_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) +static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc) { - struct uhci_device *dev = usb_to_uhci(usb_dev); - unsigned long destination, status; - struct uhci_td *td; - struct uhci_iso_td *isodesc; - int i; + struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev); + struct uhci *uhci = dev->uhci; + unsigned long destination, status; + struct uhci_td *td; + int ix, cur_frame, pipeinput, frlen; + int cb_frames = 0; + struct isoc_frame_desc *fd; + unsigned char *bufptr; + + if (!isocdesc->callback_fn) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_run_isoc: caller must have a callback function\n"); +#endif + return -EINVAL; + } - isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL); - if (!isodesc) { - printk(KERN_ERR "Couldn't allocate isodesc!\n"); - return NULL; + /* Check buffer size large enough for maxpacketsize * frame_count. */ + if (isocdesc->buf_size < (isocdesc->frame_count * isocdesc->frame_size)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: buf_size too small (%d < %d)\n", + isocdesc->buf_size, isocdesc->frame_count * isocdesc->frame_size); +#endif + return -EINVAL; } - memset(isodesc, 0, sizeof(*isodesc)); + /* Check buffer ptr for Null. */ + if (!isocdesc->data) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: data ptr is null\n"); +#endif + return -EINVAL; + } - /* Carefully work around the non contiguous pages */ - isodesc->num = len / maxsze; - isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL); - isodesc->frame = isodesc->endframe = -1; - isodesc->data = data; - isodesc->maxsze = maxsze; - - if (!isodesc->td) { - printk(KERN_ERR "couldn't allocate td's\n"); - kfree(isodesc); - return NULL; +#ifdef NEED_ALIGNMENT + /* Check data page alignment. */ + if (((int)(isocdesc->data) & (PAGE_SIZE - 1)) != 0) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: buffer must be page-aligned (%p)\n", + isocdesc->data); +#endif + return -EINVAL; } +#endif /* NEED_ALIGNMENT */ - isodesc->frame = isodesc->endframe = -1; + /* + * Check start_type unless pr_isocdesc is used. + */ + if (!pr_isocdesc && (isocdesc->start_type > START_TYPE_MAX)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_run_isoc: invalid start_type (%d)\n", + isocdesc->start_type); +#endif + return -EINVAL; + } + + /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */ + if (!pr_isocdesc && (isocdesc->start_type != START_ASAP)) + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > 1000)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } /* - * Build the DATA TD's + * Set the start/end frame numbers. */ - i = 0; - do { - /* Build the TD for control status */ - td = &isodesc->td[i]; + if (!pr_isocdesc) + cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev); - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (pipe & PIPE_DEVEP_MASK) - | usb_packetid (pipe); /* add IN or OUT */ + if (pr_isocdesc) { + isocdesc->start_frame = pr_isocdesc->end_frame + 1; + } else if (isocdesc->start_type == START_ABSOLUTE) { + /* Use start_frame as is. */ + } else if (isocdesc->start_type == START_RELATIVE) { + if (isocdesc->start_frame < START_FRAME_FUDGE) + isocdesc->start_frame = START_FRAME_FUDGE; + isocdesc->start_frame += cur_frame; + } else if (isocdesc->start_type == START_ASAP) { + isocdesc->start_frame = cur_frame + START_FRAME_FUDGE; + } + + /* and see if start_frame needs any correction */ + if (isocdesc->start_frame >= 1000) + isocdesc->start_frame -= 1000; + + /* and fix the end_frame value */ + isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1; + if (isocdesc->end_frame >= 1000) + isocdesc->end_frame -= 1000; + + isocdesc->prev_completed_frame = -1; + isocdesc->cur_completed_frame = -1; + + destination = (isocdesc->pipe & PIPE_DEVEP_MASK) | + usb_packetid (isocdesc->pipe); + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; /* mark Isoc.; can't be low speed */ + pipeinput = usb_pipein (isocdesc->pipe); + cur_frame = isocdesc->start_frame; + bufptr = isocdesc->data; + + /* + * Build the Data TDs. + * TBD: Not using frame_spacing (Yet). Defaults to 1 (every frame). + * (frame_spacing is a way to request less bandwidth.) + * This can also be done by using frame_length = 0 in the + * frame_desc array, but this way won't take less bandwidth + * allocation into account. + */ + + if (isocdesc->frame_spacing <= 0) + isocdesc->frame_spacing = 1; + + for (ix = 0, td = isocdesc->td, fd = isocdesc->frames; + ix < isocdesc->frame_count; ix++, td++, fd++, cur_frame++) { + frlen = fd->frame_length; + if (frlen > isocdesc->frame_size) + frlen = isocdesc->frame_size; + +#ifdef NOTDEF + td->info = destination | /* use Actual len on OUT; max. on IN */ + (pipeinput ? ((isocdesc->frame_size - 1) << 21) + : ((frlen - 1) << 21)); +#endif + + td->dev_id = isocdesc; /* can get dev_id or context from isocdesc */ + td->status = status; + td->info = destination | ((frlen - 1) << 21); + td->buffer = virt_to_bus (bufptr); + td->dev = dev; + td->isoc_td_number = ix; /* 0-based; does not wrap 999 -> 0 */ + + if (isocdesc->callback_frames && + (++cb_frames >= isocdesc->callback_frames)) { + td->status |= TD_CTRL_IOC; + td->completed = isocdesc->callback_fn; + cb_frames = 0; + } - status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOS; + bufptr += fd->frame_length; /* or isocdesc->frame_size; */ /* - * Build the TD for the control request + * Insert the TD in the frame list. */ - td->status = status; - td->info = destination | ((maxsze - 1) << 21); - td->buffer = virt_to_bus(data); - td->backptr = NULL; + td->backptr = &uhci->fl->frame [cur_frame]; + td->link = uhci->fl->frame [cur_frame]; + uhci->fl->frame [cur_frame] = virt_to_bus (td); + + if (cur_frame >= 999) + cur_frame = -1; + } /* end for ix */ - i++; + /* + * Add IOC on the last TD. + */ + td--; + td->status |= TD_CTRL_IOC; + uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */ - data += maxsze; - len -= maxsze; - } while (i < isodesc->num); + return 0; +} /* end uhci_run_isoc */ - uhci_add_irq_list(dev->uhci, td, completed, dev_id); +/* + * uhci_kill_isoc() + * + * Marks a TD list as Inactive and removes it from the Isoc. + * TD frame list. + * + * Does not free any memory resources. + * + * Returns 0 for success or negative value for error. + */ +static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc) +{ + struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev); + struct uhci *uhci = dev->uhci; + struct uhci_td *td; + int ix, cur_frame; - return isodesc; -} + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= 1000)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } + + for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame; + ix < isocdesc->frame_count; ix++, td++) { + td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); + uhci->fl->frame [cur_frame] = td->link; -static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc) + if (++cur_frame >= 1000) + cur_frame = 0; + } /* end for ix */ + + isocdesc->start_frame = -1; + return 0; +} /* end uhci_kill_isoc */ + +static void uhci_free_isoc (struct usb_isoc_desc *isocdesc) { - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + /* If still Active, kill it. */ + if (isocdesc->start_frame >= 0) + uhci_kill_isoc (isocdesc); - /* If it's still scheduled, unschedule them */ - if (isodesc->frame) - uhci_unschedule_isochronous(usb_dev, isodesc); + /* Remove it from the IRQ list. */ + uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1])); - /* Remove it from the IRQ list */ - uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]); + /* Free the associate memory. */ + if (isocdesc->td) + kfree (isocdesc->td); - kfree(isodesc->td); - kfree(isodesc); -} + kfree (isocdesc); +} /* end uhci_free_isoc */ /* * Control thread operations: we just mark the last TD @@ -718,26 +944,6 @@ uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup); -#if 0 - /* FIXME: This is kinda kludged */ - /* Walk the TD list and update the QH pointer */ - { - struct uhci_td *curtd; - int count = 100; - - curtd = first; - do { - curtd->qh = ctrl_qh; - if (curtd->link & TD_CTRL_TERM) - break; - - curtd = uhci_ptr_to_virt(curtd->link); - } while (--count); - if (!count) - printk(KERN_DEBUG "runaway tds!\n"); - } -#endif - uhci_insert_tds_in_qh(qh, first, last); /* Add it into the skeleton */ @@ -755,7 +961,7 @@ uhci_qh_free(qh); - return uhci_td_result(dev, last, NULL); + return uhci_td_result(dev, last, NULL, 1); } /* @@ -778,6 +984,11 @@ * 29 TD's is a minimum of 232 bytes worth of control * information, that's just ridiculously high. Most * control messages have just a few bytes of data. + * + * 232 is not ridiculously high with many of the + * configurations on audio devices, etc. anyway, + * there is no restriction on length of transfers + * anymore */ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len) { @@ -787,12 +998,14 @@ int ret, count; int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)); __u32 nextlink; + unsigned long bytesrequested = len; + unsigned long bytesread = 0; first = td = uhci_td_alloc(dev); if (!td) return -ENOMEM; - /* The "pipe" thing contains the destination in bits 8--18. */ + /* The "pipe" thing contains the destination in bits 8--18 */ destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* 3 errors */ @@ -811,7 +1024,7 @@ */ destination ^= (USB_PID_SETUP ^ USB_PID_IN); /* SETUP -> IN */ if (usb_pipeout(pipe)) - destination ^= (USB_PID_OUT ^ USB_PID_IN); /* IN -> OUT */ + destination ^= (USB_PID_IN ^ USB_PID_OUT); /* IN -> OUT */ prevtd = td; td = uhci_td_alloc(dev); @@ -851,7 +1064,13 @@ /* * Build the final TD for control status */ - destination ^= (USB_PID_OUT ^ USB_PID_IN); /* OUT -> IN */ + /* It's only IN if the pipe is out AND we aren't expecting data */ + destination &= ~0xFF; + if (usb_pipeout(pipe) | (bytesrequested == 0)) + destination |= USB_PID_IN; + else + destination |= USB_PID_OUT; + destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ td->status = status | TD_CTRL_IOC; /* no limit on errors on final packet */ @@ -863,9 +1082,13 @@ /* Start it up.. */ ret = uhci_run_control(dev, first, td); - count = 100; + count = 1000; td = first; do { + if (!uhci_status_bits(td->status) && ((td->info & 0xFF) == + USB_PID_IN)) + bytesread += uhci_actual_length(td->status); + nextlink = td->link; uhci_remove_td(td); uhci_td_free(td); @@ -879,6 +1102,12 @@ if (!count) printk(KERN_ERR "runaway td's!?\n"); + if (ret && (bytesread >= bytesrequested)) { + printk(KERN_DEBUG "Recovered sufficient data (asked for %ld, got %ld) from failed cmd\n", + bytesrequested, bytesread); + ret = 0; + } + if (uhci_debug && ret) { __u8 *p = (__u8 *)cmd; @@ -911,32 +1140,12 @@ uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup); -#if 0 - /* FIXME: This is kinda kludged */ - /* Walk the TD list and update the QH pointer */ - { - struct uhci_td *curtd; - int count = 100; - - curtd = first; - do { - curtd->qh = bulk_qh; - if (curtd->link & UHCI_PTR_TERM) - break; - - curtd = uhci_ptr_to_virt(curtd->link); - } while (--count); - if (!count) - printk(KERN_ERR "runaway tds!\n"); - } -#endif - uhci_insert_tds_in_qh(qh, first, last); /* Add it into the skeleton */ uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh); - schedule_timeout(HZ*5); /* 5 seconds */ + schedule_timeout(HZ * 5); /* 5 seconds */ remove_wait_queue(&qh->wakeup, &wait); @@ -947,7 +1156,7 @@ uhci_qh_free(qh); - return uhci_td_result(dev, last, rval); + return uhci_td_result(dev, last, rval, 1); } /* @@ -1107,82 +1316,36 @@ } /* - *Remove a handler from a pipe. This terminates the transfer. - *We have some assumptions here: + * Remove a handler from a pipe. This terminates the transfer. + * We have some assumptions here: * There is only one queue using this pipe. (the one we remove) * Any data that is in the queue is useless for us, we throw it away. */ -static int uhci_terminate_bulk(struct usb_device *dev, void * first) +static int uhci_terminate_bulk(struct usb_device *dev, void *first) { /* none found? there is nothing to remove! */ if (!first) return 0; - uhci_remove_transfer(first,1); + uhci_remove_transfer(first, 1); return 1; } -static struct usb_device *uhci_usb_alloc(struct usb_device *parent) -{ - struct usb_device *usb_dev; - struct uhci_device *dev; - - /* Allocate the USB device */ - usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); - if (!usb_dev) - return NULL; - - memset(usb_dev, 0, sizeof(*usb_dev)); - - /* Allocate the UHCI device private data */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - kfree(usb_dev); - return NULL; - } - - /* Initialize "dev" */ - memset(dev, 0, sizeof(*dev)); - - usb_dev->hcpriv = dev; - dev->usb = usb_dev; - - usb_dev->parent = parent; - - if (parent) { - usb_dev->bus = parent->bus; - dev->uhci = usb_to_uhci(parent)->uhci; - } - - return usb_dev; -} - -static int uhci_usb_free(struct usb_device *usb_dev) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - - kfree(dev); - usb_destroy_configuration(usb_dev); - kfree(usb_dev); - - return 0; -} - struct usb_operations uhci_device_operations = { - uhci_usb_alloc, - uhci_usb_free, + uhci_alloc_dev, + uhci_free_dev, uhci_control_msg, uhci_bulk_msg, uhci_request_irq, uhci_release_irq, uhci_request_bulk, uhci_terminate_bulk, - uhci_allocate_isochronous, - uhci_delete_isochronous, - uhci_schedule_isochronous, - uhci_unschedule_isochronous, - uhci_compress_isochronous + uhci_get_current_frame_number, + uhci_init_isoc, + uhci_free_isoc, + uhci_run_isoc, + uhci_kill_isoc }; /* @@ -1207,7 +1370,7 @@ wait_ms(10); status = inw(port); - if(!(status & USBPORTSC_PE)) { + if (!(status & USBPORTSC_PE)) { outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ wait_ms(50); } @@ -1251,7 +1414,7 @@ * Ok, we got a new connection. Allocate a device to it, * and find out what it wants to do.. */ - usb_dev = uhci_usb_alloc(root_hub->usb); + usb_dev = usb_alloc_dev(root_hub->usb, root_hub->usb->bus); if (!usb_dev) return; @@ -1303,6 +1466,58 @@ } while (nr < maxchild); } +static int fixup_isoc_desc (struct uhci_td *td) +{ + struct usb_isoc_desc *isocdesc = td->dev_id; + struct uhci_td *prtd; + struct isoc_frame_desc *frm; + int first_comp = isocdesc->cur_completed_frame + 1; /* 0-based */ + int cur_comp = td->isoc_td_number; /* 0-based */ + int ix, fx; + int num_comp; + + if (first_comp >= isocdesc->frame_count) + first_comp = 0; + num_comp = cur_comp - first_comp + 1; + +#ifdef CONFIG_USB_DEBUG_ISOC + printk ("fixup_isoc_desc.1: td = %p, id = %p, first_comp = %d, cur_comp = %d, num_comp = %d\n", + td, isocdesc, first_comp, cur_comp, num_comp); +#endif + + for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp]; + ix < num_comp; ix++) { + frm->frame_length = uhci_actual_length (prtd->status); + isocdesc->total_length += frm->frame_length; + + if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status), + uhci_packetout (prtd->info)))) + isocdesc->error_count++; + + prtd++; + frm++; + if (++fx >= isocdesc->frame_count) { /* wrap fx, prtd, and frm */ + fx = 0; + prtd = isocdesc->td; + frm = isocdesc->frames; + } /* end wrap */ + } /* end for */ + + /* + * Update some other fields for drivers. + */ + isocdesc->prev_completed_frame = isocdesc->cur_completed_frame; + isocdesc->cur_completed_frame = cur_comp; + isocdesc->total_completed_frames += num_comp; /* 1-based */ + +#ifdef CONFIG_USB_DEBUG_ISOC + printk ("fixup_isoc_desc.2: total_comp_frames = %d, total_length = %d, error_count = %d\n", + isocdesc->total_completed_frames, isocdesc->total_length, isocdesc->error_count); +#endif /* CONFIG_USB_DEBUG_ISOC */ + + return 0; +} + static void uhci_interrupt_notify(struct uhci *uhci) { struct list_head *tmp, *head = &uhci->interrupt_list; @@ -1311,57 +1526,43 @@ spin_lock(&irqlist_lock); tmp = head->next; while (tmp != head) { - struct uhci_td *first, *td = list_entry(tmp, - struct uhci_td, irq_list); + struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); + unsigned long rval; tmp = tmp->next; - /* We check the TD which had the IOC bit as well as the */ - /* first TD */ - /* XXX: Shouldn't we check all of the TD's in the chain? */ - if ((td->qh) && (td->qh->element & ~UHCI_PTR_BITS)) - first = uhci_link_to_td(td->qh->element); - else - first = NULL; - - /* If any of the error bits are set OR the active is NOT set */ - /* then we're interested in this TD */ - status = td->status & 0xF60000; - - if ((!(status ^ TD_CTRL_ACTIVE)) && (first) && - (!(first->status & TD_CTRL_ACTIVE))) - status = first->status & 0xF60000; + /* We're interested if there was an error or if the chain of */ + /* TD's completed successfully */ + status = uhci_td_result(td->dev, td, &rval, 0); - if (!(status ^ TD_CTRL_ACTIVE)) + if ((status == USB_ST_NOERROR) && (td->status & TD_CTRL_ACTIVE)) continue; - /* remove from IRQ list */ list_del(&td->irq_list); INIT_LIST_HEAD(&td->irq_list); - if (td->completed(uhci_map_status(uhci_status_bits(status), uhci_packetout(td->info)), - bus_to_virt(td->buffer), -1, td->dev_id)) { + if (td->completed(status, bus_to_virt(td->buffer), rval, + td->dev_id)) { + struct usb_device *usb_dev = td->dev->usb; + list_add(&td->irq_list, &uhci->interrupt_list); - /* Isochronous TD's don't need this */ - if (!(td->status & TD_CTRL_IOS)) { - struct usb_device *usb_dev = td->dev->usb; - - usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */ - td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info), - uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */ - td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; - /* The HC removes it, so re-add it */ - uhci_insert_td_in_qh(td->qh, td); - } + usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); + td->info &= ~(1 << 19); /* clear data toggle */ + td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), + usb_pipeout(td->info) ^ 1) << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; + /* The HC only removes it when it completed */ + /* successfully, so force remove and readd it */ + uhci_remove_td(td); + uhci_insert_td_in_qh(td->qh, td); } else if (td->flags & UHCI_TD_REMOVE) { struct usb_device *usb_dev = td->dev->usb; /* marked for removal */ td->flags &= ~UHCI_TD_REMOVE; - usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); + usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); uhci_remove_qh(td->qh->skel, td->qh); uhci_qh_free(td->qh); uhci_td_free(td); @@ -1406,7 +1607,8 @@ unsigned short status; /* - * Read the interrupt status, and write it back to clear the interrupt cause + * Read the interrupt status, and write it back to clear the + * interrupt cause */ status = inw(io_addr + USBSTS); outw(status, io_addr + USBSTS); @@ -1511,9 +1713,9 @@ * Queues are dynamically allocated for devices now, * this code only sets up the skeleton queue */ -static struct uhci *alloc_uhci(unsigned int io_addr) +static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) { - int i; + int i, port; struct uhci *uhci; struct usb_bus *bus; struct uhci_device *dev; @@ -1527,6 +1729,7 @@ uhci->irq = -1; uhci->io_addr = io_addr; + uhci->io_size = io_size; INIT_LIST_HEAD(&uhci->interrupt_list); /* We need exactly one page (per UHCI specs), how convenient */ @@ -1544,7 +1747,7 @@ /* * Allocate the root_hub */ - usb = uhci_usb_alloc(NULL); + usb = usb_alloc_dev(NULL, bus); if (!usb) goto au_free_bus; @@ -1556,10 +1759,29 @@ uhci->bus->root_hub = uhci_to_usb(dev); /* Initialize the root hub */ + /* UHCI specs says devices must have 2 ports, but goes on to say */ /* they may have more but give no way to determine how many they */ /* have, so default to 2 */ - usb->maxchild = 2; + /* According to the UHCI spec, Bit 7 is always set to 1. So we try */ + /* to use this to our advantage */ + for (port = 0; port < (io_size - 0x10) / 2; port++) { + unsigned int portstatus; + + portstatus = inw(io_addr + 0x10 + (port * 2)); + if (!(portstatus & 0x0080)) + break; + } + printk(KERN_DEBUG "Detected %d ports\n", port); + + /* This is experimental so anything less than 2 or greater than 8 is */ + /* something weird and we'll ignore it */ + if (port < 2 || port > 8) { + printk(KERN_DEBUG "Port count misdetected, forcing to 2 ports\n"); + port = 2; + } + + usb->maxchild = port; usb_init_root_hub(usb); /* 8 Interrupt queues */ @@ -1650,7 +1872,7 @@ kfree(uhci); } -static int uhci_control_thread(void * __uhci) +static int uhci_control_thread(void *__uhci) { struct uhci *uhci = (struct uhci *)__uhci; @@ -1693,7 +1915,7 @@ if (signr == SIGUSR1) { printk(KERN_DEBUG "UHCI queue dump:\n"); - show_queues(uhci); + uhci_show_queues(uhci); } else if (signr == SIGUSR2) { uhci_debug = !uhci_debug; printk(KERN_DEBUG "UHCI debug toggle = %x\n", @@ -1716,19 +1938,19 @@ * If we've successfully found a UHCI, now is the time to increment the * module usage count, start the control thread, and return success.. */ -static int found_uhci(int irq, unsigned int io_addr) +static int found_uhci(int irq, unsigned int io_addr, unsigned int io_size) { int retval; struct uhci *uhci; - uhci = alloc_uhci(io_addr); + uhci = alloc_uhci(io_addr, io_size); if (!uhci) return -ENOMEM; INIT_LIST_HEAD(&uhci->uhci_list); list_add(&uhci->uhci_list, &uhci_list); - request_region(uhci->io_addr, 32, "usb-uhci"); + request_region(uhci->io_addr, io_size, "usb-uhci"); reset_hc(uhci); @@ -1754,7 +1976,7 @@ } reset_hc(uhci); - release_region(uhci->io_addr, 32); + release_region(uhci->io_addr, uhci->io_size); release_uhci(uhci); return retval; @@ -1767,18 +1989,18 @@ /* Search for the IO base address.. */ for (i = 0; i < 6; i++) { unsigned int io_addr = dev->resource[i].start; + unsigned int io_size = + dev->resource[i].end - dev->resource[i].start; /* IO address? */ if (!(dev->resource[i].flags & 1)) continue; -#if 0 /* Is it already in use? */ - if (check_region(io_addr, 32)) + if (check_region(io_addr, io_size)) break; -#endif - return found_uhci(dev->irq, io_addr); + return found_uhci(dev->irq, io_addr, io_size); } return -1; } @@ -1819,30 +2041,15 @@ int retval; struct pci_dev *dev = NULL; u8 type; - char *name; - /* FIXME: This is lame, but I guess it's better to leak memory than */ - /* crash */ - name = kmalloc(10, GFP_KERNEL); - if (!name) - return -ENOMEM; - - strcpy(name, "uhci_td"); - - uhci_td_cachep = kmem_cache_create(name, + uhci_td_cachep = kmem_cache_create("uhci_td", sizeof(struct uhci_td), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!uhci_td_cachep) return -ENOMEM; - name = kmalloc(10, GFP_KERNEL); - if (!name) - return -ENOMEM; - - strcpy(name, "uhci_qh"); - - uhci_qh_cachep = kmem_cache_create(name, + uhci_qh_cachep = kmem_cache_create("uhci_qh", sizeof(struct uhci_qh), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); @@ -1854,10 +2061,12 @@ dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev); if (!dev) break; + /* Is it UHCI */ pci_read_config_byte(dev, PCI_CLASS_PROG, &type); - if(type != 0) + if (type != 0) continue; + /* Ok set it up */ retval = start_uhci(dev); if (retval < 0) @@ -1889,7 +2098,8 @@ /* Check if the process is still running */ ret = kill_proc(uhci->control_pid, 0, 1); if (!ret) { - int count = 10; + /* Try a maximum of 10 seconds */ + int count = 10 * 100; uhci->control_continue = 0; wake_up(&uhci_configure); @@ -1910,7 +2120,7 @@ usb_deregister_bus(uhci->bus); reset_hc(uhci); - release_region(uhci->io_addr, 32); + release_region(uhci->io_addr, uhci->io_size); release_uhci(uhci); diff -u --recursive --new-file v2.3.14/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.14/linux/drivers/usb/uhci.h Tue Aug 17 16:47:26 1999 +++ linux/drivers/usb/uhci.h Wed Aug 25 15:03:54 1999 @@ -60,6 +60,10 @@ #define UHCI_PTR_QH 0x0002 #define UHCI_PTR_DEPTH 0x0004 +#define UHCI_NUMFRAMES 1024 + +struct uhci_td; + struct uhci_qh { /* Hardware fields */ __u32 link; /* Next queue */ @@ -70,6 +74,8 @@ struct uhci_device *dev; /* The owning device */ struct uhci_qh *skel; /* Skeleton head */ + struct uhci_td *first; /* First TD in the chain */ + wait_queue_head_t wakeup; } __attribute__((aligned(16))); @@ -81,6 +87,7 @@ * for TD : */ #define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ +#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ #define TD_CTRL_LS (1 << 26) /* Low Speed Device */ #define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ #define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ @@ -89,14 +96,14 @@ #define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ #define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ #define TD_CTRL_NAK (1 << 19) /* NAK Received */ -#define TD_CTRL_CRCTIME (1 << 18) /* CTC/Time Out Error */ +#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ #define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ #define TD_CTRL_ACTLEN_MASK 0x7ff /* actual length, encoded as n - 1 */ #define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) -#define uhci_status_bits(ctrl_sts) ((ctrl_sts >> 16) & 0xff) +#define uhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000) #define uhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ #define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS) @@ -120,6 +127,20 @@ #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) +/* + * for TD : (a.k.a. Token) + */ +#define TD_TOKEN_TOGGLE 19 + +#define uhci_maxlen(token) ((token) >> 21) +#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) +#define uhci_endpoint(token) (((token) >> 15) & 0xf) +#define uhci_devaddr(token) (((token) >> 8) & 0x7f) +#define uhci_devep(token) (((token) >> 8) & 0x7ff) +#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) +#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) + /* * The documentation says "4 words for hardware, 4 words for software". @@ -152,6 +173,7 @@ struct uhci_device *dev; /* The owning device */ struct uhci_qh *qh; /* QH this TD is a part of (ignored for Isochronous) */ int flags; /* Remove, etc */ + int isoc_td_number; /* 0-relative number within a usb_isoc_desc. */ } __attribute__((aligned(16))); struct uhci_iso_td { @@ -180,10 +202,12 @@ #define UHCI_MAXQH 16 #endif -/* The usb device part must be first! */ +/* The usb device part must be first! Not anymore -jerdfelt */ struct uhci_device { struct usb_device *usb; + atomic_t refcnt; + struct uhci *uhci; #if 0 struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */ @@ -260,6 +284,7 @@ struct uhci { int irq; unsigned int io_addr; + unsigned int io_size; int control_pid; int control_running; @@ -281,9 +306,10 @@ struct uhci_td *uhci_link_to_td(unsigned int element); /* Debugging code */ -void show_td(struct uhci_td * td); -void show_status(struct uhci *uhci); -void show_queues(struct uhci *uhci); +void uhci_show_td(struct uhci_td *td); +void uhci_show_status(struct uhci *uhci); +void uhci_show_queue(struct uhci_qh *qh); +void uhci_show_queues(struct uhci *uhci); #endif diff -u --recursive --new-file v2.3.14/linux/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c --- v2.3.14/linux/drivers/usb/usb-debug.c Mon Aug 16 23:19:13 1999 +++ linux/drivers/usb/usb-debug.c Wed Aug 25 15:03:54 1999 @@ -18,24 +18,27 @@ int i; usb_show_interface_descriptor(altsetting); - for (i = 0 ; i < altsetting->bNumEndpoints; i++) + + for (i = 0; i < altsetting->bNumEndpoints; i++) usb_show_endpoint(altsetting->endpoint + i); } static void usb_show_config(struct usb_config_descriptor *config) { - int i, j; - struct usb_interface *intf; + int i, j; + struct usb_interface *ifp; - usb_show_config_descriptor(config); - for (i = 0; i < config->bNumInterfaces; i++) { - intf = config->interface + i; - if ((intf) == NULL) - break; - printk("\n Interface: %d\n", i); - for (j = 0 ; j < intf->num_altsetting; j++) - usb_show_interface(intf->altsetting + j); - } + usb_show_config_descriptor(config); + for (i = 0; i < config->bNumInterfaces; i++) { + ifp = config->interface + i; + + if (!ifp) + break; + + printk("\n Interface: %d\n", i); + for (j = 0; j < ifp->num_altsetting; j++) + usb_show_interface(ifp->altsetting + j); + } } void usb_show_device(struct usb_device *dev) @@ -47,7 +50,6 @@ usb_show_config(dev->config + i); } - /* * Parse and show the different USB descriptors. */ @@ -72,10 +74,25 @@ case 0: printk(" Per-interface classes\n"); break; - case 9: + case USB_CLASS_AUDIO: + printk(" Audio device class\n"); + break; + case USB_CLASS_COMM: + printk(" Communications class\n"); + break; + case USB_CLASS_HID: + printk(" Human Interface Devices class\n"); + break; + case USB_CLASS_PRINTER: + printk(" Printer device class\n"); + break; + case USB_CLASS_MASS_STORAGE: + printk(" Mass Storage device class\n"); + break; + case USB_CLASS_HUB: printk(" Hub device class\n"); break; - case 0xff: + case USB_CLASS_VENDOR_SPEC: printk(" Vendor class\n"); break; default: @@ -83,7 +100,7 @@ } } -void usb_show_config_descriptor(struct usb_config_descriptor * desc) +void usb_show_config_descriptor(struct usb_config_descriptor *desc) { printk("Configuration:\n"); printk(" bLength = %4d%s\n", desc->bLength, @@ -97,7 +114,7 @@ printk(" MaxPower = %4dmA\n", desc->MaxPower * 2); } -void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) +void usb_show_interface_descriptor(struct usb_interface_descriptor *desc) { printk(" Alternate Setting: %2d\n", desc->bAlternateSetting); printk(" bLength = %4d%s\n", desc->bLength, @@ -111,15 +128,33 @@ printk(" iInterface = %02x\n", desc->iInterface); } -void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) +void usb_show_hid_descriptor(struct usb_hid_descriptor * desc) { - char *bLengthCommentString = (USB_DT_AUCLSTEP_SIZE == desc->bLength) ? - " (!Audio)" : " (!!!)"; + int i; + + printk(" HID:\n"); + printk(" HID version %x.%02x\n", desc->bcdHID >> 8, desc->bcdHID & 0xff); + printk(" bLength = %4d\n", desc->bLength); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bCountryCode = %02x\n", desc->bCountryCode); + printk(" bNumDescriptors = %02x\n", desc->bNumDescriptors); + for (i=0; ibNumDescriptors; i++) { + printk(" %d:\n", i); + printk(" bDescriptorType = %02x\n", desc->desc[i].bDescriptorType); + printk(" wDescriptorLength = %04x\n", desc->desc[i].wDescriptorLength); + } +} + +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc) +{ + char *LengthCommentString = (desc->bLength == + USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength == + USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)"; char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; printk(" Endpoint:\n"); printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : bLengthCommentString); + LengthCommentString); printk(" bDescriptorType = %02x\n", desc->bDescriptorType); printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, (desc->bEndpointAddress & 0x80) ? "in" : "out"); @@ -127,29 +162,19 @@ EndpointType[3 & desc->bmAttributes]); printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); printk(" bInterval = %02x\n", desc->bInterval); - if (USB_DT_AUCLSTEP_SIZE == desc->bLength) { - printk(" bRefresh = %04x\n", desc->bRefresh); - printk(" bSynchAddress = %02x\n", desc->bSynchAddress); - } -} - -void usb_show_hub_descriptor(struct usb_hub_descriptor * desc) -{ - int len = 7; - unsigned char *ptr = (unsigned char *) desc; - printk("Interface:"); - while (len) { - printk(" %02x", *ptr); - ptr++; len--; + /* Audio extensions to the endpoint descriptor */ + if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) { + printk(" bRefresh = %02x\n", desc->bRefresh); + printk(" bSynchAddress = %02x\n", desc->bSynchAddress); } - printk("\n"); } -void usb_show_string(struct usb_device* dev, char *id, int index) +void usb_show_string(struct usb_device *dev, char *id, int index) { char *p = usb_string(dev, index); if (p != 0) printk(KERN_INFO "%s: %s\n", id, p); } + diff -u --recursive --new-file v2.3.14/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.14/linux/drivers/usb/usb.c Wed Aug 18 16:22:23 1999 +++ linux/drivers/usb/usb.c Wed Aug 25 15:03:54 1999 @@ -2,6 +2,7 @@ * drivers/usb/usb.c * * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -12,30 +13,6 @@ * are evil. */ -/* - * Table 9-2 - * - * Offset Field Size Value Desc - * 0 bmRequestType 1 Bitmap D7: Direction - * 0 = Host-to-device - * 1 = Device-to-host - * D6..5: Type - * 0 = Standard - * 1 = Class - * 2 = Vendor - * 3 = Reserved - * D4..0: Recipient - * 0 = Device - * 1 = Interface - * 2 = Endpoint - * 3 = Other - * 4..31 = Reserved - * 1 bRequest 1 Value Specific request (9-3) - * 2 wValue 2 Value Varies - * 4 wIndex 2 Index/Offset Varies - * 6 wLength 2 Count Bytes for data - */ - #include #include #include @@ -67,7 +44,7 @@ */ tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { - struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); + struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); tmp = tmp->next; usb_check_support(bus->root_hub); @@ -96,12 +73,13 @@ } } -/* This function is part of a depth-first search down the device tree, +/* + * This function is part of a depth-first search down the device tree, * removing any instances of a device driver. */ -void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) +static void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) { - int i; + int i; if (!dev) { printk(KERN_ERR "usbcore: null device being purged!!!\n"); @@ -158,16 +136,16 @@ if (!bus) return; - if (bus->bus_list.next != &bus->bus_list) - printk(KERN_ERR "usbcore: freeing non-empty bus\n"); - kfree(bus); } -void usb_register_bus(struct usb_bus *new_bus) +void usb_register_bus(struct usb_bus *bus) { + proc_usb_add_bus(bus); + /* Add it to the list of buses */ - list_add(&new_bus->bus_list, &usb_bus_list); + list_add(&bus->bus_list, &usb_bus_list); + printk("New USB bus registered\n"); } @@ -179,13 +157,15 @@ * itself up */ list_del(&bus->bus_list); + + proc_usb_remove_bus(bus); } /* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */ -void usb_check_support(struct usb_device *dev) +static void usb_check_support(struct usb_device *dev) { int i; @@ -209,7 +189,7 @@ * looking for one that will accept this device as * his.. */ -int usb_find_driver(struct usb_device *dev) +static int usb_find_driver(struct usb_device *dev) { struct list_head *tmp = usb_driver_list.next; @@ -231,283 +211,311 @@ } /* - * Parse the fairly incomprehensible output of - * the USB configuration data, and build up the - * USB device database. + * Only HC's should call usb_alloc_dev and usb_free_dev directly + * Anybody may use usb_inc_dev_use or usb_dec_dev_use */ -static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex) +struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) { - int parsed = 0; - int n_len; - unsigned short n_desc; + struct usb_device *dev; - for (;;) { - int i; + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; - if (len < descindex) - return -1; - n_desc = le16_to_cpup((unsigned short *)ptr); - n_len = ptr[0]; + memset(dev, 0, sizeof(*dev)); - if (n_desc == ((desctype << 8) + descindex)) - break; + dev->bus = bus; + dev->parent = parent; + atomic_set(&dev->refcnt, 1); - if (((n_desc >> 8)&0xFF) == desctype && - n_len > descindex) - { - printk("bug: oversized descriptor.\n"); - break; - } - - if (n_len < 2 || n_len > len) - { - printk("Short descriptor\n"); - return -1; - } - printk( - "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", - desctype, descindex, - (n_desc >> 8) & 0xFF, n_desc & 0xFF); - for (i = 0 ; i < n_len; i++) - printk(" %d %02x\n", i, ptr[i]); - len -= n_len; - ptr += n_len; - parsed += n_len; - } - - printk("Found %02X:%02X\n", - desctype, descindex); - return parsed; + dev->bus->op->allocate(dev); + + return dev; } -/* - * Parse the even more incomprehensible mess made of the USB spec - * by USB audio having private magic to go with it. - */ - -static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desctype) +void usb_free_dev(struct usb_device *dev) { - int n_len = ptr[0]; - - if (len <= 0) - return -1; + if (atomic_dec_and_test(&dev->refcnt)) { + usb_destroy_configuration(dev); + kfree(dev); - if (n_len < 2 || n_len > len) { - int i; - printk("Short descriptor. (%d, %d):\n", len, n_len); - for (i = 0; i < len; ++i) - printk(" %d: %x\n", i, ptr[i]); - return -1; + dev->bus->op->deallocate(dev); } - - if (ptr[1] == desctype) - return 0; - - return -1; } - -static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) +void usb_inc_dev_use(struct usb_device *dev) { - int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE); - int i; - - if (parsed < 0) - return parsed; - memcpy(endpoint, ptr + parsed, ptr[parsed]); - le16_to_cpus(&endpoint->wMaxPacketSize); - - parsed += ptr[parsed]; - len -= parsed; - - while((i = usb_check_descriptor(ptr+parsed, len, 0x25)) >= 0) { - usb_audio_endpoint(endpoint, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; - } - - return parsed;// + ptr[parsed]; + atomic_inc(&dev->refcnt); } -static int usb_parse_altsetting(struct usb_device *dev, struct usb_interface_descriptor *altsetting, unsigned char *ptr, int len) +static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) { - int i; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE); - int retval; + struct usb_descriptor_header *header; + int parsed = 0; - if (parsed < 0) - return parsed; + header = (struct usb_descriptor_header *)buffer; - memcpy(altsetting, ptr + parsed, *ptr); - len -= ptr[parsed]; - parsed += ptr[parsed]; - - while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) { - usb_audio_interface(altsetting, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; - } - - if (altsetting->bNumEndpoints > USB_MAXENDPOINTS) { - printk(KERN_WARNING "usb: too many endpoints.\n"); + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); return -1; } - - altsetting->endpoint = (struct usb_endpoint_descriptor *) - kmalloc(altsetting->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); - if (!altsetting->endpoint) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; + + if (header->bDescriptorType != USB_DT_ENDPOINT) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + endpoint->bDescriptorType); + return parsed; } - memset(altsetting->endpoint, 0, altsetting->bNumEndpoints*sizeof(struct usb_endpoint_descriptor)); - - for (i = 0; i < altsetting->bNumEndpoints; i++) { -// if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) { -// parsed += 9; /* skip over the HID descriptor for now */ -// len -= 9; -// } - retval = usb_parse_endpoint(dev, altsetting->endpoint + i, ptr + parsed, len); - if (retval < 0) - return retval; - parsed += retval; - len -= retval; + + memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE); + le16_to_cpus(&endpoint->wMaxPacketSize); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; + + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + printk(KERN_INFO "usb: skipping descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; } + return parsed; } -static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len) +#if 0 +static int usb_parse_hid(struct usb_device *dev, struct usb_hid_descriptor *hid, unsigned char *ptr, int len) { + int parsed = usb_expect_descriptor(ptr, len, USB_DT_HID, ptr[0]); int i; - int retval; - struct usb_interface *intf; - struct usb_interface_descriptor as; /* This is needing for copying. */ - int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); - unsigned short bNumInterfaces; - unsigned short bIntfaceNum = 0, bAltSetting = 0; if (parsed < 0) return parsed; - memcpy(config, ptr + parsed, *ptr); - len -= *ptr; - parsed += *ptr; - le16_to_cpus(&config->wTotalLength); - bNumInterfaces = config->bNumInterfaces; + memcpy(hid, ptr + parsed, ptr[parsed]); + le16_to_cpus(&hid->bcdHID); - if (bNumInterfaces > USB_MAXINTERFACES) { - printk(KERN_WARNING "usb: too many interfaces.\n"); - return -1; - } + for (i=0; ibNumDescriptors; i++) + le16_to_cpus(&(hid->desc[i].wDescriptorLength)); - config->interface = (struct usb_interface *) - kmalloc(bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL); - if (!config->interface) { - printk(KERN_WARNING "usb: out of memory.\n"); + return parsed + ptr[parsed]; +} +#endif + +static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size) +{ + int i; + int retval, parsed = 0; + struct usb_descriptor_header *header; + struct usb_interface_descriptor *ifp; + + interface->act_altsetting = 0; + interface->num_altsetting = 0; + + interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * USB_MAXALTSETTING, GFP_KERNEL); + if (!interface->altsetting) { + printk("couldn't kmalloc interface->altsetting\n"); return -1; } - memset(config->interface, - 0, (bNumInterfaces) * sizeof(struct usb_interface)); - for (i = 0; i < bNumInterfaces; i++) { - intf = (config->interface) +i; - /* We have at least one interface */ - intf->num_altsetting = 1; - intf->altsetting = (struct usb_interface_descriptor*) - kmalloc((USB_MAXALTSETTING +1) * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if (!config->interface[i].altsetting) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(intf->altsetting, - 0, (USB_MAXALTSETTING+1) * sizeof(struct usb_interface_descriptor)); - } - - /* Ok, we now have allocated the necessary structures, now decide - * where to put the parsed interface descriptors - sort by - * bAltSetting and bInterfaceNumber. - */ - while (len > 0) { - retval = usb_parse_altsetting(dev, &as, ptr + parsed, len); - if (retval < 0) - return parsed; // HACK - // return retval; - parsed += retval; - len -= retval; - bIntfaceNum = as.bInterfaceNumber; - if (bIntfaceNum > config->bNumInterfaces) { - printk(KERN_WARNING "usb: bInterfaceNumber %2u exceeding config->bNumINterfaces.\n", bIntfaceNum); + while (size > 0) { + ifp = interface->altsetting + interface->num_altsetting; + interface->num_altsetting++; + + if (interface->num_altsetting >= USB_MAXALTSETTING) { + printk(KERN_WARNING "usb: too many alternate settings\n"); return -1; } - bAltSetting = as.bAlternateSetting; - if (bAltSetting > USB_MAXALTSETTING) { - printk(KERN_WARNING "usb: illegal bAlternateSetting %2u.\n", bAltSetting); + memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); + + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; + + /* Skip over at Interface class or vendor descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT)) + break; + + if ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + if (header->bDescriptorType == USB_DT_HID) + printk(KERN_INFO "usb: skipping HID descriptor\n"); + else + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + parsed += header->bLength; + size -= header->bLength; + } + + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + printk(KERN_WARNING "usb: too many endpoints\n"); return -1; } - if (bAltSetting > config->interface[bIntfaceNum].num_altsetting) { - config->interface[bIntfaceNum].num_altsetting = bAltSetting +1; + + ifp->endpoint = (struct usb_endpoint_descriptor *) + kmalloc(ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); + if (!ifp->endpoint) { + printk(KERN_WARNING "usb: out of memory\n"); + return -1; } - memcpy( &(config->interface[bIntfaceNum].altsetting[bAltSetting]), - &as, sizeof(struct usb_interface_descriptor)); + + memset(ifp->endpoint, 0, ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + + for (i = 0; i < ifp->bNumEndpoints; i++) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + + /* We check to see if it's an alternate to this one */ + ifp = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE || + ifp->bDescriptorType != USB_DT_INTERFACE || + !ifp->bAlternateSetting) + return parsed; } - printk("parsed = %d len = %d\n", parsed, len); return parsed; } -int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) +static int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer) { int i; - unsigned char *ptr = __buf; + int retval; + int size; + struct usb_descriptor_header *header; - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { - printk(KERN_WARNING "usb: too many configurations.\n"); + memcpy(config, buffer, USB_DT_INTERFACE_SIZE); + + le16_to_cpus(&config->wTotalLength); + size = config->wTotalLength; + + if (config->bNumInterfaces > USB_MAXINTERFACES) { + printk(KERN_WARNING "usb: too many interfaces\n"); return -1; } - dev->config = (struct usb_config_descriptor *) - kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL); - if (!dev->config) { - printk(KERN_WARNING "usb: out of memory.\n"); + config->interface = (struct usb_interface *) + kmalloc(config->bNumInterfaces * + sizeof(struct usb_interface), GFP_KERNEL); + if (!config->interface) { + printk(KERN_WARNING "usb: out of memory\n"); return -1; } - memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor)); - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - int retval = usb_parse_config(dev, dev->config + i, ptr, bytes); + + memset(config->interface, 0, + config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + + buffer += config->bLength; + size -= config->bLength; + + for (i = 0; i < config->bNumInterfaces; i++) { + header = (struct usb_descriptor_header *)buffer; + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + if (header->bDescriptorType != USB_DT_INTERFACE) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + continue; + } + + retval = usb_parse_interface(dev, config->interface + i, buffer, size); if (retval < 0) return retval; - ptr += retval; - bytes -= retval; + + buffer += retval; + size -= retval; } - if (bytes) - printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes); - return 0; + + return size; } void usb_destroy_configuration(struct usb_device *dev) { - int c, a, i; - struct usb_config_descriptor *cf; - struct usb_interface *intf; - struct usb_interface_descriptor *as; + int c, i, j; if (!dev->config) return; for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { - cf = &dev->config[c]; + struct usb_config_descriptor *cf = &dev->config[c]; + if (!cf->interface) break; - for (a = 0; a < cf->bNumInterfaces; a++) { - intf = &cf->interface[a]; - if (intf->altsetting == NULL) + + for (i = 0; i < cf->bNumInterfaces; i++) { + struct usb_interface *ifp = + &cf->interface[i]; + + if (!ifp->altsetting) break; - for(i=0; i <= USB_MAXALTSETTING ;i++) { - as = &intf->altsetting[i]; - if(as->endpoint==NULL) - break; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = + &ifp->altsetting[j]; + + if (!as->endpoint) + break; + kfree(as->endpoint); } - kfree(intf->altsetting); + kfree(ifp->altsetting); } kfree(cf->interface); } @@ -531,29 +539,33 @@ void usb_disconnect(struct usb_device **pdev) { struct usb_device * dev = *pdev; + int i; - if (dev) { - int i; - - *pdev = NULL; + if (!dev) + return; - printk("USB disconnect on device %d\n", dev->devnum); + *pdev = NULL; - if(dev->driver) dev->driver->disconnect(dev); + printk("USB disconnect on device %d\n", dev->devnum); - /* Free up all the children.. */ - for (i = 0; i < USB_MAXCHILDREN; i++) { - struct usb_device **child = dev->children + i; - usb_disconnect(child); - } + if (dev->driver) + dev->driver->disconnect(dev); - /* Free up the device itself, including its device number */ - if (dev->devnum > 0) - clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - dev->bus->op->deallocate(dev); + /* Free up all the children.. */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + usb_disconnect(child); } -} + /* remove /proc/bus/usb entry */ + proc_usb_remove_device(dev); + + /* Free up the device itself, including its device number */ + if (dev->devnum > 0) + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + + usb_free_dev(dev); +} /* * Connect a new USB device. This basically just initializes @@ -704,12 +716,13 @@ static void usb_set_maxpacket(struct usb_device *dev) { int i, j; - struct usb_interface *intf; + struct usb_interface *ifp; for (i=0; iactconfig->bNumInterfaces; i++) { - intf = (dev->actconfig->interface) +i; - for (j = 0; j < intf->num_altsetting; j++) { - struct usb_interface_descriptor *as = intf->altsetting +j; + ifp = dev->actconfig->interface + i; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = ifp->altsetting + j; struct usb_endpoint_descriptor *ep = as->endpoint; int e; @@ -718,7 +731,7 @@ dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] = ep[e].wMaxPacketSize; else - dev->epmaxpacketin[ep[e].bEndpointAddress & 0x0f] = + dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] = ep[e].wMaxPacketSize; } } @@ -823,60 +836,78 @@ return 0; } -int usb_get_report(struct usb_device *dev) +int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) { - unsigned char buf[8]; devrequest dr; dr.requesttype = USB_RT_HIDD | 0x80; dr.request = USB_REQ_GET_REPORT; - dr.value = 0x100; - dr.index = 1; - dr.length = 3; + dr.value = (type << 8) + id; + dr.index = index; + dr.length = size; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3)) + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size)) return -1; - return buf[0]; + return 0; } int usb_get_configuration(struct usb_device *dev) { unsigned int cfgno; - unsigned char * bufptr; - unsigned char * buffer; - int parse; + unsigned char buffer[8]; + unsigned char *bigbuffer; + struct usb_config_descriptor *desc = + (struct usb_config_descriptor *)buffer; - buffer = (unsigned char *) __get_free_page (GFP_KERNEL); - if (!buffer) + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + printk(KERN_WARNING "usb: too many configurations\n"); return -1; + } - bufptr = buffer; - for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { - unsigned int size; - /* Get the first 8 bytes - guaranteed */ - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) { - __free_page ((struct page *) buffer); + dev->config = (struct usb_config_descriptor *) + kmalloc(dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor), GFP_KERNEL); + if (!dev->config) { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { + int result; + + /* We grab the first 8 bytes so we know how long the whole */ + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); + if (result) return -1; - } /* Get the full buffer */ - size = le16_to_cpup((unsigned short *)(bufptr+2)); - if (bufptr+size > buffer+PAGE_SIZE) { - printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); - size = buffer+PAGE_SIZE-bufptr; - } - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) { - __free_page ((struct page *) buffer); + le16_to_cpus(&desc->wTotalLength); + + bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); + if (!bigbuffer) + return -1; + + /* Now that we know the length, get the whole thing */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); + if (result) { + kfree(bigbuffer); return -1; } - /* Prepare for next configuration */ - bufptr += size; + result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); + kfree(bigbuffer); + + if (result > 0) + printk(KERN_INFO "usb: descriptor data left\n"); + else if (result < 0) + return -1; } - parse = usb_parse_configuration(dev, buffer, bufptr - buffer); - __free_page ((struct page *) buffer); - return parse; + + return 0; } @@ -903,14 +934,15 @@ dev->string_langid |= 0x10000; /* so it's non-zero */ } - if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) - || usb_get_string(dev, dev->string_langid, index, u.buffer, + if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) || + usb_get_string(dev, dev->string_langid, index, u.buffer, u.desc.bLength)) return 0; len = u.desc.bLength / 2; /* includes terminating null */ + ptr = kmalloc(len, GFP_KERNEL); - if (ptr == 0) + if (!ptr) return 0; for (i = 0; i < len - 1; ++i) @@ -943,7 +975,7 @@ /* Slow devices */ if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) { - printk(KERN_ERR "USB device not responding, giving up\n"); + printk(KERN_ERR "usbcore: USB device not responding, giving up\n"); dev->devnum = -1; return 1; } @@ -960,7 +992,7 @@ dev->devnum = addr; if (usb_set_address(dev)) { - printk(KERN_ERR "USB device not accepting new address\n"); + printk(KERN_ERR "usbcore: USB device not accepting new address\n"); dev->devnum = -1; return 1; } @@ -968,13 +1000,13 @@ wait_ms(10); /* Let the SET_ADDRESS settle */ if (usb_get_device_descriptor(dev)) { - printk(KERN_ERR "Unable to get device descriptor\n"); + printk(KERN_ERR "usbcore: unable to get device descriptor\n"); dev->devnum = -1; return 1; } if (usb_get_configuration(dev)) { - printk(KERN_ERR "Unable to get configuration\n"); + printk(KERN_ERR "usbcore: unable to get configuration\n"); dev->devnum = -1; return 1; } @@ -987,6 +1019,9 @@ usb_show_string(dev, "Product", dev->descriptor.iProduct); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); + /* now that the basic setup is over, add a /proc/bus/usb entry */ + proc_usb_add_device(dev); + if (!usb_find_driver(dev)) { /* * Ok, no driver accepted the device, so show the info for @@ -999,7 +1034,21 @@ return 0; } -void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size) +{ + devrequest dr; + + dr.requesttype = requesttype; + dr.request = request; + dr.value = cpu_to_le16p(&value); + dr.index = cpu_to_le16p(&index); + dr.length = cpu_to_le16p(&size); + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, + data, size); +} + +void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); } @@ -1014,44 +1063,56 @@ return dev->bus->op->terminate_bulk(dev, first); } -void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) +int usb_release_irq(struct usb_device *dev, void *handle) { - return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id); + return dev->bus->op->release_irq(dev, handle); } -void usb_delete_isochronous (struct usb_device *dev, void *_isodesc) +/* + * usb_get_current_frame_number() + * + * returns the current frame number for the parent USB bus/controller + * of the given USB device. + */ +int usb_get_current_frame_number (struct usb_device *usb_dev) { - return dev->bus->op->delete_isoc (dev, _isodesc); + return usb_dev->bus->op->get_frame_number (usb_dev); } -int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) +int usb_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc) { - return usb_dev->bus->op->sched_isoc (usb_dev, _isodesc, _pisodesc); + return usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc); } -int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc) +void usb_free_isoc (struct usb_isoc_desc *isocdesc) { - return usb_dev->bus->op->unsched_isoc (usb_dev, _isodesc); + isocdesc->usb_dev->bus->op->free_isoc (isocdesc); } -int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) +int usb_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc) { - return usb_dev->bus->op->compress_isoc (usb_dev, _isodesc); + return isocdesc->usb_dev->bus->op->run_isoc (isocdesc, pr_isocdesc); } -int usb_release_irq(struct usb_device *dev, void* handle) +int usb_kill_isoc (struct usb_isoc_desc *isocdesc) { - return dev->bus->op->release_irq(dev, handle); + return isocdesc->usb_dev->bus->op->kill_isoc (isocdesc); } #ifdef CONFIG_PROC_FS -struct list_head * usb_driver_get_list (void) +struct list_head *usb_driver_get_list(void) { return &usb_driver_list; } -struct list_head * usb_bus_get_list (void) +struct list_head *usb_bus_get_list(void) { return &usb_bus_list; } #endif + diff -u --recursive --new-file v2.3.14/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.14/linux/drivers/usb/usb.h Wed Aug 18 16:22:23 1999 +++ linux/drivers/usb/usb.h Wed Aug 25 15:03:54 1999 @@ -12,7 +12,7 @@ extern int usb_mouse_init(void); extern int usb_printer_init(void); -extern void hub_cleanup(void); +extern void usb_hub_cleanup(void); extern void usb_mouse_cleanup(void); static __inline__ void wait_ms(unsigned int ms) @@ -21,14 +21,13 @@ schedule_timeout(1 + ms * HZ / 1000); } - typedef struct { - unsigned char requesttype; - unsigned char request; - unsigned short value; - unsigned short index; - unsigned short length; -} devrequest; + __u8 requesttype; + __u8 request; + __u16 value; + __u16 index; + __u16 length; +} devrequest __attribute__ ((packed)); /* * Device and/or Interface Class codes @@ -40,6 +39,7 @@ #define USB_CLASS_PRINTER 7 #define USB_CLASS_MASS_STORAGE 8 #define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 #define USB_CLASS_VENDOR_SPEC 0xff /* @@ -53,6 +53,8 @@ #define USB_DT_HUB 0x29 #define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 /* * Descriptor sizes per descriptor type @@ -61,7 +63,7 @@ #define USB_DT_CONFIG_SIZE 9 #define USB_DT_INTERFACE_SIZE 9 #define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_AUCLSTEP_SIZE 9 /* Audio Classes are special */ +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define USB_DT_HUB_NONVAR_SIZE 7 /* @@ -114,6 +116,10 @@ #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 +#define USB_HID_RPT_INPUT 0x01 +#define USB_HID_RPT_OUTPUT 0x02 +#define USB_HID_RPT_FEATURE 0x03 + /* * Request target types. */ @@ -127,7 +133,7 @@ #define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) /* - * Status codes (these follow an OHCI controllers condition codes) + * Status codes (these follow OHCI controllers condition codes) */ #define USB_ST_NOERROR 0x0 #define USB_ST_CRC 0x1 @@ -151,6 +157,7 @@ #define USB_ST_TIMEOUT 0x110 #define USB_ST_INTERNALERROR -1 #define USB_ST_NOTSUPPORTED -2 +#define USB_ST_BANDWIDTH_ERROR -3 /* * USB device number allocation bitmap. There's one bitmap @@ -164,14 +171,21 @@ * This is a USB device descriptor. * * USB device information - * */ +/* Everything but the endpoint maximums are aribtrary */ #define USB_MAXCONFIG 8 -#define USB_MAXALTSETTING 6 +#define USB_MAXALTSETTING 16 #define USB_MAXINTERFACES 32 #define USB_MAXENDPOINTS 32 +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); + +/* Device descriptor */ struct usb_device_descriptor { __u8 bLength; __u8 bDescriptorType; @@ -187,7 +201,7 @@ __u8 iProduct; __u8 iSerialNumber; __u8 bNumConfigurations; -}; +} __attribute__ ((packed)); /* Endpoint descriptor */ struct usb_endpoint_descriptor { @@ -199,8 +213,23 @@ __u8 bInterval; __u8 bRefresh; __u8 bSynchAddress; - void *audio; -}; +} __attribute__ ((packed)); + +/* HID descriptor */ +struct usb_hid_class_descriptor { + __u8 bDescriptorType; + __u16 wDescriptorLength; +} __attribute__ ((packed)); + +struct usb_hid_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdHID; + __u8 bCountryCode; + __u8 bNumDescriptors; + + struct usb_hid_class_descriptor desc[1]; +} __attribute__ ((packed)); /* Interface descriptor */ struct usb_interface_descriptor { @@ -214,14 +243,15 @@ __u8 bInterfaceProtocol; __u8 iInterface; + struct usb_hid_descriptor *hid; struct usb_endpoint_descriptor *endpoint; - void *audio; -}; +} __attribute__ ((packed)); struct usb_interface { - struct usb_interface_descriptor *altsetting; - int act_altsetting; /* active alternate setting */ - int num_altsetting; /* number of alternate settings */ + struct usb_interface_descriptor *altsetting; + + int act_altsetting; /* active alternate setting */ + int num_altsetting; /* number of alternate settings */ }; /* Configuration descriptor information.. */ @@ -234,35 +264,25 @@ __u8 iConfiguration; __u8 bmAttributes; __u8 MaxPower; + struct usb_interface *interface; -}; +} __attribute__ ((packed)); /* String descriptor */ struct usb_string_descriptor { __u8 bLength; __u8 bDescriptorType; __u16 wData[1]; -}; - -/* Hub descriptor */ -struct usb_hub_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bNbrPorts; - __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */ - __u8 bPwrOn2PwrGood; - __u8 bHubContrCurrent; - /* DeviceRemovable and PortPwrCtrlMask want to be variable-length - bitmaps that hold max 256 entries, but for now they're ignored */ - __u8 filler; -}; +} __attribute__ ((packed)); struct usb_device; struct usb_driver { - const char * name; + const char *name; + int (*probe)(struct usb_device *); void (*disconnect)(struct usb_device *); + struct list_head driver_list; }; @@ -284,21 +304,97 @@ */ typedef int (*usb_device_irq)(int, void *, int, void *); +/* + * Isoc. support additions + */ +#define START_FRAME_FUDGE 3 + +/* for start_type: */ +enum { + START_ASAP = 0, + START_ABSOLUTE, + START_RELATIVE +}; +#define START_TYPE_MAX START_RELATIVE + +/* + * Completion/Callback routine returns an enum, + * which tells the interrupt handler what to do + * with the completed frames (TDs). + */ +enum { + CB_CONTINUE = 0, /* OK, remove all TDs; + needs to be 0 to be consistent with + current callback function ret. values */ + CB_REUSE, /* leave descriptors as NULL, not active */ + CB_RESTART, /* leave descriptors as they are, alive */ + CB_ABORT /* kill this USB transfer request */ +}; + +struct isoc_frame_desc { + int frame_length; /* may be 0 (i.e., allowed) */ + /* set by driver for OUTs to devices; + * set by USBD for INs from devices, + * after I/O complete */ + unsigned int frame_status; + /* set by USBD after I/O complete */ +}; + +struct usb_isoc_desc { + /* + * The following fields are set by the usb_init_isoc() call. + */ + struct usb_device *usb_dev; + unsigned int pipe; + int frame_count; + void *context; /* driver context (private) ptr */ + int frame_size; + /* + * The following fields are set by the driver between the + * usb_init_isoc() and usb_run_isoc() calls + * (along with the "frames" array for OUTput). + */ + int start_type; + int start_frame; /* optional, depending on start_type */ + int frame_spacing; /* not using (yet?) */ + int callback_frames; /* every # frames + last one */ + /* 0 means no callbacks until IOC on last frame */ + usb_device_irq callback_fn; + void *data; + int buf_size; + /* + * The following fields are set by the usb_run_isoc() call. + */ + int end_frame; + void *td; /* UHCI or OHCI TD ptr */ + /* + * The following fields are set by the USB HCD interrupt handler + * before calling the driver's callback function. + */ + int total_completed_frames; + int prev_completed_frame; /* from the previous callback */ + int cur_completed_frame; /* from this callback */ + int total_length; /* accumulated */ + int error_count; /* accumulated */ + struct isoc_frame_desc frames [0]; /* variable size: [frame_count] */ +}; + struct usb_operations { - struct usb_device *(*allocate)(struct usb_device *); + int (*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int); int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *); - void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); - int (*release_irq)(struct usb_device *, void* handle); + void *(*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); + int (*release_irq)(struct usb_device *, void *); void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *); int (*terminate_bulk)(struct usb_device *, void *); - void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id); - void (*delete_isoc)(struct usb_device *dev, void *_isodesc); - int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); - int (*unsched_isoc)(struct usb_device *usb_dev, void *_isodesc); - int (*compress_isoc)(struct usb_device *usb_dev, void *_isodesc); + int (*get_frame_number) (struct usb_device *usb_dev); + int (*init_isoc) (struct usb_device *usb_dev, unsigned int pipe, + int frame_count, void *context, struct usb_isoc_desc **isocdesc); + void (*free_isoc) (struct usb_isoc_desc *isocdesc); + int (*run_isoc) (struct usb_isoc_desc *isocdesc, struct usb_isoc_desc *pr_isocdesc); + int (*kill_isoc) (struct usb_isoc_desc *isocdesc); }; /* @@ -310,14 +406,20 @@ struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; void *hcpriv; /* Host Controller private data */ -}; + /* procfs entry */ + int proc_busnum; + struct proc_dir_entry *proc_entry; +}; -#define USB_MAXCHILDREN (8) +#define USB_MAXCHILDREN (8) /* This is arbitrary */ struct usb_device { int devnum; /* Device number on USB bus */ int slow; /* Slow device? */ + + atomic_t refcnt; /* Reference count */ + int maxpacketsize; /* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */ unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ @@ -326,14 +428,23 @@ int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ int ifnum; /* active interface number */ + + struct usb_device *parent; struct usb_bus *bus; /* Bus we're part of */ struct usb_driver *driver; /* Driver */ + struct usb_device_descriptor descriptor;/* Descriptor */ struct usb_config_descriptor *config; /* All of the configs */ - struct usb_device *parent; + char *string; /* pointer to the last string read from the device */ int string_langid; /* language ID for strings */ + void *hcpriv; /* Host Controller private data */ + void *private; /* Upper layer private data */ + + /* procfs entry */ + struct proc_dir_entry *proc_entry; + /* * Child devices - these can be either new devices * (if this is a hub device), or different instances @@ -344,20 +455,28 @@ int maxchild; /* Number of ports if hub */ struct usb_device *children[USB_MAXCHILDREN]; - - void *hcpriv; /* Host Controller private data */ - void *private; /* Upper layer private data */ }; extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); +int usb_find_driver(struct usb_device *); +void usb_check_support(struct usb_device *); +void usb_driver_purge(struct usb_driver *, struct usb_device *); + extern struct usb_bus *usb_alloc_bus(struct usb_operations *); extern void usb_free_bus(struct usb_bus *); extern void usb_register_bus(struct usb_bus *); extern void usb_deregister_bus(struct usb_bus *); -extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); +extern struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *); +extern void usb_free_dev(struct usb_device *); +extern void usb_inc_dev_use(struct usb_device *); +#define usb_dec_dev_use usb_free_dev + +extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); + +extern void *usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); extern int usb_release_irq(struct usb_device *dev, void *handle); extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *); @@ -367,10 +486,6 @@ extern void usb_connect(struct usb_device *dev); extern void usb_disconnect(struct usb_device **); -extern int usb_find_driver(struct usb_device *dev); -void usb_check_support(struct usb_device *); -void usb_driver_purge(struct usb_driver *,struct usb_device *); -extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); extern void usb_destroy_configuration(struct usb_device *dev); extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, @@ -380,6 +495,21 @@ extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc); extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc); +int usb_get_current_frame_number (struct usb_device *usb_dev); + +int usb_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc); + +void usb_free_isoc (struct usb_isoc_desc *isocdesc); + +int usb_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc); + +int usb_kill_isoc (struct usb_isoc_desc *isocdesc); + /* * Calling this entity a "pipe" is glorifying it. A USB pipe * is something embarrassingly simple: it basically consists @@ -479,7 +609,7 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id); int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_configuration(struct usb_device *dev, int configuration); -int usb_get_report(struct usb_device *dev); +int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size); char *usb_string(struct usb_device *dev, int index); int usb_clear_halt(struct usb_device *dev, int endp); @@ -489,21 +619,25 @@ void usb_show_device_descriptor(struct usb_device_descriptor *); void usb_show_config_descriptor(struct usb_config_descriptor *); void usb_show_interface_descriptor(struct usb_interface_descriptor *); +void usb_show_hid_descriptor(struct usb_hid_descriptor * desc); void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); -void usb_show_hub_descriptor(struct usb_hub_descriptor *); void usb_show_device(struct usb_device *); -void usb_show_string(struct usb_device* dev, char *id, int index); +void usb_show_string(struct usb_device *dev, char *id, int index); /* - * Audio parsing helpers + * procfs stuff */ -#ifdef CONFIG_USB_AUDIO -void usb_audio_interface(struct usb_interface_descriptor *, u8 *); -void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +#ifdef CONFIG_USB_PROC +void proc_usb_add_bus(struct usb_bus *bus); +void proc_usb_remove_bus(struct usb_bus *bus); +void proc_usb_add_device(struct usb_device *dev); +void proc_usb_remove_device(struct usb_device *dev); #else -extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {} -extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {} +extern inline void proc_usb_add_bus(struct usb_bus *bus) {} +extern inline void proc_usb_remove_bus(struct usb_bus *bus) {} +extern inline void proc_usb_add_device(struct usb_device *dev) {} +extern inline void proc_usb_remove_device(struct usb_device *dev) {} #endif #endif diff -u --recursive --new-file v2.3.14/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c --- v2.3.14/linux/drivers/usb/usb_scsi.c Mon Aug 9 20:38:13 1999 +++ linux/drivers/usb/usb_scsi.c Wed Aug 25 15:03:54 1999 @@ -1108,9 +1108,9 @@ protocol = US_PR_CB; subclass = US_SC_8070; /* an assumption */ } else if (dev->descriptor.bDeviceClass != 0 || - dev->config->altsetting->interface->bInterfaceClass != 8 || - dev->config->altsetting->interface->bInterfaceSubClass < US_SC_MIN || - dev->config->altsetting->interface->bInterfaceSubClass > US_SC_MAX) { + dev->config[0].interface[0].altsetting[0].bInterfaceClass != 8 || + dev->config[0].interface[0].altsetting[0].bInterfaceSubClass < US_SC_MIN || + dev->config[0].interface[0].altsetting[0].bInterfaceSubClass > US_SC_MAX) { return -1; } @@ -1143,7 +1143,7 @@ memset(ss, 0, sizeof(struct us_data)); } - interface = dev->config->altsetting->interface; + interface = &dev->config[0].interface[0].altsetting[0]; ss->filter = filter; ss->fdata = fdata; ss->flags = flags; diff -u --recursive --new-file v2.3.14/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c --- v2.3.14/linux/drivers/usb/uss720.c Thu Aug 12 11:50:15 1999 +++ linux/drivers/usb/uss720.c Wed Aug 25 15:03:54 1999 @@ -30,6 +30,7 @@ * for no apparent reason (that is for me, anyway) * ECP currently untested * 0.3 10.08.99 fixing merge errors + * 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable * */ @@ -559,7 +560,8 @@ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) && - (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001)) + (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) && + (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284)) return -1; /* We don't handle multiple configurations */ @@ -571,7 +573,7 @@ return -1; /* We don't handle multiple interfaces */ - if (usbdev->config[0].num_altsetting != 3) + if (usbdev->config[0].interface[0].num_altsetting != 3) return -1; printk(KERN_DEBUG "uss720: set configuration\n"); @@ -580,7 +582,7 @@ i = usb_set_interface(usbdev, 0, 2); printk(KERN_DEBUG "uss720: set inteface result %d\n", i); - interface = &usbdev->config[0].altsetting[2].interface[0]; + interface = &usbdev->config[0].interface[0].altsetting[2]; //printk(KERN_DEBUG "uss720: get interface\n"); //i = usb_get_interface(usbdev, 0); @@ -655,7 +657,7 @@ static int __init uss720_init(void) { usb_register(&uss720_driver); - printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.3 registered.\n" + printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.4 registered.\n" KERN_INFO "uss720: (C) 1999 by Thomas Sailer, \n"); return 0; } diff -u --recursive --new-file v2.3.14/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.14/linux/drivers/video/Config.in Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/Config.in Wed Aug 25 14:58:12 1999 @@ -7,7 +7,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then tristate 'Cirrus Logic suport (experimental)' CONFIG_FB_CLGEN - bool 'Permedia2 support (experimental)' CONFIG_FB_PM2 + tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2 if [ "$CONFIG_FB_PM2" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT diff -u --recursive --new-file v2.3.14/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.14/linux/drivers/video/Makefile Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/Makefile Wed Aug 25 14:58:12 1999 @@ -82,6 +82,11 @@ ifeq ($(CONFIG_FB_PM2),y) L_OBJS += pm2fb.o CONFIG_FBGEN_BUILTIN = y +else + ifeq ($(CONFIG_FB_PM2),m) + M_OBJS += pm2fb.o + CONFIG_FBGEN_MODULE = y + endif endif ifeq ($(CONFIG_FB_APOLLO),y) diff -u --recursive --new-file v2.3.14/linux/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c --- v2.3.14/linux/drivers/video/S3triofb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/S3triofb.c Thu Aug 19 11:01:00 1999 @@ -446,11 +446,11 @@ s3trio_init(dp); address = 0xc6000000; s3trio_base = ioremap(address,64*1024*1024); - fb_fix.smem_start = (char *)address; + fb_fix.smem_start = address; fb_fix.type = FB_TYPE_PACKED_PIXELS; fb_fix.type_aux = 0; fb_fix.accel = FB_ACCEL_S3_TRIO64; - fb_fix.mmio_start = (char *)address+0x1000000; + fb_fix.mmio_start = address+0x1000000; fb_fix.mmio_len = 0x1000000; fb_fix.xpanstep = 1; diff -u --recursive --new-file v2.3.14/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.3.14/linux/drivers/video/acornfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/acornfb.c Thu Aug 19 11:01:00 1999 @@ -1037,7 +1037,7 @@ else display = &global_disp; - fix->smem_start = (char *)current_par.screen_base_p; + fix->smem_start = current_par.screen_base_p; fix->smem_len = current_par.screen_size; fix->type = display->type; fix->type_aux = display->type_aux; diff -u --recursive --new-file v2.3.14/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.3.14/linux/drivers/video/amifb.c Wed Aug 18 10:10:29 1999 +++ linux/drivers/video/amifb.c Thu Aug 19 11:01:00 1999 @@ -1981,7 +1981,7 @@ { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, amifb_name); - fix->smem_start = (char *)videomemory_phys; + fix->smem_start = videomemory_phys; fix->smem_len = videomemorysize; #ifdef FBCON_HAS_MFB diff -u --recursive --new-file v2.3.14/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.3.14/linux/drivers/video/atyfb.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/atyfb.c Wed Aug 25 14:58:12 1999 @@ -390,7 +390,9 @@ #ifdef CONFIG_FB_OF void atyfb_of_init(struct device_node *dp); #endif +#ifndef MODULE int atyfb_setup(char*); +#endif static int currcon = 0; @@ -411,7 +413,10 @@ static u32 default_vram __initdata = 0; static int default_pll __initdata = 0; static int default_mclk __initdata = 0; + +#ifndef MODULE static const char *mode_option __initdata = NULL; +#endif #if defined(CONFIG_PPC) static int default_vmode __initdata = VMODE_NVRAM; @@ -1926,7 +1931,7 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, atyfb_name); - fix->smem_start = (char *)info->frame_buffer_phys; + fix->smem_start = info->frame_buffer_phys; fix->smem_len = (u32)info->total_vram; #ifdef __LITTLE_ENDIAN @@ -1943,19 +1948,19 @@ * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 */ if (Gx == GX_CHIP_ID || Gx == CX_CHIP_ID) { - fix->mmio_start = (char *)info->ati_regbase_phys; + fix->mmio_start = info->ati_regbase_phys; fix->mmio_len = 0x400; fix->accel = FB_ACCEL_ATI_MACH64GX; } else if (Gx == CT_CHIP_ID || Gx == ET_CHIP_ID) { - fix->mmio_start = (char *)info->ati_regbase_phys; + fix->mmio_start = info->ati_regbase_phys; fix->mmio_len = 0x400; fix->accel = FB_ACCEL_ATI_MACH64CT; } else if (Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == VV_CHIP_ID) { - fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); + fix->mmio_start = info->ati_regbase_phys-0x400; fix->mmio_len = 0x800; fix->accel = FB_ACCEL_ATI_MACH64VT; } else { - fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); + fix->mmio_start = info->ati_regbase_phys-0x400; fix->mmio_len = 0x800; fix->accel = FB_ACCEL_ATI_MACH64GT; } @@ -2869,7 +2874,7 @@ memset(info, 0, sizeof(struct fb_info_aty)); rp = &pdev->resource[0]; - if (rp->flags & IORESOURCE_IOPORT) + if (rp->flags & IORESOURCE_IO) rp = &pdev->resource[1]; addr = rp->start; if (!addr) @@ -2912,7 +2917,7 @@ base = rp->start; - io = (rp->flags & IORESOURCE_IOPORT); + io = (rp->flags & IORESOURCE_IO); size = rp->end - base + 1; @@ -3261,6 +3266,7 @@ #endif /* CONFIG_FB_OF */ +#ifndef MODULE int __init atyfb_setup(char *options) { char *this_opt; @@ -3328,9 +3334,12 @@ } } #endif + else + mode_option = this_opt; } return 0; } +#endif /* !MODULE */ #ifdef CONFIG_ATARI static int __init store_video_par(char *video_str, unsigned char m64_num) diff -u --recursive --new-file v2.3.14/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c --- v2.3.14/linux/drivers/video/chipsfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/chipsfb.c Thu Aug 19 11:01:00 1999 @@ -549,7 +549,7 @@ int i; strcpy(p->fix.id, "C&T 65550"); - p->fix.smem_start = (char *) p->frame_buffer_phys; + p->fix.smem_start = p->frame_buffer_phys; // FIXME: Assumes 1MB frame buffer, but 65550 supports 1MB or 2MB. // * "3500" PowerBook G3 (the original PB G3) has 2MB. diff -u --recursive --new-file v2.3.14/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c --- v2.3.14/linux/drivers/video/clgenfb.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/clgenfb.c Wed Aug 25 14:58:13 1999 @@ -31,8 +31,9 @@ * */ -#define CLGEN_VERSION "1.9.4.1" +#define CLGEN_VERSION "1.9.4.3" +#include #include #include #include @@ -98,7 +99,6 @@ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ - *(int*)0 = 0;\ } #else #define assert(expr) @@ -325,6 +325,8 @@ #ifdef CONFIG_ZORRO int keyRAM; /* RAM, REG zorro board keys */ int keyREG; + unsigned long board_addr, + board_size; #endif #ifdef CONFIG_PCI @@ -339,7 +341,9 @@ static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */ -static unsigned clgen_def_mode = 0; +static unsigned clgen_def_mode = 1; + +static int release_io_ports = 0; @@ -635,18 +639,18 @@ switch (_par->var.bits_per_pixel) { case 1: case 8: - fix->smem_start = (char *) _info->fbmem_phys; + fix->smem_start = _info->fbmem_phys; break; case 16: - fix->smem_start = (char *) _info->fbmem_phys + 1 * MB_; + fix->smem_start = _info->fbmem_phys + 1 * MB_; break; case 24: case 32: - fix->smem_start = (char *) _info->fbmem_phys + 2 * MB_; + fix->smem_start = _info->fbmem_phys + 2 * MB_; break; } } else { - fix->smem_start = (char *) _info->fbmem_phys; + fix->smem_start = _info->fbmem_phys; } /* monochrome: only 1 memory plane */ @@ -662,7 +666,7 @@ fix->line_length = _par->line_length; /* FIXME: map region at 0xB8000 if available, fill in here */ - fix->mmio_start = (char *) NULL; + fix->mmio_start = 0; fix->mmio_len = 0; fix->accel = FB_ACCEL_NONE; @@ -831,7 +835,7 @@ if (_par->var.yoffset > _par->var.yres_virtual - _par->var.yres) _par->var.yoffset = _par->var.yres_virtual - _par->var.yres - 1; - switch (var->bits_per_pixel) { + switch (_par->var.bits_per_pixel) { case 1: _par->line_length = _par->var.xres_virtual / 8; _par->visual = FB_VISUAL_MONO10; @@ -900,7 +904,8 @@ break; default: - assert (0); + DPRINTK("Unsupported bpp size: %d\n", _par->var.bits_per_pixel); + assert (FALSE); /* should never occur */ break; } @@ -951,7 +956,7 @@ bestclock (freq, &_par->freq, &_par->nom, &_par->den, &_par->div, maxclock); - _par->mclk = clgen_get_mclk (freq, var->bits_per_pixel, &_par->divMCLK); + _par->mclk = clgen_get_mclk (freq, _par->var.bits_per_pixel, &_par->divMCLK); xres = _par->var.xres; hfront = _par->var.right_margin; @@ -1787,12 +1792,16 @@ break; } +#ifdef CLGEN_USE_HARDCODED_RAM_SETTINGS /* "pre-set" a RAMsize; if the test succeeds, double it */ if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4) fb_info->size = 0x400000; else fb_info->size = 0x200000; +#else + assert (fb_info->size > 0); /* make sure RAM size set by this point */ +#endif /* assume it's a "large memory" board (2/4 MB) */ fb_info->smallboard = FALSE; @@ -2326,7 +2335,7 @@ clgen_pci_probe_list[i].device, NULL); if (pdev) - *btype = clgen_pci_probe_list[i].btype; + *btype = clgen_pci_probe_list[i - 1].btype; DPRINTK ("EXIT, returning %p\n", pdev); return pdev; @@ -2362,7 +2371,7 @@ #else - if (pdev->resource[0].flags & IORESOURCE_IOPORT) { + if (pdev->resource[0].flags & IORESOURCE_IO) { *display = pdev->resource[1].start; *registers = pdev->resource[0].start; } else { @@ -2380,6 +2389,21 @@ +/* clgen_pci_unmap only used in modules */ +#ifdef MODULE +static void clgen_pci_unmap (struct clgenfb_info *info) +{ + iounmap (info->fbmem); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + __release_region (&iomem_resource, info->fbmem_phys, info->size); + __release_region (&iomem_resource, 0xA0000, 65535); + if (release_io_ports) + __release_region (&ioport_resource, 0x3C0, 32); +#endif +} +#endif /* MODULE */ + + static int __init clgen_pci_setup (struct clgenfb_info *info, clgen_board_t *btype) { @@ -2411,8 +2435,8 @@ pci_read_config_word (pdev, PCI_COMMAND, &tmp16); if (!(tmp16 & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))) { - tmp16 |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - pci_write_config_word (pdev, PCI_COMMAND, tmp16); + u16 tmp16_o = tmp16 | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, tmp16_o); } #ifdef CONFIG_FB_OF @@ -2453,10 +2477,33 @@ } else { board_size = clgen_get_memsize (info->regs); } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + + if (!__request_region (&iomem_resource, board_addr, + board_size, "clgenfb")) { + pci_write_config_word (pdev, PCI_COMMAND, tmp16); + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + board_addr); + return -1; + } + if (!__request_region (&iomem_resource, 0xA0000, 65535, "clgenfb")) { + pci_write_config_word (pdev, PCI_COMMAND, tmp16); + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + 0xA0000L); + __release_region(&iomem_resource, board_addr, board_size); + return -1; + } + if (__request_region(&ioport_resource, 0x3C0, 32, "clgenfb")) + release_io_ports = 1; + +#endif /* kernel > 2.3.13 */ + info->fbmem = ioremap (board_addr, board_size); info->fbmem_phys = board_addr; + info->size = board_size; - printk (" RAM (%lu MB) at $%lx, ", board_size / 0x100000, board_addr); + printk (" RAM (%lu MB) at 0x%lx, ", info->size / MB_, board_addr); printk (KERN_INFO "Cirrus Logic chipset on PCI bus\n"); @@ -2485,7 +2532,7 @@ *key2_o = zorro_find (clgen_zorro_probe_list[i].key2, 0, 0); else *key2_o = 0; - *btype = clgen_zorro_probe_list[i].btype; + *btype = clgen_zorro_probe_list[i - 1].btype; printk (KERN_INFO "clgen: %s board detected; ", clgen_board_info[*btype].name); @@ -2499,6 +2546,25 @@ +/* clgen_zorro_unmap only used in modules */ +#ifdef MODULE +static void clgen_zorro_unmap (struct clgenfb_info *info) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + __release_region(&iomem_resource, info->board_addr, info->board_size); +#endif + if (info->btype == BT_PICASSO4) { + iounmap (info->board_addr); + iounmap (info->fbmem_phys); + } else { + if (info->board_addr > 0x01000000) + iounmap (info->board_addr); + } +} +#endif /* MODULE */ + + + static int __init clgen_zorro_setup (struct clgenfb_info *info, clgen_board_t *btype) { @@ -2520,9 +2586,17 @@ info->keyRAM = key; info->keyREG = key2; cd = zorro_get_board (key); - board_addr = (unsigned long) cd->cd_BoardAddr; - board_size = (unsigned long) cd->cd_BoardSize; - printk (" RAM (%lu MB) at $%lx, ", board_size / 0x100000, board_addr); + info->board_addr = board_addr = (unsigned long) cd->cd_BoardAddr; + info->board_size = board_size = (unsigned long) cd->cd_BoardSize; + + if (!__request_region(&iomem_resource, board_addr, + board_size, "clgenfb")) { + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + board_addr); + return -1; + } + + printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); if (*btype == BT_PICASSO4) { printk (" REG at $%lx\n", board_addr + 0x600000); @@ -2683,9 +2757,13 @@ #ifdef CONFIG_ZORRO switch_monitor (info, 0); + clgen_zorro_unmap (info); + zorro_unconfig_board (info->keyRAM, 0); if (info->btype != BT_PICASSO4) zorro_unconfig_board (info->keyREG, 0); +#else + clgen_pci_unmap (info); #endif /* CONFIG_ZORRO */ unregister_framebuffer ((struct fb_info *) info); @@ -3277,7 +3355,7 @@ break; default: /* should never occur */ - assert (0); + assert (FALSE); break; } diff -u --recursive --new-file v2.3.14/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c --- v2.3.14/linux/drivers/video/controlfb.c Wed Aug 18 10:00:52 1999 +++ linux/drivers/video/controlfb.c Thu Aug 19 11:01:00 1999 @@ -998,7 +998,7 @@ { memset(fix, 0, sizeof(*fix)); strcpy(fix->id, "control"); - fix->mmio_start = (char *)p->control_regs_phys; + fix->mmio_start = p->control_regs_phys; fix->mmio_len = sizeof(struct control_regs); fix->type = FB_TYPE_PACKED_PIXELS; @@ -1010,7 +1010,7 @@ fix->xpanstep = 0; */ - fix->smem_start = (void *)(p->frame_buffer_phys + fix->smem_start = (p->frame_buffer_phys + control_reg_init[par->vmode-1]->offset[par->cmode]); fix->smem_len = p->total_vram - control_reg_init[par->vmode-1]->offset[par->cmode]; fix->visual = (par->cmode == CMODE_8) ? diff -u --recursive --new-file v2.3.14/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c --- v2.3.14/linux/drivers/video/cyber2000fb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/cyber2000fb.c Thu Aug 19 11:01:00 1999 @@ -765,9 +765,9 @@ else display = &global_disp; - fix->smem_start = (char *)current_par.screen_base_p; + fix->smem_start = current_par.screen_base_p; fix->smem_len = current_par.screen_size; - fix->mmio_start = (char *)current_par.regs_base_p; + fix->mmio_start = current_par.regs_base_p; fix->mmio_len = 0x000c0000; fix->type = display->type; fix->type_aux = display->type_aux; diff -u --recursive --new-file v2.3.14/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c --- v2.3.14/linux/drivers/video/cyberfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/cyberfb.c Thu Aug 19 11:01:00 1999 @@ -406,9 +406,9 @@ DPRINTK("ENTER\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, cyberfb_name); - fix->smem_start = (char*) CyberMem_phys; + fix->smem_start = CyberMem_phys; fix->smem_len = CyberSize; - fix->mmio_start = (char*) CyberRegs_phys; + fix->mmio_start = CyberRegs_phys; fix->mmio_len = 0x10000; fix->type = FB_TYPE_PACKED_PIXELS; diff -u --recursive --new-file v2.3.14/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c --- v2.3.14/linux/drivers/video/dnfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/dnfb.c Thu Aug 19 11:01:00 1999 @@ -169,7 +169,7 @@ { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"Apollo Mono"); - fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE); + fix->smem_start=FRAME_BUFFER_START+IO_BASE; fix->smem_len=FRAME_BUFFER_LEN; fix->type=FB_TYPE_PACKED_PIXELS; fix->type_aux=0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.3.14/linux/drivers/video/fbmem.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/fbmem.c Wed Aug 25 14:58:13 1999 @@ -470,10 +470,18 @@ return -ENODEV; if (fb->fb_mmap) return fb->fb_mmap(info, file, vma); + +#if defined(__sparc__) + /* Should never get here, all fb drivers should have their own + mmap routines */ + return -EINVAL; +#else + /* non-SPARC... */ + fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); /* frame buffer memory */ - start = (unsigned long)fix.smem_start; + start = fix.smem_start; len = (start & ~PAGE_MASK)+fix.smem_len; start &= PAGE_MASK; len = (len+~PAGE_MASK) & PAGE_MASK; @@ -483,7 +491,7 @@ fb->fb_get_var(&var, PROC_CONSOLE(info), info); if (var.accel_flags) return -EINVAL; - start = (unsigned long)fix.mmio_start; + start = fix.mmio_start; len = (start & ~PAGE_MASK)+fix.mmio_len; start &= PAGE_MASK; len = (len+~PAGE_MASK) & PAGE_MASK; @@ -505,9 +513,6 @@ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; #elif defined(__alpha__) /* Caching is off in the I/O space quadrant by design. */ -#elif defined(__sparc__) - /* Should never get here, all fb drivers should have their own - mmap routines */ #elif defined(__i386__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; @@ -524,10 +529,12 @@ #else #warning What do we have to do here?? #endif - if (remap_page_range(vma->vm_start, vma->vm_offset, + if (io_remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; + +#endif /* defined(__sparc__) */ } static int diff -u --recursive --new-file v2.3.14/linux/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c --- v2.3.14/linux/drivers/video/fm2fb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/fm2fb.c Thu Aug 19 11:01:00 1999 @@ -415,13 +415,13 @@ fb_var = fb_var_modes[fm2fb_mode]; strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); - fb_fix.smem_start = (char *)fm2fb_mem_phys; + fb_fix.smem_start = fm2fb_mem_phys; fb_fix.smem_len = FRAMEMASTER_REG; fb_fix.type = FB_TYPE_PACKED_PIXELS; fb_fix.type_aux = 0; fb_fix.visual = FB_VISUAL_TRUECOLOR; fb_fix.line_length = 768<<2; - fb_fix.mmio_start = (char *)fm2fb_reg_phys; + fb_fix.mmio_start = fm2fb_reg_phys; fb_fix.mmio_len = 8; fb_fix.accel = FB_ACCEL_NONE; diff -u --recursive --new-file v2.3.14/linux/drivers/video/g364fb.c linux/drivers/video/g364fb.c --- v2.3.14/linux/drivers/video/g364fb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/g364fb.c Thu Aug 19 11:01:00 1999 @@ -345,7 +345,7 @@ fb_var.yres = yres; fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel; - fb_fix.smem_start = (char *)0x40000000; /* physical address */ + fb_fix.smem_start = 0x40000000; /* physical address */ /* get size of video memory; this is special for the JAZZ hardware */ mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3; fb_fix.smem_len = (1 << (mem*2)) * 512 * 1024; @@ -355,7 +355,7 @@ fb_fix.xpanstep = 0; fb_fix.ypanstep = 1; fb_fix.ywrapstep = 0; - fb_fix.mmio_start = NULL; + fb_fix.mmio_start = 0; fb_fix.mmio_len = 0; fb_fix.accel = FB_ACCEL_NONE; diff -u --recursive --new-file v2.3.14/linux/drivers/video/hpfb.c linux/drivers/video/hpfb.c --- v2.3.14/linux/drivers/video/hpfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/hpfb.c Thu Aug 19 11:01:00 1999 @@ -192,7 +192,7 @@ /* * X works, but screen wraps ... */ - fix->smem_start=(char *)fb_start; + fix->smem_start=fb_start; fix->smem_len=fb_size; fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_PSEUDOCOLOR; diff -u --recursive --new-file v2.3.14/linux/drivers/video/igafb.c linux/drivers/video/igafb.c --- v2.3.14/linux/drivers/video/igafb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/igafb.c Thu Aug 19 11:01:00 1999 @@ -217,7 +217,7 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, igafb_name); - fix->smem_start = (char *)fb->frame_buffer; + fix->smem_start = fb->frame_buffer; fix->smem_len = fb->total_vram; fix->xpanstep = 0; fix->ypanstep = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c --- v2.3.14/linux/drivers/video/imsttfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/imsttfb.c Thu Aug 19 11:01:00 1999 @@ -1797,9 +1797,9 @@ } sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP"); - p->fix.smem_start = (__u8 *)p->frame_buffer_phys; + p->fix.smem_start = p->frame_buffer_phys; p->fix.smem_len = p->total_vram; - p->fix.mmio_start = (__u8 *)p->dc_regs_phys; + p->fix.mmio_start = p->dc_regs_phys; p->fix.mmio_len = 0x1000; p->fix.accel = FB_ACCEL_IMS_TWINTURBO; p->fix.type = FB_TYPE_PACKED_PIXELS; diff -u --recursive --new-file v2.3.14/linux/drivers/video/macfb.c linux/drivers/video/macfb.c --- v2.3.14/linux/drivers/video/macfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/macfb.c Thu Aug 19 11:01:00 1999 @@ -157,7 +157,7 @@ /* * fbmem.c accepts non page aligned mappings now! */ - fix->smem_start=(char *)mac_videobase; + fix->smem_start=mac_videobase; fix->smem_len=mac_videosize; fix->type = FB_TYPE_PACKED_PIXELS; if (mac_depth == 1) diff -u --recursive --new-file v2.3.14/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c --- v2.3.14/linux/drivers/video/matroxfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/matroxfb.c Wed Aug 25 14:58:13 1999 @@ -2680,7 +2680,7 @@ /* --------------------------------------------------------------------- */ static struct fb_var_screeninfo vesafb_defined __initdata = { - 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ + 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ 0,0, /* virtual -> visible no offset */ 8, /* depth -> load bits_per_pixel */ 0, /* greyscale ? */ @@ -2692,8 +2692,8 @@ FB_ACTIVATE_NOW, -1,-1, FB_ACCELF_TEXT, /* accel flags */ - 0L,0L,0L,0L,0L, - 0L,0L,0, /* No sync info */ + 39721L,48L,16L,33L,10L, + 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED, {0,0,0,0,0,0} }; @@ -4622,7 +4622,7 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"MATROX"); - fix->smem_start = (void*)ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); + fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); fix->type = p->type; fix->type_aux = p->type_aux; @@ -4631,7 +4631,7 @@ fix->ypanstep = 1; fix->ywrapstep = 0; fix->line_length = p->line_length; - fix->mmio_start = (void*)ACCESS_FBINFO(mmio.base); + fix->mmio_start = ACCESS_FBINFO(mmio.base); fix->mmio_len = ACCESS_FBINFO(mmio.len); fix->accel = ACCESS_FBINFO(devflags.accelerator); return 0; @@ -5152,7 +5152,10 @@ static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ static char fontname[64]; /* "matrox:font:xxxxx" */ + +#ifndef MODULE static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +#endif #ifndef MODULE int __init matroxfb_setup(char *options) { @@ -5207,7 +5210,7 @@ else if (!strncmp(this_opt, "vesa:", 5)) vesa = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "font:", 5)) - strcpy(fontname, this_opt+5); + strncpy(fontname, this_opt+5, sizeof(fontname)-1); else if (!strncmp(this_opt, "maxclk:", 7)) maxclk = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "fh:", 3)) @@ -5217,7 +5220,7 @@ else if (!strncmp(this_opt, "mem:", 4)) mem = simple_strtoul(this_opt+4, NULL, 0); else if (!strncmp(this_opt, "mode:", 5)) - strcpy(videomode, this_opt+5); + strncpy(videomode, this_opt+5, sizeof(videomode)-1); #ifdef CONFIG_FB_OF else if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); @@ -5289,13 +5292,13 @@ else if (!strcmp(this_opt, "grayscale")) grayscale = value; else { - printk(KERN_ERR "matroxfb: unknown parameter %s%s\n", value?"":"no", this_opt); + strncpy(videomode, this_opt, sizeof(videomode)-1); } } } return 0; } -#endif +#endif /* !MODULE */ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){ vaddr_t vm; @@ -5847,15 +5850,6 @@ if (depth == -1) depth = RSDepth(RSptr->info); } -#if 0 - if (sync == -1) { - sync = 0; - if (yres < 400) - sync |= FB_SYNC_HOR_HIGH_ACT; - else if (yres < 480) - sync |= FB_SYNC_VERT_HIGH_ACT; - } -#endif if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) { strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8"); } @@ -5879,13 +5873,23 @@ ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT; ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; -#if 0 - fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, - NULL, 0, NULL, vesafb_defined.bits_per_pixel); -#endif +#ifndef MODULE + /* mode database is marked __init ... */ + { + /* it cannot be static const struct due to __initdata + marker */ + static struct fb_videomode defaultmode __initdata = { + /* 640x480 @ 60Hz, 31.5 kHz */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED + }; + + fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, + NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); + } +#endif /* !MODULE */ + /* mode modifiers */ - if (sync != -1) - vesafb_defined.sync = sync; if (hslen) vesafb_defined.hsync_len = hslen; if (vslen) @@ -5902,6 +5906,16 @@ vesafb_defined.xres = xres; if (yres) vesafb_defined.yres = yres; + if (sync != -1) + vesafb_defined.sync = sync; + else if (vesafb_defined.sync == ~0) { + vesafb_defined.sync = 0; + if (yres < 400) + vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; + else if (yres < 480) + vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; + } + /* fv, fh, maxclk limits was specified */ { unsigned int tmp; diff -u --recursive --new-file v2.3.14/linux/drivers/video/modedb.c linux/drivers/video/modedb.c --- v2.3.14/linux/drivers/video/modedb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/modedb.c Thu Aug 19 17:33:46 1999 @@ -0,0 +1,410 @@ +/* + * linux/drivers/video/modedb.c -- Standard video mode database management + * + * Copyright (C) 1999 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include + + +#define DEBUG + +#define name_matches(v, s, l) \ + ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l)) +#define res_matches(v, x, y) \ + ((v).xres == (x) && (v).yres == (y)) + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + + +const char *global_mode_option = NULL; + + + /* + * Standard video mode definitions (taken from XFree86) + */ + +#define DEFAULT_MODEDB_INDEX 0 + +static const struct fb_videomode modedb[] __initdata = { + { + /* 640x400 @ 70 Hz, 31.5 kHz hsync */ + NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 56 Hz, 35.15 kHz hsync */ + NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ + NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, + 0, FB_VMODE_INTERLACED + }, { + /* 640x400 @ 85 Hz, 37.86 kHz hsync */ + NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 72 Hz, 36.5 kHz hsync */ + NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 75 Hz, 37.50 kHz hsync */ + NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 85 Hz, 43.27 kHz hsync */ + NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ + NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, + 0, FB_VMODE_INTERLACED + }, { + /* 800x600 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ + NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 100 Hz, 53.01 kHz hsync */ + NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ + NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 85 Hz, 55.84 kHz hsync */ + NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ + NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ + NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, + 0, FB_VMODE_INTERLACED + }, { + /* 800x600 @ 100 Hz, 64.02 kHz hsync */ + NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ + NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ + NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ + NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ + NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ + NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ + NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ + NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ + NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ + NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 100Hz, 80.21 kHz hsync */ + NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ + NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ + NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ + NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ + NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ + NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ + NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ + NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ + NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ + NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 512x384 @ 78 Hz, 31.50 kHz hsync */ + NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 512x384 @ 85 Hz, 34.38 kHz hsync */ + NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ + NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ + NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 320x240 @ 72 Hz, 36.5 kHz hsync */ + NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ + NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ + NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 63 Hz, 39.6 kHz hsync */ + NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, + 0, FB_VMODE_DOUBLE + }, +}; + + +static int __init my_atoi(const char *name) +{ + int val = 0; + + for (;; name++) { + switch (*name) { + case '0'...'9': + val = 10*val+(*name-'0'); + break; + default: + return val; + } + } +} + +static int __init PROC_CONSOLE(const struct fb_info *info) +{ + int fgc; + + if (info->display_fg != NULL) + fgc = info->display_fg->vc_num; + else + return -1; + + if (!current->tty) + return fgc; + + if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + /* XXX Should report error here? */ + return fgc; + + if (MINOR(current->tty->device) < 1) + return fgc; + + return MINOR(current->tty->device) - 1; +} + +static int __init try_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const struct fb_videomode *mode, unsigned int bpp) +{ + int err; + + DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname", + mode->xres, mode->yres, bpp, mode->refresh); + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = mode->xres; + var->yres_virtual = mode->yres; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = bpp; + var->activate |= FB_ACTIVATE_TEST; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = mode->vmode; + err = info->fbops->fb_set_var(var, PROC_CONSOLE(info), info); + var->activate &= ~FB_ACTIVATE_TEST; + return !err; +} + + + /* + * + * Find a suitable video mode + * + * Valid mode specifiers (mode_option): + * + * x[-][@] + * [-][@] + * + * with , , and decimal numbers and a + * string + * + * The passed struct fb_var_screeninfo is _not_ cleared! This allows you + * to supply values for e.g. the grayscale and accel_flags fields. + */ + +int __init fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp) +{ + int i, j; + + /* Set up defaults */ + if (!db) { + db = modedb; + dbsize = sizeof(modedb)/sizeof(*modedb); + } + if (!default_mode) + default_mode = &modedb[DEFAULT_MODEDB_INDEX]; + if (!default_bpp) + default_bpp = 8; + + /* Did the user specify a video mode? */ + if (mode_option || (mode_option = global_mode_option)) { + const char *name = mode_option; + unsigned int namelen = strlen(name); + int res_specified = 0, bpp_specified = 0, refresh_specified = 0; + unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; + int yres_specified = 0; + + for (i = namelen-1; i >= 0; i--) { + switch (name[i]) { + case '@': + namelen = i; + if (!refresh_specified && !bpp_specified && + !yres_specified) { + refresh = my_atoi(&name[i+1]); + refresh_specified = 1; + } else + goto done; + break; + case '-': + namelen = i; + if (!bpp_specified && !yres_specified) { + bpp = my_atoi(&name[i+1]); + bpp_specified = 1; + } else + goto done; + break; + case 'x': + if (!yres_specified) { + yres = my_atoi(&name[i+1]); + yres_specified = 1; + } else + goto done; + break; + case '0'...'9': + break; + default: + goto done; + } + } + if (i < 0 && yres_specified) { + xres = my_atoi(name); + res_specified = 1; + } +done: + for (i = refresh_specified; i >= 0; i--) { + DPRINTK("Trying specified video mode%s\n", + i ? "" : " (ignoring refresh rate)"); + for (j = 0; j < dbsize; j++) + if ((name_matches(db[j], name, namelen) || + (res_specified && res_matches(db[j], xres, yres))) && + (!i || db[j].refresh == refresh) && + try_mode(var, info, &db[j], bpp)) + return 2-i; + } + } + + DPRINTK("Trying default video mode\n"); + if (try_mode(var, info, default_mode, default_bpp)) + return 3; + + DPRINTK("Trying all modes\n"); + for (i = 0; i < dbsize; i++) + if (try_mode(var, info, &db[i], default_bpp)) + return 4; + + DPRINTK("No valid mode found\n"); + return 0; +} diff -u --recursive --new-file v2.3.14/linux/drivers/video/offb.c linux/drivers/video/offb.c --- v2.3.14/linux/drivers/video/offb.c Sat Aug 14 22:27:41 1999 +++ linux/drivers/video/offb.c Thu Aug 19 11:01:00 1999 @@ -533,7 +533,7 @@ var->yres = var->yres_virtual = height; fix->line_length = pitch; - fix->smem_start = (char *)address; + fix->smem_start = address; fix->smem_len = pitch * height; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c --- v2.3.14/linux/drivers/video/platinumfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/platinumfb.c Thu Aug 19 11:01:00 1999 @@ -837,9 +837,9 @@ { memset(fix, 0, sizeof(*fix)); strcpy(fix->id, "platinum"); - fix->smem_start = (void *) (info->frame_buffer_phys + 0x1000); + fix->smem_start = (info->frame_buffer_phys + 0x1000); fix->smem_len = (u32) info->total_vram - 0x1000; - fix->mmio_start = (char *) (info->platinum_regs_phys); + fix->mmio_start = (info->platinum_regs_phys); fix->mmio_len = 0x1000; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/pm2fb.c linux/drivers/video/pm2fb.c --- v2.3.14/linux/drivers/video/pm2fb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/pm2fb.c Wed Aug 25 14:58:13 1999 @@ -192,12 +192,12 @@ int board; /* Permedia2 board index (see board_table[] below) */ struct { - unsigned char* fb_base; /* framebuffer memory base */ + unsigned long fb_base; /* physical framebuffer memory base */ u32 fb_size; /* framebuffer memory size */ - unsigned char* rg_base; /* register memory base */ - unsigned char* p_fb; /* physical address of frame buffer */ + unsigned long rg_base; /* physical register memory base */ + unsigned long p_fb; /* physical address of frame buffer */ unsigned char* v_fb; /* virtual address of frame buffer */ - unsigned char* p_regs; /* physical address of registers + unsigned long p_regs; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ @@ -750,13 +750,26 @@ return 0; } DPRINTK("found board: %s\n", board_table[p->board].name); + p->regions.p_fb=p->regions.fb_base; + if (!__request_region(&iomem_resource, p->regions.p_fb, + p->regions.fb_size, "pm2fb")) { + printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n"); + return 0; + } p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size); + #ifdef __LITTLE_ENDIAN p->regions.p_regs=p->regions.rg_base; #else p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE; #endif + if (!__request_region(&iomem_resource, p->regions.p_regs, + PM2_REGS_SIZE, "pm2fb")) { + printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n"); + UNMAP(p->regions.v_fb, p->regions.fb_size); + return 0; + } p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE); return 1; } @@ -809,9 +822,9 @@ if (!cvppc_PCI_init(&p->board_par.cvppc)) return 0; - p->regions.fb_base=(unsigned char* )CVPPC_FB_APERTURE_ONE; + p->regions.fb_base=CVPPC_FB_APERTURE_ONE; p->regions.fb_size=CVPPC_FB_SIZE; - p->regions.rg_base=(unsigned char* )CVPPC_REGS_REGION; + p->regions.rg_base=CVPPC_REGS_REGION; p->memclock=CVPPC_MEMCLOCK; return 1; } @@ -855,24 +868,18 @@ pci->dev->resource[0].start, pci->dev->resource[1].start, pci->dev->resource[2].start, - pci->dev->rom_address); + pci->dev->resource[PCI_ROM_RESOURCE].start); #ifdef __sparc__ - p->regions.rg_base=(unsigned char* ) - __pa(pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - __pa(pci->dev->resource[1].start); + p->regions.rg_base= __pa(pci->dev->resource[0].start); + p->regions.fb_base= __pa(pci->dev->resource[1].start); #else if (pm2fb_options.flags & OPTF_VIRTUAL) { - p->regions.rg_base=(unsigned char* ) - __pa(pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - __pa(pci->dev->resource[1].start); + p->regions.rg_base= __pa(pci->dev->resource[0].start); + p->regions.fb_base= __pa(pci->dev->resource[1].start); } else { - p->regions.rg_base=(unsigned char* ) - (pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - (pci->dev->resource[0].start); + p->regions.rg_base= (pci->dev->resource[0].start); + p->regions.fb_base= (pci->dev->resource[0].start); } #endif #ifdef __BIG_ENDIAN @@ -1581,15 +1588,23 @@ * Begin of public functions ***************************************************************************/ -void pm2fb_cleanup(struct fb_info* info) { - struct pm2fb_info* i=(struct pm2fb_info* )info; +#ifdef MODULE +static void pm2fb_cleanup(void) { + struct pm2fb_info* i = &fb_info; - unregister_framebuffer(info); + unregister_framebuffer((struct fb_info *)i); pm2fb_reset(i); - /* FIXME UNMAP()??? */ + + UNMAP(i->regions.v_fb, i->regions.fb_size); + __release_region(&iomem_resource, i->regions.p_fb, i->regions.fb_size); + + UNMAP(i->regions.v_regs, PM2_REGS_SIZE); + __release_region(&iomem_resource, i->regions.p_regs, PM2_REGS_SIZE); + if (board_table[i->board].cleanup) board_table[i->board].cleanup(i); } +#endif /* MODULE */ int __init pm2fb_init(void){ diff -u --recursive --new-file v2.3.14/linux/drivers/video/q40fb.c linux/drivers/video/q40fb.c --- v2.3.14/linux/drivers/video/q40fb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/q40fb.c Thu Aug 19 11:01:00 1999 @@ -86,7 +86,7 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"Q40"); - fix->smem_start=(char*)q40_screen_addr; + fix->smem_start=q40_screen_addr; fix->smem_len=1024*1024; fix->type=FB_TYPE_PACKED_PIXELS; fix->type_aux=0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c --- v2.3.14/linux/drivers/video/retz3fb.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/retz3fb.c Thu Aug 19 11:01:00 1999 @@ -794,9 +794,9 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, retz3fb_name); - fix->smem_start = (char *)(zinfo->physfbmem); + fix->smem_start = zinfo->physfbmem; fix->smem_len = zinfo->fbsize; - fix->mmio_start = (char *)(zinfo->physregs); + fix->mmio_start = zinfo->physregs; fix->mmio_len = 0x00c00000; fix->type = FB_TYPE_PACKED_PIXELS; diff -u --recursive --new-file v2.3.14/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c --- v2.3.14/linux/drivers/video/sgivwfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/sgivwfb.c Thu Aug 19 11:01:00 1999 @@ -501,7 +501,7 @@ { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, sgivwfb_name); - fix->smem_start = (char *) sgivwfb_mem_phys; + fix->smem_start = sgivwfb_mem_phys; fix->smem_len = sgivwfb_mem_size; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; @@ -517,7 +517,7 @@ fix->xpanstep = 0; fix->ypanstep = ypan; fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); - fix->mmio_start = (char *) DBE_REG_PHYS; + fix->mmio_start = DBE_REG_PHYS; fix->mmio_len = DBE_REG_SIZE; } diff -u --recursive --new-file v2.3.14/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.3.14/linux/drivers/video/tgafb.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/tgafb.c Thu Aug 19 11:01:00 1999 @@ -328,9 +328,9 @@ fix->visual = FB_VISUAL_TRUECOLOR; fix->line_length = par->xres * (par->bits_per_pixel >> 3); - fix->smem_start = ioremap(fb_info.tga_fb_base); + fix->smem_start = fb_info.tga_fb_base; fix->smem_len = fix->line_length * par->yres; - fix->mmio_start = ioremap(fb_info.tga_regs_base); + fix->mmio_start = fb_info.tga_regs_base; fix->mmio_len = 0x1000; /* Is this sufficient? */ fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0; fix->accel = FB_ACCEL_DEC_TGA; diff -u --recursive --new-file v2.3.14/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c --- v2.3.14/linux/drivers/video/valkyriefb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/valkyriefb.c Thu Aug 19 11:01:00 1999 @@ -783,7 +783,7 @@ struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p) { - fix->smem_start = (void *)(p->frame_buffer_phys + 0x1000); + fix->smem_start = p->frame_buffer_phys + 0x1000; #if 1 fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode); #else diff -u --recursive --new-file v2.3.14/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c --- v2.3.14/linux/drivers/video/vesafb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/vesafb.c Wed Aug 25 14:58:13 1999 @@ -41,7 +41,7 @@ */ /* card */ -char *video_base; +unsigned long video_base; /* physical addr */ int video_size; char *video_vbase; /* mapped */ @@ -166,7 +166,7 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"VESA VGA"); - fix->smem_start=(char *) video_base; + fix->smem_start=video_base; fix->smem_len=video_size; fix->type = video_type; fix->visual = video_visual; @@ -530,7 +530,7 @@ if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return -ENXIO; - video_base = (char*)screen_info.lfb_base; + video_base = screen_info.lfb_base; video_bpp = screen_info.lfb_depth; video_width = screen_info.lfb_width; video_height = screen_info.lfb_height; @@ -538,9 +538,18 @@ video_size = screen_info.lfb_size * 65536; video_visual = (video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - video_vbase = ioremap((unsigned long)video_base, video_size); - printk(KERN_INFO "vesafb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n", + if (!__request_region(&iomem_resource, video_base, video_size, + "vesafb")) { + printk(KERN_ERR + "vesafb: abort, cannot reserve video memory at 0x%lu\n", + video_base); + return -1; + } + + video_vbase = ioremap(video_base, video_size); + + printk(KERN_INFO "vesafb: framebuffer at 0x%lu, mapped to 0x%p, size %dk\n", video_base, video_vbase, video_size/1024); printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", video_width, video_height, video_bpp, video_linelength, screen_info.pages); @@ -633,9 +642,13 @@ } video_cmap_len = 256; } - request_region(0x3c0, 32, "vga+"); + + /* request failure does not faze us, as vgacon probably has this + * region already (FIXME) */ + __request_region(&ioport_resource, 0x3c0, 32, "vesafb"); + if (mtrr) - mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1); + mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 1); strcpy(fb_info.modename, "VESA VGA"); fb_info.changevar = NULL; diff -u --recursive --new-file v2.3.14/linux/drivers/video/vfb.c linux/drivers/video/vfb.c --- v2.3.14/linux/drivers/video/vfb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/vfb.c Thu Aug 19 11:01:00 1999 @@ -507,7 +507,7 @@ { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, vfb_name); - fix->smem_start = (char *)videomemory; + fix->smem_start = videomemory; fix->smem_len = videomemorysize; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; diff -u --recursive --new-file v2.3.14/linux/drivers/video/vga.h linux/drivers/video/vga.h --- v2.3.14/linux/drivers/video/vga.h Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/vga.h Mon Aug 23 13:44:03 1999 @@ -17,6 +17,7 @@ #ifndef __linux_video_vga_h__ #define __linux_video_vga_h__ +#include #include #include #ifndef CONFIG_AMIGA diff -u --recursive --new-file v2.3.14/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c --- v2.3.14/linux/drivers/video/vga16fb.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/vga16fb.c Wed Aug 25 14:58:13 1999 @@ -32,6 +32,9 @@ #define dac_reg (0x3c8) #define dac_val (0x3c9) +#define VGA_FB_PHYS 0xA0000 +#define VGA_FB_PHYS_LEN 65535 + /* --------------------------------------------------------------------- */ /* @@ -101,6 +104,8 @@ static int currcon = 0; +static int release_io_ports = 0; + /* --------------------------------------------------------------------- */ /* @@ -158,8 +163,8 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"VGA16 VGA"); - fix->smem_start = (char *) 0xa0000; - fix->smem_len = 65536; + fix->smem_start = VGA_FB_PHYS; + fix->smem_len = VGA_FB_PHYS_LEN; fix->type = FB_TYPE_VGA_PLANES; fix->visual = FB_VISUAL_PSEUDOCOLOR; fix->xpanstep = 8; @@ -919,7 +924,13 @@ printk(KERN_DEBUG "vga16fb: initializing\n"); - vga16fb.video_vbase = ioremap((unsigned long)0xa0000, 65536); + if (!__request_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN, + "vga16fb")) { + printk (KERN_ERR "vga16fb: unable to reserve VGA memory, exiting\n"); + return -1; + } + + vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN); printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase); vga16fb.isVGA = ORIG_VIDEO_ISVGA; @@ -937,10 +948,11 @@ palette[i].green = default_grn[j]; palette[i].blue = default_blu[j]; } - if (vga16fb.isVGA) - request_region(0x3c0, 32, "vga+"); - else - request_region(0x3C0, 32, "ega"); + + /* note - does not cause failure, b/c vgacon probably still owns this + * region (FIXME) */ + if (__request_region(&ioport_resource, 0x3C0, 32, "vga16fb")) + release_io_ports = 1; disp.var = vga16fb_defined; @@ -981,8 +993,10 @@ void cleanup_module(void) { unregister_framebuffer(&vga16fb.fb_info); - release_region(0x3c0, 32); iounmap(vga16fb.video_vbase); + __release_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN); + if (release_io_ports) + __release_region(&ioport_resource, 0x3c0, 32); } #endif diff -u --recursive --new-file v2.3.14/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c --- v2.3.14/linux/drivers/video/virgefb.c Thu Aug 12 10:22:33 1999 +++ linux/drivers/video/virgefb.c Thu Aug 19 11:01:00 1999 @@ -441,19 +441,19 @@ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, virgefb_name); if (cv3d_on_zorro2) { - fix->smem_start = (char*) CyberMem_phys; + fix->smem_start = CyberMem_phys; } else { switch (par->bpp) { case 8: - fix->smem_start = (char*) (CyberMem_phys + CYBMEM_OFFSET_8); + fix->smem_start = (CyberMem_phys + CYBMEM_OFFSET_8); break; case 16: - fix->smem_start = (char*) (CyberMem_phys + CYBMEM_OFFSET_16); + fix->smem_start = (CyberMem_phys + CYBMEM_OFFSET_16); break; } } fix->smem_len = CyberSize; - fix->mmio_start = (char*) CyberRegs_phys; + fix->mmio_start = CyberRegs_phys; fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */ fix->type = FB_TYPE_PACKED_PIXELS; diff -u --recursive --new-file v2.3.14/linux/fs/buffer.c linux/fs/buffer.c --- v2.3.14/linux/fs/buffer.c Mon Aug 9 11:49:24 1999 +++ linux/fs/buffer.c Mon Aug 23 11:15:53 1999 @@ -227,7 +227,6 @@ continue; atomic_inc(&bh->b_count); - bh->b_flushtime = 0; spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); atomic_dec(&bh->b_count); @@ -308,7 +307,7 @@ return sync_buffers(dev, 1); } -asmlinkage int sys_sync(void) +asmlinkage long sys_sync(void) { fsync_dev(0); return 0; @@ -338,7 +337,7 @@ return sync_buffers(dev, 1); } -asmlinkage int sys_fsync(unsigned int fd) +asmlinkage long sys_fsync(unsigned int fd) { struct file * file; struct dentry * dentry; @@ -375,7 +374,7 @@ return err; } -asmlinkage int sys_fdatasync(unsigned int fd) +asmlinkage long sys_fdatasync(unsigned int fd) { struct file * file; struct dentry * dentry; @@ -437,7 +436,6 @@ } if (atomic_read(&bh->b_count)) continue; - bh->b_flushtime = 0; clear_bit(BH_Protected, &bh->b_state); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Dirty, &bh->b_state); @@ -652,7 +650,6 @@ clear_bit(BH_Dirty, &bh->b_state); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Req, &bh->b_state); - bh->b_flushtime = 0; } if (atomic_read(&bh->b_count) == 0) { __remove_from_queues(bh); @@ -678,7 +675,6 @@ void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id) { bh->b_list = BUF_CLEAN; - bh->b_flushtime = 0; bh->b_end_io = handler; bh->b_dev_id = dev_id; } @@ -792,12 +788,8 @@ repeat: bh = get_hash_table(dev, block, size); - if (bh) { - if (!buffer_dirty(bh)) { - bh->b_flushtime = 0; - } + if (bh) goto out; - } isize = BUFSIZE_INDEX(size); spin_lock(&free_list[isize].lock); @@ -1132,7 +1124,6 @@ bh->b_data = (char *) (page+offset); bh->b_list = BUF_CLEAN; - bh->b_flushtime = 0; bh->b_end_io = end_buffer_io_bad; } return head; @@ -2324,7 +2315,6 @@ continue; /* OK, now we are committed to write it out. */ - bh->b_flushtime = 0; atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); @@ -2343,7 +2333,7 @@ * We would want to verify each parameter, however, to make sure that it * is reasonable. */ -asmlinkage int sys_bdflush(int func, long data) +asmlinkage long sys_bdflush(int func, long data) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2448,7 +2438,6 @@ major = MAJOR(bh->b_dev); written++; - bh->b_flushtime = 0; /* * For the loop major we can try to do asynchronous writes, diff -u --recursive --new-file v2.3.14/linux/fs/coda/cache.c linux/fs/coda/cache.c --- v2.3.14/linux/fs/coda/cache.c Tue Jul 6 19:08:33 1999 +++ linux/fs/coda/cache.c Mon Aug 23 10:14:44 1999 @@ -65,7 +65,7 @@ if ( ! list_empty(&el->cc_cclist) ) list_del(&el->cc_cclist); else - printk("coda_cnremove: loose cc entry!"); + printk("coda_ccremove: loose cc entry!"); } /* remove a cache entry from the inode's list */ @@ -139,7 +139,7 @@ /* remove all cached acl matches from an inode */ void coda_cache_clear_inode(struct inode *inode) { - struct list_head *lh, *le; + struct list_head *le; struct coda_inode_info *cii; struct coda_cache *cc; ENTRY; @@ -150,9 +150,10 @@ } cii = ITOC(inode); - lh = le = &cii->c_cnhead; - while ( (le = le->next ) != lh ) { + le = cii->c_cnhead.next; + while ( le != &cii->c_cnhead ) { cc = list_entry(le, struct coda_cache, cc_cnlist); + le = le->next; coda_cnremove(cc); coda_ccremove(cc); CODA_FREE(cc, sizeof(*cc)); @@ -162,7 +163,7 @@ /* remove all acl caches */ void coda_cache_clear_all(struct super_block *sb) { - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc; struct coda_sb_info *sbi = coda_sbp(sb); @@ -174,9 +175,10 @@ if ( list_empty(&sbi->sbi_cchead) ) return; - lh = le = &sbi->sbi_cchead; - while ( (le = le->next ) != lh ) { + le = sbi->sbi_cchead.next; + while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); + le = le->next; coda_cnremove(cc); coda_ccremove(cc); CODA_FREE(cc, sizeof(*cc)); @@ -186,7 +188,7 @@ /* remove all acl caches for a principal */ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) { - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc; struct coda_sb_info *sbi = coda_sbp(sb); @@ -198,9 +200,10 @@ if (list_empty(&sbi->sbi_cchead)) return; - lh = le = &sbi->sbi_cchead; - while ( (le = le->next ) != lh ) { + le = sbi->sbi_cchead.next; + while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); + le = le->next; if ( coda_cred_eq(&cc->cc_cred, cred)) { coda_cnremove(cc); coda_ccremove(cc); diff -u --recursive --new-file v2.3.14/linux/fs/coda/cnode.c linux/fs/coda/cnode.c --- v2.3.14/linux/fs/coda/cnode.c Tue Jul 6 19:08:33 1999 +++ linux/fs/coda/cnode.c Mon Aug 23 10:14:44 1999 @@ -108,10 +108,10 @@ if ( coda_f2i(fid) != ino ) { if ( !coda_fid_is_weird(fid) ) printk("Coda: unknown weird fid: ino %ld, fid %s." - "Tell Peter.\n", ino, coda_f2s(&cnp->c_fid)); + "Tell Peter.\n", (long)ino, coda_f2s(&cnp->c_fid)); list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead); CDEBUG(D_UPCALL, "Added %ld ,%s to volroothead\n", - ino, coda_f2s(&cnp->c_fid)); + (long)ino, coda_f2s(&cnp->c_fid)); } coda_fill_inode(*inode, &attr); @@ -199,7 +199,7 @@ inode = iget(sb, nr); if ( !inode ) { printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n", - sb, nr); + sb, (long)nr); return NULL; } diff -u --recursive --new-file v2.3.14/linux/fs/coda/dir.c linux/fs/coda/dir.c --- v2.3.14/linux/fs/coda/dir.c Tue Jul 6 19:08:33 1999 +++ linux/fs/coda/dir.c Mon Aug 23 10:14:44 1999 @@ -125,12 +125,12 @@ if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", - coda_f2s(&dircnp->c_fid), length, name); + coda_f2s(&dircnp->c_fid), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } - CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", - name, length, dir->i_ino, coda_f2s(&dircnp->c_fid)); + CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n", + name, (long)length, dir->i_ino, coda_f2s(&dircnp->c_fid)); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { @@ -157,7 +157,7 @@ return ERR_PTR(error); } else if (error != -ENOENT) { CDEBUG(D_INODE, "error for %s(%*s)%d\n", - coda_f2s(&dircnp->c_fid), length, name, error); + coda_f2s(&dircnp->c_fid), (int)length, name, error); return ERR_PTR(error); } CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", @@ -504,10 +504,10 @@ old_cnp = ITOC(old_dir); new_cnp = ITOC(new_dir); - CDEBUG(D_INODE, "old: %s, (%d length, %d strlen), new: %s" - "(%d length, %d strlen).old:d_count: %d, new:d_count: %d\n", - old_name, old_length, strlen(old_name), new_name, new_length, - strlen(new_name),old_dentry->d_count, new_dentry->d_count); + CDEBUG(D_INODE, "old: %s, (%d length, %ld strlen), new: %s" + "(%d length, %ld strlen).old:d_count: %d, new:d_count: %d\n", + old_name, old_length, (long)strlen(old_name), new_name, new_length, + (long)strlen(new_name),old_dentry->d_count, new_dentry->d_count); /* the C library will do unlink/create etc */ if ( coda_crossvol_rename == 0 && @@ -594,12 +594,12 @@ error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); if (error) { CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n", - dev, ino, error); + dev, (long)ino, error); return error; } /* coda_upcall returns ino number of cached object, get inode */ - CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, ino); + CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, (long)ino); error = coda_inode_grab(dev, ino, &cont_inode); if ( error || !cont_inode ){ @@ -622,9 +622,9 @@ CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", error, i->i_count, i->i_ino); - CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %x\n", + CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", cnp->c_ovp->i_ino, cnp->c_ovp->i_count, - (int)(cnp->c_ovp->i_op)); + (cnp->c_ovp->i_op)); EXIT; return 0; } diff -u --recursive --new-file v2.3.14/linux/fs/coda/file.c linux/fs/coda/file.c --- v2.3.14/linux/fs/coda/file.c Tue Jun 29 09:22:08 1999 +++ linux/fs/coda/file.c Mon Aug 23 10:14:44 1999 @@ -155,8 +155,8 @@ result = cont_file.f_op->read(&cont_file , buff, count, &(cont_file.f_pos)); - CDEBUG(D_FILE, "ops at %x result %d, count %d, position: %d\n", - (int)cont_file.f_op, result, count, (int)cont_file.f_pos); + CDEBUG(D_FILE, "ops at %p result %d, count %ld, position: %d\n", + cont_file.f_op, result, (long)count, (int)cont_file.f_pos); coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file); return result; @@ -292,10 +292,10 @@ if ( *ind == NULL ) { printk("coda_inode_grab: iget(dev: %d, ino: %ld) - returns NULL.\n", dev, ino); + returns NULL.\n", dev, (long)ino); return -ENOENT; } - CDEBUG(D_FILE, "ino: %ld, ops at %x\n", ino, (int)(*ind)->i_op); + CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op); return 0; } diff -u --recursive --new-file v2.3.14/linux/fs/coda/inode.c linux/fs/coda/inode.c --- v2.3.14/linux/fs/coda/inode.c Tue Jul 6 19:08:33 1999 +++ linux/fs/coda/inode.c Mon Aug 23 10:14:44 1999 @@ -203,7 +203,7 @@ coda_cache_clear_inode(inode); CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags); - inode->u.generic_ip = NULL; + inode->u.coda_i.c_magic = 0; clear_inode(inode); EXIT; } diff -u --recursive --new-file v2.3.14/linux/fs/coda/psdev.c linux/fs/coda/psdev.c --- v2.3.14/linux/fs/coda/psdev.c Wed Jun 2 11:29:13 1999 +++ linux/fs/coda/psdev.c Mon Aug 23 10:14:44 1999 @@ -98,8 +98,8 @@ if (copy_from_user(&hdr, buf, 2 * sizeof(u_long))) return -EFAULT; - CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %d\n", - current->pid, hdr.opcode, hdr.unique, count); + CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %ld\n", + current->pid, hdr.opcode, hdr.unique, (long)count); if (DOWNCALL(hdr.opcode)) { struct super_block *sb = NULL; @@ -160,8 +160,8 @@ /* move data into response buffer. */ if (req->uc_outSize < count) { - printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n", - req->uc_outSize, count, hdr.opcode, hdr.unique); + printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n", + req->uc_outSize, (long)count, hdr.opcode, hdr.unique); count = req->uc_outSize; /* don't have more space! */ } if (copy_from_user(req->uc_data, buf, count)) @@ -172,8 +172,8 @@ req->uc_flags |= REQ_WRITE; CDEBUG(D_PSDEV, - "Found! Count %d for (opc,uniq)=(%ld,%ld), upc_req at %x\n", - count, hdr.opcode, hdr.unique, (int)&req); + "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n", + (long)count, hdr.opcode, hdr.unique, &req); wake_up(&req->uc_sleep); return(count); @@ -190,7 +190,7 @@ struct upc_req *req; int result = count ; - CDEBUG(D_PSDEV, "count %d\n", count); + CDEBUG(D_PSDEV, "count %ld\n", (long)count); if (list_empty(&(vcp->vc_pending))) { return -1; } @@ -203,8 +203,8 @@ result = req->uc_inSize; if (count < req->uc_inSize) { - printk ("psdev_read: Venus read %d bytes of %d in message\n", - count, req->uc_inSize); + printk ("psdev_read: Venus read %ld bytes of %d in message\n", + (long)count, req->uc_inSize); } if ( copy_to_user(buf, req->uc_data, result)) diff -u --recursive --new-file v2.3.14/linux/fs/coda/upcall.c linux/fs/coda/upcall.c --- v2.3.14/linux/fs/coda/upcall.c Tue Jul 6 19:08:33 1999 +++ linux/fs/coda/upcall.c Mon Aug 23 10:14:44 1999 @@ -710,8 +710,8 @@ /* Append msg to pending queue and poke Venus. */ list_add(&(req->uc_chain), vcommp->vc_pending.prev); CDEBUG(D_UPCALL, - "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n", - current->pid, req->uc_opcode, req->uc_unique, (int)req); + "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n", + current->pid, req->uc_opcode, req->uc_unique, req); wake_up_interruptible(&vcommp->vc_waitq); /* We can be interrupted while we wait for Venus to process @@ -731,8 +731,8 @@ req->uc_opcode, jiffies - req->uc_posttime, req->uc_unique, req->uc_outSize); CDEBUG(D_UPCALL, - "..process %d woken up by Venus for req at 0x%x, data at %x\n", - current->pid, (int)req, (int)req->uc_data); + "..process %d woken up by Venus for req at %p, data at %p\n", + current->pid, req, req->uc_data); if (vcommp->vc_pid) { /* i.e. Venus is still alive */ /* Op went through, interrupt or not... */ if (req->uc_flags & REQ_WRITE) { diff -u --recursive --new-file v2.3.14/linux/fs/dcache.c linux/fs/dcache.c --- v2.3.14/linux/fs/dcache.c Tue Jun 8 10:47:58 1999 +++ linux/fs/dcache.c Mon Aug 23 11:15:53 1999 @@ -813,7 +813,7 @@ * return NULL; * } */ -asmlinkage int sys_getcwd(char *buf, unsigned long size) +asmlinkage long sys_getcwd(char *buf, unsigned long size) { int error; struct dentry *pwd = current->fs->pwd; diff -u --recursive --new-file v2.3.14/linux/fs/dquot.c linux/fs/dquot.c --- v2.3.14/linux/fs/dquot.c Sat Jul 3 10:42:21 1999 +++ linux/fs/dquot.c Mon Aug 23 11:15:53 1999 @@ -1337,7 +1337,7 @@ * calls. Maybe we need to add the process quotas etc. in the future, * but we probably should use rlimits for that. */ -asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = 0, type = 0, flags = 0; kdev_t dev; diff -u --recursive --new-file v2.3.14/linux/fs/exec.c linux/fs/exec.c --- v2.3.14/linux/fs/exec.c Thu Aug 12 11:53:18 1999 +++ linux/fs/exec.c Mon Aug 23 11:15:53 1999 @@ -135,7 +135,7 @@ * * Also note that we take the address to load from from the file itself. */ -asmlinkage int sys_uselib(const char * library) +asmlinkage long sys_uselib(const char * library) { int fd, retval; struct file * file; diff -u --recursive --new-file v2.3.14/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.3.14/linux/fs/ext2/balloc.c Wed Jun 16 19:26:27 1999 +++ linux/fs/ext2/balloc.c Mon Aug 23 10:16:34 1999 @@ -368,11 +368,10 @@ struct super_block * sb; struct ext2_group_desc * gdp; struct ext2_super_block * es; - - *err = -ENOSPC; #ifdef EXT2FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif + *err = -ENOSPC; sb = inode->i_sb; if (!sb) { printk ("ext2_new_block: nonexistent device"); diff -u --recursive --new-file v2.3.14/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.3.14/linux/fs/ext2/inode.c Sat Jun 26 12:04:39 1999 +++ linux/fs/ext2/inode.c Thu Aug 19 10:54:06 1999 @@ -259,20 +259,22 @@ } if (metadata) { result = getblk (inode->i_dev, tmp, blocksize); + memset(result->b_data, 0, blocksize); + mark_buffer_uptodate(result, 1); + mark_buffer_dirty(result, 1); if (*p) { ext2_free_blocks (inode, tmp, 1); - brelse (result); + bforget (result); goto repeat; } - memset(result->b_data, 0, blocksize); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); } else { if (*p) { /* * Nobody is allowed to change block allocation * state from under us: */ + ext2_error (inode->i_sb, "block_getblk", + "data block filled under us"); BUG(); ext2_free_blocks (inode, tmp, 1); goto repeat; @@ -366,22 +368,28 @@ goto out; if (metadata) { result = getblk (bh->b_dev, tmp, blocksize); + memset(result->b_data, 0, inode->i_sb->s_blocksize); + mark_buffer_uptodate(result, 1); + mark_buffer_dirty(result, 1); if (*p) { ext2_free_blocks (inode, tmp, 1); - brelse (result); + bforget (result); goto repeat; } - memset(result->b_data, 0, inode->i_sb->s_blocksize); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result, 1); } else { + if (*p) { + /* + * Nobody is allowed to change block allocation + * state from under us: + */ + ext2_error (inode->i_sb, "block_getblk", + "data block filled under us"); + BUG(); + ext2_free_blocks (inode, tmp, 1); + goto repeat; + } *phys = tmp; *new = 1; - } - if (*p) { - ext2_free_blocks (inode, tmp, 1); - brelse (result); - goto repeat; } *p = le32_to_cpu(tmp); mark_buffer_dirty(bh, 1); diff -u --recursive --new-file v2.3.14/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.3.14/linux/fs/fat/inode.c Mon Aug 9 11:43:49 1999 +++ linux/fs/fat/inode.c Mon Aug 23 10:16:34 1999 @@ -307,12 +307,12 @@ else opts->quiet = 1; } else if (!strcmp(this_char,"blocksize")) { - if (*value) ret = 0; - else if (*blksize != 512 && - *blksize != 1024 && - *blksize != 2048) { - printk ("MSDOS FS: Invalid blocksize " - "(512, 1024, or 2048)\n"); + if (!value || !*value) ret = 0; + else { + *blksize = simple_strtoul(value,&value,0); + if (*value || (*blksize != 512 && + *blksize != 1024 && *blksize != 2048)) + ret = 0; } } else if (!strcmp(this_char,"sys_immutable")) { @@ -516,7 +516,7 @@ /* Must be FAT32 */ fat32 = 1; - MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult; + MSDOS_SB(sb)->fat_length= CF_LE_L(b->fat32_length)*sector_mult; MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster); /* MC - if info_sector is 0, don't multiply by 0 */ diff -u --recursive --new-file v2.3.14/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.3.14/linux/fs/fcntl.c Mon Jul 26 22:41:09 1999 +++ linux/fs/fcntl.c Mon Aug 23 11:15:53 1999 @@ -88,7 +88,7 @@ return ret; } -asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) +asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) { int err = -EBADF; struct file * file; @@ -133,7 +133,7 @@ goto out; } -asmlinkage int sys_dup(unsigned int fildes) +asmlinkage long sys_dup(unsigned int fildes) { int ret = -EBADF; struct file * file = fget(fildes); diff -u --recursive --new-file v2.3.14/linux/fs/fifo.c linux/fs/fifo.c --- v2.3.14/linux/fs/fifo.c Sun Jul 4 10:02:30 1999 +++ linux/fs/fifo.c Tue Aug 24 10:12:00 1999 @@ -12,38 +12,38 @@ #include #include -static int fifo_open(struct inode * inode,struct file * filp) +static int fifo_open(struct inode *inode, struct file *filp) { - int retval = 0; - unsigned long page = 0; - struct pipe_inode_info *info, *tmp = NULL; - - if (inode->i_pipe) - goto got_it; - tmp = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL); - if (inode->i_pipe) - goto got_it; - if (!tmp) - goto oom; - page = __get_free_page(GFP_KERNEL); - if (inode->i_pipe) - goto got_it; - if (!page) - goto oom; - inode->i_pipe = tmp; - PIPE_LOCK(*inode) = 0; - PIPE_START(*inode) = PIPE_LEN(*inode) = 0; - PIPE_BASE(*inode) = (char *) page; - PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; - PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; - init_waitqueue_head(&PIPE_WAIT(*inode)); - tmp = NULL; /* no need to free it */ - page = 0; + int ret; -got_it: + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto err_nolock_nocleanup; + + if (! inode->i_pipe) { + unsigned long page; + struct pipe_inode_info *info; + + info = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL); + + ret = -ENOMEM; + if (!info) + goto err_nocleanup; + page = __get_free_page(GFP_KERNEL); + if (!page) { + kfree(info); + goto err_nocleanup; + } + + inode->i_pipe = info; - switch( filp->f_mode ) { + init_waitqueue_head(PIPE_WAIT(*inode)); + PIPE_BASE(*inode) = (char *) page; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; + } + switch (filp->f_mode) { case 1: /* * O_RDONLY @@ -51,26 +51,26 @@ * opened, even when there is no process writing the FIFO. */ filp->f_op = &connecting_fifo_fops; - if (!PIPE_READERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) { - PIPE_RD_OPENERS(*inode)++; + if (PIPE_READERS(*inode)++ == 0) + wake_up_interruptible(PIPE_WAIT(*inode)); + + if (!(filp->f_flags & O_NONBLOCK)) { while (!PIPE_WRITERS(*inode)) { - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (signal_pending(current)) + goto err_rd; + up(PIPE_SEM(*inode)); + interruptible_sleep_on(PIPE_WAIT(*inode)); + + /* Note that using down_interruptible here + and similar places below is pointless, + since we have to acquire the lock to clean + up properly. */ + down(PIPE_SEM(*inode)); } - if (!--PIPE_RD_OPENERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); } - while (PIPE_WR_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (PIPE_WRITERS(*inode)) filp->f_op = &read_fifo_fops; - if (retval && !--PIPE_READERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); break; case 2: @@ -79,29 +79,21 @@ * POSIX.1 says that O_NONBLOCK means return -1 with * errno=ENXIO when there is no process reading the FIFO. */ - if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) { - retval = -ENXIO; - break; - } + ret = -ENXIO; + if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) + goto err; + filp->f_op = &write_fifo_fops; if (!PIPE_WRITERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (!PIPE_READERS(*inode)) { - PIPE_WR_OPENERS(*inode)++; - while (!PIPE_READERS(*inode)) { - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); - } - if (!--PIPE_WR_OPENERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); + wake_up_interruptible(PIPE_WAIT(*inode)); + + while (!PIPE_READERS(*inode)) { + if (signal_pending(current)) + goto err_wr; + up(PIPE_SEM(*inode)); + interruptible_sleep_on(PIPE_WAIT(*inode)); + down(PIPE_SEM(*inode)); } - while (PIPE_RD_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); - if (retval && !--PIPE_WRITERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); break; case 3: @@ -112,39 +104,47 @@ * the process can at least talk to itself. */ filp->f_op = &rdwr_fifo_fops; - if (!PIPE_READERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - while (PIPE_WR_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); - if (!PIPE_WRITERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - while (PIPE_RD_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); + + PIPE_READERS(*inode)++; + PIPE_WRITERS(*inode)++; + if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1) + wake_up_interruptible(PIPE_WAIT(*inode)); break; default: - retval = -EINVAL; + ret = -EINVAL; + goto err; } - if (retval) - goto cleanup; -out: - if (tmp) - kfree(tmp); - if (page) - free_page(page); - return retval; -cleanup: + /* Ok! */ + up(PIPE_SEM(*inode)); + return 0; + +err_rd: + if (!--PIPE_READERS(*inode)) + wake_up_interruptible(PIPE_WAIT(*inode)); + ret = -ERESTARTSYS; + goto err; + +err_wr: + if (!--PIPE_WRITERS(*inode)) + wake_up_interruptible(PIPE_WAIT(*inode)); + ret = -ERESTARTSYS; + goto err; + +err: if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { - info = inode->i_pipe; + struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; free_page((unsigned long)info->base); kfree(info); } - goto out; -oom: - retval = -ENOMEM; - goto out; + +err_nocleanup: + up(PIPE_SEM(*inode)); + +err_nolock_nocleanup: + return ret; } /* diff -u --recursive --new-file v2.3.14/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.3.14/linux/fs/ioctl.c Mon Jul 26 22:41:09 1999 +++ linux/fs/ioctl.c Mon Aug 23 11:15:53 1999 @@ -48,7 +48,7 @@ } -asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; unsigned int flag; diff -u --recursive --new-file v2.3.14/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c --- v2.3.14/linux/fs/lockd/clntlock.c Tue May 11 14:37:40 1999 +++ linux/fs/lockd/clntlock.c Mon Aug 23 10:16:34 1999 @@ -172,7 +172,7 @@ /* First, reclaim all locks that have been granted previously. */ do { - for (fl = file_lock_table; fl; fl = fl->fl_next) { + for (fl = file_lock_table; fl; fl = fl->fl_nextlink) { inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic == NFS_SUPER_MAGIC && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) diff -u --recursive --new-file v2.3.14/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c --- v2.3.14/linux/fs/lockd/svclock.c Wed Feb 17 09:44:33 1999 +++ linux/fs/lockd/svclock.c Mon Aug 23 10:16:34 1999 @@ -335,9 +335,12 @@ /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); - /* Now add block to block list of the conflicting lock */ - dprintk("lockd: blocking on this lock.\n"); - posix_block_lock(conflock, &block->b_call.a_args.lock.fl); + if (!block->b_call.a_args.lock.fl.fl_prevblock) { + /* Now add block to block list of the conflicting lock + if we haven't done so. */ + dprintk("lockd: blocking on this lock.\n"); + posix_block_lock(conflock, &block->b_call.a_args.lock.fl); + } up(&file->f_sema); return nlm_lck_blocked; @@ -440,7 +443,7 @@ dprintk("lockd: VFS unblock notification for block %p\n", fl); posix_unblock_lock(fl); for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) { - if (&block->b_call.a_args.lock.fl == fl) { + if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) { svc_wake_up(block->b_daemon); nlmsvc_insert_block(block, 0); return; diff -u --recursive --new-file v2.3.14/linux/fs/locks.c linux/fs/locks.c --- v2.3.14/linux/fs/locks.c Mon Jul 5 20:11:07 1999 +++ linux/fs/locks.c Mon Aug 23 11:15:53 1999 @@ -193,6 +193,14 @@ { struct file_lock *prevblock; + if (waiter->fl_prevblock) { + printk(KERN_ERR "locks_insert_block: remove duplicated lock " + "(pid=%d %ld-%ld type=%d)\n", + waiter->fl_pid, waiter->fl_start, + waiter->fl_end, waiter->fl_type); + locks_delete_block(waiter->fl_prevblock, waiter); + } + if (blocker->fl_prevblock == NULL) /* No previous waiters - list is empty */ prevblock = blocker; @@ -282,7 +290,7 @@ /* flock() system call entry point. Apply a FL_FLOCK style lock to * an open file descriptor. */ -asmlinkage int sys_flock(unsigned int fd, unsigned int cmd) +asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) { struct file_lock file_lock; struct file *filp; diff -u --recursive --new-file v2.3.14/linux/fs/namei.c linux/fs/namei.c --- v2.3.14/linux/fs/namei.c Mon Jul 5 20:34:31 1999 +++ linux/fs/namei.c Mon Aug 23 11:15:53 1999 @@ -250,7 +250,7 @@ * FIXME! This could use version numbering or similar to * avoid unnecessary cache lookups. */ - result = cached_lookup(parent, name, flags); + result = d_lookup(parent, name); if (!result) { struct dentry * dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); @@ -261,8 +261,19 @@ else result = dentry; } + up(&dir->i_sem); + return result; } + + /* + * Uhhuh! Nasty case: the cache was re-populated while + * we waited on the semaphore. Need to revalidate, but + * we're going to return this entry regardless (same + * as if it was busy). + */ up(&dir->i_sem); + if (result->d_op && result->d_op->d_revalidate) + result->d_op->d_revalidate(result, flags); return result; } @@ -838,7 +849,7 @@ return retval; } -asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) +asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev) { int error; char * tmp; @@ -929,7 +940,7 @@ return error; } -asmlinkage int sys_mkdir(const char * pathname, int mode) +asmlinkage long sys_mkdir(const char * pathname, int mode) { int error; char * tmp; @@ -1024,7 +1035,7 @@ return error; } -asmlinkage int sys_rmdir(const char * pathname) +asmlinkage long sys_rmdir(const char * pathname) { int error; char * tmp; @@ -1077,7 +1088,7 @@ return error; } -asmlinkage int sys_unlink(const char * pathname) +asmlinkage long sys_unlink(const char * pathname) { int error; char * tmp; @@ -1128,7 +1139,7 @@ return error; } -asmlinkage int sys_symlink(const char * oldname, const char * newname) +asmlinkage long sys_symlink(const char * oldname, const char * newname) { int error; char * from; @@ -1216,7 +1227,7 @@ return error; } -asmlinkage int sys_link(const char * oldname, const char * newname) +asmlinkage long sys_link(const char * oldname, const char * newname) { int error; char * from; @@ -1387,7 +1398,7 @@ return error; } -asmlinkage int sys_rename(const char * oldname, const char * newname) +asmlinkage long sys_rename(const char * oldname, const char * newname) { int error; char * from; diff -u --recursive --new-file v2.3.14/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.3.14/linux/fs/nfs/dir.c Wed Jun 30 11:30:55 1999 +++ linux/fs/nfs/dir.c Mon Aug 23 10:16:34 1999 @@ -601,6 +601,8 @@ /* Filehandle matches? */ if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) { + if (!list_empty(&dentry->d_subdirs)) + shrink_dcache_parent(dentry); if (dentry->d_count < 2) goto out_bad; } diff -u --recursive --new-file v2.3.14/linux/fs/nls/Config.in linux/fs/nls/Config.in --- v2.3.14/linux/fs/nls/Config.in Tue Apr 20 15:17:20 1999 +++ linux/fs/nls/Config.in Mon Aug 23 10:16:34 1999 @@ -38,6 +38,7 @@ tristate 'NLS ISO 8859-7 (Modern Greek)' CONFIG_NLS_ISO8859_7 tristate 'NLS ISO 8859-8 (Hebrew)' CONFIG_NLS_ISO8859_8 tristate 'NLS ISO 8859-9 (Latin 5; Turkish)' CONFIG_NLS_ISO8859_9 + tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14 tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15 tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R endmenu diff -u --recursive --new-file v2.3.14/linux/fs/nls/Makefile linux/fs/nls/Makefile --- v2.3.14/linux/fs/nls/Makefile Fri Dec 18 08:09:51 1998 +++ linux/fs/nls/Makefile Mon Aug 23 10:16:34 1999 @@ -286,6 +286,14 @@ endif endif +ifeq ($(CONFIG_NLS_ISO8859_14),y) +NLS += nls_iso8859-14.o +else + ifeq ($(CONFIG_NLS_ISO8859_14),m) + M_OBJS += nls_iso8859-14.o + endif +endif + ifeq ($(CONFIG_NLS_ISO8859_15),y) NLS += nls_iso8859-15.o else diff -u --recursive --new-file v2.3.14/linux/fs/nls/nls_base.c linux/fs/nls/nls_base.c --- v2.3.14/linux/fs/nls/nls_base.c Fri Dec 18 08:09:51 1998 +++ linux/fs/nls/nls_base.c Mon Aug 23 10:16:34 1999 @@ -429,6 +429,9 @@ #ifdef CONFIG_NLS_ISO8859_9 init_nls_iso8859_9(); #endif +#ifdef CONFIG_NLS_ISO8859_14 + init_nls_iso8859_14(); +#endif #ifdef CONFIG_NLS_ISO8859_15 init_nls_iso8859_15(); #endif diff -u --recursive --new-file v2.3.14/linux/fs/nls/nls_iso8859-14.c linux/fs/nls/nls_iso8859-14.c --- v2.3.14/linux/fs/nls/nls_iso8859-14.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_iso8859-14.c Mon Aug 23 10:16:34 1999 @@ -0,0 +1,275 @@ +/* + * linux/fs/nls_iso8859-14.c + * + * Charset iso8859-14 translation tables. + * + * Generated automatically from the Unicode and charset table + * provided by the Unicode Organisation at + * http://www.unicode.org/ + * The Unicode to charset table has only exact mappings. + * + * Rhys Jones, Swansea University Computer Society + * rhys@sucs.swan.ac.uk + */ + +#include +#include +#include +#include + +static struct nls_unicode charset2uni[256] = { + /* 0x00*/ + {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00}, + {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00}, + {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00}, + {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, + /* 0x10*/ + {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, + {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, + {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, + {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00}, + /* 0x20*/ + {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, + {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, + {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00}, + /* 0x30*/ + {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, + {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00}, + {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, + {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, + /* 0x40*/ + {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, + {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, + {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00}, + {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00}, + /* 0x50*/ + {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00}, + {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, + {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00}, + {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00}, + /* 0x60*/ + {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00}, + {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00}, + {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00}, + {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00}, + /* 0x70*/ + {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00}, + {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00}, + {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00}, + {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00}, + /* 0x80*/ + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + /* 0x90*/ + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, + /* 0xa0*/ + {0xa0, 0x00}, {0x02, 0x1e}, {0x03, 0x1e}, {0xa3, 0x00}, + {0x0a, 0x01}, {0x0b, 0x01}, {0x0a, 0x1e}, {0xa7, 0x00}, + {0x80, 0x1e}, {0xa9, 0x00}, {0x82, 0x1e}, {0x0b, 0x1e}, + {0xf2, 0x1e}, {0xad, 0x00}, {0xae, 0x00}, {0x78, 0x01}, + /* 0xb0*/ + {0x1e, 0x1e}, {0x1f, 0x1e}, {0x20, 0x01}, {0x21, 0x01}, + {0x40, 0x1e}, {0x41, 0x1e}, {0xb6, 0x00}, {0x56, 0x1e}, + {0x81, 0x1e}, {0x57, 0x1e}, {0x83, 0x1e}, {0x60, 0x1e}, + {0xf3, 0x1e}, {0x84, 0x1e}, {0x85, 0x1e}, {0x61, 0x1e}, + /* 0xc0*/ + {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00}, + {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00}, + {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00}, + {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00}, + /* 0xd0*/ + {0x74, 0x01}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00}, + {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0x6a, 0x1e}, + {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00}, + {0xdc, 0x00}, {0xdd, 0x00}, {0x76, 0x01}, {0xdf, 0x00}, + /* 0xe0*/ + {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00}, + {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00}, + {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00}, + {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00}, + /* 0xf0*/ + {0x75, 0x01}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00}, + {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0x6b, 0x1e}, + {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00}, + {0xfc, 0x00}, {0xfd, 0x00}, {0x77, 0x01}, {0xff, 0x00}, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */ + 0x00, 0xa9, 0x00, 0x00, 0x00, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0x00, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x00, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char page01[256] = { + 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */ + 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */ + 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page1e[256] = { + 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */ + 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */ + 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, page1e, NULL, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static void inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static struct nls_table table = { + "iso8859-14", + page_uni2charset, + charset2uni, + inc_use_count, + dec_use_count, + NULL +}; + +int init_nls_iso8859_14(void) +{ + return register_nls(&table); +} + +#ifdef MODULE +int init_module(void) +{ + return init_nls_iso8859_14(); +} + + +void cleanup_module(void) +{ + unregister_nls(&table); + return; +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.3.14/linux/fs/noquot.c linux/fs/noquot.c --- v2.3.14/linux/fs/noquot.c Fri May 8 17:54:39 1998 +++ linux/fs/noquot.c Mon Aug 23 11:15:53 1999 @@ -9,7 +9,7 @@ int nr_dquots = 0, nr_free_dquots = 0; int max_dquots = 0; -asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) { return(-ENOSYS); } diff -u --recursive --new-file v2.3.14/linux/fs/open.c linux/fs/open.c --- v2.3.14/linux/fs/open.c Mon Jul 26 22:41:09 1999 +++ linux/fs/open.c Mon Aug 23 11:15:53 1999 @@ -12,7 +12,7 @@ #include -asmlinkage int sys_statfs(const char * path, struct statfs * buf) +asmlinkage long sys_statfs(const char * path, struct statfs * buf) { struct dentry * dentry; int error; @@ -34,7 +34,7 @@ return error; } -asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) +asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf) { struct file * file; struct super_block * sb; @@ -79,7 +79,7 @@ return error; } -asmlinkage int sys_truncate(const char * path, unsigned long length) +asmlinkage long sys_truncate(const char * path, unsigned long length) { struct dentry * dentry; struct inode * inode; @@ -128,7 +128,7 @@ return error; } -asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length) +asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) { struct inode * inode; struct dentry *dentry; @@ -176,7 +176,7 @@ * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -asmlinkage int sys_utime(char * filename, struct utimbuf * times) +asmlinkage long sys_utime(char * filename, struct utimbuf * times) { int error; struct dentry * dentry; @@ -224,7 +224,7 @@ * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -asmlinkage int sys_utimes(char * filename, struct timeval * utimes) +asmlinkage long sys_utimes(char * filename, struct timeval * utimes) { int error; struct dentry * dentry; @@ -270,7 +270,7 @@ * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ -asmlinkage int sys_access(const char * filename, int mode) +asmlinkage long sys_access(const char * filename, int mode) { struct dentry * dentry; int old_fsuid, old_fsgid; @@ -311,7 +311,7 @@ return res; } -asmlinkage int sys_chdir(const char * filename) +asmlinkage long sys_chdir(const char * filename) { int error; struct inode *inode; @@ -346,7 +346,7 @@ return error; } -asmlinkage int sys_fchdir(unsigned int fd) +asmlinkage long sys_fchdir(unsigned int fd) { struct file *file; struct dentry *dentry; @@ -382,7 +382,7 @@ return error; } -asmlinkage int sys_chroot(const char * filename) +asmlinkage long sys_chroot(const char * filename) { int error; struct inode *inode; @@ -422,7 +422,7 @@ return error; } -asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) +asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) { struct inode * inode; struct dentry * dentry; @@ -460,7 +460,7 @@ return err; } -asmlinkage int sys_chmod(const char * filename, mode_t mode) +asmlinkage long sys_chmod(const char * filename, mode_t mode) { struct dentry * dentry; struct inode * inode; @@ -551,7 +551,7 @@ return error; } -asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) +asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group) { struct dentry * dentry; int error; @@ -568,7 +568,7 @@ return error; } -asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group) +asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group) { struct dentry * dentry; int error; @@ -586,7 +586,7 @@ } -asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) +asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) { struct dentry * dentry; struct file * file; @@ -748,7 +748,7 @@ write_unlock(¤t->files->file_lock); } -asmlinkage int sys_open(const char * filename, int flags, int mode) +asmlinkage long sys_open(const char * filename, int flags, int mode) { char * tmp; int fd, error; @@ -784,7 +784,7 @@ * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage int sys_creat(const char * pathname, int mode) +asmlinkage long sys_creat(const char * pathname, int mode) { return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } @@ -847,7 +847,7 @@ goto out; } -asmlinkage int sys_close(unsigned int fd) +asmlinkage long sys_close(unsigned int fd) { return do_close(fd, 1); } @@ -856,7 +856,7 @@ * This routine simulates a hangup on the tty, to arrange that users * are given clean terminals at login time. */ -asmlinkage int sys_vhangup(void) +asmlinkage long sys_vhangup(void) { int ret = -EPERM; diff -u --recursive --new-file v2.3.14/linux/fs/pipe.c linux/fs/pipe.c --- v2.3.14/linux/fs/pipe.c Tue Jul 6 19:08:33 1999 +++ linux/fs/pipe.c Tue Aug 24 18:40:00 1999 @@ -1,7 +1,7 @@ /* * linux/fs/pipe.c * - * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1991, 1992, 1999 Linus Torvalds */ #include @@ -22,187 +22,263 @@ #undef FIFO_SUNOS_BRAINDAMAGE #endif -/* We don't use the head/tail construction any more. Now we use the start/len*/ -/* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */ -/* Florian Coosmann (FGC) ^ current = 1 */ -/* Additionally, we now use locking technique. This prevents race condition */ -/* in case of paging and multiple read/write on the same pipe. (FGC) */ -/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */ - -static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count) -{ - struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, size = 0, read = 0; - char *pipebuf; +/* + * We use a start+len construction, which provides full use of the + * allocated memory. + * -- Florian Coosmann (FGC) + * + * Reads with count = 0 should always return 0. + * -- Julian Bradfield 1999-06-07. + */ + +/* Drop the inode semaphore and wait for a pipe event, atomically */ +static void pipe_wait(struct inode * inode) +{ + DECLARE_WAITQUEUE(wait, current); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(PIPE_WAIT(*inode), &wait); + up(PIPE_SEM(*inode)); + schedule(); + remove_wait_queue(PIPE_WAIT(*inode), &wait); + current->state = TASK_RUNNING; +} +static ssize_t +pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + ssize_t size, read, ret; + + /* Seeks are not allowed on pipes. */ + ret = -ESPIPE; + if (ppos != &filp->f_pos) + goto out_nolock; + + /* Always return 0 on null read. */ + ret = 0; + if (count == 0) + goto out_nolock; + + /* Grab, or try to grab, the pipe's semaphore with data present. */ if (filp->f_flags & O_NONBLOCK) { - if (PIPE_LOCK(*inode)) - return -EAGAIN; - if (PIPE_EMPTY(*inode)) { - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - else - return 0; - } - } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) { + ret = -EAGAIN; + if (down_trylock(PIPE_SEM(*inode))) + goto out_nolock; + ret = PIPE_WRITERS(*inode) ? -EAGAIN : 0; + if (PIPE_EMPTY(*inode)) + goto out; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + if (PIPE_EMPTY(*inode)) { - if (!PIPE_WRITERS(*inode) || !count) - return 0; + ret = 0; + if (!PIPE_WRITERS(*inode)) + goto out; + + for (;;) { + pipe_wait(inode); + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out_nolock; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + ret = 0; + if (!PIPE_EMPTY(*inode)) + break; + if (!PIPE_WRITERS(*inode)) + goto out; + } } - if (signal_pending(current)) - return -ERESTARTSYS; - interruptible_sleep_on(&PIPE_WAIT(*inode)); } - PIPE_LOCK(*inode)++; - while (count>0 && (size = PIPE_SIZE(*inode))) { - chars = PIPE_MAX_RCHUNK(*inode); + + /* Read what data is available. */ + ret = -EFAULT; + read = 0; + while (count > 0 && (size = PIPE_LEN(*inode))) { + char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode); + ssize_t chars = PIPE_MAX_RCHUNK(*inode); + if (chars > count) chars = count; if (chars > size) chars = size; + + if (copy_to_user(buf, pipebuf, chars)) + goto out; + read += chars; - pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode); PIPE_START(*inode) += chars; - PIPE_START(*inode) &= (PIPE_BUF-1); + PIPE_START(*inode) &= (PIPE_SIZE - 1); PIPE_LEN(*inode) -= chars; count -= chars; - copy_to_user(buf, pipebuf, chars ); buf += chars; } - PIPE_LOCK(*inode)--; - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (read) { + + /* Cache behaviour optimization */ + if (!PIPE_LEN(*inode)) + PIPE_START(*inode) = 0; + + /* Signal writers there is more room. */ + wake_up_interruptible(PIPE_WAIT(*inode)); + + if (read) UPDATE_ATIME(inode); - return read; - } - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - return 0; + ret = read; + +out: + up(PIPE_SEM(*inode)); +out_nolock: + return ret; } -static ssize_t do_pipe_write(struct file * filp, const char * buf, size_t count) +static ssize_t +pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, free = 0, written = 0, err=0; - char *pipebuf; - - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - return -EPIPE; - } - /* if count <= PIPE_BUF, we have to make it atomic */ - if (count <= PIPE_BUF) - free = count; - else - free = 1; /* can't do it atomically, wait for any free space */ - if (down_interruptible(&inode->i_sem)) { - return -ERESTARTSYS; - } - while (count>0) { - while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - err = -EPIPE; - goto errout; - } - if (signal_pending(current)) { - err = -ERESTARTSYS; - goto errout; - } - if (filp->f_flags & O_NONBLOCK) { - err = -EAGAIN; - goto errout; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); + struct inode *inode = filp->f_dentry->d_inode; + ssize_t free, written, ret; + + /* Seeks are not allowed on pipes. */ + ret = -ESPIPE; + if (ppos != &filp->f_pos) + goto out_nolock; + + /* Null write succeeds. */ + ret = 0; + if (count == 0) + goto out_nolock; + + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + + /* No readers yields SIGPIPE. */ + if (!PIPE_READERS(*inode)) + goto sigpipe; + + /* If count <= PIPE_BUF, we have to make it atomic. */ + free = (count <= PIPE_BUF ? count : 1); + written = 0; + + /* Wait, or check for, available space. */ + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (PIPE_FREE(*inode) < free) + goto out; + } else { + while (PIPE_FREE(*inode) < free) { + pipe_wait(inode); + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out_nolock; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + + if (!PIPE_READERS(*inode)) + goto sigpipe; } - PIPE_LOCK(*inode)++; - while (count>0 && (free = PIPE_FREE(*inode))) { - chars = PIPE_MAX_WCHUNK(*inode); + } + + /* Copy into available space. */ + ret = -EFAULT; + while (count > 0) { + int space; + char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode); + ssize_t chars = PIPE_MAX_WCHUNK(*inode); + + if ((space = PIPE_FREE(*inode)) != 0) { if (chars > count) chars = count; - if (chars > free) - chars = free; - pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode); + if (chars > space) + chars = space; + + if (copy_from_user(pipebuf, buf, chars)) + goto out; + written += chars; PIPE_LEN(*inode) += chars; count -= chars; - copy_from_user(pipebuf, buf, chars ); buf += chars; + space = PIPE_FREE(*inode); + continue; } - PIPE_LOCK(*inode)--; - wake_up_interruptible(&PIPE_WAIT(*inode)); - free = 1; - } - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty(inode); -errout: - up(&inode->i_sem); - return written ? written : err; -} - -static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *ppos) -{ - ssize_t retval; - - - if (ppos != &filp->f_pos) - return -ESPIPE; - - if ( !count ) return 0; - lock_kernel(); - retval = do_pipe_read(filp, buf, count); - unlock_kernel(); - return retval; -} + ret = written; + if (filp->f_flags & O_NONBLOCK) + break; + + do { + /* This should be a synchronous wake-up: don't do idle reschedules! */ + wake_up_interruptible(PIPE_WAIT(*inode)); + pipe_wait(inode); + if (signal_pending(current)) + goto out; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + if (!PIPE_READERS(*inode)) + goto sigpipe; + } while (!PIPE_FREE(*inode)); + ret = -EFAULT; + } -static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) -{ - ssize_t retval; + /* Signal readers there is more data. */ + wake_up_interruptible(PIPE_WAIT(*inode)); - if (ppos != &filp->f_pos) - return -ESPIPE; + ret = (written ? written : -EAGAIN); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); - lock_kernel(); - retval = do_pipe_write(filp, buf, count); - unlock_kernel(); - return retval; +out: + up(PIPE_SEM(*inode)); +out_nolock: + return ret; + +sigpipe: + up(PIPE_SEM(*inode)); + send_sig(SIGPIPE, current, 0); + return -EPIPE; } -static long long pipe_lseek(struct file * file, long long offset, int orig) +static loff_t +pipe_lseek(struct file *file, loff_t offset, int orig) { return -ESPIPE; } -static ssize_t bad_pipe_r(struct file * filp, char * buf, - size_t count, loff_t *ppos) +static ssize_t +bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos) { return -EBADF; } -static ssize_t bad_pipe_w(struct file * filp, const char * buf, - size_t count, loff_t *ppos) +static ssize_t +bad_pipe_w(struct file *filp, const char *buf, size_t count, loff_t *ppos) { return -EBADF; } -static int pipe_ioctl(struct inode *pino, struct file * filp, - unsigned int cmd, unsigned long arg) +static int +pipe_ioctl(struct inode *pino, struct file *filp, + unsigned int cmd, unsigned long arg) { switch (cmd) { case FIONREAD: - return put_user(PIPE_SIZE(*pino),(int *) arg); + return put_user(PIPE_LEN(*pino), (int *)arg); default: return -EINVAL; } } -static unsigned int pipe_poll(struct file * filp, poll_table * wait) +static unsigned int +pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + + poll_wait(filp, PIPE_WAIT(*inode), wait); - poll_wait(filp, &PIPE_WAIT(*inode), wait); + /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; @@ -210,6 +286,7 @@ mask |= POLLHUP; if (!PIPE_READERS(*inode)) mask |= POLLERR; + return mask; } @@ -218,17 +295,21 @@ * Argh! Why does SunOS have to have different select() behaviour * for pipes and FIFOs? Hate, hate, hate! SunOS lacks POLLHUP. */ -static unsigned int fifo_poll(struct file * filp, poll_table * wait) +static unsigned int +fifo_poll(struct file *filp, poll_table *wait) { unsigned int mask; - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; - poll_wait(filp, &PIPE_WAIT(*inode), wait); + poll_wait(filp, PIPE_WAIT(*inode), wait); + + /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; if (!PIPE_READERS(*inode)) mask |= POLLERR; + return mask; } #else @@ -242,82 +323,112 @@ * the open() code hasn't guaranteed a connection (O_NONBLOCK), * and we need to act differently until we do get a writer.. */ -static ssize_t connect_read(struct file * filp, char * buf, - size_t count, loff_t *ppos) +static ssize_t +connect_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + + /* Reading only -- no need for aquiring the semaphore. */ if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode)) return 0; + filp->f_op = &read_fifo_fops; - return pipe_read(filp,buf,count,ppos); + return pipe_read(filp, buf, count, ppos); } -static unsigned int connect_poll(struct file * filp, poll_table * wait) +static unsigned int +connect_poll(struct file *filp, poll_table *wait) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + unsigned int mask = 0; + + poll_wait(filp, PIPE_WAIT(*inode), wait); - poll_wait(filp, &PIPE_WAIT(*inode), wait); + /* Reading only -- no need for aquiring the semaphore. */ if (!PIPE_EMPTY(*inode)) { filp->f_op = &read_fifo_fops; - return POLLIN | POLLRDNORM; - } - if (PIPE_WRITERS(*inode)) + mask = POLLIN | POLLRDNORM; + } else if (PIPE_WRITERS(*inode)) { filp->f_op = &read_fifo_fops; - return POLLOUT | POLLWRNORM; + mask = POLLOUT | POLLWRNORM; + } + + return mask; } -static int pipe_release(struct inode * inode) +static int +pipe_release(struct inode *inode, int decr, int decw) { + down(PIPE_SEM(*inode)); + PIPE_READERS(*inode) -= decr; + PIPE_WRITERS(*inode) -= decw; if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; free_page((unsigned long) info->base); kfree(info); - return 0; + } else { + wake_up_interruptible(PIPE_WAIT(*inode)); } - wake_up_interruptible(&PIPE_WAIT(*inode)); + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_read_release(struct inode * inode, struct file * filp) +static int +pipe_read_release(struct inode *inode, struct file *filp) { - PIPE_READERS(*inode)--; - return pipe_release(inode); + return pipe_release(inode, 1, 0); } -static int pipe_write_release(struct inode * inode, struct file * filp) +static int +pipe_write_release(struct inode *inode, struct file *filp) { - PIPE_WRITERS(*inode)--; - return pipe_release(inode); + return pipe_release(inode, 0, 1); } -static int pipe_rdwr_release(struct inode * inode, struct file * filp) +static int +pipe_rdwr_release(struct inode *inode, struct file *filp) { - if (filp->f_mode & FMODE_READ) - PIPE_READERS(*inode)--; - if (filp->f_mode & FMODE_WRITE) - PIPE_WRITERS(*inode)--; - return pipe_release(inode); + int decr, decw; + + decr = (filp->f_mode & FMODE_READ) != 0; + decw = (filp->f_mode & FMODE_WRITE) != 0; + return pipe_release(inode, decr, decw); } -static int pipe_read_open(struct inode * inode, struct file * filp) +static int +pipe_read_open(struct inode *inode, struct file *filp) { + /* We could have perhaps used atomic_t, but this and friends + below are the only places. So it doesn't seem worthwhile. */ + down(PIPE_SEM(*inode)); PIPE_READERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_write_open(struct inode * inode, struct file * filp) +static int +pipe_write_open(struct inode *inode, struct file *filp) { + down(PIPE_SEM(*inode)); PIPE_WRITERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_rdwr_open(struct inode * inode, struct file * filp) +static int +pipe_rdwr_open(struct inode *inode, struct file *filp) { + down(PIPE_SEM(*inode)); if (filp->f_mode & FMODE_READ) PIPE_READERS(*inode)++; if (filp->f_mode & FMODE_WRITE) PIPE_WRITERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } @@ -433,22 +544,20 @@ goto fail_inode; page = __get_free_page(GFP_USER); - if (!page) goto fail_iput; - /* XXX */ inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); if (!inode->i_pipe) goto fail_page; - PIPE_BASE(*inode) = (char *) page; inode->i_op = &pipe_inode_operations; - init_waitqueue_head(&PIPE_WAIT(*inode)); + + init_waitqueue_head(PIPE_WAIT(*inode)); + PIPE_BASE(*inode) = (char *) page; PIPE_START(*inode) = PIPE_LEN(*inode) = 0; - PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; - PIPE_LOCK(*inode) = 0; + /* * Mark the inode dirty from the very beginning, * that way it will never be moved to the dirty diff -u --recursive --new-file v2.3.14/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.3.14/linux/fs/proc/array.c Wed Aug 18 10:00:52 1999 +++ linux/fs/proc/array.c Mon Aug 23 11:15:53 1999 @@ -100,6 +100,9 @@ memset(&dump, 0, sizeof(struct user)); dump.magic = CMAGIC; dump.u_dsize = max_mapnr; +#if defined (__i386__) + dump.start_code = PAGE_OFFSET; +#endif #ifdef __alpha__ dump.start_data = PAGE_OFFSET; #endif @@ -361,7 +364,7 @@ len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n" "Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n" "Swap: %8lu %8lu %8lu\n", - i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, atomic_read(&page_cache_size)*PAGE_SIZE, + i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, (unsigned long) atomic_read(&page_cache_size)*PAGE_SIZE, i.totalswap, i.totalswap-i.freeswap, i.freeswap); /* * Tagged format, for easy grepping and expansion. The above will go away @@ -549,7 +552,22 @@ return ((unsigned long *)schedule_frame)[12]; } return pc; - } + } +#elif defined(__mips__) + /* + * The same comment as on the Alpha applies here, too ... + */ + { + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long *)(long)p->tss.reg30)[16]; + return (unsigned long)((unsigned long *)schedule_frame)[11]; + } + return pc; + } #elif defined(__mc68000__) { unsigned long fp, pc; @@ -628,6 +646,7 @@ } while (++count < 16); } #endif + return 0; } @@ -664,6 +683,12 @@ #elif defined(__sparc__) # define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc) # define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP]) +#elif defined(__mips__) +# define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg \ + - sizeof(struct pt_regs)) +#define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32) +# define KSTK_EIP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc))) +# define KSTK_ESP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29]))) #endif /* Gcc optimizes away "strlen(x)" for constant x */ @@ -1382,6 +1407,14 @@ #ifdef CONFIG_RTC case PROC_RTC: return get_rtc_status(page); +#endif +#ifdef CONFIG_SGI_DS1286 + case PROC_RTC: + return get_ds1286_status(page); +#endif +#ifdef CONFIG_SGI_DS1286 + case PROC_RTC: + return get_ds1286_status(page); #endif case PROC_LOCKS: return get_locks_status(page, start, offset, length); diff -u --recursive --new-file v2.3.14/linux/fs/read_write.c linux/fs/read_write.c --- v2.3.14/linux/fs/read_write.c Mon Jun 28 13:31:07 1999 +++ linux/fs/read_write.c Mon Aug 23 11:15:53 1999 @@ -73,9 +73,9 @@ } #if !defined(__alpha__) -asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, - unsigned long offset_low, loff_t * result, - unsigned int origin) +asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, + unsigned long offset_low, loff_t * result, + unsigned int origin) { int retval; struct file * file; diff -u --recursive --new-file v2.3.14/linux/fs/readdir.c linux/fs/readdir.c --- v2.3.14/linux/fs/readdir.c Tue Dec 1 21:45:10 1998 +++ linux/fs/readdir.c Mon Aug 23 11:15:53 1999 @@ -142,7 +142,7 @@ return 0; } -asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) +asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count) { struct file * file; struct dentry * dentry; diff -u --recursive --new-file v2.3.14/linux/fs/select.c linux/fs/select.c --- v2.3.14/linux/fs/select.c Wed Jul 28 13:52:38 1999 +++ linux/fs/select.c Mon Aug 23 11:15:53 1999 @@ -237,7 +237,7 @@ #define MAX_SELECT_SECONDS \ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) -asmlinkage int +asmlinkage long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { fd_set_bits fds; @@ -371,7 +371,7 @@ return count; } -asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) +asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) { int i, fdcount, err, size; struct pollfd * fds, *fds1; diff -u --recursive --new-file v2.3.14/linux/fs/stat.c linux/fs/stat.c --- v2.3.14/linux/fs/stat.c Mon May 24 22:47:43 1999 +++ linux/fs/stat.c Mon Aug 23 11:15:53 1999 @@ -119,7 +119,7 @@ * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf) +asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf) { struct dentry * dentry; int error; @@ -140,7 +140,7 @@ } #endif -asmlinkage int sys_newstat(char * filename, struct stat * statbuf) +asmlinkage long sys_newstat(char * filename, struct stat * statbuf) { struct dentry * dentry; int error; @@ -166,7 +166,7 @@ * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf) +asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf) { struct dentry * dentry; int error; @@ -188,7 +188,7 @@ #endif -asmlinkage int sys_newlstat(char * filename, struct stat * statbuf) +asmlinkage long sys_newlstat(char * filename, struct stat * statbuf) { struct dentry * dentry; int error; @@ -214,7 +214,7 @@ * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf) +asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf) { struct file * f; int err = -EBADF; @@ -235,7 +235,7 @@ #endif -asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf) +asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf) { struct file * f; int err = -EBADF; @@ -254,7 +254,7 @@ return err; } -asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz) +asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz) { struct dentry * dentry; int error; diff -u --recursive --new-file v2.3.14/linux/fs/super.c linux/fs/super.c --- v2.3.14/linux/fs/super.c Wed Aug 4 15:39:26 1999 +++ linux/fs/super.c Mon Aug 23 11:15:53 1999 @@ -256,7 +256,7 @@ /* * Whee.. Weird sysv syscall. */ -asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2) +asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) { int retval = -EINVAL; @@ -474,7 +474,7 @@ return NULL; } -asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf) +asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf) { struct super_block *s; struct ustat tmp; @@ -768,7 +768,7 @@ * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD */ -asmlinkage int sys_umount(char * name, int flags) +asmlinkage long sys_umount(char * name, int flags) { struct dentry * dentry; int retval; @@ -808,7 +808,7 @@ * The 2.0 compatible umount. No flags. */ -asmlinkage int sys_oldumount(char * name) +asmlinkage long sys_oldumount(char * name) { return sys_umount(name,0); } @@ -1018,8 +1018,8 @@ * aren't used, as the syscall assumes we are talking to an older * version that didn't understand them. */ -asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void * data) +asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void * data) { struct file_system_type * fstype; struct dentry * dentry = NULL; diff -u --recursive --new-file v2.3.14/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h --- v2.3.14/linux/include/asm-alpha/dma.h Thu Aug 5 18:44:28 1999 +++ linux/include/asm-alpha/dma.h Mon Aug 23 10:59:10 1999 @@ -346,7 +346,7 @@ /* From PCI */ -#ifdef CONFIG_PCI_QUIRKS +#ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) diff -u --recursive --new-file v2.3.14/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.3.14/linux/include/asm-alpha/io.h Mon Aug 16 10:33:58 1999 +++ linux/include/asm-alpha/io.h Thu Aug 19 08:28:49 1999 @@ -121,7 +121,7 @@ # define __raw_readl __readl # define __raw_readq __readq # define __raw_writeb __writeb -# define __raw_writeb __writew +# define __raw_writew __writew # define __raw_writel __writel # define __raw_writeq __writeq @@ -271,7 +271,7 @@ extern unsigned long ___raw_readl(unsigned long addr); extern unsigned long ___raw_readq(unsigned long addr); extern void ___raw_writeb(unsigned char b, unsigned long addr); -extern void ___raw_writeb(unsigned short b, unsigned long addr); +extern void ___raw_writew(unsigned short b, unsigned long addr); extern void ___raw_writel(unsigned int b, unsigned long addr); extern void ___raw_writeq(unsigned long b, unsigned long addr); @@ -291,8 +291,8 @@ #ifdef __raw_writeb # define writeb(v,a) ({ __raw_writeb((v),(a)); mb(); }) #endif -#ifdef __raw_writeb -# define writew(v,a) ({ __raw_writeb((v),(a)); mb(); }) +#ifdef __raw_writew +# define writew(v,a) ({ __raw_writew((v),(a)); mb(); }) #endif #ifdef __raw_writel # define writel(v,a) ({ __raw_writel((v),(a)); mb(); }) @@ -317,8 +317,8 @@ #ifndef __raw_writeb # define __raw_writeb(v,a) ___raw_writeb((v),(unsigned long)(a)) #endif -#ifndef __raw_writeb -# define __raw_writeb(v,a) ___raw_writeb((v),(unsigned long)(a)) +#ifndef __raw_writew +# define __raw_writew(v,a) ___raw_writew((v),(unsigned long)(a)) #endif #ifndef __raw_writel # define __raw_writel(v,a) ___raw_writel((v),(unsigned long)(a)) diff -u --recursive --new-file v2.3.14/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h --- v2.3.14/linux/include/asm-alpha/pgtable.h Thu Jul 29 13:37:22 1999 +++ linux/include/asm-alpha/pgtable.h Thu Aug 19 11:01:00 1999 @@ -621,4 +621,7 @@ #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) +#define io_remap_page_range(start, busaddr, size, prot) \ + remap_page_range(start, virt_to_phys(ioremap(busaddr)), size, prot) + #endif /* _ALPHA_PGTABLE_H */ diff -u --recursive --new-file v2.3.14/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.3.14/linux/include/asm-alpha/unistd.h Wed Aug 4 15:48:00 1999 +++ linux/include/asm-alpha/unistd.h Mon Aug 23 11:15:53 1999 @@ -502,19 +502,19 @@ sys_idle(); } -extern int sys_open(const char *, int, int); -static inline int open(const char * name, int mode, int flags) +extern long sys_open(const char *, int, int); +static inline long open(const char * name, int mode, int flags) { return sys_open(name, mode, flags); } -extern int sys_dup(int); -static inline int dup(int fd) +extern long sys_dup(int); +static inline long dup(int fd) { return sys_dup(fd); } -static inline int close(int fd) +static inline long close(int fd) { return sys_close(fd); } @@ -525,47 +525,47 @@ return sys_lseek(fd, off, whense); } -extern int sys_exit(int); -static inline int _exit(int value) +extern long sys_exit(int); +static inline long _exit(int value) { return sys_exit(value); } #define exit(x) _exit(x) -extern int sys_write(int, const char *, int); -static inline int write(int fd, const char * buf, int nr) +extern long sys_write(int, const char *, int); +static inline long write(int fd, const char * buf, int nr) { return sys_write(fd, buf, nr); } -extern int sys_read(int, char *, int); -static inline int read(int fd, char * buf, int nr) +extern long sys_read(int, char *, int); +static inline long read(int fd, char * buf, int nr) { return sys_read(fd, buf, nr); } extern int __kernel_execve(char *, char **, char **, struct pt_regs *); -static inline int execve(char * file, char ** argvp, char ** envp) +static inline long execve(char * file, char ** argvp, char ** envp) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); return __kernel_execve(file, argvp, envp, ®s); } -extern int sys_setsid(void); -static inline int setsid(void) +extern long sys_setsid(void); +static inline long setsid(void) { return sys_setsid(); } -extern int sys_sync(void); -static inline int sync(void) +extern long sys_sync(void); +static inline long sync(void) { return sys_sync(); } -extern int sys_wait4(int, int *, int, struct rusage *); +extern long sys_wait4(int, int *, int, struct rusage *); static inline pid_t waitpid(int pid, int * wait_stat, int flags) { return sys_wait4(pid, wait_stat, flags, NULL); @@ -576,8 +576,8 @@ return waitpid(-1,wait_stat,0); } -extern int sys_delete_module(const char *name); -static inline int delete_module(const char *name) +extern long sys_delete_module(const char *name); +static inline long delete_module(const char *name) { return sys_delete_module(name); } diff -u --recursive --new-file v2.3.14/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h --- v2.3.14/linux/include/asm-arm/dma.h Thu Aug 5 18:44:28 1999 +++ linux/include/asm-arm/dma.h Mon Aug 23 10:59:10 1999 @@ -135,7 +135,7 @@ #define NO_DMA 255 #endif -#ifdef CONFIG_PCI_QUIRKS +#ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) diff -u --recursive --new-file v2.3.14/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h --- v2.3.14/linux/include/asm-arm/unistd.h Wed Jul 28 10:30:10 1999 +++ linux/include/asm-arm/unistd.h Mon Aug 23 11:15:53 1999 @@ -306,39 +306,39 @@ #ifdef __KERNEL_SYSCALLS__ -static inline int idle(void) +static inline long idle(void) { - extern int sys_idle(void); + extern long sys_idle(void); return sys_idle(); } -static inline int pause(void) +static inline long pause(void) { - extern int sys_pause(void); + extern long sys_pause(void); return sys_pause(); } -static inline int sync(void) +static inline long sync(void) { - extern int sys_sync(void); + extern long sys_sync(void); return sys_sync(); } static inline pid_t setsid(void) { - extern int sys_setsid(void); + extern long sys_setsid(void); return sys_setsid(); } -static inline int write(int fd, const char *buf, off_t count) +static inline long write(int fd, const char *buf, off_t count) { - extern int sys_write(int, const char *, int); + extern long sys_write(int, const char *, int); return sys_write(fd, buf, count); } -static inline int read(int fd, char *buf, off_t count) +static inline long read(int fd, char *buf, off_t count) { - extern int sys_read(int, char *, int); + extern long sys_read(int, char *, int); return sys_read(fd, buf, count); } @@ -348,44 +348,44 @@ return sys_lseek(fd, offset, count); } -static inline int dup(int fd) +static inline long dup(int fd) { - extern int sys_dup(int); + extern long sys_dup(int); return sys_dup(fd); } -static inline int open(const char *file, int flag, int mode) +static inline long open(const char *file, int flag, int mode) { - extern int sys_open(const char *, int, int); + extern long sys_open(const char *, int, int); return sys_open(file, flag, mode); } -static inline int close(int fd) +static inline long close(int fd) { return sys_close(fd); } -static inline int _exit(int exitcode) +static inline long _exit(int exitcode) { - extern int sys_exit(int) __attribute__((noreturn)); + extern long sys_exit(int) __attribute__((noreturn)); return sys_exit(exitcode); } static inline pid_t waitpid(pid_t pid, int *wait_stat, int options) { - extern int sys_wait4(int, int *, int, struct rusage *); + extern long sys_wait4(int, int *, int, struct rusage *); return sys_wait4((int)pid, wait_stat, options, NULL); } -static inline int delete_module(const char *name) +static inline long delete_module(const char *name) { - extern int sys_delete_module(const char *name); + extern long sys_delete_module(const char *name); return sys_delete_module(name); } static inline pid_t wait(int * wait_stat) { - extern int sys_wait4(int, int *, int, struct rusage *); + extern long sys_wait4(int, int *, int, struct rusage *); return sys_wait4(-1, wait_stat, 0, NULL); } diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.3.14/linux/include/asm-i386/atomic.h Wed Aug 18 16:43:28 1999 +++ linux/include/asm-i386/atomic.h Tue Aug 24 17:02:07 1999 @@ -73,6 +73,17 @@ return c != 0; } +extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + LOCK "addl %2,%0; sets %1" + :"=m" (__atomic_fool_gcc(v)), "=qm" (c) + :"ir" (i), "m" (__atomic_fool_gcc(v))); + return c; +} + /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ __asm__ __volatile__(LOCK "andl %0,%1" \ diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/dma.h linux/include/asm-i386/dma.h --- v2.3.14/linux/include/asm-i386/dma.h Wed Aug 18 16:44:06 1999 +++ linux/include/asm-i386/dma.h Tue Aug 24 17:09:25 1999 @@ -289,7 +289,7 @@ /* From PCI */ -#ifdef CONFIG_PCI_QUIRKS +#ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h --- v2.3.14/linux/include/asm-i386/hardirq.h Wed Aug 18 16:43:29 1999 +++ linux/include/asm-i386/hardirq.h Tue Aug 24 17:09:19 1999 @@ -53,7 +53,7 @@ static inline int hardirq_trylock(int cpu) { - return !atomic_read(&global_irq_count) && !test_bit(0,&global_irq_lock); + return !local_irq_count[cpu] && !test_bit(0,&global_irq_lock); } #define hardirq_endlock(cpu) do { } while (0) diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/io.h linux/include/asm-i386/io.h --- v2.3.14/linux/include/asm-i386/io.h Wed Aug 18 16:43:57 1999 +++ linux/include/asm-i386/io.h Wed Aug 25 14:57:47 1999 @@ -152,10 +152,16 @@ #define readb(addr) (*(volatile unsigned char *) __io_virt(addr)) #define readw(addr) (*(volatile unsigned short *) __io_virt(addr)) #define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel #define memset_io(a,b,c) memset(__io_virt(a),(b),(c)) #define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c)) diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.3.14/linux/include/asm-i386/pgtable.h Wed Aug 18 16:43:30 1999 +++ linux/include/asm-i386/pgtable.h Mon Aug 23 14:48:52 1999 @@ -525,4 +525,6 @@ #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) +#define io_remap_page_range remap_page_range + #endif /* _I386_PAGE_H */ diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/semaphore-helper.h linux/include/asm-i386/semaphore-helper.h --- v2.3.14/linux/include/asm-i386/semaphore-helper.h Wed Feb 17 09:34:13 1999 +++ linux/include/asm-i386/semaphore-helper.h Wed Dec 31 16:00:00 1969 @@ -1,94 +0,0 @@ -#ifndef _I386_SEMAPHORE_HELPER_H -#define _I386_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (atomic_read(&sem->count) <= 0) - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * We must undo the sem->count down_interruptible() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - atomic_inc(&sem->count); - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * We must undo the sem->count down_trylock() increment while we are - * protected by the spinlock in order to make atomic this atomic_inc() with the - * atomic_read() in wake_one_more(), otherwise we can race. -arca - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - atomic_inc(&sem->count); - else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h --- v2.3.14/linux/include/asm-i386/semaphore.h Wed Aug 18 16:43:30 1999 +++ linux/include/asm-i386/semaphore.h Tue Aug 24 17:02:33 1999 @@ -35,7 +35,7 @@ struct semaphore { atomic_t count; - int waking; + int sleepers; wait_queue_head_t wait; #if WAITQUEUE_DEBUG long __magic; @@ -71,7 +71,7 @@ * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well. */ atomic_set(&sem->count, val); - sem->waking = 0; + sem->sleepers = 0; init_waitqueue_head(&sem->wait); #if WAITQUEUE_DEBUG sem->__magic = (int)&sem->__magic; diff -u --recursive --new-file v2.3.14/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.3.14/linux/include/asm-i386/system.h Wed Aug 18 16:43:29 1999 +++ linux/include/asm-i386/system.h Mon Aug 23 14:48:49 1999 @@ -130,24 +130,26 @@ /* * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. --ANK */ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { switch (size) { case 1: - __asm__("xchgb %b0,%1" + __asm__ __volatile__("xchgb %b0,%1" :"=q" (x) :"m" (*__xg(ptr)), "0" (x) :"memory"); break; case 2: - __asm__("xchgw %w0,%1" + __asm__ __volatile__("xchgw %w0,%1" :"=r" (x) :"m" (*__xg(ptr)), "0" (x) :"memory"); break; case 4: - __asm__("xchgl %0,%1" + __asm__ __volatile__("xchgl %0,%1" :"=r" (x) :"m" (*__xg(ptr)), "0" (x) :"memory"); diff -u --recursive --new-file v2.3.14/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v2.3.14/linux/include/asm-m68k/pgtable.h Mon Aug 9 12:27:31 1999 +++ linux/include/asm-m68k/pgtable.h Thu Aug 19 11:01:00 1999 @@ -777,4 +777,6 @@ #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) +#define io_remap_page_range remap_page_range + #endif /* _M68K_PGTABLE_H */ diff -u --recursive --new-file v2.3.14/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h --- v2.3.14/linux/include/asm-ppc/dma.h Thu Aug 5 18:44:28 1999 +++ linux/include/asm-ppc/dma.h Mon Aug 23 10:59:10 1999 @@ -399,7 +399,7 @@ extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ extern void free_dma(unsigned int dmanr); /* release it again */ -#ifdef CONFIG_PCI_QUIRKS +#ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) diff -u --recursive --new-file v2.3.14/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h --- v2.3.14/linux/include/asm-ppc/pgtable.h Sun Jul 25 13:45:25 1999 +++ linux/include/asm-ppc/pgtable.h Thu Aug 19 11:01:00 1999 @@ -647,5 +647,7 @@ #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) +#define io_remap_page_range remap_page_range + #endif __ASSEMBLY__ #endif /* _PPC_PGTABLE_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/arequipa.h linux/include/linux/arequipa.h --- v2.3.14/linux/include/linux/arequipa.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/arequipa.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,63 @@ +/* arequipa.h - Arequipa interface definitions */ + +/* Written 1996-1998 by Jean-Michel Pittet and Werner Almesberger, EPFL ICA */ + + +#ifndef _LINUX_AREQUIPA_H +#define _LINUX_AREQUIPA_H + +#include + + +enum arequipa_msg_type { amt_invalid,amt_close,amt_sync }; + +struct arequipa_msg { + enum arequipa_msg_type type; + void *ptr; +}; + + +#define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) +#define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) +#define AREQUIPA_EXPECT _IO('a',ATMIOC_AREQUIPA+2) +#define AREQUIPA_CLOSE _IO('a',ATMIOC_AREQUIPA+3) +#define AREQUIPA_CTRL _IO('a',ATMIOC_AREQUIPA+4) +/* #define AREQUIPA_CLS3RD removed */ +#define AREQUIPA_SYNCREQ _IO('a',ATMIOC_AREQUIPA+6) +/* #define AREQUIPA_SYNCACK removed */ +#define AREQUIPA_WORK _IO('a',ATMIOC_AREQUIPA+8) +#define AREQUIPA_RENEGOTIATE _IO('a',ATMIOC_AREQUIPA+9) + + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + + +extern struct atm_vcc *aqd; /* for net/atm/proc.c */ +/* extern struct rtable *arequipa_rt; - not needed; we use a local dcl instead*/ +extern struct net_device *arequipa_dev; + +int atm_init_arequipa(void); +int arequipa_attach(struct socket *lower,struct sock *upper, + unsigned long generation); + +int arequipa_preset(struct socket *lower,struct sock *upper); +int arequipa_expect(struct sock *upper,int on,int kmalloc_flags); +int arequipa_incoming(struct socket *lower); +int arequipa_close(struct sock *upper); +int arequipa_renegotiate(struct sock *upper,struct atm_qos *u_qos); +void arequipa_synchronize(void); +void arequipa_work(void); + +int arequipad_attach(struct atm_vcc *vcc); + + +#endif /* __KERNEL__ */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atm.h linux/include/linux/atm.h --- v2.3.14/linux/include/linux/atm.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm.h Mon Aug 23 14:49:40 1999 @@ -0,0 +1,244 @@ +/* atm.h - general ATM declarations */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +/* + * WARNING: User-space programs should not #include directly. + * Instead, #include + */ + +#ifndef _LINUX_ATM_H +#define _LINUX_ATM_H + +/* + * BEGIN_xx and END_xx markers are used for automatic generation of + * documentation. Do not change them. + */ + +#ifdef __KERNEL__ +#include +#include +#endif +#include +#include + + +/* general ATM constants */ +#define ATM_CELL_SIZE 53 /* ATM cell size incl. header */ +#define ATM_CELL_PAYLOAD 48 /* ATM payload size */ +#define ATM_AAL0_SDU 52 /* AAL0 SDU size */ +#define ATM_MAX_AAL34_PDU 65535 /* maximum AAL3/4 PDU payload */ +#define ATM_AAL5_TRAILER 8 /* AAL5 trailer size */ +#define ATM_MAX_AAL5_PDU 65535 /* maximum AAL5 PDU payload */ +#define ATM_MAX_CDV 9999 /* maximum (default) CDV */ +#define ATM_NOT_RSV_VCI 32 /* first non-reserved VCI value */ + +#define ATM_MAX_VPI 255 /* maximum VPI at the UNI */ +#define ATM_MAX_VPI_NNI 4096 /* maximum VPI at the NNI */ +#define ATM_MAX_VCI 65535 /* maximum VCI */ + + +/* "protcol" values for the socket system call */ +#define ATM_NO_AAL 0 /* AAL not specified */ +#define ATM_AAL0 13 /* "raw" ATM cells */ +#define ATM_AAL1 1 /* AAL1 (CBR) */ +#define ATM_AAL2 2 /* AAL2 (VBR) */ +#define ATM_AAL34 3 /* AAL3/4 (data) */ +#define ATM_AAL5 5 /* AAL5 (data) */ + +/* socket option name coding functions */ + +#define __SO_ENCODE(l,n,t) (((l) << 22) | ((n) << 16) | sizeof(t)) +#define __SO_LEVEL(c) ((c) >> 22) +#define __SO_NUMBER(c) (((c) >> 16) & 0x3f) +#define __SO_SIZE(c) ((c) & 0x3fff) + +/* + * ATM layer + */ + +#define SO_SETCLP __SO_ENCODE(SOL_ATM,0,int) + /* set CLP bit value - TODO */ +#define SO_CIRANGE __SO_ENCODE(SOL_ATM,1,struct atm_cirange) + /* connection identifier range; socket must be + bound or connected */ +#define SO_ATMQOS __SO_ENCODE(SOL_ATM,2,struct atm_qos) + /* Quality of Service setting */ +#define SO_ATMSAP __SO_ENCODE(SOL_ATM,3,struct atm_sap) + /* Service Access Point */ + +/* + * Note @@@: since the socket layers don't really distinguish the control and + * the data plane but generally seems to be data plane-centric, any layer is + * about equally wrong for the SAP. If you have a better idea about this, + * please speak up ... + */ + +/* socket layer */ +#define SO_BCTXOPT __SO_ENCODE(SOL_SOCKET,16,struct atm_buffconst) + /* not ATM specific - should go somewhere else */ +#define SO_BCRXOPT __SO_ENCODE(SOL_SOCKET,17,struct atm_buffconst) + + +/* for SO_BCTXOPT and SO_BCRXOPT */ + +struct atm_buffconst { + unsigned long buf_fac; /* buffer alignment factor */ + unsigned long buf_off; /* buffer alignment offset */ + unsigned long size_fac; /* buffer size factor */ + unsigned long size_off; /* buffer size offset */ + unsigned long min_size; /* minimum size */ + unsigned long max_size; /* maximum size, 0 = unlimited */ +}; + + +/* ATM cell header (for AAL0) */ + +/* BEGIN_CH */ +#define ATM_HDR_GFC_MASK 0xf0000000 +#define ATM_HDR_GFC_SHIFT 28 +#define ATM_HDR_VPI_MASK 0x0ff00000 +#define ATM_HDR_VPI_SHIFT 20 +#define ATM_HDR_VCI_MASK 0x000ffff0 +#define ATM_HDR_VCI_SHIFT 4 +#define ATM_HDR_PTI_MASK 0x0000000e +#define ATM_HDR_PTI_SHIFT 1 +#define ATM_HDR_CLP 0x00000001 +/* END_CH */ + + +/* PTI codings */ + +/* BEGIN_PTI */ +#define ATM_PTI_US0 0 /* user data cell, congestion not exp, SDU-type 0 */ +#define ATM_PTI_US1 1 /* user data cell, congestion not exp, SDU-type 1 */ +#define ATM_PTI_UCES0 2 /* user data cell, cong. experienced, SDU-type 0 */ +#define ATM_PTI_UCES1 3 /* user data cell, cong. experienced, SDU-type 1 */ +#define ATM_PTI_SEGF5 4 /* segment OAM F5 flow related cell */ +#define ATM_PTI_E2EF5 5 /* end-to-end OAM F5 flow related cell */ +#define ATM_PTI_RSV_RM 6 /* reserved for traffic control/resource mgmt */ +#define ATM_PTI_RSV 7 /* reserved */ +/* END_PTI */ + + +/* + * The following items should stay in linux/atm.h, which should be linked to + * netatm/atm.h + */ + +/* Traffic description */ + +#define ATM_NONE 0 /* no traffic */ +#define ATM_UBR 1 +#define ATM_CBR 2 +#define ATM_VBR 3 +#define ATM_ABR 4 +#define ATM_ANYCLASS 5 /* compatible with everything */ + +#define ATM_MAX_PCR -1 /* maximum available PCR */ + +struct atm_trafprm { + unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */ + int max_pcr; /* maximum PCR in cells per second */ + int pcr; /* desired PCR in cells per second */ + int min_pcr; /* minimum PCR in cells per second */ + int max_cdv; /* maximum CDV in microseconds */ + int max_sdu; /* maximum SDU in bytes */ +}; + +struct atm_qos { + struct atm_trafprm txtp; /* parameters in TX direction */ + struct atm_trafprm rxtp; /* parameters in RX direction */ + unsigned char aal; +}; + +/* PVC addressing */ + +#define ATM_ITF_ANY -1 /* "magic" PVC address values */ +#define ATM_VPI_ANY -1 +#define ATM_VCI_ANY -1 +#define ATM_VPI_UNSPEC -2 +#define ATM_VCI_UNSPEC -2 + + +struct sockaddr_atmpvc { + unsigned short sap_family; /* address family, AF_ATMPVC */ + struct { /* PVC address */ + short itf; /* ATM interface */ + short vpi; /* VPI (only 8 bits at UNI) */ + int vci; /* VCI (only 16 bits at UNI) */ + } sap_addr; /* PVC address */ +}; + +/* SVC addressing */ + +#define ATM_ESA_LEN 20 /* ATM End System Address length */ +#define ATM_E164_LEN 12 /* maximum E.164 number length */ + +#define ATM_AFI_DCC 0x39 /* DCC ATM Format */ +#define ATM_AFI_ICD 0x47 /* ICD ATM Format */ +#define ATM_AFI_E164 0x45 /* E.164 ATM Format */ +#define ATM_AFI_LOCAL 0x49 /* Local ATM Format */ + +#define ATM_AFI_DCC_GROUP 0xBD /* DCC ATM Group Format */ +#define ATM_AFI_ICD_GROUP 0xC5 /* ICD ATM Group Format */ +#define ATM_AFI_E164_GROUP 0xC3 /* E.164 ATM Group Format */ +#define ATM_AFI_LOCAL_GROUP 0xC7 /* Local ATM Group Format */ + +#define ATM_LIJ_NONE 0 /* no leaf-initiated join */ +#define ATM_LIJ 1 /* request joining */ +#define ATM_LIJ_RPJ 2 /* set to root-prompted join */ +#define ATM_LIJ_NJ 3 /* set to network join */ + + +struct sockaddr_atmsvc { + unsigned short sas_family; /* address family, AF_ATMSVC */ + struct { /* SVC address */ + unsigned char prv[ATM_ESA_LEN];/* private ATM address */ + char pub[ATM_E164_LEN+1]; /* public address (E.164) */ + /* unused addresses must be bzero'ed */ + char lij_type; /* role in LIJ call; one of ATM_LIJ* */ + uint32_t lij_id; /* LIJ call identifier */ + } sas_addr; /* SVC address */ +}; + + +static __inline__ int atmsvc_addr_in_use(struct sockaddr_atmsvc addr) +{ + return *addr.sas_addr.prv || *addr.sas_addr.pub; +} + + +static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr) +{ + return addr.sap_addr.itf || addr.sap_addr.vpi || addr.sap_addr.vci; +} + + +/* + * Some stuff for linux/sockios.h + */ + +struct atmif_sioc { + int number; + int length; + void *arg; +}; + + +#define ATM_CREATE_LEAF _IO('a',ATMIOC_SPECIAL+2) + /* create a point-to-multipoint leaf socket */ + + +#ifdef __KERNEL__ + +#include /* struct net_proto */ + + +void atmpvc_proto_init(struct net_proto *pro); +void atmsvc_proto_init(struct net_proto *pro); + +#endif /* __KERNEL__ */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atm_eni.h linux/include/linux/atm_eni.h --- v2.3.14/linux/include/linux/atm_eni.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm_eni.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,15 @@ +/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by + driver-specific utilities) */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + +#ifndef LINUX_ATM_ENI_H +#define LINUX_ATM_ENI_H + +#include + +#define ENI_MEMDUMP _IOW('a',ATMIOC_SARPRV,struct atmif_sioc) + /* printk memory map */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atm_nicstar.h linux/include/linux/atm_nicstar.h --- v2.3.14/linux/include/linux/atm_nicstar.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm_nicstar.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * atm_nicstar.h + * + * Driver-specific declarations for use by NICSTAR driver specific utils. + * + * Author: Rui Prior + * + * (C) INESC 1998 + * + ******************************************************************************/ + + +#ifndef LINUX_ATM_NICSTAR_H +#define LINUX_ATM_NICSTAR_H + +/* Note: non-kernel programs including this file must also include + * sys/types.h for struct timeval + */ + +#include + +#define NS_GETPSTAT _IOWR('a',ATMIOC_SARPRV+1,struct atmif_sioc) + /* get pool statistics */ +#define NS_SETBUFLEV _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc) + /* set buffer level markers */ +#define NS_ADJBUFLEV _IO('a',ATMIOC_SARPRV+3) + /* adjust buffer level */ + +typedef struct buf_nr +{ + unsigned min; + unsigned init; + unsigned max; +} buf_nr; + + +typedef struct pool_levels +{ + int buftype; + int count; /* (At least for now) only used in NS_GETPSTAT */ + buf_nr level; +} pool_levels; + +/* type must be one of the following: */ +#define NS_BUFTYPE_SMALL 1 +#define NS_BUFTYPE_LARGE 2 +#define NS_BUFTYPE_HUGE 3 +#define NS_BUFTYPE_IOVEC 4 + + +#endif /* LINUX_ATM_NICSTAR_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/atm_suni.h linux/include/linux/atm_suni.h --- v2.3.14/linux/include/linux/atm_suni.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm_suni.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,19 @@ +/* atm_suni.h - Driver-specific declarations of the SUNI driver (for use by + driver-specific utilities) */ + +/* Written 1998 by Werner Almesberger, EPFL ICA */ + + +#ifndef LINUX_ATM_SUNI_H +#define LINUX_ATM_SUNI_H + +#include + +#define SUNI_GETLOOP _IOR('a',ATMIOC_PHYPRV,int) /* get loopback mode */ +#define SUNI_SETLOOP _IO('a',ATMIOC_PHYPRV+1) /* set loopback mode */ + +#define SUNI_LM_NONE 0 /* no loopback */ +#define SUNI_LM_DIAG 1 /* diagnostic (i.e. loop TX to RX) */ +#define SUNI_LM_LOOP 2 /* line (i.e. loop RX to TX) */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atm_tcp.h linux/include/linux/atm_tcp.h --- v2.3.14/linux/include/linux/atm_tcp.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm_tcp.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,46 @@ +/* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by + driver-specific utilities) */ + +/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef LINUX_ATM_TCP_H +#define LINUX_ATM_TCP_H + +#ifdef __KERNEL__ +#include +#endif +#include + + +/* + * All values are in network byte order + */ + +struct atmtcp_hdr { + uint16_t vpi; + uint16_t vci; + uint32_t length; /* ... of data part */ +}; + + +#define SIOCSIFATMTCP _IO('a',ATMIOC_ITF) /* set ATMTCP mode */ +#define ATMTCP_CREATE _IO('a',ATMIOC_ITF+14) /* create persistent ATMTCP + interface */ +#define ATMTCP_REMOVE _IO('a',ATMIOC_ITF+15) /* destroy persistent ATMTCP + interface*/ + + +#ifdef __KERNEL__ + +struct atm_tcp_ops { + int (*attach)(struct atm_vcc *vcc,int itf); + int (*create_persistent)(int itf); + int (*remove_persistent)(int itf); +}; + +extern struct atm_tcp_ops atm_tcp_ops; + +#endif + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atm_zatm.h linux/include/linux/atm_zatm.h --- v2.3.14/linux/include/linux/atm_zatm.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atm_zatm.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,54 @@ +/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by + driver-specific utilities) */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + +#ifndef LINUX_ATM_ZATM_H +#define LINUX_ATM_ZATM_H + +/* + * Note: non-kernel programs including this file must also include + * sys/types.h for struct timeval + */ + +#include + +#define ZATM_GETPOOL _IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc) + /* get pool statistics */ +#define ZATM_GETPOOLZ _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc) + /* get statistics and zero */ +#define ZATM_SETPOOL _IOW('a',ATMIOC_SARPRV+3,struct atmif_sioc) + /* set pool parameters */ +#define ZATM_GETTHIST _IOW('a',ATMIOC_SARPRV+4,struct atmif_sioc) + /* get a history of timer + differences */ + +struct zatm_pool_info { + int ref_count; /* free buffer pool usage counters */ + int low_water,high_water; /* refill parameters */ + int rqa_count,rqu_count; /* queue condition counters */ + int offset,next_off; /* alignment optimizations: offset */ + int next_cnt,next_thres; /* repetition counter and threshold */ +}; + +struct zatm_pool_req { + int pool_num; /* pool number */ + struct zatm_pool_info info; /* actual information */ +}; + +struct zatm_t_hist { + struct timeval real; /* real (wall-clock) time */ + struct timeval expected; /* expected real time */ +}; + + +#define ZATM_OAM_POOL 0 /* free buffer pool for OAM cells */ +#define ZATM_AAL0_POOL 1 /* free buffer pool for AAL0 cells */ +#define ZATM_AAL5_POOL_BASE 2 /* first AAL5 free buffer pool */ +#define ZATM_LAST_POOL ZATM_AAL5_POOL_BASE+10 /* max. 64 kB */ + +#define ZATM_TIMER_HISTORY_SIZE 16 /* number of timer adjustments to + record; must be 2^n */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmarp.h linux/include/linux/atmarp.h --- v2.3.14/linux/include/linux/atmarp.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmarp.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,42 @@ +/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef _LINUX_ATMARP_H +#define _LINUX_ATMARP_H + +#ifdef __KERNEL__ +#include +#endif +#include + + +#define ATMARP_RETRY_DELAY 30 /* request next resolution or forget + NAK after 30 sec - should go into + atmclip.h */ +#define ATMARP_MAX_UNRES_PACKETS 5 /* queue that many packets while + waiting for the resolver */ + + +#define ATMARPD_CTRL _IO('a',ATMIOC_CLIP+1) /* become atmarpd ctrl sock */ +#define ATMARP_MKIP _IO('a',ATMIOC_CLIP+2) /* attach socket to IP */ +#define ATMARP_SETENTRY _IO('a',ATMIOC_CLIP+3) /* fill or hide ARP entry */ +#define ATMARP_ENCAP _IO('a',ATMIOC_CLIP+5) /* change encapsulation */ + + +enum atmarp_ctrl_type { + act_invalid, /* catch uninitialized structures */ + act_need, /* need address resolution */ + act_up, /* interface is coming up */ + act_down, /* interface is going down */ + act_change /* interface configuration has changed */ +}; + +struct atmarp_ctrl { + enum atmarp_ctrl_type type; /* message type */ + int itf_num;/* interface number (if present) */ + uint32_t ip; /* IP address (act_need only) */ +}; + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmclip.h linux/include/linux/atmclip.h --- v2.3.14/linux/include/linux/atmclip.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmclip.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,25 @@ +/* atmclip.h - Classical IP over ATM */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef LINUX_ATMCLIP_H +#define LINUX_ATMCLIP_H + +#include +#include + + +#define RFC1483LLC_LEN 8 /* LLC+OUI+PID = 8 */ +#define RFC1626_MTU 9180 /* RFC1626 default MTU */ + +#define CLIP_DEFAULT_IDLETIMER 1200 /* 20 minutes, see RFC1755 */ +#define CLIP_CHECK_INTERVAL 10 /* check every ten seconds */ + +#define SIOCMKCLIP _IO('a',ATMIOC_CLIP) /* create IP interface */ + +#ifdef __KERNEL__ +extern const unsigned char llc_oui[6]; +#endif + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmdev.h linux/include/linux/atmdev.h --- v2.3.14/linux/include/linux/atmdev.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmdev.h Tue Aug 24 17:12:23 1999 @@ -0,0 +1,362 @@ +/* atmdev.h - ATM device driver declarations and various related items */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef LINUX_ATMDEV_H +#define LINUX_ATMDEV_H + + +#include +#include + + +#define ESI_LEN 6 + +#define ATM_OC3_PCR (155520000/270*260/8/53) + /* OC3 link rate: 155520000 bps + SONET overhead: /270*260 (9 section, 1 path) + bits per cell: /8/53 + max cell rate: 353207.547 cells/sec */ + +#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer + quota per PDU */ + +#define ATM_SD(s) ((s)->sk->protinfo.af_atm) + + +struct atm_aal_stats { + long tx,tx_err; /* TX okay and errors */ + long rx,rx_err; /* RX okay and errors */ + long rx_drop; /* RX out of memory */ +}; + + +struct atm_dev_stats { + struct atm_aal_stats aal0; + struct atm_aal_stats aal34; + struct atm_aal_stats aal5; +}; + + +#define ATM_GETLINKRATE _IOW('a',ATMIOC_ITF+1,struct atmif_sioc) + /* get link rate */ +#define ATM_GETNAMES _IOW('a',ATMIOC_ITF+3,struct atm_iobuf) + /* get interface names (numbers) */ +#define ATM_GETTYPE _IOW('a',ATMIOC_ITF+4,struct atmif_sioc) + /* get interface type name */ +#define ATM_GETESI _IOW('a',ATMIOC_ITF+5,struct atmif_sioc) + /* get interface ESI */ +#define ATM_GETADDR _IOW('a',ATMIOC_ITF+6,struct atmif_sioc) + /* get itf's local ATM addr. list */ +#define ATM_RSTADDR _IOW('a',ATMIOC_ITF+7,struct atmif_sioc) + /* reset itf's ATM address list */ +#define ATM_ADDADDR _IOW('a',ATMIOC_ITF+8,struct atmif_sioc) + /* add a local ATM address */ +#define ATM_DELADDR _IOW('a',ATMIOC_ITF+9,struct atmif_sioc) + /* remove a local ATM address */ +#define ATM_GETCIRANGE _IOW('a',ATMIOC_ITF+10,struct atmif_sioc) + /* get connection identifier range */ +#define ATM_SETCIRANGE _IOW('a',ATMIOC_ITF+11,struct atmif_sioc) + /* set connection identifier range */ +#define ATM_SETESI _IOW('a',ATMIOC_ITF+12,struct atmif_sioc) + /* set interface ESI */ +#define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) + /* force interface ESI */ +#define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) + /* get AAL layer statistics */ +#define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) + /* get AAL layer statistics and zero */ +#define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int) + /* enable or disable single-copy */ + +/* for ATM_GETTYPE */ +#define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */ + + + +struct atm_iobuf { + int length; + void *buffer; +}; + +/* for ATM_GETCIRANGE / ATM_SETCIRANGE */ + +#define ATM_CI_MAX -1 /* use maximum range of VPI/VCI */ + +struct atm_cirange { + char vpi_bits; /* 1..8, ATM_CI_MAX (-1) for maximum */ + char vci_bits; /* 1..16, ATM_CI_MAX (-1) for maximum */ +}; + +/* for ATM_SETSC; actually taken from the ATM_VF number space */ + +#define ATM_SC_RX 1024 /* enable RX single-copy */ +#define ATM_SC_TX 2048 /* enable TX single-copy */ + +#define ATM_BACKLOG_DEFAULT 32 /* if we get more, we're likely to time out + anyway */ + +/* MF: change_qos (Modify) flags */ + +#define ATM_MF_IMMED 1 /* Block until change is effective */ +#define ATM_MF_INC_RSV 2 /* Change reservation on increase */ +#define ATM_MF_INC_SHP 4 /* Change shaping on increase */ +#define ATM_MF_DEC_RSV 8 /* Change reservation on decrease */ +#define ATM_MF_DEC_SHP 16 /* Change shaping on decrease */ +#define ATM_MF_BWD 32 /* Set the backward direction parameters */ + +#define ATM_MF_SET (ATM_MF_INC_RSV | ATM_MF_INC_SHP | ATM_MF_DEC_RSV | \ + ATM_MF_DEC_SHP | ATM_MF_BWD) + +/* + * ATM_VS_* are used to express VC state in a human-friendly way. + */ + +#define ATM_VS_IDLE 0 /* VC is not used */ +#define ATM_VS_CONNECTED 1 /* VC is connected */ +#define ATM_VS_CLOSING 2 /* VC is closing */ +#define ATM_VS_LISTEN 3 /* VC is listening for incoming setups */ +#define ATM_VS_INUSE 4 /* VC is in use (registered with atmsigd) */ +#define ATM_VS_BOUND 5 /* VC is bound */ + +#define ATM_VS2TXT_MAP \ + "IDLE", "CONNECTED", "CLOSING", "LISTEN", "INUSE", "BOUND" + + +#ifdef __KERNEL__ + +#include /* wait_queue_head_t */ +#include /* struct timeval */ +#include +#include /* struct sk_buff */ +#include +#include +#include + +#ifdef CONFIG_PROC_FS +#include +#endif + +#ifdef CONFIG_AREQUIPA +#include /* for struct sock */ +#endif + + +#define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared + by device driver. */ +#define ATM_VF_READY 2 /* VC is ready to transfer data. Set by device + driver, cleared by anybody. */ +#define ATM_VF_PARTIAL 4 /* resources are bound to PVC (partial PVC + setup), controlled by socket layer */ +#define ATM_VF_BOUND 16384 /* local SAP is set, controlled by SVC socket + layer */ +#define ATM_VF_REGIS 8 /* registered with demon, controlled by SVC + socket layer */ +#define ATM_VF_RELEASED 16 /* demon has indicated/requested release, + controlled by SVC socket layer */ +#define ATM_VF_HASQOS 32 /* QOS parameters have been set */ +#define ATM_VF_LISTEN 64 /* socket is used for listening */ +#define ATM_VF_META 128 /* SVC socket isn't used for normal data + traffic and doesn't depend on signaling + to be available */ +#define ATM_VF_AQREL 256 /* Arequipa VC is being released */ +#define ATM_VF_AQDANG 512 /* VC is in Arequipa's dangling list */ +#define ATM_VF_SCRX ATM_SC_RX /* 1024; allow single-copy in the RX dir. */ +#define ATM_VF_SCTX ATM_SC_TX /* 2048; allow single-copy in the TX dir. */ +#define ATM_VF_SESSION 4096 /* VCC is p2mp session control descriptor */ +#define ATM_VF_HASSAP 8192 /* SAP has been set */ +#define ATM_VF_CLOSE 32768 /* asynchronous close - treat like VF_RELEASED*/ + +#define ATM_VF2VS(flags) \ + ((flags) & ATM_VF_READY ? ATM_VS_CONNECTED : \ + (flags) & ATM_VF_RELEASED ? ATM_VS_CLOSING : \ + (flags) & ATM_VF_LISTEN ? ATM_VS_LISTEN : \ + (flags) & ATM_VF_REGIS ? ATM_VS_INUSE : \ + (flags) & ATM_VF_BOUND ? ATM_VS_BOUND : ATM_VS_IDLE) + +#define ATM_DF_CLOSE 1 /* close device when last VCC is closed */ + +#define ATM_PHY_SIG_LOST 0 /* no carrier/light */ +#define ATM_PHY_SIG_UNKNOWN 1 /* carrier/light status is unknown */ +#define ATM_PHY_SIG_FOUND 2 /* carrier/light okay */ + +#define ATM_ATMOPT_CLP 1 /* set CLP bit */ + + +struct atm_vcc { + unsigned short flags; /* VCC flags (ATM_VF_*) */ + unsigned char family; /* address family; 0 if unused */ + short vpi; /* VPI and VCI (types must be equal */ + /* with sockaddr) */ + int vci; + unsigned long aal_options; /* AAL layer options */ + unsigned long atm_options; /* ATM layer options */ + struct atm_dev *dev; /* device back pointer */ + struct atm_qos qos; /* QOS */ + struct atm_sap sap; /* SAP */ + unsigned long tx_quota,rx_quota; /* buffer quotas */ + atomic_t tx_inuse,rx_inuse; /* buffer space in use */ + void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); + void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ + struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size); + /* TX allocation routine - can be */ + /* modified by protocol or by driver.*/ + /* NOTE: this interface will change */ + int (*push_oam)(struct atm_vcc *vcc,void *cell); + void *dev_data; /* per-device data */ + void *proto_data; /* per-protocol data */ + struct timeval timestamp; /* AAL timestamps */ + struct sk_buff_head recvq; /* receive queue */ + struct atm_aal_stats *stats; /* pointer to AAL stats group */ + wait_queue_head_t sleep; /* if socket is busy */ + wait_queue_head_t wsleep; /* if waiting for write buffer space */ + struct atm_vcc *prev,*next; + /* SVC part --- may move later ------------------------------------- */ + short itf; /* interface number */ + struct sockaddr_atmsvc local; + struct sockaddr_atmsvc remote; + void (*callback)(struct atm_vcc *vcc); + struct sk_buff_head listenq; + int backlog_quota; /* number of connection requests we */ + /* can still accept */ + int reply; + /* Multipoint part ------------------------------------------------- */ + struct atm_vcc *session; /* session VCC descriptor */ + /* Other stuff ----------------------------------------------------- */ + void *user_back; /* user backlink - not touched */ +#ifdef CONFIG_AREQUIPA + struct sock *upper; /* our "master" */ + struct socket *sock; /* back pointer to our own socket */ + struct atm_vcc *aq_next,*aq_prev; /* for consistency checks */ + unsigned long generation; /* generation number */ +#endif +}; + + +struct atm_dev_addr { + struct sockaddr_atmsvc addr; /* ATM address */ + struct atm_dev_addr *next; /* next address */ +}; + + +struct atm_dev { + const struct atmdev_ops *ops; /* device operations; NULL if unused */ + const struct atmphy_ops *phy; /* PHY operations, may be undefined */ + /* (NULL) */ + const char *type; /* device type name */ + int number; /* device index */ + struct atm_vcc *vccs; /* VCC table (or NULL) */ + struct atm_vcc *last; /* last VCC (or undefined) */ + void *dev_data; /* per-device data */ + void *phy_data; /* private PHY date */ + unsigned long flags; /* device flags (ATM_DF_*) */ + struct atm_dev_addr *local; /* local ATM addresses */ + unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ + struct atm_cirange ci_range; /* VPI/VCI range */ + struct atm_dev_stats stats; /* statistics */ + char signal; /* signal status (ATM_PHY_SIG_*) */ + int link_rate; /* link rate (default: OC3) */ +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_entry; /* proc entry */ + char *proc_name; /* proc entry name */ +#endif + struct atm_dev *prev,*next; /* linkage */ +}; + + +/* + * ioctl, getsockopt, setsockopt, and sg_send are optional and can be set to + * NULL. */ + +/* OF: send_Oam Flags */ + +#define ATM_OF_IMMED 1 /* Attempt immediate delivery */ +#define ATM_OF_INRATE 2 /* Attempt in-rate delivery */ + +struct atmdev_ops { /* only send is required */ + void (*dev_close)(struct atm_dev *dev); + int (*open)(struct atm_vcc *vcc,short vpi,int vci); + void (*close)(struct atm_vcc *vcc); + int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg); + int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen); + int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, + void *optval,int optlen); + int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); + int (*sg_send)(struct atm_vcc *vcc,unsigned long start, + unsigned long size); +#if 0 /* keep the current hack for now */ + int (*send_iovec)(struct atm_vcc *vcc,struct iovec *iov,int size, + void (*discard)(struct atm_vcc *vcc,void *user),void *user); +#endif + int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); + void (*phy_put)(struct atm_dev *dev,unsigned char value, + unsigned long addr); + unsigned char (*phy_get)(struct atm_dev *dev,unsigned long addr); + void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb, + unsigned long start,unsigned long dest,int len); + int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags); + void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb); + /* @@@ temporary hack */ + int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page); +}; + + +struct atmphy_ops { + int (*start)(struct atm_dev *dev); + int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg); + void (*interrupt)(struct atm_dev *dev); +}; + +struct atm_skb_data { + struct atm_vcc *vcc; /* ATM VCC */ + int iovcnt; /* 0 for "normal" operation */ + unsigned long atm_options; /* ATM layer options */ +}; + +#define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb)) + +struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, + int number,unsigned long flags); /* number == -1: pick first available */ +struct atm_dev *atm_find_dev(int number); +void atm_dev_deregister(struct atm_dev *dev); +void shutdown_atm_dev(struct atm_dev *dev); +void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev); + + +/* This is the algorithm used by alloc_skb + + SHIT! It is fully illegal. If we could derive truesize + from another skb parameter, we would not create this variable. + Do not wonder, if allocating 5K skbm truesize will be > 8K. + */ + +static __inline__ int atm_pdu2truesize(int pdu_size) +{ + return ((pdu_size+15) & ~15) + sizeof(struct sk_buff); +} + + +static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize) +{ + atomic_add(truesize+ATM_PDU_OVHD,&vcc->rx_inuse); +} + + +static __inline__ void atm_return(struct atm_vcc *vcc,int truesize) +{ + atomic_sub(truesize+ATM_PDU_OVHD,&vcc->rx_inuse); +} + + +int atm_charge(struct atm_vcc *vcc,int truesize); +void atm_return(struct atm_vcc *vcc,int truesize); +int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); +int atm_pcr_goal(struct atm_trafprm *tp); + +void atm_async_release_vcc(struct atm_vcc *vcc,int reply); + +#endif /* __KERNEL__ */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmioc.h linux/include/linux/atmioc.h --- v2.3.14/linux/include/linux/atmioc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmioc.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,39 @@ +/* atmioc.h - ranges for ATM-related ioctl numbers */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC */ + + +/* + * See http://lrcwww.epfl.ch/linux-atm/magic.html for the complete list of + * "magic" ioctl numbers. + */ + + +#ifndef _LINUX_ATMIOC_H +#define _LINUX_ATMIOC_H + +#include + /* everybody including atmioc.h will also need _IO{,R,W,WR} */ + +#define ATMIOC_PHYCOM 0x00 /* PHY device common ioctls, globally unique */ +#define ATMIOC_PHYCOM_END 0x0f +#define ATMIOC_PHYTYP 0x10 /* PHY dev type ioctls, unique per PHY type */ +#define ATMIOC_PHYTYP_END 0x2f +#define ATMIOC_PHYPRV 0x30 /* PHY dev private ioctls, unique per driver */ +#define ATMIOC_PHYPRV_END 0x4f +#define ATMIOC_SARCOM 0x50 /* SAR device common ioctls, globally unique */ +#define ATMIOC_SARCOM_END 0x50 +#define ATMIOC_SARPRV 0x60 /* SAR dev private ioctls, unique per driver */ +#define ATMIOC_SARPRV_END 0x7f +#define ATMIOC_ITF 0x80 /* Interface ioctls, globally unique */ +#define ATMIOC_ITF_END 0x8f +/* 0x90-0xbf: Reserved for future use */ +#define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */ +#define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */ +#define ATMIOC_MPOA 0xd8 /* MPOA, globally unique */ +#define ATMIOC_CLIP 0xe0 /* Classical IP over ATM control, globally u. */ +#define ATMIOC_CLIP_END 0xef +#define ATMIOC_SPECIAL 0xf0 /* Special-purpose controls, globally unique */ +#define ATMIOC_SPECIAL_END 0xff + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmlec.h linux/include/linux/atmlec.h --- v2.3.14/linux/include/linux/atmlec.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmlec.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,85 @@ +/* + * + * ATM Lan Emulation Daemon vs. driver interface + * + * carnil@cs.tut.fi + * + */ + +#ifndef _ATMLEC_H_ +#define _ATMLEC_H_ + +#include +#include +#include +/* ATM lec daemon control socket */ +#define ATMLEC_CTRL _IO('a',ATMIOC_LANE) +#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1) +#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2) + +/* Maximum number of LEC interfaces (tweakable) */ +#define MAX_LEC_ITF 48 + +/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring. + * E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for + * Ethernet ELANs and lec40-lec47 are for Token Ring ELANS. + */ +#define NUM_TR_DEVS 8 + +typedef enum { + l_set_mac_addr, l_del_mac_addr, + l_svc_setup, + l_addr_delete, l_topology_change, + l_flush_complete, l_arp_update, + l_narp_req, /* LANE2 mandates the use of this */ + l_config, l_flush_tran_id, + l_set_lecid, l_arp_xmt, + l_rdesc_arp_xmt, + l_associate_req, + l_should_bridge /* should we bridge this MAC? */ +} atmlec_msg_type; + +#define ATMLEC_MSG_TYPE_MAX l_should_bridge + +struct atmlec_config_msg { + unsigned int maximum_unknown_frame_count; + unsigned long max_unknown_frame_time; + unsigned short max_retry_count; + unsigned long aging_time; + unsigned long forward_delay_time; + unsigned long arp_response_time; + unsigned long flush_timeout; + unsigned long path_switching_delay; + unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */ + int mtu; +}; + +struct atmlec_msg { + atmlec_msg_type type; + int sizeoftlvs; /* LANE2: if != 0, tlvs follow */ + union { + struct { + unsigned char mac_addr[ETH_ALEN]; + unsigned char atm_addr[ATM_ESA_LEN]; + unsigned long flag;/* Topology_change flag, + remoteflag, permanent flag, + lecid, transaction id */ + unsigned int targetless_le_arp; /* LANE2 */ + unsigned int no_source_le_narp; /* LANE2 */ + } normal; + struct atmlec_config_msg config; + struct { + uint16_t lec_id; /* requestor lec_id */ + uint32_t tran_id; /* transaction id */ + unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */ + unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */ + } proxy; /* For mapping LE_ARP requests to responses. Filled by */ + } content; /* zeppelin, returned by kernel. Used only when proxying */ +}; + +struct atmlec_ioc { + int dev_num; + unsigned char atm_addr[ATM_ESA_LEN]; + unsigned char receive; /* 1= receive vcc, 0 = send vcc */ +}; +#endif /* _ATMLEC_H_ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/atmmpc.h linux/include/linux/atmmpc.h --- v2.3.14/linux/include/linux/atmmpc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmmpc.h Mon Aug 23 09:56:31 1999 @@ -0,0 +1,124 @@ +#ifndef _ATMMPC_H_ +#define _ATMMPC_H_ + +#include +#include + +#define ATMMPC_CTRL _IO('a', ATMIOC_MPOA) +#define ATMMPC_DATA _IO('a', ATMIOC_MPOA+1) + +#define MPC_SOCKET_INGRESS 1 +#define MPC_SOCKET_EGRESS 2 + +struct atmmpc_ioc { + int dev_num; + uint32_t ipaddr; /* the IP address of the shortcut */ + int type; /* ingress or egress */ +}; + +typedef struct in_ctrl_info { + uint8_t Last_NHRP_CIE_code; + uint8_t Last_Q2931_cause_value; + uint8_t eg_MPC_ATM_addr[ATM_ESA_LEN]; + uint32_t tag; + uint32_t in_dst_ip; /* IP address this ingress MPC sends packets to */ + uint16_t holding_time; + uint32_t request_id; +} in_ctrl_info; + +typedef struct eg_ctrl_info { + uint8_t DLL_header[256]; + uint8_t DH_length; + uint32_t cache_id; + uint32_t tag; + uint32_t mps_ip; + uint32_t eg_dst_ip; /* IP address to which ingress MPC sends packets */ + uint8_t in_MPC_data_ATM_addr[ATM_ESA_LEN]; + uint16_t holding_time; +} eg_ctrl_info; + +struct mpc_parameters{ + uint16_t mpc_p1; /* Shortcut-Setup Frame Count */ + uint16_t mpc_p2; /* Shortcut-Setup Frame Time */ + uint8_t mpc_p3[8]; /* Flow-detection Protocols */ + uint16_t mpc_p4; /* MPC Initial Retry Time */ + uint16_t mpc_p5; /* MPC Retry Time Maximum */ + uint16_t mpc_p6; /* Hold Down Time */ +}; + +struct k_message{ + uint16_t type; + uint32_t ip_mask; + uint8_t MPS_ctrl[ATM_ESA_LEN]; + union { + in_ctrl_info in_info; + eg_ctrl_info eg_info; + struct mpc_parameters params; + } content; + struct atm_qos qos; +}; + +struct llc_snap_hdr { /* RFC 1483 LLC/SNAP encapsulation for routed IP PDUs */ + uint8_t dsap; /* Destination Service Access Point (0xAA) */ + uint8_t ssap; /* Source Service Access Point (0xAA) */ + uint8_t ui; /* Unnumbered Information (0x03) */ + uint8_t org[3]; /* Organizational identification (0x000000) */ + uint8_t type[2]; /* Ether type (for IP) (0x0800) */ +}; + +/* TLVs this MPC recognizes */ +#define TLV_MPOA_DEVICE_TYPE 0x00a03e2a + +/* MPOA device types in MPOA Device Type TLV */ +#define NON_MPOA 0 +#define MPS 1 +#define MPC 2 +#define MPS_AND_MPC 3 + + +/* MPC parameter defaults */ + +#define MPC_P1 10 /* Shortcut-Setup Frame Count */ +#define MPC_P2 1 /* Shortcut-Setup Frame Time */ +#define MPC_P3 0 /* Flow-detection Protocols */ +#define MPC_P4 5 /* MPC Initial Retry Time */ +#define MPC_P5 40 /* MPC Retry Time Maximum */ +#define MPC_P6 160 /* Hold Down Time */ +#define HOLDING_TIME_DEFAULT 1200 /* same as MPS-p7 */ + +/* MPC constants */ + +#define MPC_C1 2 /* Retry Time Multiplier */ +#define MPC_C2 60 /* Initial Keep-Alive Lifetime */ + +/* Message types - to MPOA daemon */ + +#define SND_MPOA_RES_RQST 201 +#define SET_MPS_CTRL_ADDR 202 +#define SND_MPOA_RES_RTRY 203 /* Different type in a retry due to req id */ +#define STOP_KEEP_ALIVE_SM 204 +#define EGRESS_ENTRY_REMOVED 205 +#define SND_EGRESS_PURGE 206 +#define DIE 207 /* tell the daemon to exit() */ +#define DATA_PLANE_PURGE 208 /* Data plane purge because of egress cache hit miss or dead MPS */ +#define OPEN_INGRESS_SVC 209 + +/* Message types - from MPOA daemon */ + +#define MPOA_TRIGGER_RCVD 101 +#define MPOA_RES_REPLY_RCVD 102 +#define INGRESS_PURGE_RCVD 103 +#define EGRESS_PURGE_RCVD 104 +#define MPS_DEATH 105 +#define CACHE_IMPOS_RCVD 106 +#define SET_MPC_CTRL_ADDR 107 /* Our MPC's control ATM address */ +#define SET_MPS_MAC_ADDR 108 +#define CLEAN_UP_AND_EXIT 109 +#define SET_MPC_PARAMS 110 /* MPC configuration parameters */ + +/* Message types - bidirectional */ + +#define RELOAD 301 /* kill -HUP the daemon for reload */ + +#endif /* _ATMMPC_H_ */ + diff -u --recursive --new-file v2.3.14/linux/include/linux/atmsap.h linux/include/linux/atmsap.h --- v2.3.14/linux/include/linux/atmsap.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmsap.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,161 @@ +/* atmsap.h - ATM Service Access Point addressing definitions */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef _LINUX_ATMSAP_H +#define _LINUX_ATMSAP_H + +/* + * BEGIN_xx and END_xx markers are used for automatic generation of + * documentation. Do not change them. + */ + + +/* + * Layer 2 protocol identifiers + */ + +/* BEGIN_L2 */ +#define ATM_L2_NONE 0 /* L2 not specified */ +#define ATM_L2_ISO1745 0x01 /* Basic mode ISO 1745 */ +#define ATM_L2_Q291 0x02 /* ITU-T Q.291 (Rec. I.441) */ +#define ATM_L2_X25_LL 0x06 /* ITU-T X.25, link layer */ +#define ATM_L2_X25_ML 0x07 /* ITU-T X.25, multilink */ +#define ATM_L2_LAPB 0x08 /* Extended LAPB, half-duplex (Rec. T.71) */ +#define ATM_L2_HDLC_ARM 0x09 /* HDLC ARM (ISO/IEC 4335) */ +#define ATM_L2_HDLC_NRM 0x0a /* HDLC NRM (ISO/IEC 4335) */ +#define ATM_L2_HDLC_ABM 0x0b /* HDLC ABM (ISO/IEC 4335) */ +#define ATM_L2_ISO8802 0x0c /* LAN LLC (ISO/IEC 8802/2) */ +#define ATM_L2_X75 0x0d /* ITU-T X.75, SLP */ +#define ATM_L2_Q922 0x0e /* ITU-T Q.922 */ +#define ATM_L2_USER 0x10 /* user-specified */ +#define ATM_L2_ISO7776 0x11 /* ISO 7776 DTE-DTE */ +/* END_L2 */ + + +/* + * Layer 3 protocol identifiers + */ + +/* BEGIN_L3 */ +#define ATM_L3_NONE 0 /* L3 not specified */ +#define ATM_L3_X25 0x06 /* ITU-T X.25, packet layer */ +#define ATM_L3_ISO8208 0x07 /* ISO/IEC 8208 */ +#define ATM_L3_X223 0x08 /* ITU-T X.223 | ISO/IEC 8878 */ +#define ATM_L3_ISO8473 0x09 /* ITU-T X.233 | ISO/IEC 8473 */ +#define ATM_L3_T70 0x0a /* ITU-T T.70 minimum network layer */ +#define ATM_L3_TR9577 0x0b /* ISO/IEC TR 9577 */ +#define ATM_L3_H310 0x0c /* ITU-T Recommendation H.310 */ +#define ATM_L3_H321 0x0d /* ITU-T Recommendation H.321 */ +#define ATM_L3_USER 0x10 /* user-specified */ +/* END_L3 */ + + +/* + * High layer identifiers + */ + +/* BEGIN_HL */ +#define ATM_HL_NONE 0 /* HL not specified */ +#define ATM_HL_ISO 0x01 /* ISO */ +#define ATM_HL_USER 0x02 /* user-specific */ +#define ATM_HL_HLP 0x03 /* high layer profile - UNI 3.0 only */ +#define ATM_HL_VENDOR 0x04 /* vendor-specific application identifier */ +/* END_HL */ + + +/* + * ITU-T coded mode of operation + */ + +/* BEGIN_IMD */ +#define ATM_IMD_NONE 0 /* mode not specified */ +#define ATM_IMD_NORMAL 1 /* normal mode of operation */ +#define ATM_IMD_EXTENDED 2 /* extended mode of operation */ +/* END_IMD */ + +/* + * H.310 code points + */ + +#define ATM_TT_NONE 0 /* terminal type not specified */ +#define ATM_TT_RX 1 /* receive only */ +#define ATM_TT_TX 2 /* send only */ +#define ATM_TT_RXTX 3 /* receive and send */ + +#define ATM_MC_NONE 0 /* no multiplexing */ +#define ATM_MC_TS 1 /* transport stream (TS) */ +#define ATM_MC_TS_FEC 2 /* transport stream with forward error corr. */ +#define ATM_MC_PS 3 /* program stream (PS) */ +#define ATM_MC_PS_FEC 4 /* program stream with forward error corr. */ +#define ATM_MC_H221 5 /* ITU-T Rec. H.221 */ + +/* + * SAP structures + */ + +#define ATM_MAX_HLI 8 /* maximum high-layer information length */ + + +struct atm_blli { + unsigned char l2_proto; /* layer 2 protocol */ + union { + struct { + unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ + /* absent */ + unsigned char window; /* window size (k), 1-127 (0 to omit) */ + } itu; /* ITU-T encoding */ + unsigned char user; /* user-specified l2 information */ + } l2; + unsigned char l3_proto; /* layer 3 protocol */ + union { + struct { + unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ + /* absent */ + unsigned char def_size; /* default packet size (log2), 4-12 (0 to */ + /* omit) */ + unsigned char window;/* packet window size, 1-127 (0 to omit) */ + } itu; /* ITU-T ecoding */ + unsigned char user; /* user specified l3 information */ + struct { /* if l3_proto = ATM_L3_H310 */ + unsigned char term_type; /* terminal type */ + unsigned char fw_mpx_cap; /* forward multiplexing capability */ + /* only if term_type != ATM_TT_NONE */ + unsigned char bw_mpx_cap; /* backward multiplexing capability */ + /* only if term_type != ATM_TT_NONE */ + } h310; + struct { /* if l3_proto = ATM_L3_TR9577 */ + unsigned char ipi; /* initial protocol id */ + unsigned char snap[5];/* IEEE 802.1 SNAP identifier */ + /* (only if ipi == NLPID_IEEE802_1_SNAP) */ + } tr9577; + } l3; + struct atm_blli *next; /* next BLLI or NULL (undefined when used in */ + /* atmsvc_msg) ONLY USED IN OLD-STYLE API */ +}; + + +struct atm_bhli { + unsigned char hl_type; /* high layer information type */ + unsigned char hl_length; /* length (only if hl_type == ATM_HL_USER || */ + /* hl_type == ATM_HL_ISO) */ + unsigned char hl_info[ATM_MAX_HLI];/* high layer information */ +}; + + +#define ATM_MAX_BLLI 3 /* maximum number of BLLI elements */ + + +struct atm_sap { + struct atm_bhli bhli; /* local SAP, high-layer information */ + struct atm_blli blli[ATM_MAX_BLLI]; /* local SAP, low-layer info */ +}; + + +static __inline__ int blli_in_use(struct atm_blli blli) +{ + return blli.l2_proto || blli.l3_proto; +} + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/atmsvc.h linux/include/linux/atmsvc.h --- v2.3.14/linux/include/linux/atmsvc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmsvc.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,53 @@ +/* atmsvc.h - ATM signaling kernel-demon interface definitions */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef _LINUX_ATMSVC_H +#define _LINUX_ATMSVC_H + +#include +#include + + +#define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL) + /* become ATM signaling demon control socket */ + +enum atmsvc_msg_type { as_catch_null,as_bind,as_connect,as_accept,as_reject, + as_listen,as_okay,as_error,as_indicate,as_close,as_itf_notify, + as_modify,as_identify,as_terminate }; + +struct atmsvc_msg { + enum atmsvc_msg_type type; + unsigned long vcc; + unsigned long listen_vcc; /* indicate */ + int reply; /* for okay and close: */ + /* < 0: error before active */ + /* (sigd has discarded ctx) */ + /* ==0: success */ + /* > 0: error when active (still */ + /* need to close) */ + struct sockaddr_atmpvc pvc; /* indicate, okay (connect) */ + struct sockaddr_atmsvc local; /* local SVC address */ + struct atm_qos qos; /* QOS parameters */ + struct atm_sap sap; /* SAP */ + unsigned long session; /* for p2pm */ + struct sockaddr_atmsvc svc; /* SVC address */ +}; + +/* + * Message contents: see ftp://lrcftp.epfl.ch/pub/linux/atm/docs/isp-*.tar.gz + */ + +/* + * Some policy stuff for atmsigd and for net/atm/svc.c. Both have to agree on + * what PCR is used to request bandwidth from the device driver. net/atm/svc.c + * tries to do better than that, but only if there's no routing decision (i.e. + * if signaling only uses one ATM interface). + */ + +#define SELECT_TOP_PCR(tp) ((tp).pcr ? (tp).pcr : \ + (tp).max_pcr && (tp).max_pcr != ATM_MAX_PCR ? (tp).max_pcr : \ + (tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR) + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/capability.h linux/include/linux/capability.h --- v2.3.14/linux/include/linux/capability.h Wed Aug 18 16:43:32 1999 +++ linux/include/linux/capability.h Tue Aug 24 17:09:19 1999 @@ -131,6 +131,7 @@ #define CAP_LINUX_IMMUTABLE 9 /* Allows binding to TCP/UDP sockets below 1024 */ +/* Allows binding to ATM VCIs below 32 */ #define CAP_NET_BIND_SERVICE 10 @@ -150,6 +151,7 @@ /* Allow clearing driver statistics */ /* Allow multicasting */ /* Allow read/write of device-specific registers */ +/* Allow activation of ATM control sockets */ #define CAP_NET_ADMIN 12 diff -u --recursive --new-file v2.3.14/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h --- v2.3.14/linux/include/linux/coda_linux.h Mon Jan 25 10:28:35 1999 +++ linux/include/linux/coda_linux.h Mon Aug 23 10:17:19 1999 @@ -113,10 +113,10 @@ do { \ if (size < 3000) { \ ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \ - CDEBUG(D_MALLOC, "kmalloced: %x at %x.\n", (int) size, (int) ptr);\ + CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr);\ } else { \ ptr = (cast)vmalloc((unsigned long) size); \ - CDEBUG(D_MALLOC, "vmalloced: %x at %x.\n", (int) size, (int) ptr);}\ + CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);}\ if (ptr == 0) { \ printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ } \ @@ -124,7 +124,7 @@ } while (0) -#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0) +#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0) /* inode to cnode */ diff -u --recursive --new-file v2.3.14/linux/include/linux/concap.h linux/include/linux/concap.h --- v2.3.14/linux/include/linux/concap.h Wed Aug 18 11:38:47 1999 +++ linux/include/linux/concap.h Wed Aug 25 15:18:08 1999 @@ -1,10 +1,11 @@ -/* $Id: concap.h,v 1.1 1998/02/01 00:15:11 keil Exp $ +/* $Id: concap.h,v 1.2 1999/08/23 15:54:21 keil Exp $ */ #ifndef _LINUX_CONCAP_H #define _LINUX_CONCAP_H #ifdef __KERNEL__ #include #include +#include /* Stuff to support encapsulation protocols genericly. The encapsulation protocol is processed at the uppermost layer of the network interface. @@ -25,11 +26,11 @@ /* this manages all data needed by the encapsulation protocol */ struct concap_proto{ - struct net_device *net_dev; /* net device using our service */ - struct concap_device_ops *dops; /* callbacks provided by device */ - struct concap_proto_ops *pops; /* callbacks provided by us */ + struct net_device *net_dev; /* net device using our service */ + struct concap_device_ops *dops; /* callbacks provided by device */ + struct concap_proto_ops *pops; /* callbacks provided by us */ int flags; - void *proto_data; /* protocol specific private data, to + void *proto_data; /* protocol specific private data, to be accessed via *pops methods only*/ /* : @@ -107,7 +108,3 @@ extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb); #endif #endif - - - - diff -u --recursive --new-file v2.3.14/linux/include/linux/elf.h linux/include/linux/elf.h --- v2.3.14/linux/include/linux/elf.h Wed Aug 18 16:45:32 1999 +++ linux/include/linux/elf.h Mon Aug 23 14:50:45 1999 @@ -61,6 +61,8 @@ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* HP/Intel IA-64 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. diff -u --recursive --new-file v2.3.14/linux/include/linux/fb.h linux/include/linux/fb.h --- v2.3.14/linux/include/linux/fb.h Wed Aug 18 10:10:06 1999 +++ linux/include/linux/fb.h Thu Aug 19 11:01:00 1999 @@ -83,7 +83,7 @@ struct fb_fix_screeninfo { char id[16]; /* identification string eg "TT Builtin" */ - char *smem_start; /* Start of frame buffer mem */ + unsigned long smem_start; /* Start of frame buffer mem */ /* (physical address) */ __u32 smem_len; /* Length of frame buffer mem */ __u32 type; /* see FB_TYPE_* */ @@ -93,7 +93,7 @@ __u16 ypanstep; /* zero if no hardware panning */ __u16 ywrapstep; /* zero if no hardware ywrap */ __u32 line_length; /* length of a line in bytes */ - char *mmio_start; /* Start of Memory Mapped I/O */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ /* (physical address) */ __u32 mmio_len; /* Length of Memory Mapped I/O */ __u32 accel; /* Type of acceleration available */ diff -u --recursive --new-file v2.3.14/linux/include/linux/fcdevice.h linux/include/linux/fcdevice.h --- v2.3.14/linux/include/linux/fcdevice.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/fcdevice.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,40 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Fibre Channel handlers. + * + * Version: @(#)fcdevice.h 1.0.0 09/26/98 + * + * Authors: Vineet Abraham + * + * Relocated to include/linux where it belongs by Alan Cox + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * WARNING: This move may well be temporary. This file will get merged with others RSN. + * + */ +#ifndef _LINUX_FCDEVICE_H +#define _LINUX_FCDEVICE_H + + +#include + +#ifdef __KERNEL__ +extern int fc_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len); +extern int fc_rebuild_header(struct sk_buff *skb); +//extern unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev); + +extern struct net_device * init_fcdev(struct net_device *, int); + +#endif + +#endif /* _LINUX_FCDEVICE_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/firewall.h linux/include/linux/firewall.h --- v2.3.14/linux/include/linux/firewall.h Wed Aug 18 16:44:42 1999 +++ linux/include/linux/firewall.h Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -#ifndef __LINUX_FIREWALL_H -#define __LINUX_FIREWALL_H - -#include - -/* - * Definitions for loadable firewall modules - */ - -#define FW_QUEUE 0 -#define FW_BLOCK 1 -#define FW_ACCEPT 2 -#define FW_REJECT (-1) -#define FW_REDIRECT 3 -#define FW_MASQUERADE 4 -#define FW_SKIP 5 - -struct firewall_ops -{ - struct firewall_ops *next; - int (*fw_forward)(struct firewall_ops *this, int pf, - struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); - int (*fw_input)(struct firewall_ops *this, int pf, - struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); - int (*fw_output)(struct firewall_ops *this, int pf, - struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); - /* Data falling in the second 486 cache line isn't used directly - during a firewall call and scan, only by insert/delete and other - unusual cases - */ - int fw_pf; /* Protocol family */ - int fw_priority; /* Priority of chosen firewalls */ -}; - -#ifdef __KERNEL__ -extern int register_firewall(int pf, struct firewall_ops *fw); -extern int unregister_firewall(int pf, struct firewall_ops *fw); -extern void fwchain_init(void); -#ifdef CONFIG_FIREWALL -extern int call_fw_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); -extern int call_in_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); -extern int call_out_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **pskb); -#else -extern __inline__ int call_fw_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - return FW_ACCEPT; -} - -extern __inline__ int call_in_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - return FW_ACCEPT; -} - -extern __inline__ int call_out_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - return FW_ACCEPT; -} - -#endif -#endif -#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.3.14/linux/include/linux/fs.h Wed Aug 18 16:43:32 1999 +++ linux/include/linux/fs.h Tue Aug 24 17:09:19 1999 @@ -706,8 +706,8 @@ /* fs/open.c */ -asmlinkage int sys_open(const char *, int, int); -asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ +asmlinkage long sys_open(const char *, int, int); +asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ extern int do_close(unsigned int, int); /* yes, it's really unsigned */ extern int do_truncate(struct dentry *, unsigned long); extern int get_unused_fd(void); diff -u --recursive --new-file v2.3.14/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.3.14/linux/include/linux/if_arp.h Wed Aug 18 16:44:31 1999 +++ linux/include/linux/if_arp.h Tue Aug 24 17:10:21 1999 @@ -35,6 +35,7 @@ #define ARPHRD_ARCNET 7 /* ARCnet */ #define ARPHRD_APPLETLK 8 /* APPLEtalk */ #define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 19 /* ATM */ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ /* Dummy types for non ARP hardware */ @@ -80,6 +81,9 @@ #define ARPOP_REPLY 2 /* ARP reply */ #define ARPOP_RREQUEST 3 /* RARP request */ #define ARPOP_RREPLY 4 /* RARP reply */ +#define ARPOP_InREQUEST 8 /* InARP request */ +#define ARPOP_InREPLY 9 /* InARP reply */ +#define ARPOP_NAK 10 /* (ATM)ARP NAK */ /* ARP ioctl request. */ diff -u --recursive --new-file v2.3.14/linux/include/linux/if_cablemodem.h linux/include/linux/if_cablemodem.h --- v2.3.14/linux/include/linux/if_cablemodem.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_cablemodem.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,22 @@ +#ifndef _LINUX_CABLEMODEM_H_ +#define _LINUX_CABLEMODEM_H_ +/* + * Author: Franco Venturi + * Copyright 1998 Franco Venturi + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +/* some useful defines for sb1000.c e cmconfig.c - fv */ +#define SIOCGCMSTATS SIOCDEVPRIVATE+0 /* get cable modem stats */ +#define SIOCGCMFIRMWARE SIOCDEVPRIVATE+1 /* get cm firmware version */ +#define SIOCGCMFREQUENCY SIOCDEVPRIVATE+2 /* get cable modem frequency */ +#define SIOCSCMFREQUENCY SIOCDEVPRIVATE+3 /* set cable modem frequency */ +#define SIOCGCMPIDS SIOCDEVPRIVATE+4 /* get cable modem PIDs */ +#define SIOCSCMPIDS SIOCDEVPRIVATE+5 /* set cable modem PIDs */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- v2.3.14/linux/include/linux/if_ether.h Wed Jun 2 11:29:13 1999 +++ linux/include/linux/if_ether.h Wed Aug 25 15:47:44 1999 @@ -75,6 +75,7 @@ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ #define ETH_P_CONTROL 0x0016 /* Card specific control frames */ #define ETH_P_IRDA 0x0017 /* Linux/IR */ +#define ETH_P_ECONET 0x0018 /* Acorn Econet */ /* * This is an Ethernet frame header. diff -u --recursive --new-file v2.3.14/linux/include/linux/if_fc.h linux/include/linux/if_fc.h --- v2.3.14/linux/include/linux/if_fc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_fc.h Mon Aug 23 10:12:38 1999 @@ -0,0 +1,50 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for Fibre Channel. + * + * Version: @(#)if_fc.h 0.0 11/20/98 + * + * Author: Fred N. van Kempen, + * Donald Becker, + * Peter De Schrijver, + * Vineet Abraham, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_FC_H +#define _LINUX_IF_FC_H + + +#define FC_ALEN 6 /* Octets in one ethernet addr */ +#define FC_HLEN (sizeof(struct fch_hdr)+sizeof(struct fcllc)) +#define FC_ID_LEN 3 /* Octets in a Fibre Channel Address */ + +/* LLC and SNAP constants */ +#define EXTENDED_SAP 0xAA +#define UI_CMD 0x03 + +/* This is NOT the Fibre Channel frame header. The FC frame header is + * constructed in the driver as the Tachyon needs certain fields in + * certains positions. So, it can't be generalized here.*/ + +struct fch_hdr { + __u8 daddr[FC_ALEN]; /* destination address */ + __u8 saddr[FC_ALEN]; /* source address */ +}; + +/* This is a Fibre Channel LLC structure */ +struct fcllc { + __u8 dsap; /* destination SAP */ + __u8 ssap; /* source SAP */ + __u8 llc; /* LLC control field */ + __u8 protid[3]; /* protocol id */ + __u16 ethertype; /* ether type field */ +}; + +#endif /* _LINUX_IF_FC_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/if_packet.h linux/include/linux/if_packet.h --- v2.3.14/linux/include/linux/if_packet.h Thu Aug 27 19:33:08 1998 +++ linux/include/linux/if_packet.h Mon Aug 23 10:01:02 1999 @@ -34,6 +34,56 @@ #define PACKET_ADD_MEMBERSHIP 1 #define PACKET_DROP_MEMBERSHIP 2 +#define PACKET_RECV_OUTPUT 3 +/* Value 4 is still used by obsolete turbo-packet. */ +#define PACKET_RX_RING 5 +#define PACKET_STATISTICS 6 + +struct tpacket_stats +{ + unsigned int tp_packets; + unsigned int tp_drops; +}; + +struct tpacket_hdr +{ + unsigned long tp_status; +#define TP_STATUS_KERNEL 0 +#define TP_STATUS_USER 1 +#define TP_STATUS_COPY 2 +#define TP_STATUS_LOSING 4 + unsigned int tp_len; + unsigned int tp_snaplen; + unsigned short tp_mac; + unsigned short tp_net; + unsigned int tp_sec; + unsigned int tp_usec; +}; + +#define TPACKET_ALIGNMENT 16 +#define TPACKET_ALIGN(x) (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1)) +#define TPACKET_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll)) + +/* + Frame structure: + + - Start. Frame must be aligned to TPACKET_ALIGNMENT=16 + - struct tpacket_hdr + - pad to TPACKET_ALIGNMENT=16 + - struct sockaddr_ll + - Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16 + - Start+tp_mac: [ Optional MAC header ] + - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16. + - Pad to align to TPACKET_ALIGNMENT=16 + */ + +struct tpacket_req +{ + unsigned int tp_block_size; /* Minimal size of contiguous block */ + unsigned int tp_block_nr; /* Number of blocks */ + unsigned int tp_frame_size; /* Size of frame */ + unsigned int tp_frame_nr; /* Total number of frames */ +}; struct packet_mreq { diff -u --recursive --new-file v2.3.14/linux/include/linux/if_pppvar.h linux/include/linux/if_pppvar.h --- v2.3.14/linux/include/linux/if_pppvar.h Wed Aug 18 11:38:46 1999 +++ linux/include/linux/if_pppvar.h Mon Aug 23 10:01:02 1999 @@ -126,7 +126,7 @@ enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */ int sc_xfer; /* PID of reserved PPP table */ - char name[8]; /* space for unit name */ + char name[16]; /* space for unit name */ struct net_device dev; /* net device structure */ struct enet_statistics estats; /* more detailed stats */ diff -u --recursive --new-file v2.3.14/linux/include/linux/igmp.h linux/include/linux/igmp.h --- v2.3.14/linux/include/linux/igmp.h Wed Aug 18 11:38:46 1999 +++ linux/include/linux/igmp.h Mon Aug 23 10:01:02 1999 @@ -95,13 +95,15 @@ struct ip_mc_list *next; struct timer_list timer; int users; + atomic_t refcnt; + spinlock_t lock; char tm_running; char reporter; char unsolicit_count; char loaded; }; -extern int ip_check_mc(struct net_device *dev, u32 mc_addr); +extern int ip_check_mc(struct in_device *dev, u32 mc_addr); extern int igmp_rcv(struct sk_buff *, unsigned short); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); diff -u --recursive --new-file v2.3.14/linux/include/linux/in.h linux/include/linux/in.h --- v2.3.14/linux/include/linux/in.h Wed Aug 18 16:43:29 1999 +++ linux/include/linux/in.h Mon Aug 23 14:48:49 1999 @@ -38,6 +38,10 @@ IPPROTO_PIM = 103, /* Protocol Independent Multicast */ + IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ + IPPROTO_AH = 51, /* Authentication Header protocol */ + IPPROTO_COMP = 108, /* Compression Header protocol */ + IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX }; diff -u --recursive --new-file v2.3.14/linux/include/linux/in6.h linux/include/linux/in6.h --- v2.3.14/linux/include/linux/in6.h Thu Apr 22 19:45:19 1999 +++ linux/include/linux/in6.h Mon Aug 23 10:01:02 1999 @@ -129,8 +129,6 @@ #define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ #define IPPROTO_ROUTING 43 /* IPv6 routing header */ #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ -#define IPPROTO_ESP 50 /* encapsulating security payload */ -#define IPPROTO_AH 51 /* authentication header */ #define IPPROTO_ICMPV6 58 /* ICMPv6 */ #define IPPROTO_NONE 59 /* IPv6 no next header */ #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ diff -u --recursive --new-file v2.3.14/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h --- v2.3.14/linux/include/linux/inetdevice.h Wed Aug 18 11:38:47 1999 +++ linux/include/linux/inetdevice.h Mon Aug 23 10:01:02 1999 @@ -16,6 +16,7 @@ int log_martians; int forwarding; int mc_forwarding; + int tag; void *sysctl; }; @@ -24,10 +25,12 @@ struct in_device { struct net_device *dev; + atomic_t refcnt; + rwlock_t lock; + int dead; struct in_ifaddr *ifa_list; /* IP ifaddr chain */ struct ip_mc_list *mc_list; /* IP multicast filter chain */ unsigned long mr_v1_seen; - unsigned flags; struct neigh_parms *arp_parms; struct ipv4_devconf cnf; }; @@ -43,6 +46,7 @@ #define IN_DEV_SHARED_MEDIA(in_dev) (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media) #define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects) #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) +#define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag) #define IN_DEV_RX_REDIRECTS(in_dev) \ ((IN_DEV_FORWARD(in_dev) && \ @@ -69,7 +73,7 @@ extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern struct net_device *ip_dev_find(u32 addr); -extern struct in_ifaddr *inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); +extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); extern int devinet_ioctl(unsigned int cmd, void *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); @@ -105,6 +109,40 @@ #define endfor_ifa(in_dev) } + +extern rwlock_t inetdev_lock; + + +extern __inline__ struct in_device * +in_dev_get(const struct net_device *dev) +{ + struct in_device *in_dev; + + read_lock(&inetdev_lock); + in_dev = dev->ip_ptr; + if (in_dev) + atomic_inc(&in_dev->refcnt); + read_unlock(&inetdev_lock); + return in_dev; +} + +extern __inline__ struct in_device * +__in_dev_get(const struct net_device *dev) +{ + return (struct in_device*)dev->ip_ptr; +} + +extern void in_dev_finish_destroy(struct in_device *idev); + +extern __inline__ void +in_dev_put(struct in_device *idev) +{ + if (atomic_dec_and_test(&idev->refcnt)) + in_dev_finish_destroy(idev); +} + +#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt) +#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/ioport.h linux/include/linux/ioport.h --- v2.3.14/linux/include/linux/ioport.h Sun Aug 15 11:50:35 1999 +++ linux/include/linux/ioport.h Mon Aug 23 10:52:02 1999 @@ -8,19 +8,6 @@ #ifndef _LINUX_IOPORT_H #define _LINUX_IOPORT_H -#define DEVICE_IO_NOTSET (~0) -#define DEVICE_IO_AUTO ((~0)-1) - -#define DEVICE_IO_FLAG_WRITEABLE (1<<0) -#define DEVICE_IO_FLAG_CACHEABLE (1<<1) -#define DEVICE_IO_FLAG_RANGELENGTH (1<<2) -#define DEVICE_IO_FLAG_SHADOWABLE (1<<4) -#define DEVICE_IO_FLAG_EXPANSIONROM (1<<5) - -#define DEVICE_IO_TYPE_8BIT 0 -#define DEVICE_IO_TYPE_16BIT 1 -#define DEVICE_IO_TYPE_8AND16BIT 2 - /* * Resources are tree-like, allowing * nesting etc.. @@ -29,22 +16,61 @@ const char *name; unsigned long start, end; unsigned long flags; - unsigned char bits; /* decoded bits */ - unsigned char fixed; /* fixed range */ - unsigned short hw_flags; /* hardware flags */ - unsigned short type; /* region type */ struct resource *parent, *sibling, *child; }; /* - * PCI-like IO resources have these defined flags. - * The low four bits come directly from the PCI specs, - * the rest are extended sw flags.. + * IO resources have these defined flags. */ -#define IORESOURCE_IOPORT 0x01 /* 0 - memory mapped, 1 - IO ports */ -#define IORESOURCE_MEMTYPE_MASK 0x06 /* PCI-specific mapping info */ -#define IORESOURCE_PREFETCH 0x08 /* No side effects */ -#define IORESOURCE_BUSY 0x10 /* Driver uses this resource */ +#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ + +#define IORESOURCE_IO 0x00000100 /* Resource type */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 + +#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ +#define IORESOURCE_READONLY 0x00002000 +#define IORESOURCE_CACHEABLE 0x00004000 +#define IORESOURCE_RANGELENGTH 0x00008000 +#define IORESOURCE_SHADOWABLE 0x00010000 + +#define IORESOURCE_UNSET 0x20000000 +#define IORESOURCE_AUTO 0x40000000 +#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ + +/* ISA PnP IRQ specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_IRQ_HIGHEDGE (1<<0) +#define IORESOURCE_IRQ_LOWEDGE (1<<1) +#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) +#define IORESOURCE_IRQ_LOWLEVEL (1<<3) + +/* ISA PnP DMA specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_DMA_TYPE_MASK (3<<0) +#define IORESOURCE_DMA_8BIT (0<<0) +#define IORESOURCE_DMA_8AND16BIT (1<<0) +#define IORESOURCE_DMA_16BIT (2<<0) + +#define IORESOURCE_DMA_MASTER (1<<2) +#define IORESOURCE_DMA_BYTE (1<<3) +#define IORESOURCE_DMA_WORD (1<<4) + +#define IORESOURCE_DMA_SPEED_MASK (3<<6) +#define IORESOURCE_DMA_COMPATIBLE (0<<6) +#define IORESOURCE_DMA_TYPEA (1<<6) +#define IORESOURCE_DMA_TYPEB (2<<6) +#define IORESOURCE_DMA_TYPEF (3<<6) + +/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ +#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ +#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ +#define IORESOURCE_MEM_TYPE_MASK (3<<3) +#define IORESOURCE_MEM_8BIT (0<<3) +#define IORESOURCE_MEM_16BIT (1<<3) +#define IORESOURCE_MEM_8AND16BIT (2<<3) +#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ +#define IORESOURCE_MEM_EXPANSIONROM (1<<6) /* PC/ISA/whatever - the normal PC address spaces: IO and memory */ extern struct resource ioport_resource; @@ -54,6 +80,10 @@ extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); +extern int allocate_resource(struct resource *root, struct resource *new, + unsigned long size, + unsigned long min, unsigned long max, + unsigned long align); /* Convenience shorthand with allocation */ #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) diff -u --recursive --new-file v2.3.14/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h --- v2.3.14/linux/include/linux/ip_fw.h Wed Aug 18 16:44:42 1999 +++ linux/include/linux/ip_fw.h Wed Dec 31 16:00:00 1969 @@ -1,193 +0,0 @@ -/* - * This code is heavily based on the code in ip_fw.h; see that file for - * copyrights and attributions. This code is basically GPL. - * - * 15-Feb-1997: Major changes to allow graphs for firewall rules. - * Paul Russell and - * Michael Neuling - * 2-Nov-1997: Changed types to __u16, etc. - * Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR. - * Added inverse flags field. - * Removed multiple port specs. - */ - -/* - * Format of an IP firewall descriptor - * - * src, dst, src_mask, dst_mask are always stored in network byte order. - * flags are stored in host byte order (of course). - * Port numbers are stored in HOST byte order. - */ - -#ifndef _IP_FWCHAINS_H -#define _IP_FWCHAINS_H - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include -#endif /* __KERNEL__ */ -#define IP_FW_MAX_LABEL_LENGTH 8 -typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1]; - -struct ip_fw -{ - struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ - struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ - __u32 fw_mark; /* ID to stamp on packet */ - __u16 fw_proto; /* Protocol, 0 = ANY */ - __u16 fw_flg; /* Flags word */ - __u16 fw_invflg; /* Inverse flags */ - __u16 fw_spts[2]; /* Source port range. */ - __u16 fw_dpts[2]; /* Destination port range. */ - __u16 fw_redirpt; /* Port to redirect to. */ - __u16 fw_outputsize; /* Max amount to output to - NETLINK */ - char fw_vianame[IFNAMSIZ]; /* name of interface "via" */ - __u8 fw_tosand, fw_tosxor; /* Revised packet priority */ -}; - -struct ip_fwuser -{ - struct ip_fw ipfw; - ip_chainlabel label; -}; - -/* Values for "fw_flg" field . */ -#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */ -#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */ -#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */ -#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */ -#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */ -#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */ -#define IP_FW_F_MASK 0x003F /* All possible flag bits mask */ - -/* Values for "fw_invflg" field. */ -#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */ -#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */ -#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */ -#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */ -#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */ -#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */ -#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */ -#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */ - -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. */ - -#define IP_FW_BASE_CTL 64 /* base for firewall socket options */ - -#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */ -#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */ -#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */ -#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */ -#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */ -#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */ -#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */ -#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */ -#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */ -#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */ -#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */ -#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */ -/* Masquerade control, only 1 optname */ - -#define IP_FW_MASQ_CTL (IP_FW_BASE_CTL+12) /* General ip_masq ctl */ - -/* Builtin chain labels */ -#define IP_FW_LABEL_FORWARD "forward" -#define IP_FW_LABEL_INPUT "input" -#define IP_FW_LABEL_OUTPUT "output" - -/* Special targets */ -#define IP_FW_LABEL_MASQUERADE "MASQ" -#define IP_FW_LABEL_REDIRECT "REDIRECT" -#define IP_FW_LABEL_ACCEPT "ACCEPT" -#define IP_FW_LABEL_BLOCK "DENY" -#define IP_FW_LABEL_REJECT "REJECT" -#define IP_FW_LABEL_RETURN "RETURN" -#define IP_FW_LABEL_QUEUE "QUEUE" - -/* Files in /proc/net */ -#define IP_FW_PROC_CHAINS "ip_fwchains" -#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames" - - -struct ip_fwpkt -{ - struct iphdr fwp_iph; /* IP header */ - union { - struct tcphdr fwp_tcph; /* TCP header or */ - struct udphdr fwp_udph; /* UDP header */ - struct icmphdr fwp_icmph; /* ICMP header */ - } fwp_protoh; - struct in_addr fwp_via; /* interface address */ - char fwp_vianame[IFNAMSIZ]; /* interface name */ -}; - -/* The argument to IP_FW_DELETE and IP_FW_APPEND */ -struct ip_fwchange -{ - struct ip_fwuser fwc_rule; - ip_chainlabel fwc_label; -}; - -/* The argument to IP_FW_CHECK. */ -struct ip_fwtest -{ - struct ip_fwpkt fwt_packet; /* Packet to be tested */ - ip_chainlabel fwt_label; /* Block to start test in */ -}; - -/* The argument to IP_FW_DELETE_NUM */ -struct ip_fwdelnum -{ - __u32 fwd_rulenum; - ip_chainlabel fwd_label; -}; - -/* The argument to IP_FW_REPLACE and IP_FW_INSERT */ -struct ip_fwnew -{ - __u32 fwn_rulenum; - struct ip_fwuser fwn_rule; - ip_chainlabel fwn_label; -}; - -/* The argument to IP_FW_POLICY */ -struct ip_fwpolicy -{ - ip_chainlabel fwp_policy; - ip_chainlabel fwp_label; -}; -/* - * timeouts for ip masquerading - */ - -extern int ip_fw_masq_timeouts(void *, int); - - -/* - * Main firewall chains definitions and global var's definitions. - */ - -#ifdef __KERNEL__ - -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include -extern void ip_fw_init(void) __init; -#else /* 2.0.x */ -extern void ip_fw_init(void); -#endif /* 2.1.x */ -extern int ip_fw_ctl(int, void *, int); -#ifdef CONFIG_IP_MASQUERADE -extern int ip_masq_uctl(int, char *, int); -#endif -#endif /* KERNEL */ - -#endif /* _IP_FWCHAINS_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/ip_masq.h linux/include/linux/ip_masq.h --- v2.3.14/linux/include/linux/ip_masq.h Mon Jan 4 15:31:35 1999 +++ linux/include/linux/ip_masq.h Wed Dec 31 16:00:00 1969 @@ -1,140 +0,0 @@ -/* - * IP_MASQ user space control interface - * $Id: ip_masq.h,v 1.2 1998/12/08 05:41:48 davem Exp $ - */ - -#ifndef _LINUX_IP_MASQ_H -#define _LINUX_IP_MASQ_H - -#ifdef __KERNEL__ -#include -#include -#else -#include -#include -#endif - -struct ip_masq_user { - int protocol; - u_int16_t sport, dport, mport; - u_int32_t saddr, daddr, maddr; - u_int32_t rt_daddr; /* dst address to use for rt query */ - u_int32_t rt_saddr; - u_int32_t ip_tos; /* TOS */ - unsigned timeout; /* in ticks (HZ per sec) */ - unsigned flags; - int fd; /* NOT IMPL: attach tunnel to this fd */ - int state; /* NOT IMPL: return conn state */ -}; - -#define IP_MASQ_USER_F_LISTEN 0x01 /* put entry to LISTEN state */ -#define IP_MASQ_USER_F_DEAD 0x02 /* mark as DEAD */ -#define IP_MASQ_USER_F_FORCE 0x04 /* force operation */ - -struct ip_masq_timeout { - int protocol; - union { - struct { - unsigned established; - unsigned syn_sent; - unsigned syn_recv; - unsigned fin_wait; - unsigned time_wait; - unsigned close; - unsigned close_wait; - unsigned last_ack; - unsigned listen; - } tcp; - unsigned udp; - unsigned icmp; - } u; -}; - -/* - * AUTOFW stuff - */ -#define IP_FWD_RANGE 1 -#define IP_FWD_PORT 2 -#define IP_FWD_DIRECT 3 - -#define IP_AUTOFW_ACTIVE 1 -#define IP_AUTOFW_USETIME 2 -#define IP_AUTOFW_SECURE 4 - - -/* WARNING: bitwise equal to ip_autofw in net/ip_autofw.h */ -struct ip_autofw_user { - void * next; - u_int16_t type; - u_int16_t low; - u_int16_t hidden; - u_int16_t high; - u_int16_t visible; - u_int16_t protocol; - u_int32_t lastcontact; - u_int32_t where; - u_int16_t ctlproto; - u_int16_t ctlport; - u_int16_t flags; - /* struct timer_list timer; */ -}; - -/* - * PORTFW stuff - */ -struct ip_portfw_user { - u_int16_t protocol; /* Which protocol are we talking? */ - u_int32_t laddr, raddr; /* Remote address */ - u_int16_t lport, rport; /* Local and remote port */ - int pref; /* Preference value */ -}; - -/* - * MFW stuff - */ -struct ip_mfw_user { - u_int32_t fwmark; /* Firewalling mark */ - u_int32_t raddr; /* remote port */ - u_int16_t rport; /* remote port */ - u_int16_t dummy; /* Make up to multiple of 4 */ - int pref; /* Preference value */ - unsigned flags; /* misc flags */ -}; - -#define IP_MASQ_MFW_SCHED 0x01 - -#define IP_FW_MASQCTL_MAX 256 -#define IP_MASQ_TNAME_MAX 32 - -struct ip_masq_ctl { - int m_target; - int m_cmd; - char m_tname[IP_MASQ_TNAME_MAX]; - union { - struct ip_portfw_user portfw_user; - struct ip_autofw_user autofw_user; - struct ip_mfw_user mfw_user; - struct ip_masq_user user; - unsigned char m_raw[IP_FW_MASQCTL_MAX]; - } u; -}; - -#define IP_MASQ_CTL_BSIZE (offsetof (struct ip_masq_ctl,u)) - -#define IP_MASQ_TARGET_CORE 1 -#define IP_MASQ_TARGET_MOD 2 /* masq_mod is selected by "name" */ -#define IP_MASQ_TARGET_USER 3 -#define IP_MASQ_TARGET_LAST 4 - -#define IP_MASQ_CMD_NONE 0 /* just peek */ -#define IP_MASQ_CMD_INSERT 1 -#define IP_MASQ_CMD_ADD 2 -#define IP_MASQ_CMD_SET 3 -#define IP_MASQ_CMD_DEL 4 -#define IP_MASQ_CMD_GET 5 -#define IP_MASQ_CMD_FLUSH 6 -#define IP_MASQ_CMD_LIST 7 /* actually fake: done via /proc */ -#define IP_MASQ_CMD_ENABLE 8 -#define IP_MASQ_CMD_DISABLE 9 - -#endif /* _LINUX_IP_MASQ_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/isapnp.h linux/include/linux/isapnp.h --- v2.3.14/linux/include/linux/isapnp.h Wed Aug 18 16:44:31 1999 +++ linux/include/linux/isapnp.h Mon Aug 23 14:49:40 1999 @@ -63,23 +63,23 @@ unsigned short max; /* max base number */ unsigned char align; /* align boundary */ unsigned char size; /* size of range */ - unsigned short flags; /* port flags */ + unsigned char flags; /* port flags */ + unsigned char pad; /* pad */ struct isapnp_resources *res; /* parent */ struct isapnp_port *next; /* next port */ }; struct isapnp_irq { unsigned short map; /* bitmaks for IRQ lines */ - unsigned short flags; /* IRQ flags */ + unsigned char flags; /* IRQ flags */ + unsigned char pad; /* pad */ struct isapnp_resources *res; /* parent */ struct isapnp_irq *next; /* next IRQ */ }; struct isapnp_dma { unsigned char map; /* bitmask for DMA channels */ - unsigned char type; /* DMA type */ unsigned char flags; /* DMA flags */ - unsigned char speed; /* DMA speed */ struct isapnp_resources *res; /* parent */ struct isapnp_dma *next; /* next port */ }; @@ -89,8 +89,8 @@ unsigned int max; /* max base number */ unsigned int align; /* align boundary */ unsigned int size; /* size of range */ - unsigned short flags; /* memory flags */ - unsigned short type; /* memory type */ + unsigned char flags; /* memory flags */ + unsigned char pad; /* pad */ struct isapnp_resources *res; /* parent */ struct isapnp_mem *next; /* next memory resource */ }; @@ -120,7 +120,7 @@ struct isapnp_resources *next; /* next resource */ }; -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) /* lowlevel configuration */ int isapnp_present(void); @@ -144,6 +144,10 @@ unsigned short vendor, unsigned short function, struct pci_dev *from); +/* misc */ +void isapnp_resource_change(struct resource *resource, + unsigned long start, + unsigned long size); /* init/main.c */ int isapnp_init(void); @@ -171,6 +175,9 @@ unsigned short vendor, unsigned short function, struct pci_dev *from) { return NULL; } +extern void isapnp_resource_change(struct resource *resource, + unsigned long start, + unsigned long size) { ; } #endif /* CONFIG_ISAPNP */ diff -u --recursive --new-file v2.3.14/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.3.14/linux/include/linux/isdn.h Wed Aug 18 11:38:46 1999 +++ linux/include/linux/isdn.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.70 1999/07/31 12:59:58 armin Exp $ +/* $Id: isdn.h,v 1.71 1999/08/23 15:54:22 keil Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.71 1999/08/23 15:54:22 keil + * more backported changes from kernel 2.3.14 + * * Revision 1.70 1999/07/31 12:59:58 armin * Added tty fax capabilities. * @@ -577,13 +580,13 @@ ulong sqfull_stamp; /* Start-Time of overload */ ulong slavedelay; /* Dynamic bundling delaytime */ int triggercps; /* BogoCPS needed for trigger slave */ - struct net_device *srobin; /* Ptr to Master device for slaves */ + struct net_device *srobin; /* Ptr to Master device for slaves */ isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ isdn_net_phone *dial; /* Pointer to dialed number */ - struct net_device *master; /* Ptr to Master device for slaves */ - struct net_device *slave; /* Ptr to Slave device for masters */ + struct net_device *master; /* Ptr to Master device for slaves */ + struct net_device *slave; /* Ptr to Slave device for masters */ struct isdn_net_local_s *next; /* Ptr to next link in bundle */ struct isdn_net_local_s *last; /* Ptr to last link in bundle */ struct isdn_net_dev_s *netdev; /* Ptr to netdev */ @@ -616,7 +619,7 @@ isdn_net_local *local; isdn_net_local *queue; void *next; /* Pointer to next isdn-interface */ - struct net_device dev; /* interface to upper levels */ + struct net_device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP struct mpqueue *mp_last; struct ippp_bundle ib; diff -u --recursive --new-file v2.3.14/linux/include/linux/isdn_compat.h linux/include/linux/isdn_compat.h --- v2.3.14/linux/include/linux/isdn_compat.h Thu Aug 12 09:42:34 1999 +++ linux/include/linux/isdn_compat.h Wed Aug 25 15:18:08 1999 @@ -104,5 +104,13 @@ #define COMPAT_HAS_NEW_WAITQ #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,12) +#define COMPAT_HAS_NEW_SETUP +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14) +#define net_device device +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_ISDN_COMPAT_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v2.3.14/linux/include/linux/isdnif.h Sun Aug 15 11:49:08 1999 +++ linux/include/linux/isdnif.h Wed Aug 25 15:18:08 1999 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.29 1999/07/31 13:00:02 armin Exp $ +/* $Id: isdnif.h,v 1.30 1999/08/23 15:54:29 keil Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.30 1999/08/23 15:54:29 keil + * more backported changes from kernel 2.3.14 + * * Revision 1.29 1999/07/31 13:00:02 armin * Added tty fax capabilities. * diff -u --recursive --new-file v2.3.14/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.3.14/linux/include/linux/kernel.h Fri Aug 6 11:43:09 1999 +++ linux/include/linux/kernel.h Mon Aug 23 10:23:23 1999 @@ -43,6 +43,7 @@ #endif extern void math_error(void); +extern struct notifier_block *panic_notifier_list; NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))); NORET_TYPE void do_exit(long error_code) diff -u --recursive --new-file v2.3.14/linux/include/linux/major.h linux/include/linux/major.h --- v2.3.14/linux/include/linux/major.h Thu Aug 5 18:48:45 1999 +++ linux/include/linux/major.h Mon Aug 23 10:18:38 1999 @@ -64,7 +64,6 @@ #define AZTECH_CDROM_MAJOR 29 #define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ #define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define USEMA_MAJOR 86 /* Linux/MIPS, SGI /dev/usema */ #define CM206_CDROM_MAJOR 32 #define IDE2_MAJOR 33 #define IDE3_MAJOR 34 @@ -76,6 +75,7 @@ #define DDV_MAJOR 39 /* AP1000 DDV block device */ #define NBD_MAJOR 43 /* Network block device */ #define RISCOM8_NORMAL_MAJOR 48 +#define DAC960_MAJOR 48 /* 48..55 */ #define RISCOM8_CALLOUT_MAJOR 49 #define MKISS_MAJOR 55 #define DSP56K_MAJOR 55 /* DSP56001 processor device */ diff -u --recursive --new-file v2.3.14/linux/include/linux/mroute.h linux/include/linux/mroute.h --- v2.3.14/linux/include/linux/mroute.h Wed Aug 18 16:44:38 1999 +++ linux/include/linux/mroute.h Mon Aug 23 14:49:57 1999 @@ -126,13 +126,9 @@ */ #ifdef __KERNEL__ -extern struct sock *mroute_socket; extern int ip_mroute_setsockopt(struct sock *, int, char *, int); extern int ip_mroute_getsockopt(struct sock *, int, char *, int *); extern int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg); -extern void mroute_close(struct sock *sk); -extern void ipmr_forward(struct sk_buff *skb, int is_frag); -extern int ip_mr_find_tunnel(__u32, __u32); extern void ip_mr_init(void); @@ -148,29 +144,35 @@ int link; /* Physical interface index */ }; +#define VIFF_STATIC 0x8000 + struct mfc_cache { struct mfc_cache *next; /* Next entry on cache line */ __u32 mfc_mcastgrp; /* Group the entry belongs to */ __u32 mfc_origin; /* Source of packet */ vifi_t mfc_parent; /* Source interface */ - struct timer_list mfc_timer; /* Expiry timer */ int mfc_flags; /* Flags on line */ - struct sk_buff_head mfc_unresolved; /* Unresolved buffers */ - int mfc_queuelen; /* Unresolved buffer counter */ - unsigned long mfc_last_assert; - int mfc_minvif; - int mfc_maxvif; - unsigned long mfc_bytes; - unsigned long mfc_pkt; - unsigned long mfc_wrong_if; - unsigned char mfc_ttls[MAXVIFS]; /* TTL thresholds */ -}; -#define MFC_QUEUED 1 -#define MFC_RESOLVED 2 -#define MFC_NOTIFY 4 + union { + struct { + unsigned long expires; + struct sk_buff_head unresolved; /* Unresolved buffers */ + } unres; + struct { + unsigned long last_assert; + int minvif; + int maxvif; + unsigned long bytes; + unsigned long pkt; + unsigned long wrong_if; + unsigned char ttls[MAXVIFS]; /* TTL thresholds */ + } res; + } mfc_un; +}; +#define MFC_STATIC 1 +#define MFC_NOTIFY 2 #define MFC_LINES 64 diff -u --recursive --new-file v2.3.14/linux/include/linux/msg.h linux/include/linux/msg.h --- v2.3.14/linux/include/linux/msg.h Tue May 11 14:37:40 1999 +++ linux/include/linux/msg.h Tue Aug 24 10:00:53 1999 @@ -11,8 +11,10 @@ #define MSG_NOERROR 010000 /* no error if message is too big */ #define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ +#ifdef __KERNEL__ + /* one msqid structure for each queue on the system */ -struct msqid_ds { +struct msqid_ds_kern { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue */ struct msg *msg_last; /* last message in queue */ @@ -28,6 +30,24 @@ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ }; +#endif + +struct msqid_ds { + struct ipc_perm msg_perm; + struct msg *msg_first; /* first message on queue */ + struct msg *msg_last; /* last message in queue */ + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + unsigned long msg_cbytes; /* Reuse junk fields for 32 bit */ + unsigned long msg_qbytes; /* ditto */ + unsigned short msg_cbytes_old; /* current number of bytes on queue */ + unsigned short msg_qnum; /* number of messages in queue */ + unsigned short msg_qbytes_old; /* max number of bytes on queue */ + __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ +}; + /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { long mtype; /* type of message */ @@ -69,11 +89,10 @@ short msg_ts; /* message text size */ }; -asmlinkage int sys_msgget (key_t key, int msgflg); -asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); -asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, - int msgflg); -asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); +asmlinkage long sys_msgget (key_t key, int msgflg); +asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); +asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); +asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/net.h linux/include/linux/net.h --- v2.3.14/linux/include/linux/net.h Wed Aug 18 16:43:30 1999 +++ linux/include/linux/net.h Mon Aug 23 14:48:49 1999 @@ -73,18 +73,17 @@ short type; unsigned char passcred; - unsigned char tli; }; #define SOCK_INODE(S) ((S)->inode) struct scm_cookie; +struct vm_area_struct; struct proto_ops { int family; - int (*dup) (struct socket *newsock, struct socket *oldsock); - int (*release) (struct socket *sock, struct socket *peer); + int (*release) (struct socket *sock); int (*bind) (struct socket *sock, struct sockaddr *umyaddr, int sockaddr_len); int (*connect) (struct socket *sock, struct sockaddr *uservaddr, @@ -107,6 +106,7 @@ unsigned long arg); int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); + int (*mmap) (struct file *file, struct socket *sock, struct vm_area_struct * vma); }; struct net_proto_family @@ -126,7 +126,6 @@ void (*init_func)(struct net_proto *); /* Bootstrap */ }; -extern struct net_proto_family *net_families[]; extern int sock_wake_async(struct socket *sk, int how); extern int sock_register(struct net_proto_family *fam); extern int sock_unregister(int family); @@ -141,6 +140,89 @@ extern int net_ratelimit(void); extern unsigned long net_random(void); extern void net_srandom(unsigned long); + +#ifndef __SMP__ +#define SOCKOPS_WRAPPED(name) name +#define SOCKOPS_WRAP(name, fam) +#else + +#define SOCKOPS_WRAPPED(name) __unlocked_##name + +#define SOCKCALL_WRAP(name, call, parms, args) \ +static int __lock_##name##_##call parms \ +{ \ + int ret; \ + lock_kernel(); \ + ret = __unlocked_##name##_ops.call args ;\ + unlock_kernel(); \ + return ret; \ +} + +#define SOCKCALL_UWRAP(name, call, parms, args) \ +static unsigned int __lock_##name##_##call parms \ +{ \ + int ret; \ + lock_kernel(); \ + ret = __unlocked_##name##_ops.call args ;\ + unlock_kernel(); \ + return ret; \ +} + + +#define SOCKOPS_WRAP(name, fam) \ +SOCKCALL_WRAP(name, release, (struct socket *sock), (sock)) \ +SOCKCALL_WRAP(name, bind, (struct socket *sock, struct sockaddr *uaddr, int addr_len), \ + (sock, uaddr, addr_len)) \ +SOCKCALL_WRAP(name, connect, (struct socket *sock, struct sockaddr * uaddr, \ + int addr_len, int flags), \ + (sock, uaddr, addr_len, flags)) \ +SOCKCALL_WRAP(name, socketpair, (struct socket *sock1, struct socket *sock2), \ + (sock1, sock2)) \ +SOCKCALL_WRAP(name, accept, (struct socket *sock, struct socket *newsock, \ + int flags), (sock, newsock, flags)) \ +SOCKCALL_WRAP(name, getname, (struct socket *sock, struct sockaddr *uaddr, \ + int *addr_len, int peer), (sock, uaddr, addr_len, peer)) \ +SOCKCALL_UWRAP(name, poll, (struct file *file, struct socket *sock, struct poll_table_struct *wait), \ + (file, sock, wait)) \ +SOCKCALL_WRAP(name, ioctl, (struct socket *sock, unsigned int cmd, \ + unsigned long arg), (sock, cmd, arg)) \ +SOCKCALL_WRAP(name, listen, (struct socket *sock, int len), (sock, len)) \ +SOCKCALL_WRAP(name, shutdown, (struct socket *sock, int flags), (sock, flags)) \ +SOCKCALL_WRAP(name, setsockopt, (struct socket *sock, int level, int optname, \ + char *optval, int optlen), (sock, level, optname, optval, optlen)) \ +SOCKCALL_WRAP(name, getsockopt, (struct socket *sock, int level, int optname, \ + char *optval, int *optlen), (sock, level, optname, optval, optlen)) \ +SOCKCALL_WRAP(name, fcntl, (struct socket *sock, unsigned int cmd, \ + unsigned long arg), (sock, cmd, arg)) \ +SOCKCALL_WRAP(name, sendmsg, (struct socket *sock, struct msghdr *m, int len, struct scm_cookie *scm), \ + (sock, m, len, scm)) \ +SOCKCALL_WRAP(name, recvmsg, (struct socket *sock, struct msghdr *m, int len, int flags, struct scm_cookie *scm), \ + (sock, m, len, flags, scm)) \ +SOCKCALL_WRAP(name, mmap, (struct file *file, struct socket *sock, struct vm_area_struct *vma), \ + (file, sock, vma)) \ + \ +static struct proto_ops name##_ops = { \ + fam, \ + \ + __lock_##name##_release, \ + __lock_##name##_bind, \ + __lock_##name##_connect, \ + __lock_##name##_socketpair, \ + __lock_##name##_accept, \ + __lock_##name##_getname, \ + __lock_##name##_poll, \ + __lock_##name##_ioctl, \ + __lock_##name##_listen, \ + __lock_##name##_shutdown, \ + __lock_##name##_setsockopt, \ + __lock_##name##_getsockopt, \ + __lock_##name##_fcntl, \ + __lock_##name##_sendmsg, \ + __lock_##name##_recvmsg, \ + __lock_##name##_mmap, \ +}; +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_NET_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.3.14/linux/include/linux/netdevice.h Wed Aug 18 16:44:28 1999 +++ linux/include/linux/netdevice.h Tue Aug 24 17:10:20 1999 @@ -35,12 +35,16 @@ #ifdef CONFIG_NET_PROFILE #include #endif + +#define NET_XMIT_SUCCESS 0 +#define NET_XMIT_DROP 1 /* skb dropped */ +#define NET_XMIT_CN 2 /* congestion notification */ +#define NET_XMIT_POLICED 3 /* skb is shot by police */ + +#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) + #endif -/* - * For future expansion when we will have different priorities. - */ - #define MAX_ADDR_LEN 7 /* Largest hardware address length */ /* @@ -206,7 +210,6 @@ /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); - void (*destructor)(struct net_device *dev); /* Interface index. Unique device identifier */ int ifindex; @@ -276,7 +279,19 @@ int xmit_lock_owner; /* device queue lock */ spinlock_t queue_lock; + /* Number of references to this device */ atomic_t refcnt; + /* The flag marking that device is unregistered, but held by an user */ + int deadbeaf; + /* New style devices allow asynchronous destruction; + netdevice_unregister for old style devices blocks until + the last user will dereference this device. + */ + int new_style; + /* Called after device is detached from network. */ + void (*uninit)(struct net_device *dev); + /* Called after last user reference disappears. */ + void (*destructor)(struct net_device *dev); /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); @@ -316,12 +331,10 @@ int (*accept_fastpath)(struct net_device *, struct dst_entry*); #ifdef CONFIG_NET_FASTROUTE - /* Really, this semaphore may be necessary and for not fastroute code; - f.e. SMP?? - */ - int tx_semaphore; + unsigned long tx_semaphore; #define NETDEV_FASTROUTE_HMASK 0xF /* Semi-private data. Keep it at the end of device struct. */ + rwlock_t fastpath_lock; struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; #endif }; @@ -350,7 +363,9 @@ extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); -extern struct net_device *dev_get(const char *name); +extern int dev_get(const char *name); +extern struct net_device *dev_get_by_name(const char *name); +extern struct net_device *__dev_get_by_name(const char *name); extern struct net_device *dev_alloc(const char *name, int *err); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); @@ -363,6 +378,7 @@ extern int unregister_netdevice_notifier(struct notifier_block *nb); extern int dev_new_index(void); extern struct net_device *dev_get_by_index(int ifindex); +extern struct net_device *__dev_get_by_index(int ifindex); extern int dev_restart(struct net_device *dev); typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); @@ -384,61 +400,39 @@ extern int netdev_nit; -/* Locking protection for page faults during outputs to devices unloaded during the fault */ - -extern atomic_t dev_lockct; - -/* - * These two don't currently need to be atomic - * but they may do soon. Do it properly anyway. - */ - -extern __inline__ void dev_lock_list(void) -{ - atomic_inc(&dev_lockct); -} - -extern __inline__ void dev_unlock_list(void) +extern __inline__ void dev_init_buffers(struct net_device *dev) { - atomic_dec(&dev_lockct); + /* DO NOTHING */ } -/* - * This almost never occurs, isn't in performance critical paths - * and we can thus be relaxed about it. - * - * FIXME: What if this is being run as a real time process ?? - * Linus: We need a way to force a yield here ? - * - * FIXME: Though dev_lockct is atomic varible, locking procedure - * is not atomic. - */ +extern int netdev_finish_unregister(struct net_device *dev); -extern __inline__ void dev_lock_wait(void) +extern __inline__ void dev_put(struct net_device *dev) { - while (atomic_read(&dev_lockct)) { - current->policy |= SCHED_YIELD; - schedule(); - } + if (atomic_dec_and_test(&dev->refcnt)) + netdev_finish_unregister(dev); } -extern __inline__ void dev_init_buffers(struct net_device *dev) -{ - /* DO NOTHING */ -} +#define __dev_put(dev) atomic_dec(&(dev)->refcnt) +#define dev_hold(dev) atomic_inc(&(dev)->refcnt) + /* These functions live elsewhere (drivers/net/net_init.c, but related) */ extern void ether_setup(struct net_device *dev); extern void fddi_setup(struct net_device *dev); extern void tr_setup(struct net_device *dev); +extern void fc_setup(struct net_device *dev); extern void tr_freedev(struct net_device *dev); +extern void fc_freedev(struct net_device *dev); extern int ether_config(struct net_device *dev, struct ifmap *map); /* Support for loadable net-drivers */ extern int register_netdev(struct net_device *dev); extern void unregister_netdev(struct net_device *dev); extern int register_trdev(struct net_device *dev); extern void unregister_trdev(struct net_device *dev); +extern int register_fcdev(struct net_device *dev); +extern void unregister_fcdev(struct net_device *dev); /* Functions used for multicast support */ extern void dev_mc_upload(struct net_device *dev); extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter.h linux/include/linux/netfilter.h --- v2.3.14/linux/include/linux/netfilter.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter.h Tue Aug 24 17:12:39 1999 @@ -0,0 +1,194 @@ +#ifndef __LINUX_NETFILTER_H +#define __LINUX_NETFILTER_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#endif + +/* Responses from hook functions. */ +#define NF_DROP 0 +#define NF_ACCEPT 1 +#define NF_STOLEN 2 +#define NF_QUEUE 3 +#define NF_MAX_VERDICT NF_QUEUE + +/* Generic cache responses from hook functions. */ +#define NFC_ALTERED 0x8000 +#define NFC_UNKNOWN 0x4000 + +#ifdef __KERNEL__ +#include +#ifdef CONFIG_NETFILTER + +extern void netfilter_init(void); + +/* Largest hook number + 1 */ +#define NF_MAX_HOOKS 5 + +struct sk_buff; +struct net_device; + +typedef unsigned int nf_hookfn(unsigned int hooknum, + struct sk_buff **skb, + const struct net_device *in, + const struct net_device *out); + +typedef unsigned int nf_cacheflushfn(const void *packet, + const struct net_device *in, + const struct net_device *out, + u_int32_t packetcount, + u_int32_t bytecount); + +struct nf_hook_ops +{ + struct list_head list; + + /* User fills in from here down. */ + nf_hookfn *hook; + nf_cacheflushfn *flush; + int pf; + int hooknum; + /* Hooks are ordered in ascending priority. */ + int priority; +}; + +struct nf_setsockopt_ops +{ + struct list_head list; + + int pf; + int optmin; + int optmax; + int (*fn)(int optval, void *user, unsigned int len); +}; + +/* Function to register/unregister hook points. */ +int nf_register_hook(struct nf_hook_ops *reg); +void nf_unregister_hook(struct nf_hook_ops *reg); + +/* Functions to register setsockopt ranges (inclusive). */ +int nf_register_sockopt(struct nf_setsockopt_ops *reg); +void nf_unregister_sockopt(struct nf_setsockopt_ops *reg); + +extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; + +/* Activate hook/flush; either okfn or kfree_skb called, unless a hook + returns NF_STOLEN (in which case, it's up to the hook to deal with + the consequences). + + Returns -ERRNO if packet dropped. Zero means queued, stolen or + accepted. +*/ + +/* RR: + > I don't want nf_hook to return anything because people might forget + > about async and trust the return value to mean "packet was ok". + + AK: + Just document it clearly, then you can expect some sense from kernel + coders :) +*/ + +/* This is gross, but inline doesn't cut it for avoiding the function + call in fast path: gcc doesn't inline (needs value tracking?). --RR */ +#ifdef CONFIG_NETFILTER_DEBUG +#define NF_HOOK nf_hook_slow +#else +#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ +(list_empty(&nf_hooks[(pf)][(hook)]) \ + ? (okfn)(skb) \ + : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn))) +#endif + +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, + struct net_device *indev, struct net_device *outdev, + int (*okfn)(struct sk_buff *)); + +void nf_cacheflush(int pf, unsigned int hook, const void *packet, + const struct net_device *indev, const struct net_device *outdev, + __u32 packetcount, __u32 bytecount); + +/* Call setsockopt() */ +int nf_setsockopt(int pf, int optval, char *opt, unsigned int len); + +struct nf_wakeme +{ + wait_queue_head_t sleep; + struct sk_buff_head skbq; +}; + +/* For netfilter device. */ +struct nf_interest +{ + struct list_head list; + + int pf; + /* Bitmask of hook numbers to match (1 << hooknum). */ + unsigned int hookmask; + /* If non-zero, only catch packets with this mark. */ + unsigned int mark; + /* If non-zero, only catch packets of this reason. */ + unsigned int reason; + + struct nf_wakeme *wake; +}; + +/* For asynchronous packet handling. */ +extern void nf_register_interest(struct nf_interest *interest); +extern void nf_unregister_interest(struct nf_interest *interest); +extern void nf_getinfo(const struct sk_buff *skb, + struct net_device **indev, + struct net_device **outdev, + unsigned long *mark); +extern void nf_reinject(struct sk_buff *skb, + unsigned long mark, + unsigned int verdict); + +#ifdef CONFIG_NETFILTER_DEBUG +extern void nf_dump_skb(int pf, struct sk_buff *skb); +#endif + +/* FIXME: Before cache is ever used, this must be implemented for real. */ +extern void nf_invalidate_cache(int pf); + +#else /* !CONFIG_NETFILTER */ +#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) +#endif /*CONFIG_NETFILTER*/ + +/* From arch/i386/kernel/smp.c: + * + * Why isn't this somewhere standard ?? + * + * Maybe because this procedure is horribly buggy, and does + * not deserve to live. Think about signedness issues for five + * seconds to see why. - Linus + */ + +/* Two signed, return a signed. */ +#define SMAX(a,b) ((ssize_t)(a)>(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) +#define SMIN(a,b) ((ssize_t)(a)<(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) + +/* Two unsigned, return an unsigned. */ +#define UMAX(a,b) ((size_t)(a)>(size_t)(b) ? (size_t)(a) : (size_t)(b)) +#define UMIN(a,b) ((size_t)(a)<(size_t)(b) ? (size_t)(a) : (size_t)(b)) + +/* Two unsigned, return a signed. */ +#define SUMAX(a,b) ((size_t)(a)>(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) +#define SUMIN(a,b) ((size_t)(a)<(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) +#endif /*__KERNEL__*/ + +enum nf_reason { + /* Do not, NOT, reorder these. Add at end. */ + NF_REASON_NONE, + NF_REASON_SET_BY_IPCHAINS, + NF_REASON_FOR_ROUTING, + NF_REASON_FOR_CLS_FW, + NF_REASON_MIN_RESERVED_FOR_CONNTRACK = 1024, +}; + +#endif /*__LINUX_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter_ddp.h linux/include/linux/netfilter_ddp.h --- v2.3.14/linux/include/linux/netfilter_ddp.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ddp.h Mon Aug 23 09:56:58 1999 @@ -0,0 +1,14 @@ +#ifndef __LINUX_DDP_NETFILTER_H +#define __LINUX_DDP_NETFILTER_H + +/* DDP-specific defines for netfilter. Complete me sometime. + * (C)1998 Rusty Russell -- This code is GPL. + */ + +#include + +/* Appletalk hooks */ +#define NF_DDP_INPUT 0 +#define NF_DDP_FORWARD 1 +#define NF_DDP_OUTPUT 2 +#endif /*__LINUX_DDP_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter_decnet.h linux/include/linux/netfilter_decnet.h --- v2.3.14/linux/include/linux/netfilter_decnet.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_decnet.h Mon Aug 23 09:56:58 1999 @@ -0,0 +1,35 @@ +#ifndef __LINUX_DECNET_NETFILTER_H +#define __LINUX_DECNET_NETFILTER_H + +/* DECnet-specific defines for netfilter. + * This file (C) Steve Whitehouse 1999 derived from the + * ipv4 netfilter header file which is + * (C)1998 Rusty Russell -- This code is GPL. + */ + +#include + +/* IP Cache bits. */ +/* Src IP address. */ +#define NFC_DN_SRC 0x0001 +/* Dest IP address. */ +#define NFC_DN_DST 0x0002 +/* Input device. */ +#define NFC_DN_IF_IN 0x0004 +/* Output device. */ +#define NFC_DN_IF_OUT 0x0008 + +/* DECnet Hooks */ +/* After promisc drops, checksum checks. */ +#define NF_DN_PRE_ROUTING 0 +/* If the packet is destined for this box. */ +#define NF_DN_LOCAL_IN 1 +/* If the packet is destined for another interface. */ +#define NF_DN_FORWARD 2 +/* Packets coming from a local process. */ +#define NF_DN_LOCAL_OUT 3 +/* Packets about to hit the wire. */ +#define NF_DN_POST_ROUTING 4 +#define NF_DN_NUMHOOKS 5 + +#endif /*__LINUX_DECNET_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter_ipv4.h linux/include/linux/netfilter_ipv4.h --- v2.3.14/linux/include/linux/netfilter_ipv4.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4.h Tue Aug 24 17:12:39 1999 @@ -0,0 +1,59 @@ +#ifndef __LINUX_IP_NETFILTER_H +#define __LINUX_IP_NETFILTER_H + +/* IPv4-specific defines for netfilter. + * (C)1998 Rusty Russell -- This code is GPL. + */ + +#include +#include + +/* IP Cache bits. */ +/* Src IP address. */ +#define NFC_IP_SRC 0x0001 +/* Dest IP address. */ +#define NFC_IP_DST 0x0002 +/* Input device. */ +#define NFC_IP_IF_IN 0x0004 +/* Output device. */ +#define NFC_IP_IF_OUT 0x0008 +/* TOS. */ +#define NFC_IP_TOS 0x0010 +/* Protocol. */ +#define NFC_IP_PROTO 0x0020 +/* IP options. */ +#define NFC_IP_OPTIONS 0x0040 +/* Frag & flags. */ +#define NFC_IP_FRAG 0x0080 + +/* Per-protocol information: only matters if proto match. */ +/* TCP flags. */ +#define NFC_IP_TCPFLAGS 0x0100 +/* Source port. */ +#define NFC_IP_SRC_PT 0x0200 +/* Dest port. */ +#define NFC_IP_DST_PT 0x0400 +/* Something else about the proto */ +#define NFC_IP_PROTO_UNKNOWN 0x2000 + +/* IP Hooks */ +/* After promisc drops, checksum checks. */ +#define NF_IP_PRE_ROUTING 0 +/* If the packet is destined for this box. */ +#define NF_IP_LOCAL_IN 1 +/* If the packet is destined for another interface. */ +#define NF_IP_FORWARD 2 +/* Packets coming from a local process. */ +#define NF_IP_LOCAL_OUT 3 +/* Packets about to hit the wire. */ +#define NF_IP_POST_ROUTING 4 +#define NF_IP_NUMHOOKS 5 + +#ifdef CONFIG_NETFILTER_DEBUG +void debug_print_hooks_ip(unsigned int nf_debug); +void nf_debug_ip_local_deliver(struct sk_buff *skb); +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb); +void nf_debug_ip_finish_output2(struct sk_buff *skb); +#endif + +#endif /*__LINUX_IP_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter_ipx.h linux/include/linux/netfilter_ipx.h --- v2.3.14/linux/include/linux/netfilter_ipx.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipx.h Mon Aug 23 09:56:58 1999 @@ -0,0 +1,14 @@ +#ifndef __LINUX_IPX_NETFILTER_H +#define __LINUX_IPX_NETFILTER_H + +/* IPX-specific defines for netfilter. Complete me sometime. + * (C)1998 Rusty Russell -- This code is GPL. + */ + +#include + +/* IPX Hooks */ +#define NF_IPX_INPUT 0 +#define NF_IPX_FORWARD 1 +#define NF_IPX_OUTPUT 2 +#endif /*__LINUX_IPX_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/netfilter_x25.h linux/include/linux/netfilter_x25.h --- v2.3.14/linux/include/linux/netfilter_x25.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_x25.h Mon Aug 23 09:56:58 1999 @@ -0,0 +1,15 @@ +#ifndef __LINUX_X25_NETFILTER_H +#define __LINUX_X25_NETFILTER_H + +/* X25-specific defines for netfilter. Complete me sometime. + * (C)1998 Rusty Russell -- This code is GPL. + */ + +#include + +/* Hooks */ +#define NF_X25_INPUT 0 +#define NF_X25_FORWARD 1 +#define NF_X25_OUTPUT 2 + +#endif /*__LINUX_X25_NETFILTER_H*/ diff -u --recursive --new-file v2.3.14/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.3.14/linux/include/linux/parport.h Wed Aug 18 16:44:35 1999 +++ linux/include/linux/parport.h Tue Aug 24 17:10:12 1999 @@ -491,7 +491,7 @@ extern void inc_parport_count(void); /* If PC hardware is the only type supported, we can optimise a bit. */ -#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !defined(CONFIG_PARPORT_OTHER) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) +#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !defined(CONFIG_PARPORT_OTHER) #undef PARPORT_NEED_GENERIC_OPS #include diff -u --recursive --new-file v2.3.14/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.3.14/linux/include/linux/pci.h Wed Aug 18 16:43:30 1999 +++ linux/include/linux/pci.h Mon Aug 23 14:48:50 1999 @@ -38,7 +38,7 @@ #define PCI_STATUS 0x06 /* 16 bits */ #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ #define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ #define PCI_STATUS_PARITY 0x100 /* Detected parity error */ #define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ @@ -86,7 +86,7 @@ #define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 #define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 #define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M */ +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ #define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ #define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ #define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) @@ -135,7 +135,8 @@ #define PCI_PREF_LIMIT_UPPER32 0x2c #define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ #define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34-0x3b is reserved */ +/* 0x34 same as for htype 0 */ +/* 0x35-0x3b is reserved */ #define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ /* 0x3c-0x3d are same as for htype 0 */ #define PCI_BRIDGE_CONTROL 0x3e @@ -185,10 +186,81 @@ /* 0x48-0x7f reserved */ /* Capability lists */ + #define PCI_CAP_LIST_ID 0 /* Capability ID */ #define PCI_CAP_ID_PM 0x01 /* Power Management */ #define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ +#define PCI_CAP_SIZEOF 4 + +/* Power Management Registers */ + +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ +#define PCI_PM_CAP_AUX_POWER 0x0010 /* Auxilliary power support */ +#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ +#define PCI_PM_CTRL 4 /* PM control and status register */ +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ +#define PCI_PM_DATA_REGISTER 7 /* (??) */ +#define PCI_PM_SIZEOF 8 + +/* AGP registers */ + +#define PCI_AGP_VERSION 2 /* BCD version number */ +#define PCI_AGP_RFU 3 /* Rest of capability flags */ +#define PCI_AGP_STATUS 4 /* Status register */ +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ +#define PCI_AGP_COMMAND 8 /* Control register */ +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 4x rate */ +#define PCI_AGP_SIZEOF 12 + +/* Slot Identification */ + +#define PCI_SID_ESR 2 /* Expansion Slot Register */ +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ + +/* Message Signalled Interrupts registers */ + +#define PCI_MSI_FLAGS 2 /* Various flags */ +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ +#define PCI_MSI_RFU 3 /* Rest of capability flags */ +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ /* Device classes and subclasses */ @@ -372,6 +444,7 @@ #define PCI_DEVICE_ID_DEC_21152 0x0024 #define PCI_DEVICE_ID_DEC_21153 0x0025 #define PCI_DEVICE_ID_DEC_21154 0x0026 +#define PCI_DEVICE_ID_DEC_21285 0x1065 #define PCI_DEVICE_ID_COMPAQ_42XX 0x0046 #define PCI_VENDOR_ID_CIRRUS 0x1013 @@ -554,6 +627,12 @@ #define PCI_VENDOR_ID_X 0x1061 #define PCI_DEVICE_ID_X_AGX016 0x0001 +#define PCI_VENDOR_ID_MYLEX 0x1069 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V2 0x0001 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V3 0x0002 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020 + #define PCI_VENDOR_ID_PICOP 0x1066 #define PCI_DEVICE_ID_PICOP_PT86C52X 0x0001 #define PCI_DEVICE_ID_PICOP_PT80C524 0x8002 @@ -570,6 +649,7 @@ #define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 #define PCI_DEVICE_ID_QLOGIC_ISP1022 0x1022 #define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 +#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 #define PCI_VENDOR_ID_CYRIX 0x1078 #define PCI_DEVICE_ID_CYRIX_5510 0x0000 @@ -1096,6 +1176,7 @@ #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82430 0x0486 #define PCI_DEVICE_ID_INTEL_82434 0x04a3 +#define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 #define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 #define PCI_DEVICE_ID_INTEL_7116 0x1223 @@ -1119,6 +1200,9 @@ #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_VENDOR_ID_COMPUTONE 0x8e0e +#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291 + #define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180 #define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181 #define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190 @@ -1190,6 +1274,10 @@ #define PCI_DEVICE_ID_ARK_STINGARK 0xa099 #define PCI_DEVICE_ID_ARK_2000MT 0xa0a1 +#define PCI_VENDOR_ID_INTERPHASE 0x107e +#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004 +#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005 + /* * The PCI interface treats multi-function devices as independent * devices. The slot/function address of each device is encoded @@ -1209,35 +1297,12 @@ #include #define DEVICE_COUNT_COMPATIBLE 4 +#define DEVICE_COUNT_IRQ 2 #define DEVICE_COUNT_DMA 2 #define DEVICE_COUNT_RESOURCE 12 -#define DEVICE_IRQ_NOTSET 0xffffffff -#define DEVICE_IRQ_AUTO 0xfffffffe -#define DEVICE_DMA_NOTSET 0xff -#define DEVICE_DMA_AUTO 0xfe - -#define DEVICE_IRQ_FLAG_HIGHEDGE (1<<0) -#define DEVICE_IRQ_FLAG_LOWEDGE (1<<1) -#define DEVICE_IRQ_FLAG_HIGHLEVEL (1<<2) -#define DEVICE_IRQ_FLAG_LOWLEVEL (1<<3) - -#define DEVICE_DMA_TYPE_8BIT 0 -#define DEVICE_DMA_TYPE_8AND16BIT 1 -#define DEVICE_DMA_TYPE_16BIT 2 - -#define DEVICE_DMA_FLAG_MASTER (1<<0) -#define DEVICE_DMA_FLAG_BYTE (1<<1) -#define DEVICE_DMA_FLAG_WORD (1<<2) - -#define DEVICE_DMA_SPEED_COMPATIBLE 0 -#define DEVICE_DMA_SPEED_TYPEA 1 -#define DEVICE_DMA_SPEED_TYPEB 2 -#define DEVICE_DMA_SPEED_TYPEF 3 - /* - * There is one pci_dev structure for each slot-number/function-number - * combination: + * The pci_dev structure is used to describe both PCI and ISAPnP devices. */ struct pci_dev { int active; /* device is active */ @@ -1253,53 +1318,47 @@ unsigned int devfn; /* encoded device & function index */ unsigned short vendor; unsigned short device; + unsigned short subsystem_vendor; + unsigned short subsystem_device; unsigned int class; /* 3 bytes: (base,sub,prog-if) */ unsigned int hdr_type; /* PCI header type */ unsigned int master : 1; /* set if device is master capable */ unsigned short regs; - + /* device is compatible with these IDs */ unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; - char name[48]; - /* - * In theory, the irq level can be read from configuration - * space and all would be fine. However, old PCI chips don't - * support these registers and return 0 instead. For example, - * the Vision864-P rev 0 chip can uses INTA, but returns 0 in - * the interrupt line and pin registers. pci_init() - * initializes this field with the value at PCI_INTERRUPT_LINE - * and it is the job of pcibios_fixup() to change it if - * necessary. The field must not be 0 unless the device - * cannot generate interrupts at all. + * Instead of touching interrupt line and base address registers + * directly, use the values stored here. They might be different! */ - unsigned int irq; /* irq generated by this device */ - unsigned short irq_flags; /* irq type */ - unsigned int irq2; - unsigned short irq2_flags; - unsigned char dma[DEVICE_COUNT_DMA]; - unsigned char dma_type[DEVICE_COUNT_DMA]; - unsigned char dma_flags[DEVICE_COUNT_DMA]; - unsigned char dma_speed[DEVICE_COUNT_DMA]; + unsigned int irq; + struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ + struct resource dma_resource[DEVICE_COUNT_DMA]; + struct resource irq_resource[DEVICE_COUNT_IRQ]; - /* Base registers for this device, can be adjusted by - * pcibios_fixup() as necessary. - */ - struct resource resource[DEVICE_COUNT_RESOURCE]; - unsigned long rom_address; + char name[48]; /* Device name */ int (*prepare)(struct pci_dev *dev); int (*activate)(struct pci_dev *dev); int (*deactivate)(struct pci_dev *dev); }; +#define PCI_ROM_RESOURCE 6 +#define PCI_NUM_RESOURCES 7 + +#define PCI_REGION_EXISTS(dev, r) (dev)->resource[r].start +#define PCI_REGION_IS_IO(dev, r) (PCI_REGION_EXISTS(dev,r) && ((dev)->resource[r].flags & PCI_BASE_ADDRESS_SPACE_IO)) +#define PCI_REGION_IS_MEM(dev, r) (PCI_REGION_EXISTS(dev,r) && !((dev)->resource[r].flags & PCI_BASE_ADDRESS_SPACE_IO)) +#define PCI_REGION_FLAG_MASK 0x0f /* These bits of resource flags tell us the PCI region flags */ + struct pci_bus { struct pci_bus *parent; /* parent bus this bridge is on */ struct pci_bus *children; /* chain of P2P bridges on this bus */ struct pci_bus *next; /* chain of all PCI buses */ + struct pci_ops *ops; /* configuration access functions */ struct pci_dev *self; /* bridge device as seen by parent */ struct pci_dev *devices; /* devices behind this bridge */ @@ -1322,11 +1381,11 @@ unsigned char pad1; }; -extern struct pci_bus pci_root; /* root bus */ +extern struct pci_bus *pci_root; /* root bus */ extern struct pci_dev *pci_devices; /* list of all devices */ /* - * Error values that may be returned by the PCI bios. + * Error values that may be returned by PCI functions. */ #define PCIBIOS_SUCCESSFUL 0x00 #define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 @@ -1338,11 +1397,24 @@ /* Low-level architecture-dependent routines */ -int pcibios_present (void); +struct pci_ops { + int (*read_byte)(struct pci_dev *, int where, u8 *val); + int (*read_word)(struct pci_dev *, int where, u16 *val); + int (*read_dword)(struct pci_dev *, int where, u32 *val); + int (*write_byte)(struct pci_dev *, int where, u8 val); + int (*write_word)(struct pci_dev *, int where, u16 val); + int (*write_dword)(struct pci_dev *, int where, u32 val); +}; + void pcibios_init(void); -void pcibios_fixup(void); void pcibios_fixup_bus(struct pci_bus *); char *pcibios_setup (char *str); + + +/* Backward compatibility, don't use in new code! */ + +int pcibios_present(void); +#define pci_present pcibios_present int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, unsigned char where, unsigned char *val); int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, @@ -1355,9 +1427,6 @@ unsigned char where, unsigned short val); int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn, unsigned char where, unsigned int val); - -/* Don't use these in new code, use pci_find_... instead */ - int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn); int pcibios_find_device (unsigned short vendor, unsigned short dev_id, unsigned short index, unsigned char *bus, @@ -1366,26 +1435,27 @@ /* Generic PCI interface functions */ void pci_init(void); -void pci_quirks_init(void); -unsigned int pci_scan_bus(struct pci_bus *bus); -struct pci_bus *pci_scan_peer_bridge(int bus); +struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); int get_pci_list(char *buf); int pci_proc_attach_device(struct pci_dev *dev); int pci_proc_detach_device(struct pci_dev *dev); +void pci_name_device(struct pci_dev *dev); struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from); +struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from); struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); #define PCI_ANY_ID (~0) -#define pci_present pcibios_present -int pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val); -int pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val); -int pci_read_config_dword(struct pci_dev *dev, u8 where, u32 *val); -int pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val); -int pci_write_config_word(struct pci_dev *dev, u8 where, u16 val); -int pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val); +int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); +int pci_read_config_word(struct pci_dev *dev, int where, u16 *val); +int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val); +int pci_write_config_byte(struct pci_dev *dev, int where, u8 val); +int pci_write_config_word(struct pci_dev *dev, int where, u16 val); +int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); void pci_set_master(struct pci_dev *dev); #ifndef CONFIG_PCI @@ -1396,7 +1466,7 @@ #define _PCI_NOP(o,s,t) \ extern inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } \ - extern inline int pci_##o##_config_##s## (struct pci_dev *dev, u8 where, t val) \ + extern inline int pci_##o##_config_##s## (struct pci_dev *dev, int where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } #define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ _PCI_NOP(o,word,u16 x) \ @@ -1414,6 +1484,26 @@ { return NULL; } #endif /* !CONFIG_PCI */ + +/* + * The world is not perfect and supplies us with broken PCI devices. + * For at least a part of these bugs we need a work-around, so both + * generic (drivers/pci/quirks.c) and per-architecture code can define + * fixup hooks to be called for particular buggy devices. + */ + +struct pci_fixup { + int pass; + u16 vendor, device; /* You can use PCI_ANY_ID here of course */ + void (*hook)(struct pci_dev *dev); +}; + +extern struct pci_fixup pcibios_fixups[]; + +#define PCI_FIXUP_HEADER 1 /* Called immediately after reading configuration header */ +#define PCI_FIXUP_FINAL 2 /* Final phase of device fixups */ + +void pci_fixup_device(int pass, struct pci_dev *dev); #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/personality.h linux/include/linux/personality.h --- v2.3.14/linux/include/linux/personality.h Mon Aug 2 10:19:52 1999 +++ linux/include/linux/personality.h Mon Aug 23 11:15:53 1999 @@ -53,6 +53,6 @@ extern struct exec_domain *lookup_exec_domain(unsigned long personality); extern int register_exec_domain(struct exec_domain *it); extern int unregister_exec_domain(struct exec_domain *it); -asmlinkage int sys_personality(unsigned long personality); +asmlinkage long sys_personality(unsigned long personality); #endif /* _PERSONALITY_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/pipe_fs_i.h linux/include/linux/pipe_fs_i.h --- v2.3.14/linux/include/linux/pipe_fs_i.h Wed Jun 16 19:26:27 1999 +++ linux/include/linux/pipe_fs_i.h Tue Aug 24 10:12:00 1999 @@ -3,32 +3,29 @@ struct pipe_inode_info { wait_queue_head_t wait; - char * base; + char *base; unsigned int start; - unsigned int lock; - unsigned int rd_openers; - unsigned int wr_openers; unsigned int readers; unsigned int writers; }; -#define PIPE_WAIT(inode) ((inode).i_pipe->wait) +/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual + memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ +#define PIPE_SIZE PAGE_SIZE + +#define PIPE_SEM(inode) (&(inode).i_sem) +#define PIPE_WAIT(inode) (&(inode).i_pipe->wait) #define PIPE_BASE(inode) ((inode).i_pipe->base) #define PIPE_START(inode) ((inode).i_pipe->start) #define PIPE_LEN(inode) ((inode).i_size) -#define PIPE_RD_OPENERS(inode) ((inode).i_pipe->rd_openers) -#define PIPE_WR_OPENERS(inode) ((inode).i_pipe->wr_openers) #define PIPE_READERS(inode) ((inode).i_pipe->readers) #define PIPE_WRITERS(inode) ((inode).i_pipe->writers) -#define PIPE_LOCK(inode) ((inode).i_pipe->lock) -#define PIPE_SIZE(inode) PIPE_LEN(inode) -#define PIPE_EMPTY(inode) (PIPE_SIZE(inode)==0) -#define PIPE_FULL(inode) (PIPE_SIZE(inode)==PIPE_BUF) -#define PIPE_FREE(inode) (PIPE_BUF - PIPE_LEN(inode)) -#define PIPE_END(inode) ((PIPE_START(inode)+PIPE_LEN(inode))&\ - (PIPE_BUF-1)) -#define PIPE_MAX_RCHUNK(inode) (PIPE_BUF - PIPE_START(inode)) -#define PIPE_MAX_WCHUNK(inode) (PIPE_BUF - PIPE_END(inode)) +#define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0) +#define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE) +#define PIPE_FREE(inode) (PIPE_SIZE - PIPE_LEN(inode)) +#define PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1)) +#define PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode)) +#define PIPE_MAX_WCHUNK(inode) (PIPE_SIZE - PIPE_END(inode)) #endif diff -u --recursive --new-file v2.3.14/linux/include/linux/pkt_sched.h linux/include/linux/pkt_sched.h --- v2.3.14/linux/include/linux/pkt_sched.h Wed Jun 9 14:45:36 1999 +++ linux/include/linux/pkt_sched.h Mon Aug 23 09:56:32 1999 @@ -277,4 +277,18 @@ #define TCA_CBQ_MAX TCA_CBQ_POLICE +/* ATM section */ + +enum { + TCA_ATM_UNSPEC, + TCA_ATM_FD, /* file/socket descriptor */ + TCA_ATM_PTR, /* pointer to descriptor - later */ + TCA_ATM_HDR, /* LL header */ + TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ + TCA_ATM_ADDR, /* PVC address (for output only) */ + TCA_ATM_STATE /* VC state (ATM_VS_*; for output only) */ +}; + +#define TCA_ATM_MAX TCA_ATM_STATE + #endif diff -u --recursive --new-file v2.3.14/linux/include/linux/prctl.h linux/include/linux/prctl.h --- v2.3.14/linux/include/linux/prctl.h Mon Sep 22 14:55:59 1997 +++ linux/include/linux/prctl.h Wed Aug 25 15:47:44 1999 @@ -1,9 +1,10 @@ #ifndef _LINUX_PRCTL_H #define _LINUX_PRCTL_H -/* Values to pass as first argument to prctl() */ +/* Values to pass as first argument to prctl() */ -#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ #endif /* _LINUX_PRCTL_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.3.14/linux/include/linux/proc_fs.h Wed Aug 18 16:44:06 1999 +++ linux/include/linux/proc_fs.h Tue Aug 24 17:09:19 1999 @@ -209,6 +209,7 @@ PROC_SCSI_PLUTO, PROC_SCSI_INI9100U, PROC_SCSI_INIA100, + PROC_SCSI_IPH5526_FC, PROC_SCSI_FCAL, PROC_SCSI_I2O, PROC_SCSI_USB_SCSI, diff -u --recursive --new-file v2.3.14/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h --- v2.3.14/linux/include/linux/rtnetlink.h Wed Jun 9 14:45:36 1999 +++ linux/include/linux/rtnetlink.h Mon Aug 23 10:01:02 1999 @@ -256,16 +256,26 @@ enum { RTAX_UNSPEC, +#define RTAX_UNSPEC RTAX_UNSPEC RTAX_LOCK, +#define RTAX_LOCK RTAX_LOCK RTAX_MTU, +#define RTAX_MTU RTAX_MTU RTAX_WINDOW, +#define RTAX_WINDOW RTAX_WINDOW RTAX_RTT, - RTAX_HOPS, +#define RTAX_RTT RTAX_RTT + RTAX_RTTVAR, +#define RTAX_RTTVAR RTAX_RTTVAR RTAX_SSTHRESH, +#define RTAX_SSTHRESH RTAX_SSTHRESH RTAX_CWND, +#define RTAX_CWND RTAX_CWND + RTAX_ADVMSS, +#define RTAX_ADVMSS RTAX_ADVMSS }; -#define RTAX_MAX RTAX_CWND +#define RTAX_MAX RTAX_ADVMSS @@ -535,6 +545,7 @@ extern struct rtnetlink_link * rtnetlink_links[NPROTO]; extern int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb); extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); +extern int rtnetlink_put_metrics(struct sk_buff *skb, unsigned *metrics); extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); @@ -565,6 +576,10 @@ extern void rtnl_unlock(void); extern void rtnetlink_init(void); +#define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0) { up(&rtnl_sem); \ +printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \ + } while(0); +#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/sem.h linux/include/linux/sem.h --- v2.3.14/linux/include/linux/sem.h Tue May 11 14:37:40 1999 +++ linux/include/linux/sem.h Mon Aug 23 11:15:53 1999 @@ -105,9 +105,9 @@ short * semadj; /* array of adjustments, one per semaphore */ }; -asmlinkage int sys_semget (key_t key, int nsems, int semflg); -asmlinkage int sys_semop (int semid, struct sembuf *sops, unsigned nsops); -asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); +asmlinkage long sys_semget (key_t key, int nsems, int semflg); +asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops); +asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/shm.h linux/include/linux/shm.h --- v2.3.14/linux/include/linux/shm.h Sun Dec 27 22:18:30 1998 +++ linux/include/linux/shm.h Mon Aug 23 11:15:53 1999 @@ -68,10 +68,10 @@ #define SHM_DEST 01000 /* segment will be destroyed on last detach */ #define SHM_LOCKED 02000 /* segment will not be swapped */ -asmlinkage int sys_shmget (key_t key, int size, int flag); -asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); -asmlinkage int sys_shmdt (char *shmaddr); -asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +asmlinkage long sys_shmget (key_t key, int size, int flag); +asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); +asmlinkage long sys_shmdt (char *shmaddr); +asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); extern void shm_unuse(unsigned long entry, unsigned long page); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.3.14/linux/include/linux/skbuff.h Wed Aug 18 16:44:22 1999 +++ linux/include/linux/skbuff.h Tue Aug 24 17:09:23 1999 @@ -31,6 +31,12 @@ #define CHECKSUM_HW 1 #define CHECKSUM_UNNECESSARY 2 +#ifdef __i386__ +#define NET_CALLER(arg) (*(((void**)&arg)-1)) +#else +#define NET_CALLER(arg) __builtin_return_address(0) +#endif + struct sk_buff_head { /* These two members must be first. */ struct sk_buff * next; @@ -49,6 +55,7 @@ struct sock *sk; /* Socket we are owned by */ struct timeval stamp; /* Time we arrived */ struct net_device *dev; /* Device we arrived on/are leaving by */ + struct net_device *rx_dev; /* Transport layer header */ union @@ -102,9 +109,17 @@ unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ void (*destructor)(struct sk_buff *); /* Destruct function */ -#ifdef CONFIG_IP_FIREWALL - __u32 fwmark; /* Label made by fwchains, used by pktsched */ +#ifdef CONFIG_NETFILTER + /* Can be used for communication between hooks. */ + unsigned long nfmark; + /* Reason for doing this to the packet (see netfilter.h) */ + __u32 nfreason; + /* Cache info */ + __u32 nfcache; +#ifdef CONFIG_NETFILTER_DEBUG + unsigned int nf_debug; #endif +#endif /*CONFIG_NETFILTER*/ #if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) __u32 shapelatency; /* Latency on frame */ __u32 shapeclock; /* Time it should go out */ @@ -200,6 +215,18 @@ return (atomic_read(&skb->users) != 1); } +extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri) +{ + if (skb_shared(skb)) { + struct sk_buff *nskb; + nskb = skb_clone(skb, pri); + kfree_skb(skb); + return nskb; + } + return skb; +} + + /* * Copy shared buffers into a new sk_buff. We effectively do COW on * packets to handle cases where we have a local reader and forward @@ -548,6 +575,13 @@ { struct sk_buff *skb; while ((skb=skb_dequeue(list))!=NULL) + kfree_skb(skb); +} + +extern __inline__ void __skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb=__skb_dequeue(list))!=NULL) kfree_skb(skb); } diff -u --recursive --new-file v2.3.14/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.3.14/linux/include/linux/socket.h Thu Apr 15 05:42:43 1999 +++ linux/include/linux/socket.h Mon Aug 23 10:01:02 1999 @@ -158,7 +158,7 @@ #define AF_DECnet 12 /* Reserved for DECnet project */ #define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ #define AF_SECURITY 14 /* Security callback pseudo AF */ -#define pseudo_AF_KEY 15 /* PF_KEY key management API */ +#define AF_KEY 15 /* PF_KEY key management API */ #define AF_NETLINK 16 #define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */ #define AF_PACKET 17 /* Packet family */ @@ -186,7 +186,7 @@ #define PF_DECnet AF_DECnet #define PF_NETBEUI AF_NETBEUI #define PF_SECURITY AF_SECURITY -#define PF_KEY pseudo_AF_KEY +#define PF_KEY AF_KEY #define PF_NETLINK AF_NETLINK #define PF_ROUTE AF_ROUTE #define PF_PACKET AF_PACKET @@ -210,22 +210,19 @@ #define MSG_DONTROUTE 4 #define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */ #define MSG_CTRUNC 8 -#define MSG_PROXY 0x10 /* Supply or ask second address. */ +#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */ #define MSG_TRUNC 0x20 #define MSG_DONTWAIT 0x40 /* Nonblocking io */ #define MSG_EOR 0x80 /* End of record */ #define MSG_WAITALL 0x100 /* Wait for a full request */ #define MSG_FIN 0x200 #define MSG_SYN 0x400 -#define MSG_URG 0x800 +#define MSG_CONFIRM 0x800 /* Confirm path validity */ #define MSG_RST 0x1000 -#define MSG_ERRQUEUE 0x2000 -#define MSG_NOSIGNAL 0x4000 - -#define MSG_CTLIGNORE 0x80000000 +#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ +#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ #define MSG_EOF MSG_FIN -#define MSG_CTLFLAGS (MSG_OOB|MSG_URG|MSG_FIN|MSG_SYN|MSG_RST) /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ diff -u --recursive --new-file v2.3.14/linux/include/linux/sonet.h linux/include/linux/sonet.h --- v2.3.14/linux/include/linux/sonet.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/sonet.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,52 @@ +/* sonet.h - SONET/SHD physical layer control */ + +/* Written 1995 by Werner Almesberger, EPFL LRC */ + + +#ifndef LINUX_SONET_H +#define LINUX_SONET_H + +struct sonet_stats { + long section_bip; /* section parity errors (B1) */ + long line_bip; /* line parity errors (B2) */ + long path_bip; /* path parity errors (B3) */ + long line_febe; /* line parity errors at remote */ + long path_febe; /* path parity errors at remote */ + long corr_hcs; /* correctable header errors */ + long uncorr_hcs; /* uncorrectable header errors */ + long tx_cells; /* cells sent */ + long rx_cells; /* cells received */ +}; + +#define SONET_GETSTAT _IOR('a',ATMIOC_PHYTYP,struct sonet_stats) + /* get statistics */ +#define SONET_GETSTATZ _IOR('a',ATMIOC_PHYTYP+1,struct sonet_stats) + /* ... and zero counters */ +#define SONET_SETDIAG _IOWR('a',ATMIOC_PHYTYP+2,int) + /* set error insertion */ +#define SONET_CLRDIAG _IOWR('a',ATMIOC_PHYTYP+3,int) + /* clear error insertion */ +#define SONET_GETDIAG _IOR('a',ATMIOC_PHYTYP+4,int) + /* query error insertion */ +#define SONET_SETFRAMING _IO('a',ATMIOC_PHYTYP+5) + /* set framing mode (SONET/SDH) */ +#define SONET_GETFRAMING _IOR('a',ATMIOC_PHYTYP+6,int) + /* get framing mode */ +#define SONET_GETFRSENSE _IOR('a',ATMIOC_PHYTYP+7, \ + unsigned char[SONET_FRSENSE_SIZE]) /* get framing sense information */ + +#define SONET_INS_SBIP 1 /* section BIP */ +#define SONET_INS_LBIP 2 /* line BIP */ +#define SONET_INS_PBIP 4 /* path BIP */ +#define SONET_INS_FRAME 8 /* out of frame */ +#define SONET_INS_LOS 16 /* set line to zero */ +#define SONET_INS_LAIS 32 /* line alarm indication signal */ +#define SONET_INS_PAIS 64 /* path alarm indication signal */ +#define SONET_INS_HCS 128 /* insert HCS error */ + +#define SONET_FRAME_SONET 0 /* SONET STS-3 framing */ +#define SONET_FRAME_SDH 1 /* SDH STM-1 framing */ + +#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */ + +#endif diff -u --recursive --new-file v2.3.14/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.3.14/linux/include/linux/swap.h Wed Aug 18 16:43:30 1999 +++ linux/include/linux/swap.h Tue Aug 24 17:09:23 1999 @@ -120,8 +120,8 @@ int next; /* swapfile to be used next */ }; extern struct swap_list_t swap_list; -asmlinkage int sys_swapoff(const char *); -asmlinkage int sys_swapon(const char *, int); +asmlinkage long sys_swapoff(const char *); +asmlinkage long sys_swapon(const char *, int); /* * vm_ops not present page codes for shared memory. diff -u --recursive --new-file v2.3.14/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.3.14/linux/include/linux/sysctl.h Wed Aug 18 09:45:10 1999 +++ linux/include/linux/sysctl.h Mon Aug 23 11:15:53 1999 @@ -224,7 +224,8 @@ NET_IPV4_ICMP_PARAMPROB_RATE=62, NET_IPV4_ICMP_ECHOREPLY_RATE=63, NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64, - NET_IPV4_IGMP_MAX_MEMBERSHIPS=65 + NET_IPV4_IGMP_MAX_MEMBERSHIPS=65, + NET_TCP_TW_RECYCLE=66 }; enum { @@ -242,7 +243,9 @@ NET_IPV4_ROUTE_ERROR_COST=12, NET_IPV4_ROUTE_ERROR_BURST=13, NET_IPV4_ROUTE_GC_ELASTICITY=14, - NET_IPV4_ROUTE_MTU_EXPIRES=15 + NET_IPV4_ROUTE_MTU_EXPIRES=15, + NET_IPV4_ROUTE_MIN_PMTU=16, + NET_IPV4_ROUTE_MIN_ADVMSS=17 }; enum @@ -265,7 +268,8 @@ NET_IPV4_CONF_RP_FILTER=8, NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, NET_IPV4_CONF_BOOTP_RELAY=10, - NET_IPV4_CONF_LOG_MARTIANS=11 + NET_IPV4_CONF_LOG_MARTIANS=11, + NET_IPV4_CONF_TAG=12 }; /* /proc/sys/net/ipv6 */ @@ -283,7 +287,8 @@ NET_IPV6_ROUTE_GC_TIMEOUT=5, NET_IPV6_ROUTE_GC_INTERVAL=6, NET_IPV6_ROUTE_GC_ELASTICITY=7, - NET_IPV6_ROUTE_MTU_EXPIRES=8 + NET_IPV6_ROUTE_MTU_EXPIRES=8, + NET_IPV6_ROUTE_MIN_ADVMSS=9 }; enum { @@ -515,7 +520,7 @@ #ifdef __KERNEL__ -extern asmlinkage int sys_sysctl(struct __sysctl_args *); +extern asmlinkage long sys_sysctl(struct __sysctl_args *); extern void sysctl_init(void); typedef struct ctl_table ctl_table; @@ -554,6 +559,7 @@ extern ctl_handler sysctl_string; extern ctl_handler sysctl_intvec; +extern ctl_handler sysctl_jiffies; extern int do_string ( void *oldval, size_t *oldlenp, void *newval, size_t newlen, diff -u --recursive --new-file v2.3.14/linux/include/linux/tcp.h linux/include/linux/tcp.h --- v2.3.14/linux/include/linux/tcp.h Wed Aug 18 16:43:34 1999 +++ linux/include/linux/tcp.h Mon Aug 23 14:48:53 1999 @@ -87,4 +87,27 @@ TCPF_CLOSING = (1 << 11) }; +/* + * The union cast uses a gcc extension to avoid aliasing problems + * (union is compatible to any of its members) + * This means this part of the code is -fstrict-aliasing safe now. + */ +union tcp_word_hdr { + struct tcphdr hdr; + __u32 words[5]; +}; + +#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) + +enum { + TCP_FLAG_URG = __constant_htonl(0x00200000), + TCP_FLAG_ACK = __constant_htonl(0x00100000), + TCP_FLAG_PSH = __constant_htonl(0x00080000), + TCP_FLAG_RST = __constant_htonl(0x00040000), + TCP_FLAG_SYN = __constant_htonl(0x00020000), + TCP_FLAG_FIN = __constant_htonl(0x00010000), + TCP_RESERVED_BITS = __constant_htonl(0x0FC00000), + TCP_DATA_OFFSET = __constant_htonl(0xF0000000) +}; + #endif /* _LINUX_TCP_H */ diff -u --recursive --new-file v2.3.14/linux/include/linux/wireless.h linux/include/linux/wireless.h --- v2.3.14/linux/include/linux/wireless.h Sat Apr 24 17:51:48 1999 +++ linux/include/linux/wireless.h Mon Aug 23 11:13:59 1999 @@ -1,9 +1,9 @@ /* * This file define a set of standard wireless extensions * - * Version : 7 23.4.99 + * Version : 8 28.7.99 * - * Authors : Jean Tourrilhes - HPLB - + * Authors : Jean Tourrilhes - HPL - */ #ifndef _LINUX_WIRELESS_H @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 6 +#define WIRELESS_EXT 8 /* * Changes : @@ -90,6 +90,12 @@ * V6 to V7 * -------- * - define IW_ESSID_MAX_SIZE and IW_MAX_AP + * + * V7 to V8 + * -------- + * - Changed my e-mail address + * - More 802.11 support (nickname, rate, rts, frag) + * - List index in frequencies */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -117,24 +123,34 @@ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ /* Access Point manipulation */ -#define SIOCSIWAP 0x8B14 /* set access point hardware addresses */ -#define SIOCGIWAP 0x8B15 /* get access point hardware addresses */ +#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ +#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ /* 802.11 specific support */ #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ #define SIOCGIWESSID 0x8B1B /* get ESSID */ -/* As the ESSID is a string up to 32 bytes long, it doesn't fit within the - * 'iwreq' structure, so we need to use the 'data' member to point to a - * string in user space, like it is done for RANGE... - * The "flags" member indicate if the ESSID is active or not. +#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ +#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ +/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to + * point to a string in user space, like it is done for RANGE... + * The "flags" member indicate if the ESSID is active or not (promiscuous). */ +/* Other parameters usefull in 802.11 and some other devices */ +#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ +#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ +#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ +#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ +#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ + /* ------------------------- IOCTL STUFF ------------------------- */ /* The first and the last (range) */ #define SIOCIWFIRST 0x8B00 -#define SIOCIWLAST 0x8B1B +#define SIOCIWLAST 0x8B25 /* Even : get (world access), odd : set (root access) */ #define IW_IS_SET(cmd) (!((cmd) & 0x1)) @@ -171,6 +187,9 @@ * don't increase this constant and don't fill the frequency list. * The user will be able to set by channel anyway... */ +/* Maximum bit rates in the range struct */ +#define IW_MAX_BITRATES 8 + /* Maximum of address that you may set with SPY */ #define IW_MAX_SPY 8 @@ -178,7 +197,7 @@ list of access points in range */ #define IW_MAX_AP 8 -/* Maximum size of the ESSID string */ +/* Maximum size of the ESSID and NICKN strings */ #define IW_ESSID_MAX_SIZE 32 /****************************** TYPES ******************************/ @@ -186,15 +205,17 @@ /* --------------------------- SUBTYPES --------------------------- */ /* * A frequency - * For numbers lower than 10^9, we encode the number in 'mant' and - * set 'exp' to 0 - * For number greater than 10^9, we divide it by a power of 10. - * The power of 10 is in 'exp', the result is in 'mant'. + * For numbers lower than 10^9, we encode the number in 'm' and + * set 'e' to 0 + * For number greater than 10^9, we divide it by the lowest power + * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... + * The power of 10 is in 'e', the result of the division is in 'm'. */ struct iw_freq { __u32 m; /* Mantissa */ __u16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ }; /* @@ -229,6 +250,15 @@ __u64 code; /* Data/key used for algorithm */ }; +/* + * Generic format for parameters + */ +struct iw_param +{ + __s32 value; /* The value of the parameter itself */ + __u8 fixed; /* Hardware should not use auto select */ +}; + /* ------------------------ WIRELESS STATS ------------------------ */ /* @@ -258,7 +288,7 @@ { union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ } ifr_ifrn; /* Data part */ @@ -281,7 +311,11 @@ struct iw_encoding encoding; /* Encoding stuff */ - __u32 sensitivity; /* signal level threshold */ + __u32 sensitivity; /* Obsolete, but compatible */ + struct iw_param sens; /* signal level threshold */ + struct iw_param bitrate; /* default bit rate */ + struct iw_param rts; /* RTS threshold threshold */ + struct iw_param frag; /* Fragmentation threshold */ struct sockaddr ap_addr; /* Access point address */ @@ -309,6 +343,12 @@ { /* Informative stuff (to choose between different interface) */ __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ /* NWID (or domain id) */ __u32 min_nwid; /* Minimal NWID we are able to set */ @@ -321,13 +361,25 @@ /* Note : this frequency list doesn't need to fit channel numbers */ /* signal level threshold range */ - __u32 sensitivity; + __s32 sensitivity; /* Quality of link & SNR stuff */ struct iw_quality max_qual; /* Quality of the link */ /* Encoder stuff */ struct iw_encoding max_encoding; /* Encoding max range */ + + /* Rates */ + __u8 num_bitrates; /* Number of entries in the list */ + __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ + + /* RTS threshold */ + __s32 min_rts; /* Minimal RTS threshold */ + __s32 max_rts; /* Maximal RTS threshold */ + + /* Frag threshold */ + __s32 min_frag; /* Minimal frag threshold */ + __s32 max_frag; /* Maximal frag threshold */ }; /* diff -u --recursive --new-file v2.3.14/linux/include/net/addrconf.h linux/include/net/addrconf.h --- v2.3.14/linux/include/net/addrconf.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/addrconf.h Mon Aug 23 10:01:02 1999 @@ -51,8 +51,10 @@ extern int addrconf_del_ifaddr(void *arg); extern int addrconf_set_dstaddr(void *arg); -extern struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr, - struct net_device *dev, int nd); +extern int ipv6_chk_addr(struct in6_addr *addr, + struct net_device *dev); +extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, + struct net_device *dev); extern int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, struct in6_addr *saddr); @@ -85,7 +87,50 @@ extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); -extern struct inet6_dev * ipv6_get_idev(struct net_device *dev); +extern __inline__ struct inet6_dev * +__in6_dev_get(struct net_device *dev) +{ + return (struct inet6_dev *)dev->ip6_ptr; +} + +extern rwlock_t addrconf_lock; + +extern __inline__ struct inet6_dev * +in6_dev_get(struct net_device *dev) +{ + struct inet6_dev *idev = NULL; + read_lock(&addrconf_lock); + idev = dev->ip6_ptr; + if (idev) + atomic_inc(&idev->refcnt); + read_unlock(&addrconf_lock); + return idev; +} + +extern void in6_dev_finish_destroy(struct inet6_dev *idev); + +extern __inline__ void +in6_dev_put(struct inet6_dev *idev) +{ + if (atomic_dec_and_test(&idev->refcnt)) + in6_dev_finish_destroy(idev); +} + +#define __in6_dev_put(idev) atomic_dec(&(idev)->refcnt) +#define in6_dev_hold(idev) atomic_inc(&(idev)->refcnt) + + +extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); + +extern __inline__ void in6_ifa_put(struct inet6_ifaddr *ifp) +{ + if (atomic_dec_and_test(&ifp->refcnt)) + inet6_ifa_finish_destroy(ifp); +} + +#define __in6_ifa_put(idev) atomic_dec(&(idev)->refcnt) +#define in6_ifa_hold(idev) atomic_inc(&(idev)->refcnt) + extern void addrconf_forwarding_on(void); /* @@ -95,7 +140,6 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr) { __u32 word; - unsigned tmp; /* * We perform the hash function over the last 64 bits of the address @@ -103,15 +147,10 @@ */ word = addr->s6_addr[2] ^ addr->s6_addr32[3]; - tmp = word ^ (word>>16); - tmp ^= (tmp >> 8); + word ^= (word>>16); + word ^= (word >> 8); - return ((tmp ^ (tmp >> 4)) & 0x0f); -} - -static __inline__ int ipv6_devindex_hash(int ifindex) -{ - return ifindex & (IN6_ADDR_HSIZE - 1); + return ((word ^ (word >> 4)) & 0x0f); } /* diff -u --recursive --new-file v2.3.14/linux/include/net/af_unix.h linux/include/net/af_unix.h --- v2.3.14/linux/include/net/af_unix.h Mon Apr 14 16:28:26 1997 +++ linux/include/net/af_unix.h Mon Aug 23 10:01:02 1999 @@ -7,9 +7,13 @@ typedef struct sock unix_socket; extern void unix_gc(void); -#define UNIX_HASH_SIZE 16 +#define UNIX_HASH_SIZE 256 extern unix_socket *unix_socket_table[UNIX_HASH_SIZE+1]; +extern rwlock_t unix_table_lock; + +extern atomic_t unix_tot_inflight; + #define forall_unix_sockets(i, s) for (i=0; i<=UNIX_HASH_SIZE; i++) \ for (s=unix_socket_table[i]; s; s=s->next) @@ -26,10 +30,14 @@ { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ - unsigned attr; /* Special attributes */ }; #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb)) #define UNIXCREDS(skb) (&UNIXCB((skb)).creds) + +#define unix_state_rlock(s) read_lock(&(s)->protinfo.af_unix.lock) +#define unix_state_runlock(s) read_unlock(&(s)->protinfo.af_unix.lock) +#define unix_state_wlock(s) write_lock(&(s)->protinfo.af_unix.lock) +#define unix_state_wunlock(s) write_unlock(&(s)->protinfo.af_unix.lock) #endif diff -u --recursive --new-file v2.3.14/linux/include/net/atmclip.h linux/include/net/atmclip.h --- v2.3.14/linux/include/net/atmclip.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/atmclip.h Tue Aug 24 17:13:02 1999 @@ -0,0 +1,62 @@ +/* net/atm/atmarp.h - RFC1577 ATM ARP */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef _ATMCLIP_H +#define _ATMCLIP_H + +#include +#include +#include +#include +#include +#include + + +#define CLIP_VCC(vcc) ((struct clip_vcc *) ((vcc)->user_back)) +#define NEIGH2ENTRY(neigh) ((struct atmarp_entry *) (neigh)->primary_key) + + +struct clip_vcc { + struct atm_vcc *vcc; /* VCC descriptor */ + struct atmarp_entry *entry; /* ATMARP table entry, NULL if IP addr. + isn't known yet */ + unsigned char encap; /* 0: NULL, 1: LLC/SNAP */ + unsigned long last_use; /* last send or receive operation */ + unsigned long idle_timeout; /* keep open idle for so many jiffies*/ + void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); + /* keep old push fn for detaching */ + struct clip_vcc *next; /* next VCC */ +}; + + +struct atmarp_entry { + u32 ip; /* IP address */ + struct clip_vcc *vccs; /* active VCCs; NULL if resolution is + pending */ + unsigned long expires; /* entry expiration time */ + struct neighbour *neigh; /* neighbour back-pointer */ +}; + + +#define PRIV(dev) ((struct clip_priv *) ((struct net_device *) (dev)+1)) + + +struct clip_priv { + char name[8]; /* interface name */ + int number; /* for convenience ... */ + struct enet_statistics stats; + struct net_device *next; /* next CLIP interface */ +}; + + +extern struct atm_vcc *atmarpd; /* ugly */ +extern struct neigh_table clip_tbl; + +int clip_create(int number); +int clip_mkip(struct atm_vcc *vcc,int timeout); +int clip_setentry(struct atm_vcc *vcc,u32 ip); +int clip_encap(struct atm_vcc *vcc,int mode); + +#endif diff -u --recursive --new-file v2.3.14/linux/include/net/br.h linux/include/net/br.h --- v2.3.14/linux/include/net/br.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/br.h Mon Aug 23 10:18:38 1999 @@ -42,7 +42,7 @@ /* broacast/multicast storm limitation. This per source. */ #define MAX_MCAST_PER_PERIOD 4 -#define MCAST_HOLD_TIME 10 /* in jiffies unit (10ms increment) */ +#define MCAST_HOLD_TIME (10*HZ/100) #define Default_path_cost 10 diff -u --recursive --new-file v2.3.14/linux/include/net/dn.h linux/include/net/dn.h --- v2.3.14/linux/include/net/dn.h Wed Aug 18 16:43:35 1999 +++ linux/include/net/dn.h Mon Aug 23 14:48:54 1999 @@ -46,6 +46,7 @@ #define DN_NOCHANGE 0 unsigned char accept_mode; unsigned short mss; + unsigned long seg_size; /* Running total of current segment */ struct optdata_dn conndata_in; struct optdata_dn conndata_out; @@ -181,7 +182,6 @@ extern struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr); extern struct sock *dn_find_by_skb(struct sk_buff *skb); -extern unsigned short dn_alloc_port(void); #define DN_ASCBUF_LEN 7 extern char *dn_addr2asc(dn_address, char *); extern void dn_destroy_sock(struct sock *sk); diff -u --recursive --new-file v2.3.14/linux/include/net/dn_dev.h linux/include/net/dn_dev.h --- v2.3.14/linux/include/net/dn_dev.h Wed Aug 18 11:38:48 1999 +++ linux/include/net/dn_dev.h Mon Aug 23 10:01:02 1999 @@ -58,8 +58,6 @@ * down() - Called to turn device off when it goes down * timer1() - Called when timer 1 goes off * timer3() - Called when timer 3 goes off - * setsrc() - Called for each incomming frame to set previous hop info - * neigh_setup() - Called to do device specific setup of neighbours * * sysctl - Hook for sysctl things * @@ -83,8 +81,6 @@ void (*down)(struct net_device *); void (*timer1)(struct net_device *); void (*timer3)(struct net_device *); - int (*setsrc)(struct sk_buff *skb); - int (*neigh_setup)(struct neighbour *); void *sysctl; }; diff -u --recursive --new-file v2.3.14/linux/include/net/dn_fib.h linux/include/net/dn_fib.h --- v2.3.14/linux/include/net/dn_fib.h Wed Jun 30 11:24:55 1999 +++ linux/include/net/dn_fib.h Mon Aug 23 10:01:02 1999 @@ -73,12 +73,12 @@ extern int dn_fib_rt_message(struct sk_buff *skb); extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +extern int dn_fib_resolve(struct dn_fib_res *res); #ifdef CONFIG_RTNETLINK extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb); -extern int dn_fib_rtm_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); #endif /* CONFIG_RTNETLINK */ #endif /* CONFIG_DECNET_ROUTER */ diff -u --recursive --new-file v2.3.14/linux/include/net/dn_neigh.h linux/include/net/dn_neigh.h --- v2.3.14/linux/include/net/dn_neigh.h Wed Aug 18 11:38:48 1999 +++ linux/include/net/dn_neigh.h Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ */ struct dn_neigh { struct neighbour n; - unsigned char addr[ETH_ALEN]; + dn_address addr; unsigned long flags; #define DN_NDFLAG_R1 0x0001 /* Router L1 */ #define DN_NDFLAG_R2 0x0002 /* Router L2 */ diff -u --recursive --new-file v2.3.14/linux/include/net/dn_route.h linux/include/net/dn_route.h --- v2.3.14/linux/include/net/dn_route.h Wed May 26 09:36:35 1999 +++ linux/include/net/dn_route.h Mon Aug 23 10:01:02 1999 @@ -14,11 +14,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ -/* dn_route.c functions prototyping */ -extern void dn_send_skb(struct sk_buff *); -extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri); -extern int dn_route_output(struct sock *sk); +extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri); +extern int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags); +extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); +extern int dn_cache_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); /* Masks for flags field */ #define DN_RT_F_PID 0x07 /* Mask for packet type */ #define DN_RT_F_PF 0x80 /* Padding Follows */ @@ -70,5 +70,55 @@ extern void dn_route_init(void); extern void dn_route_cleanup(void); + +#include +#include + +extern __inline__ void dn_rt_send(struct sk_buff *skb) +{ + dev_queue_xmit(skb); +} + +extern __inline__ void dn_rt_finish_output(struct sk_buff *skb, char *dst) +{ + struct net_device *dev = skb->dev; + + if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) + dst = NULL; + + if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT, + dst, NULL, skb->len) >= 0)) + dn_rt_send(skb); + else + kfree_skb(skb); +} + +extern __inline__ void dn_nsp_send(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + struct dn_scp *scp = &sk->protinfo.dn; + struct dst_entry *dst; + + skb->h.raw = skb->data; + scp->stamp = jiffies; + + if ((dst = sk->dst_cache) && !dst->obsolete) { +try_again: + skb->dst = dst_clone(dst); + dst->output(skb); + return; + } + + dst_release(xchg(&sk->dst_cache, NULL)); + + if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer), dn_saddr2dn(&scp->addr), 0) == 0) { + dst = sk->dst_cache; + goto try_again; + } + + sk->err = EHOSTUNREACH; + if (!sk->dead) + sk->state_change(sk); +} #endif /* _NET_DN_ROUTE_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/dst.h linux/include/net/dst.h --- v2.3.14/linux/include/net/dst.h Wed Aug 18 16:44:34 1999 +++ linux/include/net/dst.h Tue Aug 24 17:10:22 1999 @@ -27,8 +27,8 @@ struct dst_entry { struct dst_entry *next; - atomic_t refcnt; /* tree/hash references */ - atomic_t use; /* client references */ + atomic_t __refcnt; /* client references */ + int __use; struct net_device *dev; int obsolete; unsigned long lastuse; @@ -37,6 +37,10 @@ unsigned pmtu; unsigned window; unsigned rtt; + unsigned rttvar; + unsigned ssthresh; + unsigned cwnd; + unsigned advmss; unsigned long rate_last; /* rate limiting for ICMP */ unsigned long rate_tokens; @@ -71,17 +75,24 @@ void (*destroy)(struct dst_entry *); struct dst_entry * (*negative_advice)(struct dst_entry *); void (*link_failure)(struct sk_buff *); + int entry_size; atomic_t entries; + kmem_cache_t *kmem_cachep; }; #ifdef __KERNEL__ +extern __inline__ void dst_hold(struct dst_entry * dst) +{ + atomic_inc(&dst->__refcnt); +} + extern __inline__ struct dst_entry * dst_clone(struct dst_entry * dst) { if (dst) - atomic_inc(&dst->use); + atomic_inc(&dst->__refcnt); return dst; } @@ -89,42 +100,10 @@ void dst_release(struct dst_entry * dst) { if (dst) - atomic_dec(&dst->use); -} - -/* The following primitive should be use if and only if - destination entry has just been removed from a location - accessed directly by hard irq. - */ -extern __inline__ -void dst_release_irqwait(struct dst_entry * dst) -{ - if (dst) { - synchronize_irq(); - atomic_dec(&dst->use); - } -} - -extern __inline__ -struct dst_entry * dst_check(struct dst_entry ** dst_p, u32 cookie) -{ - struct dst_entry * dst = *dst_p; - if (dst && dst->obsolete) - dst = dst->ops->check(dst, cookie); - return (*dst_p = dst); -} - -extern __inline__ -struct dst_entry * dst_reroute(struct dst_entry ** dst_p, struct sk_buff *skb) -{ - struct dst_entry * dst = *dst_p; - if (dst && dst->obsolete) - dst = dst->ops->reroute(dst, skb); - return (*dst_p = dst); + atomic_dec(&dst->__refcnt); } - -extern void * dst_alloc(int size, struct dst_ops * ops); +extern void * dst_alloc(struct dst_ops * ops); extern void __dst_free(struct dst_entry * dst); extern void dst_destroy(struct dst_entry * dst); @@ -133,7 +112,7 @@ { if (dst->obsolete > 1) return; - if (!atomic_read(&dst->use)) { + if (!atomic_read(&dst->__refcnt)) { dst_destroy(dst); return; } diff -u --recursive --new-file v2.3.14/linux/include/net/icmp.h linux/include/net/icmp.h --- v2.3.14/linux/include/net/icmp.h Wed Aug 18 16:44:40 1999 +++ linux/include/net/icmp.h Tue Aug 24 17:12:21 1999 @@ -36,7 +36,4 @@ /* Move into dst.h ? */ extern int xrlim_allow(struct dst_entry *dst, int timeout); -/* CONFIG_IP_TRANSPARENT_PROXY */ -extern int icmp_chkaddr(struct sk_buff *skb); - #endif /* _ICMP_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/if_inet6.h linux/include/net/if_inet6.h --- v2.3.14/linux/include/net/if_inet6.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/if_inet6.h Mon Aug 23 10:01:02 1999 @@ -15,22 +15,6 @@ #ifndef _NET_IF_INET6_H #define _NET_IF_INET6_H -/* These flags match corresponding IFA_F_* flags but ADDR_INVALID, - which is invisible externally. - */ - -#define ADDR_PERMANENT 0x80 - -#define DAD_COMPLETE 0x00 -#define DAD_INCOMPLETE 0x40 -#define DAD_STATUS 0x40 - -#define ADDR_STATUS 0x21 -#define ADDR_DEPRECATED 0x20 -#define ADDR_INVALID 0x01 - - - #define IF_RA_RCVD 0x20 #define IF_RS_SENT 0x10 @@ -45,6 +29,7 @@ __u32 prefered_lft; unsigned long tstamp; atomic_t refcnt; + spinlock_t lock; __u8 probes; __u8 flags; @@ -57,8 +42,9 @@ struct inet6_ifaddr *lst_next; /* next addr in addr_lst */ struct inet6_ifaddr *if_next; /* next addr in inet6_dev */ -}; + int dead; +}; struct ipv6_mc_socklist { @@ -74,9 +60,8 @@ struct ifmcaddr6 { struct in6_addr mca_addr; - struct net_device *dev; + struct inet6_dev *idev; struct ifmcaddr6 *next; - struct ifmcaddr6 *if_next; struct timer_list mca_timer; unsigned mca_flags; atomic_t mca_users; @@ -110,7 +95,9 @@ struct inet6_ifaddr *addr_list; struct ifmcaddr6 *mc_list; rwlock_t lock; + atomic_t refcnt; __u32 if_flags; + int dead; struct neigh_parms *nd_parms; struct inet6_dev *next; diff -u --recursive --new-file v2.3.14/linux/include/net/inet_common.h linux/include/net/inet_common.h --- v2.3.14/linux/include/net/inet_common.h Thu Feb 26 20:17:58 1998 +++ linux/include/net/inet_common.h Mon Aug 23 10:01:02 1999 @@ -11,8 +11,7 @@ extern void inet_remove_sock(struct sock *sk1); extern void inet_put_sock(unsigned short num, struct sock *sk); -extern int inet_release(struct socket *sock, - struct socket *peer); +extern int inet_release(struct socket *sock); extern int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags); @@ -39,6 +38,10 @@ unsigned int cmd, unsigned long arg); extern int inet_listen(struct socket *sock, int backlog); + +extern void inet_sock_release(struct sock *sk); +extern void inet_sock_destruct(struct sock *sk); +extern atomic_t inet_sock_nr; #endif diff -u --recursive --new-file v2.3.14/linux/include/net/ip.h linux/include/net/ip.h --- v2.3.14/linux/include/net/ip.h Wed Aug 18 16:44:36 1999 +++ linux/include/net/ip.h Tue Aug 24 17:12:21 1999 @@ -66,6 +66,7 @@ }; extern struct ip_ra_chain *ip_ra_chain; +extern rwlock_t ip_ra_lock; /* IP flags. */ #define IP_CE 0x8000 /* Flag: "Congestion" */ @@ -92,11 +93,11 @@ extern int ip_mr_input(struct sk_buff *skb); extern int ip_output(struct sk_buff *skb); extern int ip_mc_output(struct sk_buff *skb); -extern void ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); +extern int ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); extern int ip_id_count; -extern void ip_queue_xmit(struct sk_buff *skb); +extern int ip_queue_xmit(struct sk_buff *skb); extern void ip_init(void); extern int ip_build_xmit(struct sock *sk, int getfrag (const void *, @@ -121,7 +122,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, unsigned int len); -extern int __ip_finish_output(struct sk_buff *skb); +extern __inline__ int ip_finish_output(struct sk_buff *skb); struct ipv4_config { @@ -136,34 +137,12 @@ extern int sysctl_local_port_range[2]; -extern __inline__ int ip_finish_output(struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - struct net_device *dev = dst->dev; - struct hh_cache *hh = dst->hh; - - skb->dev = dev; - skb->protocol = __constant_htons(ETH_P_IP); - - if (hh) { - read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) - return dst->neighbour->output(skb); - - kfree_skb(skb); - return -EINVAL; -} - -extern __inline__ void ip_send(struct sk_buff *skb) +extern __inline__ int ip_send(struct sk_buff *skb) { if (skb->len > skb->dst->pmtu) - ip_fragment(skb, __ip_finish_output); + return ip_fragment(skb, ip_finish_output); else - ip_finish_output(skb); + return ip_finish_output(skb); } extern __inline__ @@ -180,8 +159,8 @@ extern __inline__ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) { - return (sk->ip_pmtudisc == IP_PMTUDISC_DO || - (sk->ip_pmtudisc == IP_PMTUDISC_WANT && + return (sk->protinfo.af_inet.pmtudisc == IP_PMTUDISC_DO || + (sk->protinfo.af_inet.pmtudisc == IP_PMTUDISC_WANT && !(dst->mxlock&(1<next = fib6_walker_list.next; w->prev = &fib6_walker_list; w->next->prev = w; w->prev->next = w; + write_unlock_bh(&fib6_walker_lock); } extern __inline__ void fib6_walker_unlink(struct fib6_walker_t *w) { + write_lock_bh(&fib6_walker_lock); w->next->prev = w->prev; w->prev->next = w->next; w->prev = w->next = w; + write_unlock_bh(&fib6_walker_lock); } struct rt6_statistics { @@ -173,5 +178,6 @@ extern void fib6_gc_cleanup(void); +extern void fib6_init(void); #endif #endif diff -u --recursive --new-file v2.3.14/linux/include/net/ip6_route.h linux/include/net/ip6_route.h --- v2.3.14/linux/include/net/ip6_route.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/ip6_route.h Mon Aug 23 10:01:02 1999 @@ -87,6 +87,8 @@ extern void rt6_ifdown(struct net_device *dev); extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); +extern rwlock_t rt6_lock; + /* * Store a destination cache entry in a socket * For UDP/RAW sockets this is done on udp_connect. @@ -95,16 +97,14 @@ extern __inline__ void ip6_dst_store(struct sock *sk, struct dst_entry *dst, struct in6_addr *daddr) { - struct ipv6_pinfo *np; - struct rt6_info *rt; - - np = &sk->net_pinfo.af_inet6; - dst_release(xchg(&sk->dst_cache,dst)); - - rt = (struct rt6_info *) dst; + struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; + struct rt6_info *rt = (struct rt6_info *) dst; + write_lock(&sk->dst_lock); + __sk_dst_set(sk, dst); np->daddr_cache = daddr; np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + write_unlock(&sk->dst_lock); } #endif diff -u --recursive --new-file v2.3.14/linux/include/net/ip_fib.h linux/include/net/ip_fib.h --- v2.3.14/linux/include/net/ip_fib.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/ip_fib.h Mon Aug 23 10:01:02 1999 @@ -58,16 +58,18 @@ { struct fib_info *fib_next; struct fib_info *fib_prev; - int fib_refcnt; + int fib_treeref; + atomic_t fib_clntref; + int fib_dead; unsigned fib_flags; int fib_protocol; u32 fib_prefsrc; u32 fib_priority; -#define FIB_MAX_METRICS RTAX_RTT - unsigned fib_metrics[FIB_MAX_METRICS]; + unsigned fib_metrics[RTAX_MAX]; #define fib_mtu fib_metrics[RTAX_MTU-1] #define fib_window fib_metrics[RTAX_WINDOW-1] #define fib_rtt fib_metrics[RTAX_RTT-1] +#define fib_advmss fib_metrics[RTAX_ADVMSS-1] int fib_nhs; #ifdef CONFIG_IP_ROUTE_MULTIPATH int fib_power; @@ -83,7 +85,6 @@ struct fib_result { - u32 *prefix; unsigned char prefixlen; unsigned char nh_sel; unsigned char type; @@ -94,6 +95,7 @@ #endif }; + #ifdef CONFIG_IP_ROUTE_MULTIPATH #define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) @@ -171,6 +173,7 @@ extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; extern int fib_lookup(const struct rt_key *key, struct fib_result *res); extern struct fib_table *__fib_new_table(int id); +extern void fib_rule_put(struct fib_rule *r); extern __inline__ struct fib_table *fib_get_table(int id) { @@ -253,5 +256,24 @@ #endif #endif } + +extern void free_fib_info(struct fib_info *fi); + +extern __inline__ void fib_info_put(struct fib_info *fi) +{ + if (atomic_dec_and_test(&fi->fib_clntref)) + free_fib_info(fi); +} + +extern __inline__ void fib_res_put(struct fib_result *res) +{ + if (res->fi) + fib_info_put(res->fi); +#ifdef CONFIG_IP_MULTIPLE_TABLES + if (res->r) + fib_rule_put(res->r); +#endif +} + #endif _NET_FIB_H diff -u --recursive --new-file v2.3.14/linux/include/net/ip_masq.h linux/include/net/ip_masq.h --- v2.3.14/linux/include/net/ip_masq.h Wed Aug 18 16:44:42 1999 +++ linux/include/net/ip_masq.h Wed Dec 31 16:00:00 1969 @@ -1,340 +0,0 @@ -/* - * IP masquerading functionality definitions - */ - -#include /* for CONFIG_IP_MASQ_DEBUG */ -#ifndef _IP_MASQ_H -#define _IP_MASQ_H - -#ifdef __KERNEL__ -#include -#include -#include -#include -#endif /* __KERNEL__ */ - -/* - * This define affects the number of ports that can be handled - * by each of the protocol helper modules. - */ -#define MAX_MASQ_APP_PORTS 12 - -/* - * Linux ports don't normally get allocated above 32K. - * I used an extra 4K port-space - */ - -#define PORT_MASQ_BEGIN 61000 -#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096) - -#define MASQUERADE_EXPIRE_TCP 15*60*HZ -#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ -#define MASQUERADE_EXPIRE_UDP 5*60*HZ -/* - * ICMP can no longer be modified on the fly using an ioctl - this - * define is the only way to change the timeouts - */ -#define MASQUERADE_EXPIRE_ICMP 125*HZ - -#define IP_MASQ_MOD_CTL 0x00 -#define IP_MASQ_USER_CTL 0x01 - -#ifdef __KERNEL__ - -#define IP_MASQ_TAB_SIZE 256 - -#define IP_MASQ_F_NO_DADDR 0x0001 /* no daddr yet */ -#define IP_MASQ_F_NO_DPORT 0x0002 /* no dport set yet */ -#define IP_MASQ_F_NO_SADDR 0x0004 /* no sport set yet */ -#define IP_MASQ_F_NO_SPORT 0x0008 /* no sport set yet */ - -#define IP_MASQ_F_DLOOSE 0x0010 /* loose dest binding */ -#define IP_MASQ_F_NO_REPLY 0x0080 /* no reply yet from outside */ - -#define IP_MASQ_F_HASHED 0x0100 /* hashed entry */ -#define IP_MASQ_F_OUT_SEQ 0x0200 /* must do output seq adjust */ -#define IP_MASQ_F_IN_SEQ 0x0400 /* must do input seq adjust */ - -#define IP_MASQ_F_MPORT 0x1000 /* own mport specified */ -#define IP_MASQ_F_USER 0x2000 /* from uspace */ - -/* - * Delta seq. info structure - * Each MASQ struct has 2 (output AND input seq. changes). - */ - -struct ip_masq_seq { - __u32 init_seq; /* Add delta from this seq */ - short delta; /* Delta in sequence numbers */ - short previous_delta; /* Delta in sequence numbers before last resized pkt */ -}; - -/* - * MASQ structure allocated for each masqueraded association - */ -struct ip_masq { - struct ip_masq *m_link, *s_link; /* hashed link ptrs */ - atomic_t refcnt; /* reference count */ - struct timer_list timer; /* Expiration timer */ - __u16 protocol; /* Which protocol are we talking? */ - __u16 sport, dport, mport; /* src, dst & masq ports */ - __u32 saddr, daddr, maddr; /* src, dst & masq addresses */ - struct ip_masq_seq out_seq, in_seq; - struct ip_masq_app *app; /* bound ip_masq_app object */ - void *app_data; /* Application private data */ - struct ip_masq *control; /* Master control connection */ - atomic_t n_control; /* Number of "controlled" masqs */ - unsigned flags; /* status flags */ - unsigned timeout; /* timeout */ - unsigned state; /* state info */ - struct ip_masq_timeout_table *timeout_table; -}; - -/* - * Timeout values - * ipchains holds a copy of this definition - */ - -struct ip_fw_masq { - int tcp_timeout; - int tcp_fin_timeout; - int udp_timeout; -}; - -union ip_masq_tphdr { - unsigned char *raw; - struct udphdr *uh; - struct tcphdr *th; - struct icmphdr *icmph; - __u16 *portp; -}; -/* - * [0]: UDP free_ports - * [1]: TCP free_ports - * [2]: ICMP free_ports - */ - -extern atomic_t ip_masq_free_ports[3]; - -/* - * ip_masq initializer (registers symbols and /proc/net entries) - */ -extern int ip_masq_init(void); - -/* - * functions called from ip layer - */ -extern int ip_fw_masquerade(struct sk_buff **, __u32 maddr); -extern int ip_fw_masq_icmp(struct sk_buff **, __u32 maddr); -extern int ip_fw_unmasq_icmp(struct sk_buff *); -extern int ip_fw_demasquerade(struct sk_buff **); - -/* - * ip_masq obj creation/deletion functions. - */ -extern struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags); - -extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms); -extern void ip_masq_control_del(struct ip_masq *ms); -extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms); - -struct ip_masq_ctl; - -struct ip_masq_hook { - int (*ctl)(int, struct ip_masq_ctl *, int); - int (*info)(char *, char **, off_t, int, int); -}; - -extern struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE]; -extern struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE]; -extern const char * ip_masq_state_name(int state); -extern struct ip_masq_hook *ip_masq_user_hook; -extern u32 ip_masq_select_addr(struct net_device *dev, u32 dst, int scope); -/* - * - * IP_MASQ_APP: IP application masquerading definitions - * - */ - -struct ip_masq_app -{ - struct ip_masq_app *next; - char *name; /* name of application proxy */ - unsigned type; /* type = proto<<16 | port (host byte order)*/ - int n_attach; - int (*masq_init_1) /* ip_masq initializer */ - (struct ip_masq_app *, struct ip_masq *); - int (*masq_done_1) /* ip_masq fin. */ - (struct ip_masq_app *, struct ip_masq *); - int (*pkt_out) /* output (masquerading) hook */ - (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32); - int (*pkt_in) /* input (demasq) hook */ - (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32); -}; - -/* - * ip_masq_app initializer - */ -extern int ip_masq_app_init(void); - -/* - * ip_masq_app object registration functions (port: host byte order) - */ -extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port); -extern int unregister_ip_masq_app(struct ip_masq_app *mapp); - -/* - * get ip_masq_app obj by proto,port(net_byte_order) - */ -extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port); - -/* - * ip_masq TO ip_masq_app (un)binding functions. - */ -extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms); -extern int ip_masq_unbind_app(struct ip_masq *ms); - -/* - * output and input app. masquerading hooks. - * - */ -extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr); -extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr); - -/* - * service routine(s). - */ - -extern struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); -extern struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); - -extern int ip_masq_listen(struct ip_masq *); - -static __inline__ struct ip_masq * ip_masq_in_get_iph(const struct iphdr *iph) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - return ip_masq_in_get(iph->protocol, - iph->saddr, portp[0], - iph->daddr, portp[1]); -} - -static __inline__ struct ip_masq * ip_masq_out_get_iph(const struct iphdr *iph) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - return ip_masq_out_get(iph->protocol, - iph->saddr, portp[0], - iph->daddr, portp[1]); -} - -extern void ip_masq_put(struct ip_masq *ms); - - -extern rwlock_t __ip_masq_lock; - - -/* - * Debugging stuff - */ - -extern int ip_masq_get_debug_level(void); - -#ifdef CONFIG_IP_MASQ_DEBUG -#define IP_MASQ_DEBUG(level, msg...) do { \ - if (level <= ip_masq_get_debug_level()) \ - printk(KERN_DEBUG "IP_MASQ:" ## msg); \ - } while (0) -#else /* NO DEBUGGING at ALL */ -#define IP_MASQ_DEBUG(level, msg...) do { } while (0) -#endif - -#define IP_MASQ_INFO(msg...) \ - printk(KERN_INFO "IP_MASQ:" ## msg) - -#define IP_MASQ_ERR(msg...) \ - printk(KERN_ERR "IP_MASQ:" ## msg) - -#define IP_MASQ_WARNING(msg...) \ - printk(KERN_WARNING "IP_MASQ:" ## msg) - - -/* - * /proc/net entry - */ -extern int ip_masq_proc_register(struct proc_dir_entry *); -extern void ip_masq_proc_unregister(struct proc_dir_entry *); -extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy); - -/* - * skb_replace function used by "client" modules to replace - * a segment of skb. - */ -extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len); - -/* - * masq_proto_num returns 0 for UDP, 1 for TCP, 2 for ICMP - */ - -static __inline__ int masq_proto_num(unsigned proto) -{ - switch (proto) - { - case IPPROTO_UDP: return (0); break; - case IPPROTO_TCP: return (1); break; - case IPPROTO_ICMP: return (2); break; - default: return (-1); break; - } -} - -static __inline__ const char *masq_proto_name(unsigned proto) -{ - static char buf[20]; - static const char *strProt[] = {"UDP","TCP","ICMP"}; - int msproto = masq_proto_num(proto); - - if (msproto<0||msproto>2) { - sprintf(buf, "IP_%d", proto); - return buf; - } - return strProt[msproto]; -} - -enum { - IP_MASQ_S_NONE = 0, - IP_MASQ_S_ESTABLISHED, - IP_MASQ_S_SYN_SENT, - IP_MASQ_S_SYN_RECV, - IP_MASQ_S_FIN_WAIT, - IP_MASQ_S_TIME_WAIT, - IP_MASQ_S_CLOSE, - IP_MASQ_S_CLOSE_WAIT, - IP_MASQ_S_LAST_ACK, - IP_MASQ_S_LISTEN, - IP_MASQ_S_UDP, - IP_MASQ_S_ICMP, - IP_MASQ_S_LAST -}; - -struct ip_masq_timeout_table { - atomic_t refcnt; - int scale; - int timeout[IP_MASQ_S_LAST+1]; -}; - -static __inline__ void ip_masq_timeout_attach(struct ip_masq *ms, struct ip_masq_timeout_table *mstim) -{ - atomic_inc (&mstim->refcnt); - ms->timeout_table=mstim; -} - -static __inline__ void ip_masq_timeout_detach(struct ip_masq *ms) -{ - struct ip_masq_timeout_table *mstim = ms->timeout_table; - - if (!mstim) - return; - atomic_dec(&mstim->refcnt); -} - -#endif /* __KERNEL__ */ - -#endif /* _IP_MASQ_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/ip_masq_mod.h linux/include/net/ip_masq_mod.h --- v2.3.14/linux/include/net/ip_masq_mod.h Sun Oct 4 10:21:45 1998 +++ linux/include/net/ip_masq_mod.h Wed Dec 31 16:00:00 1969 @@ -1,86 +0,0 @@ -/* - * IP Masquerading Modules Support - * - * Version: @(#)ip_masq_mod.h 0.01 97/10/30 - * - * Author: Juan Jose Ciarlante, - * - */ - - -#ifdef __KERNEL__ -#include -#include -#include -#include - -#define IP_MASQ_MOD_NOP 0 -#define IP_MASQ_MOD_ACCEPT 1 -#define IP_MASQ_MOD_REJECT -1 - -struct ip_masq_mod { - struct ip_masq_mod *next; /* next mod for addrs. lookups */ - struct ip_masq_mod *next_reg; /* next mod for configuration ctls */ - char *mmod_name; - atomic_t refcnt; - atomic_t mmod_nent; /* number of entries */ - struct proc_dir_entry *mmod_proc_ent; - int (*mmod_ctl) (int optname, struct ip_masq_ctl *, int optlen); - int (*mmod_init) (void); - int (*mmod_done) (void); - int (*mmod_in_rule) (const struct sk_buff *, const struct iphdr *); - int (*mmod_in_update) (const struct sk_buff *, const struct iphdr *, - struct ip_masq *); - struct ip_masq * (*mmod_in_create) (const struct sk_buff *, const struct iphdr *, __u32); - int (*mmod_out_rule) (const struct sk_buff *, const struct iphdr *); - int (*mmod_out_update) (const struct sk_buff *, const struct iphdr *, - struct ip_masq *); - struct ip_masq * (*mmod_out_create) (const struct sk_buff *, const struct iphdr *, __u32); -}; - -/* - * Service routines (called from ip_masq.c) - */ - -int ip_masq_mod_out_rule(const struct sk_buff *, const struct iphdr *); -int ip_masq_mod_out_update(const struct sk_buff *, const struct iphdr *, struct ip_masq *ms); -struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr); - -int ip_masq_mod_in_rule(const struct sk_buff *, const struct iphdr *iph); -int ip_masq_mod_in_update(const struct sk_buff *, const struct iphdr *iph, struct ip_masq *ms); -struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr); - -extern int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *, int len); - -/* - * ip_masq_mod registration functions - */ -extern int register_ip_masq_mod(struct ip_masq_mod *mmod); -extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod); -extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod); -extern int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod); - -/* - * init functions protos - */ -extern int ip_portfw_init(void); -extern int ip_markfw_init(void); -extern int ip_autofw_init(void); - -/* - * Utility ... - */ -static __inline__ void ip_masq_mod_dec_nent(struct ip_masq_mod *mmod) -{ - if (atomic_dec_and_test(&mmod->mmod_nent)) { - ip_masq_mod_lkp_unlink(mmod); - } -} -static __inline__ void ip_masq_mod_inc_nent(struct ip_masq_mod *mmod) -{ - atomic_inc(&mmod->mmod_nent); - if (atomic_read(&mmod->mmod_nent)==1) - ip_masq_mod_lkp_link(mmod); -} - -#endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.14/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.3.14/linux/include/net/ipv6.h Wed Aug 18 16:44:36 1999 +++ linux/include/net/ipv6.h Tue Aug 24 17:12:34 1999 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.16 1999/04/22 10:07:27 davem Exp $ + * $Id: ipv6.h,v 1.18 1999/08/20 11:00:53 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -89,6 +89,7 @@ extern struct ipv6_mib ipv6_statistics; extern struct icmpv6_mib icmpv6_statistics; extern struct udp_mib udp_stats_in6; +extern atomic_t inet6_sock_nr; struct ip6_ra_chain { @@ -99,6 +100,7 @@ }; extern struct ip6_ra_chain *ip6_ra_chain; +extern rwlock_t ip6_ra_lock; /* This structure is prepared by protocol, when parsing diff -u --recursive --new-file v2.3.14/linux/include/net/neighbour.h linux/include/net/neighbour.h --- v2.3.14/linux/include/net/neighbour.h Wed Aug 18 16:44:28 1999 +++ linux/include/net/neighbour.h Tue Aug 24 17:10:21 1999 @@ -96,9 +96,10 @@ __u8 flags; __u8 nud_state; __u8 type; + __u8 dead; atomic_t probes; rwlock_t lock; - unsigned char ha[MAX_ADDR_LEN]; + unsigned char ha[(MAX_ADDR_LEN+sizeof(unsigned long)-1)&~(sizeof(unsigned long)-1)]; struct hh_cache *hh; atomic_t refcnt; int (*output)(struct sk_buff *skb); @@ -141,10 +142,12 @@ int family; int entry_size; int key_len; + __u32 (*hash)(const void *pkey, const struct net_device *); int (*constructor)(struct neighbour *); int (*pconstructor)(struct pneigh_entry *); void (*pdestructor)(struct pneigh_entry *); void (*proxy_redo)(struct sk_buff *skb); + char *id; struct neigh_parms parms; /* HACK. gc_* shoul follow parms without a gap! */ int gc_interval; @@ -159,6 +162,7 @@ rwlock_t lock; unsigned long last_rand; struct neigh_parms *parms_list; + kmem_cache_t *kmem_cachep; struct neigh_statistics stats; struct neighbour *hash_buckets[NEIGH_HASHMASK+1]; struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1]; @@ -174,7 +178,7 @@ struct net_device *dev); extern void neigh_destroy(struct neighbour *neigh); extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); -extern int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp); +extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp); extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); extern int neigh_resolve_output(struct sk_buff *skb); extern int neigh_connected_output(struct sk_buff *skb); @@ -205,15 +209,11 @@ /* * Neighbour references - * - * When neighbour pointers are passed to "client" code the - * reference count is increased. The count is 0 if the node - * is only referenced by the corresponding table. */ extern __inline__ void neigh_release(struct neighbour *neigh) { - if (atomic_dec_and_test(&neigh->refcnt) && neigh->tbl == NULL) + if (atomic_dec_and_test(&neigh->refcnt)) neigh_destroy(neigh); } @@ -223,6 +223,8 @@ atomic_inc(&neigh->refcnt); return neigh; } + +#define neigh_hold(n) atomic_inc(&(n)->refcnt) extern __inline__ void neigh_confirm(struct neighbour *neigh) { diff -u --recursive --new-file v2.3.14/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h --- v2.3.14/linux/include/net/pkt_sched.h Wed Aug 18 11:38:47 1999 +++ linux/include/net/pkt_sched.h Mon Aug 23 10:01:02 1999 @@ -137,16 +137,23 @@ extern __inline__ unsigned long cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl) { + unsigned long old_cl; + tcf_tree_lock(tp); - cl = xchg(clp, cl); + old_cl = *clp; + *clp = cl; tcf_tree_unlock(tp); - return cl; + return old_cl; } extern __inline__ unsigned long __cls_set_class(unsigned long *clp, unsigned long cl) { - return xchg(clp, cl); + unsigned long old_cl; + + old_cl = *clp; + *clp = cl; + return old_cl; } @@ -453,7 +460,7 @@ extern __inline__ void qdisc_run(struct Qdisc *q) { spin_lock(&qdisc_runqueue_lock); - if (!qdisc_on_runqueue(q)) { + if (!qdisc_on_runqueue(q) && q->dev) { q->h.forw = &qdisc_head; q->h.back = qdisc_head.back; qdisc_head.back->forw = &q->h; @@ -462,18 +469,27 @@ spin_unlock(&qdisc_runqueue_lock); } +extern __inline__ int __qdisc_wakeup(struct net_device *dev) +{ + int res; + + while ((res = qdisc_restart(dev))<0 && !dev->tbusy) + /* NOTHING */; + + return res; +} + + /* If the device is not throttled, restart it and add to run list. - * BH must be disabled on this CPU. + * BH must be disabled on this CPU. Usually, it is called by timers. */ extern __inline__ void qdisc_wakeup(struct net_device *dev) { - if (!dev->tbusy) { - spin_lock(&dev->queue_lock); - if (qdisc_restart(dev)) - qdisc_run(dev->qdisc); - spin_unlock(&dev->queue_lock); - } + spin_lock(&dev->queue_lock); + if (dev->tbusy || __qdisc_wakeup(dev)) + qdisc_run(dev->qdisc); + spin_unlock(&dev->queue_lock); } /* Calculate maximal size of packet seen by hard_start_xmit diff -u --recursive --new-file v2.3.14/linux/include/net/protocol.h linux/include/net/protocol.h --- v2.3.14/linux/include/net/protocol.h Wed Aug 18 16:43:34 1999 +++ linux/include/net/protocol.h Mon Aug 23 14:48:53 1999 @@ -45,6 +45,9 @@ const char *name; }; +extern rwlock_t inet_protocol_lock; + + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct inet6_protocol { @@ -61,6 +64,8 @@ void *data; const char *name; }; + +extern rwlock_t inet6_protocol_lock; #endif extern struct inet_protocol *inet_protocol_base; diff -u --recursive --new-file v2.3.14/linux/include/net/rarp.h linux/include/net/rarp.h --- v2.3.14/linux/include/net/rarp.h Tue Aug 8 23:52:29 1995 +++ linux/include/net/rarp.h Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -/* linux/net/inet/rarp.h */ -#ifndef _RARP_H -#define _RARP_H - -extern int rarp_ioctl(unsigned int cmd, void *arg); -extern int rarp_get_info(char *buffer, - char **start, - off_t offset, - int length, - int dummy); -#endif /* _RARP_H */ - diff -u --recursive --new-file v2.3.14/linux/include/net/raw.h linux/include/net/raw.h --- v2.3.14/linux/include/net/raw.h Sun Nov 30 14:00:39 1997 +++ linux/include/net/raw.h Mon Aug 23 10:01:02 1999 @@ -30,9 +30,13 @@ #define RAWV4_HTABLE_SIZE MAX_INET_PROTOS extern struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE]; +extern rwlock_t raw_v4_lock; -extern struct sock *raw_v4_lookup(struct sock *sk, unsigned short num, - unsigned long raddr, unsigned long laddr, - int dif); + +extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, + unsigned long raddr, unsigned long laddr, + int dif); + +extern struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash); #endif /* _RAW_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/rawv6.h linux/include/net/rawv6.h --- v2.3.14/linux/include/net/rawv6.h Thu Aug 27 19:33:08 1998 +++ linux/include/net/rawv6.h Mon Aug 23 10:01:02 1999 @@ -5,10 +5,14 @@ #define RAWV6_HTABLE_SIZE MAX_INET_PROTOS extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; +extern rwlock_t raw_v6_lock; +extern struct sock * ipv6_raw_deliver(struct sk_buff *skb, + int nexthdr, unsigned long len); -extern struct sock *raw_v6_lookup(struct sock *sk, unsigned short num, - struct in6_addr *loc_addr, struct in6_addr *rmt_addr); + +extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, + struct in6_addr *loc_addr, struct in6_addr *rmt_addr); extern int rawv6_rcv(struct sock *sk, struct sk_buff *skb, diff -u --recursive --new-file v2.3.14/linux/include/net/route.h linux/include/net/route.h --- v2.3.14/linux/include/net/route.h Wed Aug 18 16:44:34 1999 +++ linux/include/net/route.h Tue Aug 24 17:12:21 1999 @@ -38,11 +38,7 @@ #define RTO_ONLINK 0x01 #define RTO_TPROXY 0x80000000 -#ifdef CONFIG_IP_TRANSPARENT_PROXY -#define RTO_CONN RTO_TPROXY -#else #define RTO_CONN 0 -#endif struct rt_key { diff -u --recursive --new-file v2.3.14/linux/include/net/sock.h linux/include/net/sock.h --- v2.3.14/linux/include/net/sock.h Wed Aug 18 16:44:34 1999 +++ linux/include/net/sock.h Tue Aug 24 17:10:22 1999 @@ -85,42 +85,32 @@ #include #endif +#if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE) +struct atm_vcc; +#endif + #ifdef CONFIG_FILTER #include #endif #include +#include #define MIN_WRITE_SPACE 2048 /* The AF_UNIX specific socket options */ struct unix_opt { - int family; - char * name; - int locks; struct unix_address *addr; struct dentry * dentry; struct semaphore readsem; struct sock * other; struct sock ** list; struct sock * gc_tree; - int inflight; - atomic_t user_count; + atomic_t inflight; + rwlock_t lock; + wait_queue_head_t peer_wait; }; -#ifdef CONFIG_NETLINK -struct netlink_callback; - -struct netlink_opt { - pid_t pid; - unsigned groups; - pid_t dst_pid; - unsigned dst_groups; - int (*handler)(int unit, struct sk_buff *skb); - atomic_t locks; - struct netlink_callback *cb; -}; -#endif /* Once the IPX ncpd patches are in these are going into protinfo. */ #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) @@ -196,6 +186,25 @@ }; #endif +#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE) +struct inet_opt +{ + int ttl; /* TTL setting */ + int tos; /* TOS */ + unsigned cmsg_flags; + struct ip_options *opt; + unsigned char hdrincl; /* Include headers ? */ + __u8 mc_ttl; /* Multicasting TTL */ + __u8 mc_loop; /* Loopback */ + __u8 recverr; + __u8 pmtudisc; + int mc_index; /* Multicast device index */ + __u32 mc_addr; + struct ip_mc_socklist *mc_list; /* Group array */ +}; +#endif + + /* This defines a selective acknowledgement block. */ struct tcp_sack_block { __u32 start_seq; @@ -252,6 +261,7 @@ */ __u32 snd_ssthresh; /* Slow start size threshold */ __u16 snd_cwnd_cnt; /* Linear increase counter */ + __u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ __u8 dup_acks; /* Consequetive duplicate acks seen from other end */ __u8 delayed_acks; __u16 user_mss; /* mss requested by user in ioctl */ @@ -287,7 +297,7 @@ __u32 rcv_tsval; /* Time stamp value */ __u32 rcv_tsecr; /* Time stamp echo reply */ __u32 ts_recent; /* Time stamp to echo next */ - __u32 ts_recent_stamp;/* Time we stored ts_recent (for aging) */ + long ts_recent_stamp;/* Time we stored ts_recent (for aging) */ int num_sacks; /* Number of SACK blocks */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ @@ -306,6 +316,7 @@ struct open_request **syn_wait_last; int syn_backlog; /* Backlog of received SYNs */ + int write_pending; }; @@ -344,6 +355,10 @@ * } tp_pinfo; * * } + * + * The idea failed because IPv6 transition asssumes dual IP/IPv6 sockets. + * So, net_pinfo is IPv6 are really, and protinfo unifies all another + * private areas. */ /* Define this to get the sk->debug debugging facility. */ @@ -371,10 +386,6 @@ } while(0); struct sock { - /* Local port binding hash linkage. */ - struct sock *bind_next; - struct sock **bind_pprev; - /* Socket demultiplex comparisons on incoming packets. */ __u32 daddr; /* Foreign IPv4 addr */ __u32 rcv_saddr; /* Bound local IPv4 addr */ @@ -385,6 +396,8 @@ /* Main hash linkage for various protocol lookup tables. */ struct sock *next; struct sock **pprev; + struct sock *bind_next; + struct sock **bind_pprev; volatile unsigned char state, /* Connection state */ zapped; /* In ax25 & ipx means not linked */ @@ -393,12 +406,14 @@ unsigned short family; /* Address family */ unsigned char reuse, /* SO_REUSEADDR setting */ nonagle; /* Disable Nagle algorithm? */ + atomic_t refcnt; /* Reference count */ socket_lock_t lock; /* Synchronizer... */ int rcvbuf; /* Size of receive buffer in bytes */ - wait_queue_head_t *sleep; /* Sock wait queue */ + wait_queue_head_t *sleep; /* Sock wait queue */ struct dst_entry *dst_cache; /* Destination cache */ + rwlock_t dst_lock; atomic_t rmem_alloc; /* Receive queue bytes committed */ struct sk_buff_head receive_queue; /* Incoming packets */ atomic_t wmem_alloc; /* Transmit queue bytes committed */ @@ -437,6 +452,8 @@ struct sk_buff *tail; } backlog; + rwlock_t callback_lock; + /* Error queue, rarely used. */ struct sk_buff_head error_queue; @@ -487,6 +504,9 @@ union { void *destruct_hook; struct unix_opt af_unix; +#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE) + struct inet_opt af_inet; +#endif #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) struct atalk_sock af_at; #endif @@ -512,32 +532,22 @@ rose_cb *rose; #endif #ifdef CONFIG_NETLINK - struct netlink_opt af_netlink; + struct netlink_opt *af_netlink; #endif #if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) struct econet_opt *af_econet; #endif +#if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE) + struct atm_vcc *af_atm; +#endif #if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE) struct irda_sock *irda; #endif } protinfo; - /* IP 'private area' or will be eventually. */ - int ip_ttl; /* TTL setting */ - int ip_tos; /* TOS */ - unsigned ip_cmsg_flags; - struct ip_options *opt; - unsigned char ip_hdrincl; /* Include headers ? */ - __u8 ip_mc_ttl; /* Multicasting TTL */ - __u8 ip_mc_loop; /* Loopback */ - __u8 ip_recverr; - __u8 ip_pmtudisc; - int ip_mc_index; /* Multicast device index */ - __u32 ip_mc_addr; - struct ip_mc_socklist *ip_mc_list; /* Group array */ - /* This part is used for the timeout functions (timer.c). */ - int timeout; /* What are we waiting for? */ + /* This part is used for the timeout functions. */ + spinlock_t timer_lock; /* Required until timer in core is repaired */ struct timer_list timer; /* This is the sock cleanup timer. */ struct timeval stamp; @@ -580,8 +590,9 @@ int (*connect)(struct sock *sk, struct sockaddr *uaddr, int addr_len); + int (*disconnect)(struct sock *sk, int flags); - struct sock * (*accept) (struct sock *sk, int flags); + struct sock * (*accept) (struct sock *sk, int flags, int *err); void (*retransmit)(struct sock *sk, int all); void (*write_wakeup)(struct sock *sk); void (*read_wakeup)(struct sock *sk); @@ -621,14 +632,6 @@ int inuse, highestinuse; }; -#define TIME_WRITE 1 /* Not yet used */ -#define TIME_RETRANS 2 /* Retransmit timer */ -#define TIME_DACK 3 /* Delayed ack timer */ -#define TIME_CLOSE 4 -#define TIME_KEEPOPEN 5 -#define TIME_DESTROY 6 -#define TIME_DONE 7 /* Used to absorb those last few packets */ -#define TIME_PROBE0 8 /* About 10 seconds */ #define SOCK_DESTROY_TIME (10*HZ) @@ -640,23 +643,6 @@ #define RCV_SHUTDOWN 1 #define SEND_SHUTDOWN 2 -/* Per-protocol hash table implementations use this to make sure - * nothing changes. - */ -extern rwlock_t sockhash_lock; -#define SOCKHASH_LOCK_READ() read_lock_bh(&sockhash_lock) -#define SOCKHASH_UNLOCK_READ() read_unlock_bh(&sockhash_lock) -#define SOCKHASH_LOCK_WRITE() write_lock_bh(&sockhash_lock) -#define SOCKHASH_UNLOCK_WRITE() write_unlock_bh(&sockhash_lock) - -/* The following variants must _only_ be used when you know you - * can only be executing in a BH context. - */ -#define SOCKHASH_LOCK_READ_BH() read_lock(&sockhash_lock) -#define SOCKHASH_UNLOCK_READ_BH() read_unlock(&sockhash_lock) -#define SOCKHASH_LOCK_WRITE_BH() write_lock(&sockhash_lock) -#define SOCKHASH_UNLOCK_WRITE_BH() write_unlock(&sockhash_lock) - /* Used by processes to "lock" a socket state, so that * interrupts and bottom half handlers won't change it * from under us. It essentially blocks any incoming @@ -667,8 +653,23 @@ * the backlog queue. This queue is processed by the * owner of the socket lock right before it is released. */ -extern void lock_sock(struct sock *sk); -extern void release_sock(struct sock *sk); +extern void __lock_sock(struct sock *sk); +extern void __release_sock(struct sock *sk); +#define lock_sock(__sk) \ +do { spin_lock_bh(&((__sk)->lock.slock)); \ + if ((__sk)->lock.users != 0) \ + __lock_sock(__sk); \ + (__sk)->lock.users = 1; \ + spin_unlock_bh(&((__sk)->lock.slock)); \ +} while(0) +#define release_sock(__sk) \ +do { spin_lock_bh(&((__sk)->lock.slock)); \ + (__sk)->lock.users = 0; \ + if ((__sk)->backlog.tail != NULL) \ + __release_sock(__sk); \ + wake_up(&((__sk)->lock.wq)); \ + spin_unlock_bh(&((__sk)->lock.slock)); \ +} while(0) /* BH context may only use the following locking interface. */ #define bh_lock_sock(__sk) spin_lock(&((__sk)->lock.slock)) @@ -696,7 +697,6 @@ extern struct sock * sk_alloc(int family, int priority, int zero_it); extern void sk_free(struct sock *sk); -extern void destroy_sock(struct sock *sk); extern struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, @@ -706,6 +706,7 @@ int priority); extern void sock_wfree(struct sk_buff *skb); extern void sock_rfree(struct sk_buff *skb); +extern void sock_cfree(struct sk_buff *skb); extern unsigned long sock_rspace(struct sock *sk); extern unsigned long sock_wspace(struct sock *sk); @@ -729,9 +730,7 @@ * Functions to fill in entries in struct proto_ops when a protocol * does not implement a particular function. */ -extern int sock_no_dup(struct socket *, struct socket *); -extern int sock_no_release(struct socket *, - struct socket *); +extern int sock_no_release(struct socket *); extern int sock_no_bind(struct socket *, struct sockaddr *, int); extern int sock_no_connect(struct socket *, @@ -760,6 +759,9 @@ extern int sock_no_recvmsg(struct socket *, struct msghdr *, int, struct scm_cookie *); +extern int sock_no_mmap(struct file *file, + struct socket *sock, + struct vm_area_struct *vma); /* * Default socket callbacks and setup code @@ -815,6 +817,139 @@ #endif /* CONFIG_FILTER */ /* + * Socket reference counting postulates. + * + * * Each user of socket SHOULD hold a reference count. + * * Each access point to socket (an hash table bucket, reference from a list, + * running timer, skb in flight MUST hold a reference count. + * * When reference count hits 0, it means it will never increase back. + * * When reference count hits 0, it means that no references from + * outside exist to this socket and current process on current CPU + * is last user and may/should destroy this socket. + * * sk_free is called from any context: process, BH, IRQ. When + * it is called, socket has no references from outside -> sk_free + * may release descendant resources allocated by the socket, but + * to the time when it is called, socket is NOT referenced by any + * hash tables, lists etc. + * * Packets, delivered from outside (from network or from another process) + * and enqueued on receive/error queues SHOULD NOT grab reference count, + * when they sit in queue. Otherwise, packets will leak to hole, when + * socket is looked up by one cpu and unhasing is made by another CPU. + * It is true for udp/raw, netlink (leak to receive and error queues), tcp + * (leak to backlog). Packet socket does all the processing inside + * ptype_lock, so that it has not this race condition. UNIX sockets + * use separate SMP lock, so that they are prone too. + */ + +/* Grab socket reference count. This operation is valid only + when sk is ALREADY grabbed f.e. it is found in hash table + or a list and the lookup is made under lock preventing hash table + modifications. + */ + +extern __inline__ void sock_hold(struct sock *sk) +{ + atomic_inc(&sk->refcnt); +} + +/* Ungrab socket in the context, which assumes that socket refcnt + cannot hit zero, f.e. it is true in context of any socketcall. + */ +extern __inline__ void __sock_put(struct sock *sk) +{ + atomic_dec(&sk->refcnt); +} + +/* Ungrab socket and destroy it, if it was the last reference. */ +extern __inline__ void sock_put(struct sock *sk) +{ + if (atomic_dec_and_test(&sk->refcnt)) + sk_free(sk); +} + +extern __inline__ struct dst_entry * +__sk_dst_get(struct sock *sk) +{ + return sk->dst_cache; +} + +extern __inline__ struct dst_entry * +sk_dst_get(struct sock *sk) +{ + struct dst_entry *dst; + + read_lock(&sk->dst_lock); + dst = sk->dst_cache; + if (dst) + dst_hold(dst); + read_unlock(&sk->dst_lock); + return dst; +} + +extern __inline__ void +__sk_dst_set(struct sock *sk, struct dst_entry *dst) +{ + struct dst_entry *old_dst; + + old_dst = sk->dst_cache; + sk->dst_cache = dst; + dst_release(old_dst); +} + +extern __inline__ void +sk_dst_set(struct sock *sk, struct dst_entry *dst) +{ + write_lock(&sk->dst_lock); + __sk_dst_set(sk, dst); + write_unlock(&sk->dst_lock); +} + +extern __inline__ void +__sk_dst_reset(struct sock *sk) +{ + struct dst_entry *old_dst; + + old_dst = sk->dst_cache; + sk->dst_cache = NULL; + dst_release(old_dst); +} + +extern __inline__ void +sk_dst_reset(struct sock *sk) +{ + write_lock(&sk->dst_lock); + __sk_dst_reset(sk); + write_unlock(&sk->dst_lock); +} + +extern __inline__ struct dst_entry * +__sk_dst_check(struct sock *sk, u32 cookie) +{ + struct dst_entry *dst = sk->dst_cache; + + if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + sk->dst_cache = NULL; + return NULL; + } + + return dst; +} + +extern __inline__ struct dst_entry * +sk_dst_check(struct sock *sk, u32 cookie) +{ + struct dst_entry *dst = sk_dst_get(sk); + + if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + sk_dst_reset(sk); + return NULL; + } + + return dst; +} + + +/* * Queue a received datagram if it will fit. Stream and sequenced * protocols can't normally use this as they need to fit buffers in * and play with them. @@ -825,6 +960,7 @@ extern __inline__ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) { + sock_hold(sk); skb->sk = sk; skb->destructor = sock_wfree; atomic_add(skb->truesize, &sk->wmem_alloc); @@ -837,12 +973,16 @@ atomic_add(skb->truesize, &sk->rmem_alloc); } +extern __inline__ void skb_set_owner_c(struct sk_buff *skb, struct sock *sk) +{ + sock_hold(sk); + skb->sk = sk; + skb->destructor = sock_cfree; +} + extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { -#ifdef CONFIG_FILTER - struct sk_filter *filter; -#endif /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ @@ -850,8 +990,21 @@ return -ENOMEM; #ifdef CONFIG_FILTER - if ((filter = sk->filter) != NULL && sk_filter(skb, filter)) - return -EPERM; /* Toss packet */ + if (sk->filter) { + int err = 0; + struct sk_filter *filter; + + /* It would be deadlock, if sock_queue_rcv_skb is used + with socket lock! We assume that users of this + function are lock free. + */ + bh_lock_sock(sk); + if ((filter = sk->filter) != NULL && sk_filter(skb, filter)) + err = -EPERM; + bh_unlock_sock(sk); + if (err) + return err; /* Toss packet */ + } #endif /* CONFIG_FILTER */ skb_set_owner_r(skb, sk); @@ -906,26 +1059,17 @@ return sock_wspace(sk) >= MIN_WRITE_SPACE; } -/* - * Declarations from timer.c - */ - -extern struct sock *timer_base; - -extern void net_delete_timer (struct sock *); -extern void net_reset_timer (struct sock *, int, unsigned long); -extern void net_timer (unsigned long); - extern __inline__ int gfp_any(void) { return in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; } + /* * Enable debug/info messages */ -#if 1 +#if 0 #define NETDEBUG(x) do { } while (0) #else #define NETDEBUG(x) do { x; } while (0) @@ -951,6 +1095,5 @@ remove_wait_queue((sk)->sleep, &wait); \ lock_sock(sk); \ } - #endif /* _SOCK_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.3.14/linux/include/net/tcp.h Wed Aug 18 16:44:39 1999 +++ linux/include/net/tcp.h Tue Aug 24 17:12:21 1999 @@ -18,17 +18,25 @@ #ifndef _TCP_H #define _TCP_H +#define TCP_DEBUG 1 + #include #include #include #include +#include /* This is for all connections with a full identity, no wildcards. * New scheme, half the table is for TIME_WAIT, the other half is * for the rest. I'll experiment with dynamic table growth later. */ +struct tcp_ehash_bucket { + rwlock_t lock; + struct sock *chain; +} __attribute__((__aligned__(SMP_CACHE_BYTES))); + extern int tcp_ehash_size; -extern struct sock **tcp_ehash; +extern struct tcp_ehash_bucket *tcp_ehash; /* This is for listening sockets, thus all sockets which possess wildcards. */ #define TCP_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */ @@ -38,6 +46,9 @@ * the port space is shared. */ extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE]; +extern rwlock_t tcp_lhash_lock; +extern atomic_t tcp_lhash_users; +extern wait_queue_head_t tcp_lhash_wait; /* There are a few simple rules, which allow for local port reuse by * an application. In essence: @@ -78,33 +89,21 @@ struct tcp_bind_bucket **pprev; }; -extern struct tcp_bind_bucket **tcp_bhash; +struct tcp_bind_hashbucket { + spinlock_t lock; + struct tcp_bind_bucket *chain; +}; + +extern struct tcp_bind_hashbucket *tcp_bhash; extern int tcp_bhash_size; +extern spinlock_t tcp_portalloc_lock; extern kmem_cache_t *tcp_bucket_cachep; -extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum); +extern struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head, + unsigned short snum); extern void tcp_bucket_unlock(struct sock *sk); extern int tcp_port_rover; -extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif); - -/* Level-1 socket-demux cache. */ -#define TCP_NUM_REGS 32 -extern struct sock *tcp_regs[TCP_NUM_REGS]; - -#define TCP_RHASH_FN(__fport) \ - ((((__fport) >> 7) ^ (__fport)) & (TCP_NUM_REGS - 1)) -#define TCP_RHASH(__fport) tcp_regs[TCP_RHASH_FN((__fport))] -#define TCP_SK_RHASH_FN(__sock) TCP_RHASH_FN((__sock)->dport) -#define TCP_SK_RHASH(__sock) tcp_regs[TCP_SK_RHASH_FN((__sock))] - -static __inline__ void tcp_reg_zap(struct sock *sk) -{ - struct sock **rpp; - - rpp = &(TCP_SK_RHASH(sk)); - if(*rpp == sk) - *rpp = NULL; -} +extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif); /* These are AF independent. */ static __inline__ int tcp_bhashfn(__u16 lport) @@ -121,8 +120,6 @@ * XXX Yes I know this is gross, but I'd have to edit every single * XXX networking file if I created a "struct sock_header". -DaveM */ - struct sock *bind_next; - struct sock **bind_pprev; __u32 daddr; __u32 rcv_saddr; __u16 dport; @@ -130,20 +127,30 @@ int bound_dev_if; struct sock *next; struct sock **pprev; + struct sock *bind_next; + struct sock **bind_pprev; unsigned char state, zapped; __u16 sport; unsigned short family; unsigned char reuse, nonagle; + atomic_t refcnt; /* And these are ours. */ + int hashent; __u32 rcv_nxt; - struct tcp_func *af_specific; + __u32 snd_nxt; + __u32 ts_recent; + long ts_recent_stamp; struct tcp_bind_bucket *tb; struct tcp_tw_bucket *next_death; struct tcp_tw_bucket **pprev_death; int death_slot; +#ifdef CONFIG_TCP_TW_RECYCLE + unsigned long ttd; + int rto; +#endif #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct in6_addr v6_daddr; struct in6_addr v6_rcv_saddr; @@ -152,6 +159,23 @@ extern kmem_cache_t *tcp_timewait_cachep; +extern __inline__ void tcp_tw_put(struct tcp_tw_bucket *tw) +{ + if (atomic_dec_and_test(&tw->refcnt)) { +#ifdef INET_REFCNT_DEBUG + printk(KERN_DEBUG "tw_bucket %p released\n", tw); +#endif + kmem_cache_free(tcp_timewait_cachep, tw); + } +} + +extern int tcp_tw_death_row_slot; +extern void tcp_timewait_kill(struct tcp_tw_bucket *tw); +extern void tcp_tw_schedule(struct tcp_tw_bucket *tw); +extern void tcp_tw_reschedule(struct tcp_tw_bucket *tw); +extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw); + + /* Socket demux engine toys. */ #ifdef __BIG_ENDIAN #define TCP_COMBINED_PORTS(__sport, __dport) \ @@ -221,10 +245,14 @@ * poor stacks do signed 16bit maths! */ #define MAX_WINDOW 32767 -#define MIN_WINDOW 2048 -#define MAX_ACK_BACKLOG 2 #define MAX_DELAY_ACK 2 -#define TCP_WINDOW_DIFF 2048 + +/* + * How much of the receive buffer do we advertize + * (the rest is reserved for headers and driver packet overhead) + * Use a power of 2. + */ +#define WINDOW_ADVERTISE_DIVISOR 2 /* urg_data states */ #define URG_VALID 0x0100 @@ -248,8 +276,6 @@ #define TCP_FIN_TIMEOUT (3*60*HZ) /* BSD style FIN_WAIT2 deadlock breaker */ #define TCP_ACK_TIME (3*HZ) /* time to delay before sending an ACK */ -#define TCP_DONE_TIME (5*HZ/2)/* maximum time to wait before actually - * destroying a socket */ #define TCP_WRITE_TIME (30*HZ) /* initial time to wait for an ACK, * after last transmit */ #define TCP_TIMEOUT_INIT (3*HZ) /* RFC 1122 initial timeout value */ @@ -267,8 +293,6 @@ * we tell the link layer that it is something * wrong (e.g. that it can expire redirects) */ -#define TCP_BUCKETGC_PERIOD (HZ) - /* TIME_WAIT reaping mechanism. */ #define TCP_TWKILL_SLOTS 8 /* Please keep this a power of 2. */ #define TCP_TWKILL_PERIOD ((HZ*60)/TCP_TWKILL_SLOTS) @@ -302,10 +326,18 @@ #define TCPOLEN_SACK_BASE_ALIGNED 4 #define TCPOLEN_SACK_PERBLOCK 8 +#define TIME_WRITE 1 /* Not yet used */ +#define TIME_RETRANS 2 /* Retransmit timer */ +#define TIME_DACK 3 /* Delayed ack timer */ +#define TIME_PROBE0 4 +#define TIME_KEEPOPEN 5 + struct open_request; struct or_calltable { + int family; void (*rtx_syn_ack) (struct sock *sk, struct open_request *req); + void (*send_ack) (struct sk_buff *skb, struct open_request *req); void (*destructor) (struct open_request *req); void (*send_reset) (struct sk_buff *skb); }; @@ -352,9 +384,6 @@ struct tcp_v6_open_req v6_req; #endif } af; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - __u16 lcl_port; /* LVE */ -#endif }; /* SLAB cache for open requests. */ @@ -363,6 +392,12 @@ #define tcp_openreq_alloc() kmem_cache_alloc(tcp_openreq_cachep, SLAB_ATOMIC) #define tcp_openreq_free(req) kmem_cache_free(tcp_openreq_cachep, req) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#define TCP_INET_FAMILY(fam) ((fam) == AF_INET) +#else +#define TCP_INET_FAMILY(fam) 1 +#endif + /* * Pointers to address related TCP functions * (i.e. things that depend on the address family) @@ -376,7 +411,7 @@ */ struct tcp_func { - void (*queue_xmit) (struct sk_buff *skb); + int (*queue_xmit) (struct sk_buff *skb); void (*send_check) (struct sock *sk, struct tcphdr *th, @@ -386,16 +421,14 @@ int (*rebuild_header) (struct sock *sk); int (*conn_request) (struct sock *sk, - struct sk_buff *skb, - __u32 isn); + struct sk_buff *skb); struct sock * (*syn_recv_sock) (struct sock *sk, struct sk_buff *skb, struct open_request *req, struct dst_entry *dst); - struct sock * (*get_sock) (struct sk_buff *skb, - struct tcphdr *th); + int (*hash_connecting) (struct sock *sk); __u16 net_header_len; @@ -474,14 +507,26 @@ struct tcphdr *th, unsigned len); -extern int tcp_timewait_state_process(struct tcp_tw_bucket *tw, +enum tcp_tw_status +{ + TCP_TW_SUCCESS = 0, + TCP_TW_RST = 1, + TCP_TW_ACK = 2, + TCP_TW_SYN = 3 +}; + +extern enum tcp_tw_status tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, struct tcphdr *th, unsigned len); +extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb, + struct open_request *req, + struct open_request *prev); + extern void tcp_close(struct sock *sk, long timeout); -extern struct sock * tcp_accept(struct sock *sk, int flags); +extern struct sock * tcp_accept(struct sock *sk, int flags, int *err); extern unsigned int tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait); extern void tcp_write_space(struct sock *sk); @@ -514,8 +559,7 @@ struct sk_buff *skb); extern int tcp_v4_conn_request(struct sock *sk, - struct sk_buff *skb, - __u32 isn); + struct sk_buff *skb); extern struct sock * tcp_create_openreq_child(struct sock *sk, struct open_request *req, @@ -533,14 +577,18 @@ struct sockaddr *uaddr, int addr_len); -extern void tcp_connect(struct sock *sk, - struct sk_buff *skb, - int est_mss); +extern int tcp_connect(struct sock *sk, + struct sk_buff *skb); extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, - struct open_request *req, - int mss); + struct open_request *req); + +extern int tcp_disconnect(struct sock *sk, int flags); + +extern void tcp_unhash(struct sock *sk); + +extern int tcp_v4_hash_connecting(struct sock *sk); /* From syncookies.c */ @@ -568,13 +616,9 @@ extern void tcp_transmit_skb(struct sock *, struct sk_buff *); extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue); extern void tcp_send_ack(struct sock *sk); -extern void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout); - -/* CONFIG_IP_TRANSPARENT_PROXY */ -extern int tcp_chkaddr(struct sk_buff *); +extern void tcp_send_delayed_ack(struct sock *sk, int max_timeout); /* tcp_timer.c */ -#define tcp_reset_msl_timer(x,y,z) net_reset_timer(x,y,z) extern void tcp_reset_xmit_timer(struct sock *, int, unsigned long); extern void tcp_init_xmit_timers(struct sock *); extern void tcp_clear_xmit_timers(struct sock *); @@ -583,8 +627,9 @@ extern void tcp_delack_timer(unsigned long); extern void tcp_probe_timer(unsigned long); -extern struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, - struct open_request *req); +extern void tcp_delete_keepalive_timer (struct sock *); +extern void tcp_reset_keepalive_timer (struct sock *, unsigned long); +extern void tcp_keepalive_timer (unsigned long); /* * TCP slow timer @@ -599,9 +644,8 @@ }; #define TCP_SLT_SYNACK 0 -#define TCP_SLT_KEEPALIVE 1 -#define TCP_SLT_TWKILL 2 -#define TCP_SLT_MAX 3 +#define TCP_SLT_TWKILL 1 +#define TCP_SLT_MAX 2 extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX]; @@ -626,6 +670,28 @@ return mss_now > 8 ? mss_now : 8; } +/* Initialize RCV_MSS value. + * RCV_MSS is an our guess about MSS used by the peer. + * We haven't any direct information about the MSS. + * It's better to underestimate the RCV_MSS rather than overestimate. + * Overestimations make us ACKing less frequently than needed. + * Underestimations are more easy to detect and fix by tcp_measure_rcv_mss(). + */ + +extern __inline__ void tcp_initialize_rcv_mss(struct sock *sk) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + struct dst_entry *dst = __sk_dst_get(sk); + int mss; + + if (dst) + mss = dst->advmss; + else + mss = tp->mss_cache; + + tp->rcv_mss = max(min(mss, 536), 8); +} + /* Compute the actual receive window we are currently advertising. * Rcv_nxt can be after the window if our peer push more data * than the offered window. @@ -686,21 +752,6 @@ return (new_win && (new_win > (cur_win << 1))); } -/* Recalculate snd_ssthresh, we want to set it to: - * - * one half the current congestion window, but no - * less than two segments - * - * We must take into account the current send window - * as well, however we keep track of that using different - * units so a conversion is necessary. -DaveM - */ -extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) -{ - __u32 snd_wnd_packets = tp->snd_wnd / max(tp->mss_cache, 1); - - return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2); -} /* TCP timestamps are only 32-bits, this causes a slight * complication on 64-bit systems since we store a snapshot @@ -768,6 +819,32 @@ return tp->packets_out - tp->fackets_out + tp->retrans_out; } +/* Recalculate snd_ssthresh, we want to set it to: + * + * one half the current congestion window, but no + * less than two segments + * + * We must take into account the current send window + * as well, however we keep track of that using different + * units so a conversion is necessary. -DaveM + * + * RED-PEN. + * RFC 2581: "an easy mistake to make is to simply use cwnd, + * rather than FlightSize" + * I see no references to FlightSize here. snd_wnd is not FlightSize, + * it is also apriory characteristics. + * + * FlightSize = min((snd_nxt-snd_una)/mss, packets_out) ? + */ +extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) +{ + u32 FlightSize = (tp->snd_nxt - tp->snd_una)/tp->mss_cache; + + FlightSize = min(FlightSize, tcp_packets_in_flight(tp)); + + return max(min(FlightSize, tp->snd_cwnd) >> 1, 2); +} + /* This checks if the data bearing packet SKB (usually tp->send_head) * should be put on the wire right now. */ @@ -797,6 +874,15 @@ !(TCP_SKB_CB(skb)->flags & (TCPCB_FLAG_URG|TCPCB_FLAG_FIN)))) nagle_check = 0; + /* + * Reset CWND after idle period longer rto. Actually, it would + * be better to save last send time, but VJ in SIGCOMM'88 proposes + * to use keepalive timestamp. Well, it is not good, certainly, + * because SMTP is still broken, but it is better than nothing yet. + */ + if (tp->packets_out==0 && (s32)(tcp_time_stamp - tp->rcv_tstamp) > tp->rto) + tp->snd_cwnd = min(tp->snd_cwnd, 2); + /* Don't be strict about the congestion window for the * final FIN frame. -DaveM */ @@ -845,6 +931,17 @@ TCPF_FIN_WAIT2|TCPF_SYN_RECV)); } +extern __inline const int tcp_established(const int state) +{ + return ((1 << state) & + (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1| + TCPF_FIN_WAIT2)); +} + + +extern void tcp_destroy_sock(struct sock *sk); + + /* * Calculate(/check) TCP checksum */ @@ -869,12 +966,6 @@ { int oldstate = sk->state; - sk->state = state; - -#ifdef STATE_TRACE - SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]); -#endif - switch (state) { case TCP_ESTABLISHED: if (oldstate != TCP_ESTABLISHED) @@ -882,17 +973,31 @@ break; case TCP_CLOSE: - { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - /* Should be about 2 rtt's */ - net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME)); sk->prot->unhash(sk); /* fall through */ - } default: if (oldstate==TCP_ESTABLISHED) tcp_statistics.TcpCurrEstab--; } + + /* Change state AFTER socket is unhashed to avoid closed + * socket sitting in hash tables. + */ + sk->state = state; + +#ifdef STATE_TRACE + SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]); +#endif +} + +static __inline__ void tcp_done(struct sock *sk) +{ + sk->shutdown = SHUTDOWN_MASK; + + if (!sk->dead) + sk->state_change(sk); + else + tcp_destroy_sock(sk); } static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp, __u32 tstamp) @@ -931,7 +1036,7 @@ /* We always get an MSS option. * The option bytes which will be seen in normal data * packets should timestamps be used, must be in the MSS - * advertised. But we subtract them from sk->mss so + * advertised. But we subtract them from tp->mss_cache so * that calculations in tcp_sendmsg are simpler etc. * So account for this fact here if necessary. If we * don't do this correctly, as a receiver we won't @@ -965,7 +1070,7 @@ * be a multiple of mss if possible. We assume here that mss >= 1. * This MUST be enforced by all callers. */ -extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss, +extern __inline__ void tcp_select_initial_window(int space, __u32 mss, __u32 *rcv_wnd, __u32 *window_clamp, int wscale_ok, @@ -999,6 +1104,18 @@ (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp); } +/* Note: caller must be prepared to deal with negative returns */ +extern __inline__ int tcp_space(struct sock *sk) +{ + return (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / + WINDOW_ADVERTISE_DIVISOR; +} + +extern __inline__ int tcp_full_space( struct sock *sk) +{ + return sk->rcvbuf / WINDOW_ADVERTISE_DIVISOR; +} + extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev) { if(!req->dl_next) @@ -1060,29 +1177,58 @@ printk(timer_bug_msg); return; }; - if(timer->prev != NULL) - del_timer(timer); + + spin_lock_bh(&sk->timer_lock); + if (timer->prev != NULL && del_timer(timer)) + __sock_put(sk); + spin_unlock_bh(&sk->timer_lock); } +/* This function does not return reliable answer. You is only as advice. + */ + static inline int tcp_timer_is_set(struct sock *sk, int what) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + int ret; switch (what) { case TIME_RETRANS: - return tp->retransmit_timer.prev != NULL; + ret = tp->retransmit_timer.prev != NULL; break; case TIME_DACK: - return tp->delack_timer.prev != NULL; + ret = tp->delack_timer.prev != NULL; break; case TIME_PROBE0: - return tp->probe_timer.prev != NULL; + ret = tp->probe_timer.prev != NULL; break; default: + ret = 0; printk(timer_bug_msg); }; - return 0; + return ret; } + +extern void tcp_listen_wlock(void); + +/* - We may sleep inside this lock. + * - If sleeping is not required (or called from BH), + * use plain read_(un)lock(&tcp_lhash_lock). + */ + +extern __inline__ void tcp_listen_lock(void) +{ + /* read_lock synchronizes to candidates to writers */ + read_lock(&tcp_lhash_lock); + atomic_inc(&tcp_lhash_users); + read_unlock(&tcp_lhash_lock); +} + +extern __inline__ void tcp_listen_unlock(void) +{ + if (atomic_dec_and_test(&tcp_lhash_users)) + wake_up(&tcp_lhash_wait); +} #endif /* _TCP_H */ diff -u --recursive --new-file v2.3.14/linux/include/net/udp.h linux/include/net/udp.h --- v2.3.14/linux/include/net/udp.h Wed Aug 18 16:44:40 1999 +++ linux/include/net/udp.h Tue Aug 24 17:12:21 1999 @@ -32,6 +32,7 @@ * the port space is shared. */ extern struct sock *udp_hash[UDP_HTABLE_SIZE]; +extern rwlock_t udp_hash_lock; extern int udp_port_rover; @@ -66,8 +67,6 @@ extern int udp_rcv(struct sk_buff *skb, unsigned short len); extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); - -/* CONFIG_IP_TRANSPARENT_PROXY */ -extern int udp_chkaddr(struct sk_buff *skb); +extern int udp_disconnect(struct sock *sk, int flags); #endif /* _UDP_H */ diff -u --recursive --new-file v2.3.14/linux/include/video/fbcon.h linux/include/video/fbcon.h --- v2.3.14/linux/include/video/fbcon.h Thu Feb 25 10:02:12 1999 +++ linux/include/video/fbcon.h Wed Aug 25 14:57:47 1999 @@ -510,4 +510,25 @@ #endif + +#if defined(__i386__) || defined(__alpha__) + +#define fb_readb __raw_readb +#define fb_readw __raw_readw +#define fb_readl __raw_readl +#define fb_writeb __raw_writeb +#define fb_writew __raw_writew +#define fb_writel __raw_writel + +#else + +#define fb_readb(addr) (*(volatile unsigned char *) __io_virt(addr)) +#define fb_readw(addr) (*(volatile unsigned short *) __io_virt(addr)) +#define fb_readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define fb_writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) +#define fb_writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) +#define fb_writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) + +#endif + #endif /* _VIDEO_FBCON_H */ diff -u --recursive --new-file v2.3.14/linux/ipc/msg.c linux/ipc/msg.c --- v2.3.14/linux/ipc/msg.c Wed Jun 30 11:24:55 1999 +++ linux/ipc/msg.c Tue Aug 24 10:00:53 1999 @@ -30,7 +30,7 @@ static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); #endif -static struct msqid_ds *msgque[MSGMNI]; +static struct msqid_ds_kern *msgque[MSGMNI]; static int msgbytes = 0; static int msghdrs = 0; static unsigned short msg_seq = 0; @@ -46,7 +46,7 @@ #endif for (id = 0; id < MSGMNI; id++) - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; init_waitqueue_head(&msg_lock); #ifdef CONFIG_PROC_FS @@ -59,7 +59,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; struct msg *msgh; long mtype; @@ -136,7 +136,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; struct msg *tmsg, *leastp = NULL; struct msg *nmsg = NULL; @@ -233,7 +233,7 @@ return -1; } -asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) +asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { int ret; @@ -243,8 +243,8 @@ return ret; } -asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, - long msgtyp, int msgflg) +asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, + long msgtyp, int msgflg) { int ret; @@ -257,7 +257,7 @@ static int findkey (key_t key) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; for (id = 0; id <= max_msqid; id++) { while ((msq = msgque[id]) == IPC_NOID) @@ -273,20 +273,20 @@ static int newque (key_t key, int msgflg) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; for (id = 0; id < MSGMNI; id++) if (msgque[id] == IPC_UNUSED) { - msgque[id] = (struct msqid_ds *) IPC_NOID; + msgque[id] = (struct msqid_ds_kern *) IPC_NOID; goto found; } return -ENOSPC; found: - msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL); + msq = (struct msqid_ds_kern *) kmalloc (sizeof (*msq), GFP_KERNEL); if (!msq) { - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; wake_up (&msg_lock); return -ENOMEM; } @@ -312,10 +312,10 @@ return (unsigned int) msq->msg_perm.seq * MSGMNI + id; } -asmlinkage int sys_msgget (key_t key, int msgflg) +asmlinkage long sys_msgget (key_t key, int msgflg) { int id, ret = -EPERM; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; lock_kernel(); if (key == IPC_PRIVATE) @@ -342,7 +342,7 @@ static void freeque (int id) { - struct msqid_ds *msq = msgque[id]; + struct msqid_ds_kern *msq = msgque[id]; struct msg *msgp, *msgh; msq->msg_perm.seq++; @@ -350,7 +350,7 @@ msgbytes -= msq->msg_cbytes; if (id == max_msqid) while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; used_queues--; while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) { wake_up (&msq->rwait); @@ -365,10 +365,10 @@ kfree(msq); } -asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) +asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int id, err = -EINVAL; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct msqid_ds tbuf; struct ipc_perm *ipcp; @@ -420,8 +420,10 @@ tbuf.msg_stime = msq->msg_stime; tbuf.msg_rtime = msq->msg_rtime; tbuf.msg_ctime = msq->msg_ctime; + tbuf.msg_cbytes_old = msq->msg_cbytes; tbuf.msg_cbytes = msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; + tbuf.msg_qbytes_old = msq->msg_qbytes; tbuf.msg_qbytes = msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; @@ -462,8 +464,10 @@ tbuf.msg_stime = msq->msg_stime; tbuf.msg_rtime = msq->msg_rtime; tbuf.msg_ctime = msq->msg_ctime; + tbuf.msg_cbytes_old = msq->msg_cbytes; tbuf.msg_cbytes = msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; + tbuf.msg_qbytes_old = msq->msg_qbytes; tbuf.msg_qbytes = msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; diff -u --recursive --new-file v2.3.14/linux/ipc/sem.c linux/ipc/sem.c --- v2.3.14/linux/ipc/sem.c Wed Jun 30 11:24:55 1999 +++ linux/ipc/sem.c Mon Aug 23 11:15:53 1999 @@ -157,7 +157,7 @@ return (unsigned int) sma->sem_perm.seq * SEMMNI + id; } -asmlinkage int sys_semget (key_t key, int nsems, int semflg) +asmlinkage long sys_semget (key_t key, int nsems, int semflg) { int id, err = -EINVAL; struct semid_ds *sma; @@ -394,7 +394,7 @@ kfree(sma); } -asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) +asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) { struct semid_ds *buf = NULL; struct semid_ds tbuf; @@ -615,7 +615,7 @@ return err; } -asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) +asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) { int id, size, error = -EINVAL; struct semid_ds *sma; diff -u --recursive --new-file v2.3.14/linux/ipc/shm.c linux/ipc/shm.c --- v2.3.14/linux/ipc/shm.c Mon Aug 2 10:16:41 1999 +++ linux/ipc/shm.c Mon Aug 23 11:15:53 1999 @@ -144,7 +144,7 @@ int shmmax = SHMMAX; -asmlinkage int sys_shmget (key_t key, int size, int shmflg) +asmlinkage long sys_shmget (key_t key, int size, int shmflg) { struct shmid_kernel *shp; int err, id = 0; @@ -222,7 +222,7 @@ return; } -asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) +asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) { struct shmid_ds tbuf; struct shmid_kernel *shp; @@ -428,7 +428,7 @@ /* * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. */ -asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) +asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) { struct shmid_kernel *shp; struct vm_area_struct *shmd; @@ -589,7 +589,7 @@ * detach and kill segment if marked destroyed. * The work is done in shm_close. */ -asmlinkage int sys_shmdt (char *shmaddr) +asmlinkage long sys_shmdt (char *shmaddr) { struct vm_area_struct *shmd, *shmdnext; diff -u --recursive --new-file v2.3.14/linux/ipc/util.c linux/ipc/util.c --- v2.3.14/linux/ipc/util.c Mon Jan 4 14:38:48 1999 +++ linux/ipc/util.c Mon Aug 23 11:15:53 1999 @@ -63,58 +63,58 @@ return 0; } -asmlinkage int sys_semget (key_t key, int nsems, int semflg) +asmlinkage long sys_semget (key_t key, int nsems, int semflg) { return -ENOSYS; } -asmlinkage int sys_semop (int semid, struct sembuf *sops, unsigned nsops) +asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops) { return -ENOSYS; } -asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) +asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) { return -ENOSYS; } -asmlinkage int sys_msgget (key_t key, int msgflg) +asmlinkage long sys_msgget (key_t key, int msgflg) { return -ENOSYS; } -asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) +asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { return -ENOSYS; } -asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, +asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { return -ENOSYS; } -asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) +asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { return -ENOSYS; } -asmlinkage int sys_shmget (key_t key, int size, int flag) +asmlinkage long sys_shmget (key_t key, int size, int flag) { return -ENOSYS; } -asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr) +asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr) { return -ENOSYS; } -asmlinkage int sys_shmdt (char *shmaddr) +asmlinkage long sys_shmdt (char *shmaddr) { return -ENOSYS; } -asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) +asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) { return -ENOSYS; } diff -u --recursive --new-file v2.3.14/linux/kernel/acct.c linux/kernel/acct.c --- v2.3.14/linux/kernel/acct.c Sat Jul 3 10:43:52 1999 +++ linux/kernel/acct.c Mon Aug 23 11:15:53 1999 @@ -146,7 +146,7 @@ * should be written. If the filename is NULL, accounting will be * shutdown. */ -asmlinkage int sys_acct(const char *name) +asmlinkage long sys_acct(const char *name) { struct file *file = NULL, *old_acct = NULL; char *tmp; @@ -354,7 +354,7 @@ * into the kernel. */ -asmlinkage int sys_acct(const char * filename) +asmlinkage long sys_acct(const char * filename) { return -ENOSYS; } diff -u --recursive --new-file v2.3.14/linux/kernel/capability.c linux/kernel/capability.c --- v2.3.14/linux/kernel/capability.c Thu Aug 5 14:43:32 1999 +++ linux/kernel/capability.c Mon Aug 23 11:15:53 1999 @@ -19,7 +19,7 @@ kernel_cap_t cap_bset = CAP_FULL_SET; -asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t dataptr) +asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) { int error, pid; __u32 version; @@ -126,7 +126,7 @@ * E: must be set to a subset of (new target) Permitted */ -asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) +asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) { kernel_cap_t inheritable, permitted, effective; __u32 version; diff -u --recursive --new-file v2.3.14/linux/kernel/exec_domain.c linux/kernel/exec_domain.c --- v2.3.14/linux/kernel/exec_domain.c Fri Nov 20 11:43:19 1998 +++ linux/kernel/exec_domain.c Mon Aug 23 11:15:53 1999 @@ -98,7 +98,7 @@ return -EINVAL; } -asmlinkage int sys_personality(unsigned long personality) +asmlinkage long sys_personality(unsigned long personality) { struct exec_domain *it; unsigned long old_personality; diff -u --recursive --new-file v2.3.14/linux/kernel/exit.c linux/kernel/exit.c --- v2.3.14/linux/kernel/exit.c Thu Jul 29 13:40:13 1999 +++ linux/kernel/exit.c Mon Aug 23 11:15:53 1999 @@ -412,12 +412,12 @@ goto fake_volatile; } -asmlinkage int sys_exit(int error_code) +asmlinkage long sys_exit(int error_code) { do_exit((error_code&0xff)<<8); } -asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) +asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) { int flag, retval; DECLARE_WAITQUEUE(wait, current); @@ -505,13 +505,13 @@ return retval; } -#ifndef __alpha__ +#if !defined(__alpha__) && !defined(__ia64__) /* * sys_waitpid() remains for compatibility. waitpid() should be * implemented by calling sys_wait4() from libc.a. */ -asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options) +asmlinkage long sys_waitpid(pid_t pid,unsigned int * stat_addr, int options) { return sys_wait4(pid, stat_addr, options, NULL); } diff -u --recursive --new-file v2.3.14/linux/kernel/info.c linux/kernel/info.c --- v2.3.14/linux/kernel/info.c Sun Jul 11 09:11:46 1999 +++ linux/kernel/info.c Mon Aug 23 11:15:53 1999 @@ -13,7 +13,7 @@ #include -asmlinkage int sys_sysinfo(struct sysinfo *info) +asmlinkage long sys_sysinfo(struct sysinfo *info) { struct sysinfo val; diff -u --recursive --new-file v2.3.14/linux/kernel/itimer.c linux/kernel/itimer.c --- v2.3.14/linux/kernel/itimer.c Wed Jul 28 10:30:45 1999 +++ linux/kernel/itimer.c Mon Aug 23 11:15:53 1999 @@ -75,7 +75,7 @@ } /* SMP: Only we modify our itimer values. */ -asmlinkage int sys_getitimer(int which, struct itimerval *value) +asmlinkage long sys_getitimer(int which, struct itimerval *value) { int error = -EFAULT; struct itimerval get_buffer; @@ -149,8 +149,8 @@ /* SMP: Again, only we play with our itimers, and signals are SMP safe * now so that is not an issue at all anymore. */ -asmlinkage int sys_setitimer(int which, struct itimerval *value, - struct itimerval *ovalue) +asmlinkage long sys_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue) { struct itimerval set_buffer, get_buffer; int error; diff -u --recursive --new-file v2.3.14/linux/kernel/module.c linux/kernel/module.c --- v2.3.14/linux/kernel/module.c Thu Jul 29 13:37:22 1999 +++ linux/kernel/module.c Wed Aug 25 14:45:50 1999 @@ -57,7 +57,7 @@ * Called at boot time */ -__initfunc(void init_modules(void)) +void __init init_modules(void) { kernel_module.nsyms = __stop___ksymtab - __start___ksymtab; @@ -157,7 +157,7 @@ * Initialize a module. */ -asmlinkage int +asmlinkage long sys_init_module(const char *name_user, struct module *mod_user) { struct module mod_tmp, *mod; @@ -349,7 +349,7 @@ return error; } -asmlinkage int +asmlinkage long sys_delete_module(const char *name_user) { struct module *mod, *next; @@ -624,7 +624,7 @@ return error; } -asmlinkage int +asmlinkage long sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret) { @@ -689,7 +689,7 @@ * which does not arbitrarily limit the length of symbols. */ -asmlinkage int +asmlinkage long sys_get_kernel_syms(struct kernel_sym *table) { struct module *mod; @@ -977,19 +977,19 @@ return -ENOSYS; } -asmlinkage int +asmlinkage long sys_init_module(const char *name_user, struct module *mod_user) { return -ENOSYS; } -asmlinkage int +asmlinkage long sys_delete_module(const char *name_user) { return -ENOSYS; } -asmlinkage int +asmlinkage long sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret) { @@ -1001,7 +1001,7 @@ return -ENOSYS; } -asmlinkage int +asmlinkage long sys_get_kernel_syms(struct kernel_sym *table) { return -ENOSYS; diff -u --recursive --new-file v2.3.14/linux/kernel/panic.c linux/kernel/panic.c --- v2.3.14/linux/kernel/panic.c Mon Aug 2 16:38:02 1999 +++ linux/kernel/panic.c Mon Aug 23 10:23:23 1999 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,8 @@ int panic_timeout = 0; +struct notifier_block *panic_notifier_list = NULL; + static int __init panic_setup(char *str) { panic_timeout = simple_strtoul(str, NULL, 0); @@ -54,6 +57,9 @@ #ifdef __SMP__ smp_send_stop(); #endif + + notifier_call_chain(&panic_notifier_list, 0, NULL); + if (panic_timeout > 0) { /* diff -u --recursive --new-file v2.3.14/linux/kernel/printk.c linux/kernel/printk.c --- v2.3.14/linux/kernel/printk.c Mon Aug 16 23:58:59 1999 +++ linux/kernel/printk.c Mon Aug 23 11:15:53 1999 @@ -10,6 +10,8 @@ * elsewhere, in preparation for a serial line console (someday). * Ted Ts'o, 2/11/93. * Modified for sysctl support, 1/8/97, Chris Horn. + * Fixed SMP synchronization, 08/08/99, Manfred Spraul + * manfreds@colorfullife.com */ #include @@ -21,6 +23,7 @@ #include #define LOG_BUF_LEN (16384) +#define LOG_BUF_MASK (LOG_BUF_LEN-1) static char buf[1024]; @@ -40,13 +43,14 @@ int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; +spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + struct console *console_drivers = NULL; static char log_buf[LOG_BUF_LEN]; static unsigned long log_start = 0; static unsigned long logged_chars = 0; struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int preferred_console = -1; -spinlock_t console_lock = SPIN_LOCK_UNLOCKED; /* * Setup a list of consoles. Called from init/main.c @@ -118,7 +122,7 @@ */ int do_syslog(int type, char * buf, int len) { - unsigned long i, j, count; + unsigned long i, j, limit, count; int do_clear = 0; char c; int error = -EPERM; @@ -145,10 +149,9 @@ i = 0; spin_lock_irq(&console_lock); while (log_size && i < len) { - c = *((char *) log_buf+log_start); + c = log_buf[log_start & LOG_BUF_MASK]; log_start++; log_size--; - log_start &= LOG_BUF_LEN-1; spin_unlock_irq(&console_lock); __put_user(c,buf); buf++; @@ -171,34 +174,41 @@ error = verify_area(VERIFY_WRITE,buf,len); if (error) goto out; + spin_lock_irq(&console_lock); count = len; if (count > LOG_BUF_LEN) count = LOG_BUF_LEN; - /* The logged_chars, log_start, and log_size are serialized - by the console_lock (the console_lock can be acquired also - from irqs by printk). */ - spin_lock_irq(&console_lock); if (count > logged_chars) count = logged_chars; - j = log_start + log_size - count; - spin_unlock_irq(&console_lock); - /* While writing data to the userspace buffer printk may - trash our information but the _only_ thing we care is to - have a coherent `j' value. */ - for (i = 0; i < count; i++) { - c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); - __put_user(c, buf++); - } if (do_clear) - { - /* the increment done in printk may undo our - not atomic assigment if we do it without the - console lock held. */ - spin_lock_irq(&console_lock); logged_chars = 0; + limit = log_start + log_size; + /* + * __put_user() could sleep, and while we sleep + * printk() could overwrite the messages + * we try to copy to user space. Therefore + * the messages are copied in reverse. + */ + for(i=0;i < count;i++) { + j = limit-1-i; + if (j+LOG_BUF_LEN < log_start+log_size) + break; + c = log_buf[ j & LOG_BUF_MASK ]; spin_unlock_irq(&console_lock); + __put_user(c,&buf[count-1-i]); + spin_lock_irq(&console_lock); } + spin_unlock_irq(&console_lock); error = i; + if(i != count) { + int offset = count-error; + /* buffer overflow during copy, correct user buffer. */ + for(i=0;i 8) goto out; - spin_lock_irq(&console_lock); if (len < minimum_console_loglevel) len = minimum_console_loglevel; + spin_lock_irq(&console_lock); console_loglevel = len; spin_unlock_irq(&console_lock); error = 0; @@ -234,14 +244,13 @@ return error; } -asmlinkage int sys_syslog(int type, char * buf, int len) +asmlinkage long sys_syslog(int type, char * buf, int len) { if ((type != 3) && !capable(CAP_SYS_ADMIN)) return -EPERM; return do_syslog(type, buf, len); } - asmlinkage int printk(const char *fmt, ...) { va_list args; @@ -275,13 +284,12 @@ } line_feed = 0; for (; p < buf_end; p++) { - log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p; + log_buf[(log_start+log_size) & LOG_BUF_MASK] = *p; if (log_size < LOG_BUF_LEN) log_size++; - else { + else log_start++; - log_start &= LOG_BUF_LEN-1; - } + logged_chars++; if (*p == '\n') { line_feed = 1; @@ -306,29 +314,33 @@ void console_print(const char *s) { - struct console *c = console_drivers; + struct console *c; + unsigned long flags; int len = strlen(s); - spin_lock_irq(&console_lock); + spin_lock_irqsave(&console_lock,flags); + c = console_drivers; while(c) { if ((c->flags & CON_ENABLED) && c->write) c->write(c, s, len); c = c->next; } - spin_unlock_irq(&console_lock); + spin_unlock_irqrestore(&console_lock,flags); } void unblank_console(void) { - struct console *c = console_drivers; - - spin_lock_irq(&console_lock); + struct console *c; + unsigned long flags; + + spin_lock_irqsave(&console_lock,flags); + c = console_drivers; while(c) { if ((c->flags & CON_ENABLED) && c->unblank) c->unblank(); c = c->next; } - spin_unlock_irq(&console_lock); + spin_unlock_irqrestore(&console_lock,flags); } /* @@ -339,13 +351,13 @@ */ void register_console(struct console * console) { - int i,j,len; + int i, j,len; int p; char buf[16]; signed char msg_level = -1; char *q; + unsigned long flags; - spin_lock_irq(&console_lock); /* * See if we want to use this console driver. If we * didn't select a console we take the first one @@ -384,12 +396,13 @@ } if (!(console->flags & CON_ENABLED)) - goto out; + return; /* * Put this console in the list - keep the * preferred driver at the head of the list. */ + spin_lock_irqsave(&console_lock,flags); if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; @@ -397,23 +410,33 @@ console->next = console_drivers->next; console_drivers->next = console; } - if ((console->flags & CON_PRINTBUFFER) == 0) goto out; - + if ((console->flags & CON_PRINTBUFFER) == 0) + goto done; /* * Print out buffered log messages. */ - for (p=log_start,i=0,j=0; i < log_size; i++) { + p = log_start & LOG_BUF_MASK; + + for (i=0,j=0; i < log_size; i++) { buf[j++] = log_buf[p]; - p++; p &= LOG_BUF_LEN-1; + p = (p+1) & LOG_BUF_MASK; if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1) continue; buf[j] = 0; q = buf; len = j; if (msg_level < 0) { - msg_level = buf[1] - '0'; - q = buf + 3; - len -= 3; + if(buf[0] == '<' && + buf[1] >= '0' && + buf[1] <= '7' && + buf[2] == '>') { + msg_level = buf[1] - '0'; + q = buf + 3; + len -= 3; + } else + { + msg_level = default_message_loglevel; + } } if (msg_level < console_loglevel) console->write(console, q, len); @@ -421,32 +444,35 @@ msg_level = -1; j = 0; } - out: - spin_unlock_irq(&console_lock); +done: + spin_unlock_irqrestore(&console_lock,flags); } int unregister_console(struct console * console) { struct console *a,*b; - int ret = 0; - - spin_lock_irq(&console_lock); + unsigned long flags; + int res = 1; + + spin_lock_irqsave(&console_lock,flags); if (console_drivers == console) { console_drivers=console->next; - goto out; - } - for (a=console_drivers->next, b=console_drivers ; - a; b=a, a=b->next) { - if (a == console) { - b->next = a->next; - goto out; - } + res = 0; + } else + { + for (a=console_drivers->next, b=console_drivers ; + a; b=a, a=b->next) { + if (a == console) { + b->next = a->next; + res = 0; + break; + } + } } - ret = 1; - out: - spin_unlock_irq(&console_lock); - return ret; + + spin_unlock_irqrestore(&console_lock,flags); + return res; } /* diff -u --recursive --new-file v2.3.14/linux/kernel/resource.c linux/kernel/resource.c --- v2.3.14/linux/kernel/resource.c Sat Aug 7 11:08:54 1999 +++ linux/kernel/resource.c Mon Aug 23 10:40:50 1999 @@ -2,6 +2,7 @@ * linux/kernel/resource.c * * Copyright (C) 1999 Linus Torvalds + * Copyright (C) 1999 Martin Mares * * Arbitrary resource management. */ @@ -121,6 +122,59 @@ } /* + * Find empty slot in the resource tree given range and alignment. + */ +static int find_resource(struct resource *root, struct resource *new, + unsigned long size, + unsigned long min, unsigned long max, + unsigned long align) +{ + struct resource *this = root->child; + unsigned long start, end; + + start = root->start; + for(;;) { + if (this) + end = this->start; + else + end = root->end; + if (start < min) + start = min; + if (end > max) + end = max; + start = (start + align - 1) & ~(align - 1); + if (start < end && end - start + 1 >= size) { + new->start = start; + new->end = start + size - 1; + return 0; + } + if (!this) + break; + start = this->end + 1; + this = this->sibling; + } + return -EBUSY; +} + +/* + * Allocate empty slot in the resource tree given range and alignment. + */ +int allocate_resource(struct resource *root, struct resource *new, + unsigned long size, + unsigned long min, unsigned long max, + unsigned long align) +{ + int err; + + write_lock(&resource_lock); + err = find_resource(root, new, size, min, max, align); + if (err >= 0 && __request_resource(root, new)) + err = -EBUSY; + write_unlock(&resource_lock); + return err; +} + +/* * This is compatibility stuff for IO resources. * * Note how this, unlike the above, knows about @@ -167,8 +221,6 @@ return res; } -/* - */ int __check_region(struct resource *parent, unsigned long start, unsigned long n) { struct resource * res; @@ -232,7 +284,7 @@ res->start = io_start; res->end = io_start + io_num - 1; res->child = NULL; - if (request_resource(&ioport_resource, res) == 0) + if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0) reserved = x+1; } } diff -u --recursive --new-file v2.3.14/linux/kernel/sched.c linux/kernel/sched.c --- v2.3.14/linux/kernel/sched.c Tue Aug 3 08:01:29 1999 +++ linux/kernel/sched.c Tue Aug 24 16:56:07 1999 @@ -36,7 +36,6 @@ #include #include #include -#include #include @@ -224,69 +223,14 @@ return goodness(p, cpu, prev->mm) - goodness(prev, cpu, prev->mm); } -/* - * If there is a dependency between p1 and p2, - * don't be too eager to go into the slow schedule. - * In particular, if p1 and p2 both want the kernel - * lock, there is no point in trying to make them - * extremely parallel.. - * - * (No lock - lock_depth < 0) - * - * There are two additional metrics here: - * - * first, a 'cutoff' interval, currently 0-200 usecs on - * x86 CPUs, depending on the size of the 'SMP-local cache'. - * If the current process has longer average timeslices than - * this, then we utilize the idle CPU. - * - * second, if the wakeup comes from a process context, - * then the two processes are 'related'. (they form a - * 'gang') - * - * An idle CPU is almost always a bad thing, thus we skip - * the idle-CPU utilization only if both these conditions - * are true. (ie. a 'process-gang' rescheduling with rather - * high frequency should stay on the same CPU). - * - * [We can switch to something more finegrained in 2.3.] - * - * do not 'guess' if the to-be-scheduled task is RT. - */ -#define related(p1,p2) (((p1)->lock_depth >= 0) && (p2)->lock_depth >= 0) && \ - (((p2)->policy == SCHED_OTHER) && ((p1)->avg_slice < cacheflush_time)) - -static inline void reschedule_idle_slow(struct task_struct * p) +static void reschedule_idle(struct task_struct * p) { #ifdef __SMP__ -/* - * (see reschedule_idle() for an explanation first ...) - * - * Pass #2 - * - * We try to find another (idle) CPU for this woken-up process. - * - * On SMP, we mostly try to see if the CPU the task used - * to run on is idle.. but we will use another idle CPU too, - * at this point we already know that this CPU is not - * willing to reschedule in the near future. - * - * An idle CPU is definitely wasted, especially if this CPU is - * running long-timeslice processes. The following algorithm is - * pretty good at finding the best idle CPU to send this process - * to. - * - * [We can try to preempt low-priority processes on other CPUs in - * 2.3. Also we can try to use the avg_slice value to predict - * 'likely reschedule' events even on other CPUs.] - */ int this_cpu = smp_processor_id(), target_cpu; struct task_struct *tsk, *target_tsk; - int cpu, best_cpu, weight, best_weight, i; + int cpu, best_cpu, i; unsigned long flags; - best_weight = 0; /* prevents negative weight */ - spin_lock_irqsave(&runqueue_lock, flags); /* @@ -302,15 +246,17 @@ for (i = 0; i < smp_num_cpus; i++) { cpu = cpu_logical_map(i); tsk = cpu_curr(cpu); - if (related(tsk, p)) - goto out_no_target; - weight = preemption_goodness(tsk, p, cpu); - if (weight > best_weight) { - best_weight = weight; + if (tsk == idle_task(cpu)) target_tsk = tsk; - } } + if (target_tsk && p->avg_slice > cacheflush_time) + goto send_now; + + tsk = cpu_curr(best_cpu); + if (preemption_goodness(tsk, p, best_cpu) > 0) + target_tsk = tsk; + /* * found any suitable CPU? */ @@ -341,35 +287,6 @@ #endif } -static void reschedule_idle(struct task_struct * p) -{ -#ifdef __SMP__ - int cpu = smp_processor_id(); - /* - * ("wakeup()" should not be called before we've initialized - * SMP completely. - * Basically a not-yet initialized SMP subsystem can be - * considered as a not-yet working scheduler, simply dont use - * it before it's up and running ...) - * - * SMP rescheduling is done in 2 passes: - * - pass #1: faster: 'quick decisions' - * - pass #2: slower: 'lets try and find a suitable CPU' - */ - - /* - * Pass #1. (subtle. We might be in the middle of __switch_to, so - * to preserve scheduling atomicity we have to use cpu_curr) - */ - if ((p->processor == cpu) && related(cpu_curr(cpu), p)) - return; -#endif /* __SMP__ */ - /* - * Pass #2 - */ - reschedule_idle_slow(p); -} - /* * Careful! * @@ -893,128 +810,6 @@ return; } -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __down_interruptible(struct semaphore * sem) -{ - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} - #define SLEEP_ON_VAR \ unsigned long flags; \ wait_queue_t wait; \ @@ -1514,13 +1309,13 @@ mark_bh(TQUEUE_BH); } -#ifndef __alpha__ +#if !defined(__alpha__) && !defined(__ia64__) /* * For backwards compatibility? This can be done in libc so Alpha * and all newer ports shouldn't need it. */ -asmlinkage unsigned int sys_alarm(unsigned int seconds) +asmlinkage unsigned long sys_alarm(unsigned int seconds) { struct itimerval it_new, it_old; unsigned int oldalarm; @@ -1537,12 +1332,16 @@ return oldalarm; } +#endif + +#ifndef __alpha__ + /* * The Alpha uses getxpid, getxuid, and getxgid instead. Maybe this * should be moved into arch/i386 instead? */ -asmlinkage int sys_getpid(void) +asmlinkage long sys_getpid(void) { /* This is SMP safe - current->pid doesn't change */ return current->pid; @@ -1571,7 +1370,7 @@ * a small window for a race, using the old pointer is * harmless for a while). */ -asmlinkage int sys_getppid(void) +asmlinkage long sys_getppid(void) { int pid; struct task_struct * me = current; @@ -1594,25 +1393,25 @@ return pid; } -asmlinkage int sys_getuid(void) +asmlinkage long sys_getuid(void) { /* Only we change this so SMP safe */ return current->uid; } -asmlinkage int sys_geteuid(void) +asmlinkage long sys_geteuid(void) { /* Only we change this so SMP safe */ return current->euid; } -asmlinkage int sys_getgid(void) +asmlinkage long sys_getgid(void) { /* Only we change this so SMP safe */ return current->gid; } -asmlinkage int sys_getegid(void) +asmlinkage long sys_getegid(void) { /* Only we change this so SMP safe */ return current->egid; @@ -1624,7 +1423,7 @@ * it for backward compatibility? */ -asmlinkage int sys_nice(int increment) +asmlinkage long sys_nice(int increment) { unsigned long newprio; int increase = 0; @@ -1754,18 +1553,18 @@ return retval; } -asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, +asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { return setscheduler(pid, policy, param); } -asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param) +asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param *param) { return setscheduler(pid, -1, param); } -asmlinkage int sys_sched_getscheduler(pid_t pid) +asmlinkage long sys_sched_getscheduler(pid_t pid) { struct task_struct *p; int retval; @@ -1790,7 +1589,7 @@ return retval; } -asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param) +asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) { struct task_struct *p; struct sched_param lp; @@ -1821,7 +1620,7 @@ return retval; } -asmlinkage int sys_sched_yield(void) +asmlinkage long sys_sched_yield(void) { spin_lock_irq(&runqueue_lock); if (current->policy == SCHED_OTHER) @@ -1832,7 +1631,7 @@ return 0; } -asmlinkage int sys_sched_get_priority_max(int policy) +asmlinkage long sys_sched_get_priority_max(int policy) { int ret = -EINVAL; @@ -1848,7 +1647,7 @@ return ret; } -asmlinkage int sys_sched_get_priority_min(int policy) +asmlinkage long sys_sched_get_priority_min(int policy) { int ret = -EINVAL; @@ -1863,7 +1662,7 @@ return ret; } -asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) +asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { struct timespec t; @@ -1874,7 +1673,7 @@ return 0; } -asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) +asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) { struct timespec t; unsigned long expire; diff -u --recursive --new-file v2.3.14/linux/kernel/signal.c linux/kernel/signal.c --- v2.3.14/linux/kernel/signal.c Wed Jul 28 10:30:45 1999 +++ linux/kernel/signal.c Mon Aug 23 11:15:53 1999 @@ -640,7 +640,7 @@ * used by various programs) */ -asmlinkage int +asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) { int error = -EINVAL; @@ -696,7 +696,7 @@ return error; } -asmlinkage int +asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize) { int error = -EINVAL; @@ -717,7 +717,7 @@ return error; } -asmlinkage int +asmlinkage long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize) { @@ -787,7 +787,7 @@ return ret; } -asmlinkage int +asmlinkage long sys_kill(int pid, int sig) { struct siginfo info; @@ -801,7 +801,7 @@ return kill_something_info(sig, &info, pid); } -asmlinkage int +asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo) { siginfo_t info; @@ -947,7 +947,7 @@ #if !defined(__alpha__) /* Alpha has its own versions with special arguments. */ -asmlinkage int +asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset) { int error; @@ -996,7 +996,7 @@ return error; } -asmlinkage int +asmlinkage long sys_sigpending(old_sigset_t *set) { int error; @@ -1013,7 +1013,7 @@ } #ifndef __sparc__ -asmlinkage int +asmlinkage long sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize) { @@ -1045,14 +1045,14 @@ /* * For backwards compatibility. Functionality superseded by sigprocmask. */ -asmlinkage int +asmlinkage long sys_sgetmask(void) { /* SMP safe */ return current->blocked.sig[0]; } -asmlinkage int +asmlinkage long sys_ssetmask(int newmask) { int old; diff -u --recursive --new-file v2.3.14/linux/kernel/sys.c linux/kernel/sys.c --- v2.3.14/linux/kernel/sys.c Sat Jul 3 12:04:12 1999 +++ linux/kernel/sys.c Wed Aug 25 15:47:44 1999 @@ -45,7 +45,7 @@ extern void adjust_clock(void); -asmlinkage int sys_ni_syscall(void) +asmlinkage long sys_ni_syscall(void) { return -ENOSYS; } @@ -72,7 +72,7 @@ return 0; } -asmlinkage int sys_setpriority(int which, int who, int niceval) +asmlinkage long sys_setpriority(int which, int who, int niceval) { struct task_struct *p; unsigned int priority; @@ -122,7 +122,7 @@ * not return the normal nice-value, but a value that has been * offset by 20 (ie it returns 0..40 instead of -20..20) */ -asmlinkage int sys_getpriority(int which, int who) +asmlinkage long sys_getpriority(int which, int who) { struct task_struct *p; long max_prio = -ESRCH; @@ -154,7 +154,7 @@ * * reboot doesn't sync: do that yourself before calling this. */ -asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg) +asmlinkage long sys_reboot(int magic1, int magic2, int cmd, void * arg) { char buffer[256]; @@ -252,7 +252,7 @@ * SMP: There are not races, the GIDs are checked only by filesystem * operations (as far as semantic preservation is concerned). */ -asmlinkage int sys_setregid(gid_t rgid, gid_t egid) +asmlinkage long sys_setregid(gid_t rgid, gid_t egid) { int old_rgid = current->gid; int old_egid = current->egid; @@ -290,7 +290,7 @@ * * SMP: Same implicit races as above. */ -asmlinkage int sys_setgid(gid_t gid) +asmlinkage long sys_setgid(gid_t gid) { int old_egid = current->egid; @@ -356,7 +356,7 @@ * 100% compatible with BSD. A program which uses just setuid() will be * 100% compatible with POSIX with saved IDs. */ -asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) +asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) { int old_ruid, old_euid, old_suid, new_ruid; @@ -418,7 +418,7 @@ * will allow a root program to temporarily drop privileges and be able to * regain them by swapping the real and effective uid. */ -asmlinkage int sys_setuid(uid_t uid) +asmlinkage long sys_setuid(uid_t uid) { int old_euid = current->euid; int old_ruid, old_suid, new_ruid; @@ -454,7 +454,7 @@ * This function implements a generic ability to update ruid, euid, * and suid. This allows you to implement the 4.4 compatible seteuid(). */ -asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) +asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { int old_ruid = current->uid; int old_euid = current->euid; @@ -493,7 +493,7 @@ return 0; } -asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) +asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { int retval; @@ -507,7 +507,7 @@ /* * Same as above, but for rgid, egid, sgid. */ -asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) +asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && @@ -533,7 +533,7 @@ return 0; } -asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) +asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { int retval; @@ -551,7 +551,7 @@ * whatever uid it wants to). It normally shadows "euid", except when * explicitly set by setfsuid() or for access.. */ -asmlinkage int sys_setfsuid(uid_t uid) +asmlinkage long sys_setfsuid(uid_t uid) { int old_fsuid; @@ -588,7 +588,7 @@ /* * Samma på svenska.. */ -asmlinkage int sys_setfsgid(gid_t gid) +asmlinkage long sys_setfsgid(gid_t gid) { int old_fsgid; @@ -630,7 +630,7 @@ * LBT 04.03.94 */ -asmlinkage int sys_setpgid(pid_t pid, pid_t pgid) +asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) { struct task_struct * p; int err = -EINVAL; @@ -683,7 +683,7 @@ return err; } -asmlinkage int sys_getpgid(pid_t pid) +asmlinkage long sys_getpgid(pid_t pid) { if (!pid) { return current->pgrp; @@ -702,13 +702,13 @@ } } -asmlinkage int sys_getpgrp(void) +asmlinkage long sys_getpgrp(void) { /* SMP - assuming writes are word atomic this is fine */ return current->pgrp; } -asmlinkage int sys_getsid(pid_t pid) +asmlinkage long sys_getsid(pid_t pid) { if (!pid) { return current->session; @@ -727,7 +727,7 @@ } } -asmlinkage int sys_setsid(void) +asmlinkage long sys_setsid(void) { struct task_struct * p; int err = -EPERM; @@ -751,7 +751,7 @@ /* * Supplementary group IDs */ -asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist) +asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist) { int i; @@ -777,7 +777,7 @@ * without another task interfering. */ -asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) +asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist) { if (!capable(CAP_SETGID)) return -EPERM; @@ -815,7 +815,7 @@ */ DECLARE_MUTEX(uts_sem); -asmlinkage int sys_newuname(struct new_utsname * name) +asmlinkage long sys_newuname(struct new_utsname * name) { int errno = 0; @@ -826,7 +826,7 @@ return errno; } -asmlinkage int sys_sethostname(char *name, int len) +asmlinkage long sys_sethostname(char *name, int len) { int errno; @@ -844,7 +844,7 @@ return errno; } -asmlinkage int sys_gethostname(char *name, int len) +asmlinkage long sys_gethostname(char *name, int len) { int i, errno; @@ -865,7 +865,7 @@ * Only setdomainname; getdomainname can be implemented by calling * uname() */ -asmlinkage int sys_setdomainname(char *name, int len) +asmlinkage long sys_setdomainname(char *name, int len) { int errno; @@ -884,7 +884,7 @@ return errno; } -asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim) +asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim) { if (resource >= RLIM_NLIMITS) return -EINVAL; @@ -893,7 +893,7 @@ ? -EFAULT : 0; } -asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) +asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim) { struct rlimit new_rlim, *old_rlim; @@ -970,21 +970,21 @@ return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; } -asmlinkage int sys_getrusage(int who, struct rusage *ru) +asmlinkage long sys_getrusage(int who, struct rusage *ru) { if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) return -EINVAL; return getrusage(current, who, ru); } -asmlinkage int sys_umask(int mask) +asmlinkage long sys_umask(int mask) { mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); return mask; } -asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) +asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { int error = 0; int sig; @@ -997,6 +997,9 @@ break; } current->pdeath_signal = sig; + break; + case PR_GET_PDEATHSIG: + error = put_user(current->pdeath_signal, (int *)arg2); break; default: error = -EINVAL; diff -u --recursive --new-file v2.3.14/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.3.14/linux/kernel/sysctl.c Thu Aug 12 10:19:59 1999 +++ linux/kernel/sysctl.c Mon Aug 23 11:15:53 1999 @@ -323,7 +323,7 @@ return -ENOTDIR; } -extern asmlinkage int sys_sysctl(struct __sysctl_args *args) +extern asmlinkage long sys_sysctl(struct __sysctl_args *args) { struct __sysctl_args tmp; int error; @@ -1177,6 +1177,34 @@ return 0; } +/* Strategy function to convert jiffies to seconds */ +int sysctl_jiffies(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + if (oldval) { + size_t olen; + if (oldlenp) { + if (get_user(olen, oldlenp)) + return -EFAULT; + if (olen!=sizeof(int)) + return -EINVAL; + } + if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || + (oldlenp && put_user(sizeof(int),oldlenp))) + return -EFAULT; + } + if (newval && newlen) { + int new; + if (newlen != sizeof(int)) + return -EINVAL; + if (get_user(new, (int *)newval)) + return -EFAULT; + *(int *)(table->data) = new*HZ; + } + return 1; +} + int do_string ( void *oldval, size_t *oldlenp, void *newval, size_t newlen, int rdwr, char *data, size_t max) @@ -1253,7 +1281,7 @@ #else /* CONFIG_SYSCTL */ -extern asmlinkage int sys_sysctl(struct __sysctl_args *args) +extern asmlinkage long sys_sysctl(struct __sysctl_args *args) { return -ENOSYS; } diff -u --recursive --new-file v2.3.14/linux/kernel/time.c linux/kernel/time.c --- v2.3.14/linux/kernel/time.c Wed Jul 28 10:30:45 1999 +++ linux/kernel/time.c Mon Aug 23 11:15:53 1999 @@ -64,7 +64,7 @@ * * XXX This function is NOT 64-bit clean! */ -asmlinkage int sys_time(int * tloc) +asmlinkage long sys_time(int * tloc) { int i; @@ -85,7 +85,7 @@ * architectures that need it). */ -asmlinkage int sys_stime(int * tptr) +asmlinkage long sys_stime(int * tptr) { int value; @@ -106,7 +106,7 @@ #endif -asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz) +asmlinkage long sys_gettimeofday(struct timeval *tv, struct timezone *tz) { if (tv) { struct timeval ktv; @@ -181,7 +181,7 @@ return 0; } -asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) +asmlinkage long sys_settimeofday(struct timeval *tv, struct timezone *tz) { struct timeval new_tv; struct timezone new_tz; @@ -400,7 +400,7 @@ return(result); } -asmlinkage int sys_adjtimex(struct timex *txc_p) +asmlinkage long sys_adjtimex(struct timex *txc_p) { struct timex txc; /* Local copy of parameter */ int ret; diff -u --recursive --new-file v2.3.14/linux/mm/filemap.c linux/mm/filemap.c --- v2.3.14/linux/mm/filemap.c Fri Aug 13 11:49:39 1999 +++ linux/mm/filemap.c Mon Aug 23 11:50:17 1999 @@ -41,6 +41,10 @@ spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; +#define CLUSTER_PAGES (1 << page_cluster) +#define CLUSTER_SHIFT (PAGE_CACHE_SHIFT + page_cluster) +#define CLUSTER_BYTES (1 << CLUSTER_SHIFT) +#define CLUSTER_OFFSET(x) (((x) >> CLUSTER_SHIFT) << CLUSTER_SHIFT) void __add_page_to_hash_queue(struct page * page, struct page **p) { @@ -500,39 +504,58 @@ } /* - * Try to read ahead in the file. "page_cache" is a potentially free page - * that we could use for the cache (if it is 0 we can try to create one, - * this is all overlapped with the IO on the previous page finishing anyway) + * This adds the requested page to the page cache if it isn't already there, + * and schedules an I/O to read in its contents from disk. */ -static unsigned long try_to_read_ahead(struct file * file, - unsigned long offset, unsigned long page_cache) +static inline void page_cache_read(struct file * file, unsigned long offset) { + unsigned long new_page; struct inode *inode = file->f_dentry->d_inode; - struct page * page; - struct page ** hash; + struct page ** hash = page_hash(inode, offset); + struct page * page; - offset &= PAGE_CACHE_MASK; - switch (page_cache) { - case 0: - page_cache = page_cache_alloc(); - if (!page_cache) - break; - default: - if (offset >= inode->i_size) - break; - hash = page_hash(inode, offset); - page = page_cache_entry(page_cache); - if (!add_to_page_cache_unique(page, inode, offset, hash)) { - /* - * We do not have to check the return value here - * because it's a readahead. - */ - inode->i_op->readpage(file, page); - page_cache = 0; - page_cache_release(page); - } + spin_lock(&pagecache_lock); + page = __find_page_nolock(inode, offset, *hash); + spin_unlock(&pagecache_lock); + if (page) + return; + + new_page = page_cache_alloc(); + if (!new_page) + return; + page = page_cache_entry(new_page); + + if (!add_to_page_cache_unique(page, inode, offset, hash)) { + inode->i_op->readpage(file, page); + page_cache_release(page); + return; } - return page_cache; + + /* + * We arrive here in the unlikely event that someone + * raced with us and added our page to the cache first. + */ + page_cache_free(new_page); + return; +} + +/* + * Read in an entire cluster at once. A cluster is usually a 64k- + * aligned block that includes the address requested in "offset." + */ +static void read_cluster_nonblocking(struct file * file, + unsigned long offset) +{ + off_t filesize = file->f_dentry->d_inode->i_size; + unsigned long pages = CLUSTER_PAGES; + + offset = CLUSTER_OFFSET(offset); + while ((pages-- > 0) && (offset < filesize)) { + page_cache_read(file, offset); + offset += PAGE_CACHE_SIZE; + } + + return; } /* @@ -813,9 +836,9 @@ return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)]; } -static inline unsigned long generic_file_readahead(int reada_ok, +static void generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, - unsigned long ppos, struct page * page, unsigned long page_cache) + unsigned long ppos, struct page * page) { unsigned long max_ahead, ahead; unsigned long raend; @@ -879,8 +902,7 @@ ahead = 0; while (ahead < max_ahead) { ahead += PAGE_CACHE_SIZE; - page_cache = try_to_read_ahead(filp, raend + ahead, - page_cache); + page_cache_read(filp, raend + ahead); } /* * If we tried to read ahead some pages, @@ -912,7 +934,7 @@ #endif } - return page_cache; + return; } /* @@ -1046,7 +1068,8 @@ * Ok, the page was not immediately readable, so let's try to read ahead while we're at it.. */ page_not_up_to_date: - page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK, page, page_cache); + generic_file_readahead(reada_ok, filp, inode, + pos & PAGE_CACHE_MASK, page); if (Page_Uptodate(page)) goto page_ok; @@ -1067,7 +1090,8 @@ goto page_ok; /* Again, try some read-ahead while waiting for the page to finish.. */ - page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK, page, page_cache); + generic_file_readahead(reada_ok, filp, inode, + pos & PAGE_CACHE_MASK, page); wait_on_page(page); if (Page_Uptodate(page)) goto page_ok; @@ -1269,31 +1293,36 @@ } /* - * Semantics for shared and private memory areas are different past the end - * of the file. A shared mapping past the last page of the file is an error - * and results in a SIGBUS, while a private mapping just maps in a zero page. + * filemap_nopage() is invoked via the vma operations vector for a + * mapped memory region to read in file data during a page fault. * * The goto's are kind of ugly, but this streamlines the normal case of having * it in the page cache, and handles the special cases reasonably without * having a lot of duplicated code. * - * WSH 06/04/97: fixed a memory leak and moved the allocation of new_page - * ahead of the wait if we're sure to need it. + * XXX - at some point, this should return unique values to indicate to + * the caller whether this is EIO, OOM, or SIGBUS. */ -static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address, int no_share) +static unsigned long filemap_nopage(struct vm_area_struct * area, + unsigned long address, int no_share) { struct file * file = area->vm_file; struct dentry * dentry = file->f_dentry; struct inode * inode = dentry->d_inode; - unsigned long offset, reada, i; struct page * page, **hash; - unsigned long old_page, new_page; - int error; + unsigned long old_page, new_page = 0; - new_page = 0; - offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset; - if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm) - goto no_page; + unsigned long offset = address - area->vm_start + area->vm_offset; + + /* + * Semantics for shared and private memory areas are different + * past the end of the file. A shared mapping past the last page + * of the file is an error and results in a SIGBUS, while a + * private mapping just maps in a zero page. + */ + if ((offset >= inode->i_size) && + (area->vm_flags & VM_SHARED) && (area->vm_mm == current->mm)) + return 0; /* * Do we have something in the page cache already? @@ -1306,15 +1335,8 @@ /* * Ok, found a page in the page cache, now we need to check - * that it's up-to-date. First check whether we'll need an - * extra page -- better to overlap the allocation with the I/O. + * that it's up-to-date. */ - if (no_share && !new_page) { - new_page = page_cache_alloc(); - if (!new_page) - goto failure; - } - if (!Page_Uptodate(page)) goto page_not_uptodate; @@ -1325,35 +1347,30 @@ */ old_page = page_address(page); if (!no_share) { - /* - * Ok, we can share the cached page directly.. Get rid - * of any potential extra pages. - */ - if (new_page) - page_cache_free(new_page); - flush_page_to_ram(old_page); return old_page; } - /* - * No sharing ... copy to the new page. - */ - copy_page(new_page, old_page); - flush_page_to_ram(new_page); + new_page = page_cache_alloc(); + if (new_page) { + copy_page(new_page, old_page); + flush_page_to_ram(new_page); + } page_cache_release(page); return new_page; no_cached_page: /* - * Try to read in an entire cluster at once. + * If the requested offset is within our file, try to read a whole + * cluster of pages at once. + * + * Otherwise, we're off the end of a privately mapped file, + * so we need to map a zero page. */ - reada = offset; - reada >>= PAGE_CACHE_SHIFT + page_cluster; - reada <<= PAGE_CACHE_SHIFT + page_cluster; - - for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_CACHE_SIZE) - new_page = try_to_read_ahead(file, reada, new_page); + if (offset < inode->i_size) + read_cluster_nonblocking(file, offset); + else + page_cache_read(file, offset); /* * The page we want has now been added to the page cache. @@ -1369,9 +1386,7 @@ goto success; } - error = inode->i_op->readpage(file, page); - - if (!error) { + if (!inode->i_op->readpage(file, page)) { wait_on_page(page); if (Page_Uptodate(page)) goto success; @@ -1383,25 +1398,25 @@ * because there really aren't any performance issues here * and we need to check for errors. */ - if (!PageLocked(page)) - PAGE_BUG(page); - ClearPageError(page); - error = inode->i_op->readpage(file, page); - if (error) - goto failure; - wait_on_page(page); - if (Page_Uptodate(page)) + lock_page(page); + if (Page_Uptodate(page)) { + UnlockPage(page); goto success; + } + ClearPageError(page); + if (!inode->i_op->readpage(file, page)) { + wait_on_page(page); + if (Page_Uptodate(page)) + goto success; + } /* * Things didn't work out. Return zero to tell the * mm layer so, possibly freeing the page cache page first. */ -failure: page_cache_release(page); if (new_page) page_cache_free(new_page); -no_page: return 0; } @@ -1683,7 +1698,7 @@ return 0; } -asmlinkage int sys_msync(unsigned long start, size_t len, int flags) +asmlinkage long sys_msync(unsigned long start, size_t len, int flags) { unsigned long end; struct vm_area_struct * vma; diff -u --recursive --new-file v2.3.14/linux/mm/memory.c linux/mm/memory.c --- v2.3.14/linux/mm/memory.c Mon Aug 9 10:27:50 1999 +++ linux/mm/memory.c Wed Aug 25 15:46:54 1999 @@ -540,8 +540,10 @@ wait_on_page(map); } - if (++repeat < 16) + if (++repeat < 16) { + ptr = va & PAGE_MASK; goto repeat; + } return -EAGAIN; } @@ -819,7 +821,6 @@ if (PageReserved(page)) ++vma->vm_mm->rss; copy_cow_page(old_page,new_page); - flush_page_to_ram(old_page); flush_page_to_ram(new_page); flush_cache_page(vma, address); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); diff -u --recursive --new-file v2.3.14/linux/mm/mlock.c linux/mm/mlock.c --- v2.3.14/linux/mm/mlock.c Thu Aug 12 12:22:36 1999 +++ linux/mm/mlock.c Mon Aug 23 11:15:53 1999 @@ -172,7 +172,7 @@ return error; } -asmlinkage int sys_mlock(unsigned long start, size_t len) +asmlinkage long sys_mlock(unsigned long start, size_t len) { unsigned long locked; unsigned long lock_limit; @@ -203,7 +203,7 @@ return error; } -asmlinkage int sys_munlock(unsigned long start, size_t len) +asmlinkage long sys_munlock(unsigned long start, size_t len) { int ret; @@ -244,7 +244,7 @@ return error; } -asmlinkage int sys_mlockall(int flags) +asmlinkage long sys_mlockall(int flags) { unsigned long lock_limit; int ret = -EINVAL; @@ -271,7 +271,7 @@ return ret; } -asmlinkage int sys_munlockall(void) +asmlinkage long sys_munlockall(void) { int ret; diff -u --recursive --new-file v2.3.14/linux/mm/mmap.c linux/mm/mmap.c --- v2.3.14/linux/mm/mmap.c Tue Jul 27 12:33:27 1999 +++ linux/mm/mmap.c Mon Aug 23 11:15:53 1999 @@ -707,7 +707,7 @@ return 0; } -asmlinkage int sys_munmap(unsigned long addr, size_t len) +asmlinkage long sys_munmap(unsigned long addr, size_t len) { int ret; diff -u --recursive --new-file v2.3.14/linux/mm/mprotect.c linux/mm/mprotect.c --- v2.3.14/linux/mm/mprotect.c Tue Jul 6 10:11:40 1999 +++ linux/mm/mprotect.c Mon Aug 23 11:15:53 1999 @@ -194,7 +194,7 @@ return 0; } -asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) { unsigned long nstart, end, tmp; struct vm_area_struct * vma, * next; diff -u --recursive --new-file v2.3.14/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.3.14/linux/mm/swapfile.c Mon Aug 9 12:37:35 1999 +++ linux/mm/swapfile.c Mon Aug 23 11:15:53 1999 @@ -380,7 +380,7 @@ return 0; } -asmlinkage int sys_swapoff(const char * specialfile) +asmlinkage long sys_swapoff(const char * specialfile) { struct swap_info_struct * p = NULL; struct dentry * dentry; @@ -524,7 +524,7 @@ * * The swapon system call */ -asmlinkage int sys_swapon(const char * specialfile, int swap_flags) +asmlinkage long sys_swapon(const char * specialfile, int swap_flags) { struct swap_info_struct * p; struct dentry * swap_dentry; diff -u --recursive --new-file v2.3.14/linux/net/802/Makefile linux/net/802/Makefile --- v2.3.14/linux/net/802/Makefile Fri Jul 10 13:51:41 1998 +++ linux/net/802/Makefile Mon Aug 23 10:12:38 1999 @@ -26,6 +26,10 @@ SNAP=y endif +ifdef CONFIG_NET_FC +O_OBJS += fc.o +endif + ifdef CONFIG_FDDI O_OBJS += fddi.o endif diff -u --recursive --new-file v2.3.14/linux/net/802/fc.c linux/net/802/fc.c --- v2.3.14/linux/net/802/fc.c Wed Dec 31 16:00:00 1969 +++ linux/net/802/fc.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,94 @@ +/* + * NET3: Fibre Channel device handling subroutines + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Vineet Abraham + * v 1.0 03/22/99 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Put the headers on a Fibre Channel packet. + */ + +int fc_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + struct fch_hdr *fch; + int hdr_len; + + /* + * Add the 802.2 SNAP header if IP as the IPv4 code calls + * dev->hard_header directly. + */ + if (type == ETH_P_IP || type == ETH_P_ARP) + { + struct fcllc *fcllc=(struct fcllc *)(fch+1); + + hdr_len = sizeof(struct fch_hdr) + sizeof(struct fcllc); + fch = (struct fch_hdr *)skb_push(skb, hdr_len); + fcllc = (struct fcllc *)(fch+1); + fcllc->dsap = fcllc->ssap = EXTENDED_SAP; + fcllc->llc = UI_CMD; + fcllc->protid[0] = fcllc->protid[1] = fcllc->protid[2] = 0x00; + fcllc->ethertype = htons(type); + } + else + { + hdr_len = sizeof(struct fch_hdr); + fch = (struct fch_hdr *)skb_push(skb, hdr_len); + } + + if(saddr) + memcpy(fch->saddr,saddr,dev->addr_len); + else + memcpy(fch->saddr,dev->dev_addr,dev->addr_len); + + if(daddr) + { + memcpy(fch->daddr,daddr,dev->addr_len); + return(hdr_len); + } + return -hdr_len; +} + +/* + * A neighbour discovery of some species (eg arp) has completed. We + * can now send the packet. + */ + +int fc_rebuild_header(struct sk_buff *skb) +{ + struct fch_hdr *fch=(struct fch_hdr *)skb->data; + struct fcllc *fcllc=(struct fcllc *)(skb->data+sizeof(struct fch_hdr)); + if(fcllc->ethertype != htons(ETH_P_IP)) { + printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype)); + return 0; + } + + return arp_find(fch->daddr, skb); +} + diff -u --recursive --new-file v2.3.14/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c --- v2.3.14/linux/net/802/llc_macinit.c Tue Jun 1 23:25:48 1999 +++ linux/net/802/llc_macinit.c Wed Aug 25 14:45:50 1999 @@ -160,7 +160,7 @@ char eye_init[] = "LLC\0"; memset(lp, 0, sizeof(*lp)); - lp->dev = dev_get(device); + lp->dev = __dev_get_by_name(device); if(lp->dev == NULL) return -ENODEV; memcpy(lp->eye, eye_init, sizeof(lp->eye)); @@ -204,7 +204,7 @@ #define ALL_TYPES_8022 0 -__initfunc(void llc_init(struct net_proto *proto)) +void __init llc_init(struct net_proto *proto) { printk(KERN_NOTICE "IEEE 802.2 LLC for Linux 2.1 (c) 1996 Tim Alpaerts\n"); return; diff -u --recursive --new-file v2.3.14/linux/net/802/p8022.c linux/net/802/p8022.c --- v2.3.14/linux/net/802/p8022.c Wed Aug 18 11:38:48 1999 +++ linux/net/802/p8022.c Wed Aug 25 14:45:50 1999 @@ -90,7 +90,7 @@ EXPORT_SYMBOL(register_8022_client); EXPORT_SYMBOL(unregister_8022_client); -__initfunc(void p8022_proto_init(struct net_proto *pro)) +void __init p8022_proto_init(struct net_proto *pro) { p8022_packet_type.type=htons(ETH_P_802_2); dev_add_pack(&p8022_packet_type); diff -u --recursive --new-file v2.3.14/linux/net/802/psnap.c linux/net/802/psnap.c --- v2.3.14/linux/net/802/psnap.c Wed Aug 18 11:38:48 1999 +++ linux/net/802/psnap.c Wed Aug 25 14:45:50 1999 @@ -89,7 +89,7 @@ EXPORT_SYMBOL(register_snap_client); EXPORT_SYMBOL(unregister_snap_client); -__initfunc(void snap_proto_init(struct net_proto *pro)) +void __init snap_proto_init(struct net_proto *pro) { snap_dl=register_8022_client(0xAA, snap_rcv); if(snap_dl==NULL) diff -u --recursive --new-file v2.3.14/linux/net/802/tr.c linux/net/802/tr.c --- v2.3.14/linux/net/802/tr.c Wed Aug 18 11:38:48 1999 +++ linux/net/802/tr.c Wed Aug 25 14:45:50 1999 @@ -50,7 +50,7 @@ struct rif_cache_s { unsigned char addr[TR_ALEN]; - unsigned char iface[5]; + int iface; __u16 rcf; __u16 rseg[8]; rif_cache next; @@ -231,9 +231,8 @@ unsigned int hash; rif_cache entry; unsigned char *olddata; - unsigned long flags; - spin_lock_irqsave(&rif_lock, flags); + spin_lock_bh(&rif_lock); /* * Broadcasts are single route as stated in RFC 1042 @@ -302,7 +301,7 @@ else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_irqrestore(&rif_lock, flags); + spin_unlock_bh(&rif_lock); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -318,10 +317,9 @@ int i; unsigned int hash, rii_p = 0; rif_cache entry; - unsigned long flags; - spin_lock_irqsave(&rif_lock, flags); + spin_lock_bh(&rif_lock); /* * Firstly see if the entry exists @@ -360,12 +358,12 @@ if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); - spin_unlock_irqrestore(&rif_lock, flags); + spin_unlock_bh(&rif_lock); return; } memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN); - memcpy(&(entry->iface[0]),dev->name,5); + entry->iface = dev->ifindex; entry->next=rif_table[hash]; entry->last_used=jiffies; rif_table[hash]=entry; @@ -402,7 +400,7 @@ } entry->last_used=jiffies; } - spin_unlock_irqrestore(&rif_lock, flags); + spin_unlock_bh(&rif_lock); } /* @@ -412,9 +410,9 @@ static void rif_check_expire(unsigned long dummy) { int i; - unsigned long now=jiffies,flags; + unsigned long now=jiffies; - spin_lock_irqsave(&rif_lock, flags); + spin_lock(&rif_lock); for(i=0; i < RIF_TABLE_SIZE;i++) { @@ -434,15 +432,13 @@ } } - spin_unlock_irqrestore(&rif_lock, flags); + spin_unlock(&rif_lock); /* * Reset the timer */ - del_timer(&rif_timer); - rif_timer.expires = jiffies + sysctl_tr_rif_timeout; - add_timer(&rif_timer); + mod_timer(&rif_timer, jiffies+sysctl_tr_rif_timeout); } @@ -467,11 +463,14 @@ pos+=size; len+=size; + spin_lock_bh(&rif_lock); for(i=0;i < RIF_TABLE_SIZE;i++) { for(entry=rif_table[i];entry;entry=entry->next) { + struct net_device *dev = __dev_get_by_index(entry->iface); + size=sprintf(buffer+len,"%s %02X:%02X:%02X:%02X:%02X:%02X %7li ", - entry->iface,entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5], + dev?dev->name:"?",entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5], sysctl_tr_rif_timeout-(now-entry->last_used)); len+=size; pos=begin+len; @@ -513,11 +512,14 @@ if(pos>offset+length) break; } + spin_unlock_bh(&rif_lock); *start=buffer+(offset-begin); /* Start of wanted data */ len-=(offset-begin); /* Start slop */ if(len>length) len=length; /* Ending slop */ + if (len<0) + len=0; return len; } #endif @@ -536,7 +538,7 @@ }; #endif -__initfunc(void rif_init(struct net_proto *unused)) +void __init rif_init(struct net_proto *unused) { rif_timer.expires = RIF_TIMEOUT; rif_timer.data = 0L; diff -u --recursive --new-file v2.3.14/linux/net/Config.in linux/net/Config.in --- v2.3.14/linux/net/Config.in Wed Aug 18 09:45:10 1999 +++ linux/net/Config.in Mon Aug 23 10:01:02 1999 @@ -4,12 +4,18 @@ mainmenu_option next_comment comment 'Networking options' tristate 'Packet socket' CONFIG_PACKET +if [ "$CONFIG_PACKET" != "n" ]; then + bool 'Packet socket: mmapped IO' CONFIG_PACKET_MMAP +fi bool 'Kernel/User netlink socket' CONFIG_NETLINK if [ "$CONFIG_NETLINK" = "y" ]; then bool 'Routing messages' CONFIG_RTNETLINK tristate 'Netlink device emulation' CONFIG_NETLINK_DEV fi -bool 'Network firewalls' CONFIG_FIREWALL +bool 'Network packet filtering' CONFIG_NETFILTER +if [ "$CONFIG_NETFILTER" = "y" ]; then + bool 'Network packet filtering debugging' CONFIG_NETFILTER_DEBUG +fi bool 'Socket Filtering' CONFIG_FILTER tristate 'Unix domain sockets' CONFIG_UNIX bool 'TCP/IP networking' CONFIG_INET @@ -27,6 +33,22 @@ source net/khttpd/Config.in fi fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Asynchronous Transfer Mode (ATM, EXPERIMENTAL)' CONFIG_ATM y + if [ "$CONFIG_ATM" = "y" ]; then + if [ "$CONFIG_INET" = "y" ]; then + bool ' Classical IP over ATM' CONFIG_ATM_CLIP y + if [ "$CONFIG_ATM_CLIP" = "y" ]; then + bool ' Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP n + fi +# bool ' Application REQUested IP over ATM' CONFIG_AREQUIPA y + fi + tristate ' LAN Emulation (LANE) support' CONFIG_ATM_LANE y + if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then + tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA y + fi + fi +fi comment ' ' tristate 'The IPX protocol' CONFIG_IPX @@ -54,7 +76,6 @@ tristate 'WAN router' CONFIG_WAN_ROUTER bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL - bool 'CPU is too slow to handle full bandwidth' CONFIG_CPU_IS_SLOW if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then mainmenu_option next_comment comment 'QoS and/or fair queueing' diff -u --recursive --new-file v2.3.14/linux/net/Makefile linux/net/Makefile --- v2.3.14/linux/net/Makefile Wed Aug 18 09:45:10 1999 +++ linux/net/Makefile Mon Aug 23 09:56:32 1999 @@ -10,7 +10,7 @@ MOD_SUB_DIRS := ipv4 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ - econet irda decnet khttpd + econet irda decnet atm khttpd SUB_DIRS := core ethernet sched MOD_LIST_NAME := NET_MISC_MODULES @@ -151,6 +151,17 @@ ifeq ($(CONFIG_SUNRPC),m) MOD_SUB_DIRS += sunrpc endif +endif + +ifeq ($(CONFIG_ATM),y) +SUB_DIRS += atm +ifeq ($(CONFIG_ATM_LANE),m) + MOD_ATM = atm +endif +ifeq ($(CONFIG_ATM_MPOA),m) + MOD_ATM = atm +endif +MOD_SUB_DIRS += $(MOD_ATM) endif ifeq ($(CONFIG_DECNET),y) diff -u --recursive --new-file v2.3.14/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v2.3.14/linux/net/appletalk/aarp.c Wed Aug 18 11:38:48 1999 +++ linux/net/appletalk/aarp.c Wed Aug 25 14:45:50 1999 @@ -1021,7 +1021,7 @@ static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3}; -__initfunc(void aarp_proto_init(void)) +void __init aarp_proto_init(void) { if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL) printk(KERN_CRIT "Unable to register AARP with SNAP.\n"); diff -u --recursive --new-file v2.3.14/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.3.14/linux/net/appletalk/ddp.c Wed Aug 18 11:38:48 1999 +++ linux/net/appletalk/ddp.c Wed Aug 25 14:45:50 1999 @@ -81,7 +81,6 @@ #include #include #include -#include #include @@ -793,7 +792,7 @@ if(copy_from_user(&atreq,arg,sizeof(atreq))) return (-EFAULT); - if((dev = dev_get(atreq.ifr_name)) == NULL) + if((dev = __dev_get_by_name(atreq.ifr_name)) == NULL) return (-ENODEV); sa=(struct sockaddr_at*)&atreq.ifr_addr; @@ -1027,7 +1026,7 @@ case SIOCADDRT: /* FIX ME: the name of the device is still in user space, isn't it? */ if (rt.rt_dev != NULL) - if ((dev = dev_get(rt.rt_dev)) == NULL) + if ((dev = __dev_get_by_name(rt.rt_dev)) == NULL) return -(ENODEV); return (atrtr_create(&rt, dev)); @@ -1201,7 +1200,7 @@ /* * Free a socket. No work needed */ -static int atalk_release(struct socket *sock, struct socket *peer) +static int atalk_release(struct socket *sock) { struct sock *sk=sock->sk; @@ -1366,12 +1365,6 @@ */ static int atalk_accept(struct socket *sock, struct socket *newsock, int flags) { - if(newsock->sk) - { - sk_free(newsock->sk); - MOD_DEC_USE_COUNT; - } - return (-EOPNOTSUPP); } @@ -1480,12 +1473,6 @@ return (0); } - if(call_in_firewall(PF_APPLETALK, skb->dev, ddp, NULL,&skb)!=FW_ACCEPT) - { - kfree_skb(skb); - return (0); - } - /* Check the packet is aimed at us */ if(ddp->deh_dnet == 0) /* Net 0 is 'this network' */ @@ -1518,15 +1505,6 @@ return (0); } - /* - * Check firewall allows this routing - */ - if(call_fw_firewall(PF_APPLETALK, skb->dev, ddp, NULL, &skb) != FW_ACCEPT) - { - kfree_skb(skb); - return (0); - } - ta.s_net = ddp->deh_dnet; ta.s_node = ddp->deh_dnode; @@ -1596,7 +1574,7 @@ struct net_device *dev; /* This needs to be able to handle ipddp"N" devices */ - if((dev = dev_get("ipddp0")) == NULL) + if((dev = __dev_get_by_name("ipddp0")) == NULL) return (-ENODEV); skb->protocol = htons(ETH_P_IP); @@ -1832,12 +1810,6 @@ else ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp)); - if(call_out_firewall(PF_APPLETALK, skb->dev, ddp, NULL, &skb) != FW_ACCEPT) - { - kfree_skb(skb); - return (-EPERM); - } - /* * Loopback broadcast packets to non gateway targets (ie routes * to group we are in) @@ -2049,11 +2021,10 @@ atalk_create }; -static struct proto_ops atalk_dgram_ops= +static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops)= { PF_APPLETALK, - sock_no_dup, atalk_release, atalk_bind, atalk_connect, @@ -2068,9 +2039,13 @@ sock_no_getsockopt, sock_no_fcntl, atalk_sendmsg, - atalk_recvmsg + atalk_recvmsg, + sock_no_mmap }; +#include +SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK); + static struct notifier_block ddp_notifier= { ddp_device_event, @@ -2133,7 +2108,7 @@ /* Called by proto.c on kernel start up */ -__initfunc(void atalk_proto_init(struct net_proto *pro)) +void __init atalk_proto_init(struct net_proto *pro) { (void) sock_register(&atalk_family_ops); if((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL) diff -u --recursive --new-file v2.3.14/linux/net/atm/Makefile linux/net/atm/Makefile --- v2.3.14/linux/net/atm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/net/atm/Makefile Mon Aug 23 09:56:32 1999 @@ -0,0 +1,66 @@ +# +# Makefile for the ATM Protocol Families. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +include ../../.config + +O_TARGET= atm.o + +ifeq ($(CONFIG_ATM),y) + +O_OBJS = addr.o pvc.o raw.o signaling.o svc.o # party.o +OX_OBJS = common.o atm_misc.o resources.o + +ifeq ($(CONFIG_MMU_HACKS),y) +O_OBJS += mmuio.o +endif + +ifeq ($(CONFIG_ATM_CLIP),y) +O_OBJS += clip.o +NEED_IPCOM = ipcommon.o +endif + +ifeq ($(CONFIG_AREQUIPA),y) +O_OBJS += arequipa.o +NEED_IPCOM = ipcommon.o +endif + +ifeq ($(CONFIG_NET_SCH_ATM),y) +NEED_IPCOM = ipcommon.o +endif + +O_OBJS += $(NEED_IPCOM) + +ifeq ($(CONFIG_PROC_FS),y) +OX_OBJS += proc.o +endif + +ifeq ($(CONFIG_ATM_LANE),y) +O_OBJS += lec.o lane_mpoa_init.o +else + ifeq ($(CONFIG_ATM_LANE),m) + O_OBJS += lane_mpoa_init.o + M_OBJS += lec.o + endif +endif + +ifeq ($(CONFIG_ATM_MPOA),y) +O_OBJS += mpc.o mpoa_caches.o mpoa_proc.o +else + ifeq ($(CONFIG_ATM_MPOA),m) + M_OBJS += mpoa.o + endif +endif + +endif + + +include $(TOPDIR)/Rules.make + +mpoa.o: mpc.o mpoa_caches.o mpoa_proc.o + ld -r -o mpoa.o mpc.o mpoa_caches.o mpoa_proc.o diff -u --recursive --new-file v2.3.14/linux/net/atm/addr.c linux/net/atm/addr.c --- v2.3.14/linux/net/atm/addr.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/addr.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,165 @@ +/* net/atm/addr.c - Local ATM address registry */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include + +#include "signaling.h" +#include "addr.h" + + +static int check_addr(struct sockaddr_atmsvc *addr) +{ + int i; + + if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; + if (!*addr->sas_addr.pub) + if (!*addr->sas_addr.prv) return -EINVAL; + else return 0; + for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */ + if (!addr->sas_addr.pub[i]) return 0; + return -EINVAL; +} + + +static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b) +{ + if (*a->sas_addr.prv) + if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN)) + return 0; + if (!*a->sas_addr.pub) return !*b->sas_addr.pub; + if (!*b->sas_addr.pub) return 0; + return !strcmp(a->sas_addr.pub,b->sas_addr.pub); +} + + +/* + * Avoid modification of any list of local interfaces while reading it + * (which may involve page faults and therefore rescheduling) + */ + + +static volatile int local_lock = 0; +static wait_queue_head_t local_wait; + + +static void lock_local(void) +{ + while (local_lock) sleep_on(&local_wait); + local_lock = 1; +} + + +static void unlock_local(void) +{ + local_lock = 0; + wake_up(&local_wait); +} + + +static void notify_sigd(struct atm_dev *dev) +{ + struct sockaddr_atmpvc pvc; + + pvc.sap_addr.itf = dev->number; + sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL); +} + + +void reset_addr(struct atm_dev *dev) +{ + struct atm_dev_addr *this; + + lock_local(); + while (dev->local) { + this = dev->local; + dev->local = this->next; + kfree(this); + } + unlock_local(); + notify_sigd(dev); +} + + +int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +{ + struct atm_dev_addr **walk; + int error; + + error = check_addr(addr); + if (error) return error; + lock_local(); + for (walk = &dev->local; *walk; walk = &(*walk)->next) + if (identical(&(*walk)->addr,addr)) { + unlock_local(); + return -EEXIST; + } + *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL); + if (!*walk) { + unlock_local(); + return -ENOMEM; + } + (*walk)->addr = *addr; + (*walk)->next = NULL; + unlock_local(); + notify_sigd(dev); + return 0; +} + + +int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +{ + struct atm_dev_addr **walk,*this; + int error; + + error = check_addr(addr); + if (error) return error; + lock_local(); + for (walk = &dev->local; *walk; walk = &(*walk)->next) + if (identical(&(*walk)->addr,addr)) break; + if (!*walk) { + unlock_local(); + return -ENOENT; + } + this = *walk; + *walk = this->next; + kfree(this); + unlock_local(); + notify_sigd(dev); + return 0; +} + + +int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) +{ + struct atm_dev_addr *walk; + int total; + + lock_local(); + total = 0; + for (walk = dev->local; walk; walk = walk->next) { + total += sizeof(struct sockaddr_atmsvc); + if (total > size) { + unlock_local(); + return -E2BIG; + } + if (copy_to_user(u_buf,&walk->addr, + sizeof(struct sockaddr_atmsvc))) { + unlock_local(); + return -EFAULT; + } + u_buf++; + } + unlock_local(); + return total; +} + + +void init_addr(void) +{ + init_waitqueue_head(&local_wait); +} diff -u --recursive --new-file v2.3.14/linux/net/atm/addr.h linux/net/atm/addr.h --- v2.3.14/linux/net/atm/addr.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/addr.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,19 @@ +/* net/atm/addr.h - Local ATM address registry */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_ADDR_H +#define NET_ATM_ADDR_H + +#include +#include + + +void reset_addr(struct atm_dev *dev); +int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); +void init_addr(void); + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/atm_misc.c linux/net/atm/atm_misc.c --- v2.3.14/linux/net/atm/atm_misc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/atm_misc.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,123 @@ +/* net/atm/atm_misc.c - Various functions for use by ATM drivers */ + +/* Written 1995-1999 by Werner Almesberger, EPFL ICA */ + + +#include +#include +#include +#include +#include +#include + +#include "tunable.h" + + +int atm_charge(struct atm_vcc *vcc,int truesize) +{ + atm_force_charge(vcc,truesize); + if (atomic_read(&vcc->rx_inuse) <= vcc->rx_quota) return 1; + atm_return(vcc,truesize); + vcc->stats->rx_drop++; + return 0; +} + + +static int check_ci(struct atm_vcc *vcc,short vpi,int vci) +{ + struct atm_vcc *walk; + + for (walk = vcc->dev->vccs; walk; walk = walk->next) + if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi && + walk->vci == vci && ((walk->qos.txtp.traffic_class != + ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || + (walk->qos.rxtp.traffic_class != ATM_NONE && + vcc->qos.rxtp.traffic_class != ATM_NONE))) + return -EADDRINUSE; + /* allow VCCs with same VPI/VCI iff they don't collide on + TX/RX (but we may refuse such sharing for other reasons, + e.g. if protocol requires to have both channels) */ + return 0; +} + + +int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) +{ + static short p = 0; /* poor man's per-device cache */ + static int c = 0; + short old_p; + int old_c; + + if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) + return check_ci(vcc,*vpi,*vci); + /* last scan may have left values out of bounds for current device */ + if (*vpi != ATM_VPI_ANY) p = *vpi; + else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; + if (*vci != ATM_VCI_ANY) c = *vci; + else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits) + c = ATM_NOT_RSV_VCI; + old_p = p; + old_c = c; + do { + if (!check_ci(vcc,p,c)) { + *vpi = p; + *vci = c; + return 0; + } + if (*vci == ATM_VCI_ANY) { + c++; + if (c >= 1 << vcc->dev->ci_range.vci_bits) + c = ATM_NOT_RSV_VCI; + } + if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) && + *vpi == ATM_VPI_ANY) { + p++; + if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; + } + } + while (old_p != p || old_c != c); + return -EADDRINUSE; +} + + +/* + * atm_pcr_goal returns the positive PCR if it should be rounded up, the + * negative PCR if it should be rounded down, and zero if the maximum available + * bandwidth should be used. + * + * The rules are as follows (* = maximum, - = absent (0), x = value "x", + * (x+ = x or next value above x, x- = x or next value below): + * + * min max pcr result min max pcr result + * - - - * (UBR only) x - - x+ + * - - * * x - * * + * - - z z- x - z z- + * - * - * x * - x+ + * - * * * x * * * + * - * z z- x * z z- + * - y - y- x y - x+ + * - y * y- x y * y- + * - y z z- x y z z- + * + * All non-error cases can be converted with the following simple set of rules: + * + * if pcr == z then z- + * else if min == x && pcr == - then x+ + * else if max == y then y- + * else * + */ + + +int atm_pcr_goal(struct atm_trafprm *tp) +{ + if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr; + if (tp->min_pcr && !tp->pcr) return tp->min_pcr; + if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr; + return 0; +} + + +EXPORT_SYMBOL(atm_charge); +EXPORT_SYMBOL(atm_return); +EXPORT_SYMBOL(atm_find_ci); +EXPORT_SYMBOL(atm_pcr_goal); diff -u --recursive --new-file v2.3.14/linux/net/atm/clip.c linux/net/atm/clip.c --- v2.3.14/linux/net/atm/clip.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/clip.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,694 @@ +/* net/atm/clip.c - RFC1577 Classical IP over ATM */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include /* for UINT_MAX */ +#include +#include +#include +#include +#include /* for some manifest constants */ +#include +#include +#include +#include +#include +#include /* for net/route.h */ +#include /* for struct sockaddr_in */ +#include /* for IFF_UP */ +#include +#include /* for struct rtable and routing */ +#include /* icmp_send */ +#include /* for HZ */ +#include /* for htons etc. */ +#include /* save/restore_flags */ +#include +#include + +#include "common.h" +#include "tunable.h" +#include "resources.h" +#include "ipcommon.h" +#include + + +#if 0 +#define DPRINTK(format,args...) printk(format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +struct net_device *clip_devs = NULL; +struct atm_vcc *atmarpd = NULL; +static struct timer_list idle_timer = { NULL, NULL, 0L, 0L, NULL }; +static int start_timer = 1; + + +static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip) +{ + struct atmarp_ctrl *ctrl; + struct sk_buff *skb; + + DPRINTK("to_atmarpd(%d)\n",type); + if (!atmarpd) return -EUNATCH; + skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); + if (!skb) return -ENOMEM; + ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl)); + ctrl->type = type; + ctrl->itf_num = itf; + ctrl->ip = ip; + atm_force_charge(atmarpd,skb->truesize); + skb_queue_tail(&atmarpd->recvq,skb); + wake_up(&atmarpd->sleep); + return 0; +} + + +static void link_vcc(struct clip_vcc *clip_vcc,struct atmarp_entry *entry) +{ + DPRINTK("link_vcc %p to entry %p (neigh %p)\n",clip_vcc,entry, + entry->neigh); + clip_vcc->entry = entry; + clip_vcc->next = entry->vccs; + entry->vccs = clip_vcc; + entry->neigh->used = jiffies; +} + + +static void unlink_clip_vcc(struct clip_vcc *clip_vcc) +{ + struct atmarp_entry *entry = clip_vcc->entry; + struct clip_vcc **walk; + + if (!entry) { + printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc); + return; + } + entry->neigh->used = jiffies; + for (walk = &entry->vccs; *walk; walk = &(*walk)->next) + if (*walk == clip_vcc) { + int error; + + *walk = clip_vcc->next; /* atomic */ + clip_vcc->entry = NULL; + if (entry->vccs) return; + entry->expires = jiffies-1; + /* force resolution or expiration */ + error = neigh_update(entry->neigh,NULL,NUD_NONE,0,0); + if (error) + printk(KERN_CRIT "unlink_clip_vcc: " + "neigh_update failed with %d\n",error); + return; + } + printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc " + "0x%p)\n",entry,clip_vcc); +} + + +static void idle_timer_check(unsigned long dummy) +{ + int i; + + /*DPRINTK("idle_timer_check\n");*/ + write_lock(&clip_tbl.lock); + for (i = 0; i <= NEIGH_HASHMASK; i++) { + struct neighbour **np; + + for (np = &clip_tbl.hash_buckets[i]; *np;) { + struct neighbour *n = *np; + struct atmarp_entry *entry = NEIGH2ENTRY(n); + struct clip_vcc *clip_vcc; + + for (clip_vcc = entry->vccs; clip_vcc; + clip_vcc = clip_vcc->next) + if (clip_vcc->idle_timeout && + time_after(jiffies, clip_vcc->last_use+ + clip_vcc->idle_timeout)) { + DPRINTK("releasing vcc %p->%p of " + "entry %p\n",clip_vcc,clip_vcc->vcc, + entry); + atm_async_release_vcc(clip_vcc->vcc, + -ETIMEDOUT); + } + if (entry->vccs || + time_before(jiffies, entry->expires)) { + np = &n->next; + continue; + } + if (atomic_read(&n->refcnt) > 1) { + struct sk_buff *skb; + + DPRINTK("destruction postponed with ref %d\n", + atomic_read(&n->refcnt)); + while ((skb = skb_dequeue(&n->arp_queue)) != + NULL) + dev_kfree_skb(skb); + np = &n->next; + continue; + } + *np = n->next; + DPRINTK("expired neigh %p\n",n); + n->dead = 1; + neigh_release(n); + } + } + mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ); + write_unlock(&clip_tbl.lock); +} + + +static int clip_arp_rcv(struct sk_buff *skb) +{ + struct atm_vcc *vcc; + + DPRINTK("clip_arp_rcv\n"); + vcc = ATM_SKB(skb)->vcc; + if (!vcc || !atm_charge(vcc,skb->truesize)) { + kfree_skb(skb); + return 0; + } + DPRINTK("pushing to %p\n",vcc); + DPRINTK("using %p\n",CLIP_VCC(vcc)->old_push); + CLIP_VCC(vcc)->old_push(vcc,skb); + return 0; +} + + +void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) +{ + struct clip_vcc *clip_vcc = CLIP_VCC(vcc); + + DPRINTK("clip push\n"); + if (!skb) { + DPRINTK("removing VCC %p\n",clip_vcc); + if (clip_vcc->entry) unlink_clip_vcc(clip_vcc); + clip_vcc->old_push(vcc,NULL); /* pass on the bad news */ + kfree(clip_vcc); + return; + } + atm_return(vcc,skb->truesize); + skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; + /* clip_vcc->entry == NULL if we don't have an IP address yet */ + if (!skb->dev) { + kfree_skb(skb); + return; + } + ATM_SKB(skb)->vcc = vcc; + skb->mac.raw = skb->data; + if (!clip_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data, + llc_oui,sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP); + else { + skb->protocol = ((u16 *) skb->data)[3]; + skb_pull(skb,RFC1483LLC_LEN); + if (skb->protocol == htons(ETH_P_ARP)) { + PRIV(skb->dev)->stats.rx_packets++; + clip_arp_rcv(skb); + return; + } + } + clip_vcc->last_use = jiffies; + PRIV(skb->dev)->stats.rx_packets++; + netif_rx(skb); +} + + +static void clip_neigh_destroy(struct neighbour *neigh) +{ + DPRINTK("clip_neigh_destroy (neigh %p)\n",neigh); + if (NEIGH2ENTRY(neigh)->vccs) + printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n"); + NEIGH2ENTRY(neigh)->vccs = (void *) 0xdeadbeef; +} + + +static void clip_neigh_solicit(struct neighbour *neigh,struct sk_buff *skb) +{ + DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n",neigh,skb); + to_atmarpd(act_need,PRIV(neigh->dev)->number,NEIGH2ENTRY(neigh)->ip); +} + + +static void clip_neigh_error(struct neighbour *neigh,struct sk_buff *skb) +{ +#ifndef CONFIG_ATM_CLIP_NO_ICMP + icmp_send(skb,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,0); +#endif + kfree_skb(skb); +} + + +static struct neigh_ops clip_neigh_ops = { + AF_INET, /* family */ + clip_neigh_destroy, /* destructor */ + clip_neigh_solicit, /* solicit */ + clip_neigh_error, /* error_report */ + dev_queue_xmit, /* output */ + dev_queue_xmit, /* connected_output */ + dev_queue_xmit, /* hh_output */ + dev_queue_xmit /* queue_xmit */ +}; + + +static int clip_constructor(struct neighbour *neigh) +{ + struct atmarp_entry *entry = NEIGH2ENTRY(neigh); + struct net_device *dev = neigh->dev; + struct in_device *in_dev = dev->ip_ptr; + + DPRINTK("clip_constructor (neigh %p, entry %p)\n",neigh,entry); + if (!in_dev) return -EINVAL; + neigh->type = inet_addr_type(entry->ip); + if (neigh->type != RTN_UNICAST) return -EINVAL; + if (in_dev->arp_parms) neigh->parms = in_dev->arp_parms; + neigh->ops = &clip_neigh_ops; + neigh->output = neigh->nud_state & NUD_VALID ? + neigh->ops->connected_output : neigh->ops->output; + entry->neigh = neigh; + entry->vccs = NULL; + entry->expires = jiffies-1; + return 0; +} + +static u32 clip_hash(const void *pkey, const struct net_device *dev) +{ + u32 hash_val; + + hash_val = *(u32*)pkey; + hash_val ^= (hash_val>>16); + hash_val ^= hash_val>>8; + hash_val ^= hash_val>>3; + hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + + return hash_val; +} + + +struct neigh_table clip_tbl = { + NULL, /* next */ + AF_INET, /* family */ + sizeof(struct neighbour)+sizeof(struct atmarp_entry), /* entry_size */ + 4, /* key_len */ + clip_hash, + clip_constructor, /* constructor */ + NULL, /* pconstructor */ + NULL, /* pdestructor */ + NULL, /* proxy_redo */ + "clip_arp_cache", + { /* neigh_parms */ + NULL, /* next */ + NULL, /* neigh_setup */ + &clip_tbl, /* tbl */ + 0, /* entries */ + NULL, /* priv */ + NULL, /* sysctl_table */ + 30*HZ, /* base_reachable_time */ + 1*HZ, /* retrans_time */ + 60*HZ, /* gc_staletime */ + 30*HZ, /* reachable_time */ + 5*HZ, /* delay_probe_time */ + 3, /* queue_len */ + 3, /* ucast_probes */ + 0, /* app_probes */ + 3, /* mcast_probes */ + 1*HZ, /* anycast_delay */ + (8*HZ)/10, /* proxy_delay */ + 1*HZ, /* proxy_qlen */ + 64 /* locktime */ + }, + 30*HZ,128,512,1024 /* copied from ARP ... */ +}; + + +/* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */ + +/* + * We play with the resolve flag: 0 and 1 have the usual meaning, but -1 means + * to allocate the neighbour entry but not to ask atmarpd for resolution. Also, + * don't increment the usage count. This is used to create entries in + * clip_setentry. + */ + + +int clip_encap(struct atm_vcc *vcc,int mode) +{ + CLIP_VCC(vcc)->encap = mode; + return 0; +} + + +static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev) +{ + struct atmarp_entry *entry; + + DPRINTK("clip_start_xmit (skb %p)\n",skb); + if (!skb->dst) { + printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); + dev_kfree_skb(skb); + return 0; + } + if (!skb->dst->neighbour) { +#if 0 + skb->dst->neighbour = clip_find_neighbour(skb->dst,1); + if (!skb->dst->neighbour) { + dev_kfree_skb(skb); /* lost that one */ + PRIV(dev)->stats.tx_dropped++; + return 0; + } +#endif +printk("clip_start_xmit: NO NEIGHBOUR !\n"); +return 0; + } + entry = NEIGH2ENTRY(skb->dst->neighbour); + if (!entry->vccs) { + if (time_after(jiffies, entry->expires)) { + /* should be resolved */ + entry->expires = jiffies+ATMARP_RETRY_DELAY*HZ; + to_atmarpd(act_need,PRIV(dev)->number,entry->ip); + } + if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS) + skb_queue_tail(&entry->neigh->arp_queue,skb); + else { + dev_kfree_skb(skb); + PRIV(dev)->stats.tx_dropped++; + } + return 0; + } + DPRINTK("neigh %p, vccs %p\n",entry,entry->vccs); + ATM_SKB(skb)->vcc = entry->vccs->vcc; + DPRINTK("using neighbour %p, vcc %p\n",skb->dst->neighbour, + ATM_SKB(skb)->vcc); + if (entry->vccs->encap) { + void *here; + + here = skb_push(skb,RFC1483LLC_LEN); + memcpy(here,llc_oui,sizeof(llc_oui)); + ((u16 *) here)[3] = skb->protocol; + } + atomic_add(skb->truesize,&ATM_SKB(skb)->vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; + entry->vccs->last_use = jiffies; + DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,ATM_SKB(skb)->vcc, + ATM_SKB(skb)->vcc->dev); + (void) ATM_SKB(skb)->vcc->dev->ops->send(ATM_SKB(skb)->vcc,skb); + PRIV(dev)->stats.tx_packets++; + return 0; +} + + +static struct enet_statistics *clip_get_stats(struct net_device *dev) +{ + return &PRIV(dev)->stats; +} + + +int clip_mkip(struct atm_vcc *vcc,int timeout) +{ + struct clip_vcc *clip_vcc; + struct sk_buff_head copy; + struct sk_buff *skb; + unsigned long flags; + + if (!vcc->push) return -EBADFD; + clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL); + if (!clip_vcc) return -ENOMEM; + DPRINTK("mkip clip_vcc %p vcc %p\n",clip_vcc,vcc); + clip_vcc->vcc = vcc; + vcc->user_back = clip_vcc; + clip_vcc->entry = NULL; + clip_vcc->encap = 1; + clip_vcc->last_use = jiffies; + clip_vcc->idle_timeout = timeout*HZ; + clip_vcc->old_push = vcc->push; + save_flags(flags); + cli(); + vcc->push = clip_push; + skb_migrate(&vcc->recvq,©); + restore_flags(flags); + /* re-process everything received between connection setup and MKIP */ + while ((skb = skb_dequeue(©))) + if (!clip_devs) { + atm_return(vcc,skb->truesize); + kfree_skb(skb); + } + else { + clip_push(vcc,skb); + PRIV(skb->dev)->stats.rx_packets--; + } + return 0; +} + + +int clip_setentry(struct atm_vcc *vcc,u32 ip) +{ + struct neighbour *neigh; + struct atmarp_entry *entry; + int error; + struct clip_vcc *clip_vcc; + struct rtable *rt; + + if (vcc->push != clip_push) { + printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n"); + return -EBADF; + } + clip_vcc = CLIP_VCC(vcc); + if (!ip) { + if (!clip_vcc->entry) { + printk(KERN_ERR "hiding hidden ATMARP entry\n"); + return 0; + } + DPRINTK("setentry: remove\n"); + unlink_clip_vcc(clip_vcc); + return 0; + } + error = ip_route_output(&rt,ip,0,1,0); + if (error) return error; + neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); + ip_rt_put(rt); + if (!neigh) + return -ENOMEM; + entry = NEIGH2ENTRY(neigh); + if (entry != clip_vcc->entry) { + if (!clip_vcc->entry) DPRINTK("setentry: add\n"); + else { + DPRINTK("setentry: update\n"); + unlink_clip_vcc(clip_vcc); + } + link_vcc(clip_vcc,entry); + } + error = neigh_update(neigh,llc_oui,NUD_PERMANENT,1,0); + neigh_release(neigh); + return error; +} + + +static int clip_init(struct net_device *dev) +{ + DPRINTK("clip_init %s\n",dev->name); + dev->hard_start_xmit = clip_start_xmit; + /* sg_xmit ... */ + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->hard_header_parse = NULL; + dev->hard_header_cache = NULL; + dev->header_cache_update = NULL; + dev->change_mtu = NULL; + dev->do_ioctl = NULL; + dev->get_stats = clip_get_stats; + dev->type = ARPHRD_ATM; + dev->hard_header_len = RFC1483LLC_LEN; + dev->mtu = RFC1626_MTU; + dev->addr_len = 0; + dev->tx_queue_len = 0; + dev->flags = 0; + dev_init_buffers(dev); /* is this ever supposed to be used ? */ + return 0; +} + + +int clip_create(int number) +{ + struct net_device *dev; + int error; + + if (number != -1) { + for (dev = clip_devs; dev; dev = PRIV(dev)->next) + if (PRIV(dev)->number == number) return -EEXIST; + } + else { + number = 0; + for (dev = clip_devs; dev; dev = PRIV(dev)->next) + if (PRIV(dev)->number >= number) + number = PRIV(dev)->number+1; + } + dev = kmalloc(sizeof(struct net_device)+sizeof(struct clip_priv), + GFP_KERNEL); + if (!dev) return -ENOMEM; + memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv)); + dev->name = PRIV(dev)->name; + sprintf(dev->name,"atm%d",number); + dev->init = clip_init; + PRIV(dev)->number = number; + error = register_netdev(dev); + if (error) { + kfree(dev); + return error; + } + PRIV(dev)->next = clip_devs; + clip_devs = dev; + DPRINTK("registered (net:%s)\n",dev->name); + return number; +} + + +static int clip_device_event(struct notifier_block *this,unsigned long event, + void *dev) +{ + /* ignore non-CLIP devices */ + if (((struct net_device *) dev)->type != ARPHRD_ATM || + ((struct net_device *) dev)->init != clip_init) + return NOTIFY_DONE; + switch (event) { + case NETDEV_UP: + DPRINTK("clip_device_event NETDEV_UP\n"); + (void) to_atmarpd(act_up,PRIV(dev)->number,0); + break; + case NETDEV_DOWN: + DPRINTK("clip_device_event NETDEV_DOWN\n"); + (void) to_atmarpd(act_down,PRIV(dev)->number,0); + break; + case NETDEV_CHANGE: + case NETDEV_CHANGEMTU: + DPRINTK("clip_device_event NETDEV_CHANGE*\n"); + (void) to_atmarpd(act_change,PRIV(dev)->number,0); + break; + case NETDEV_REBOOT: + case NETDEV_REGISTER: + DPRINTK("clip_device_event %ld\n",event); + /* ignore */ + break; + default: + printk(KERN_WARNING "clip_device_event: unknown event " + "%ld\n",event); + break; + } + return NOTIFY_DONE; +} + + +static int clip_inet_event(struct notifier_block *this,unsigned long event, + void *ifa) +{ + struct in_device *in_dev; + + in_dev = ((struct in_ifaddr *) ifa)->ifa_dev; + if (!in_dev || !in_dev->dev) { + printk(KERN_WARNING "clip_inet_event: no device\n"); + return NOTIFY_DONE; + } + /* + * Transitions are of the down-change-up type, so it's sufficient to + * handle the change on up. + */ + if (event != NETDEV_UP) return NOTIFY_DONE; + return clip_device_event(this,NETDEV_CHANGE,in_dev->dev); +} + + +static struct notifier_block clip_dev_notifier = { + clip_device_event, + NULL, + 0 +}; + + + +static struct notifier_block clip_inet_notifier = { + clip_inet_event, + NULL, + 0 +}; + + + +static void atmarpd_close(struct atm_vcc *vcc) +{ + struct sk_buff *skb; + + DPRINTK("atmarpd_close\n"); + atmarpd = NULL; /* assumed to be atomic */ + barrier(); + unregister_inetaddr_notifier(&clip_inet_notifier); + unregister_netdevice_notifier(&clip_dev_notifier); + if (skb_peek(&vcc->recvq)) + printk(KERN_ERR "atmarpd_close: closing with requests " + "pending\n"); + while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb); + DPRINTK("(done)\n"); +} + + +static struct atmdev_ops atmarpd_dev_ops = { + NULL, /* no dev_close */ + NULL, /* no open */ + atmarpd_close, /* close */ + NULL, /* no ioctl */ + NULL, /* no getsockopt */ + NULL, /* no setsockopt */ + NULL, /* send */ + NULL, /* no sg_send */ + NULL, /* no send_oam */ + NULL, /* no phy_put */ + NULL, /* no phy_get */ + NULL, /* no feedback */ + NULL, /* no change_qos */ + NULL /* no free_rx_skb */ +}; + + +static struct atm_dev atmarpd_dev = { + &atmarpd_dev_ops, + NULL, /* no PHY */ + "arpd", /* type */ + 999, /* dummy device number */ + NULL,NULL, /* pretend not to have any VCCs */ + NULL,NULL, /* no data */ + 0, /* no flags */ + NULL, /* no local address */ + { 0 } /* no ESI, no statistics */ +}; + + +int atm_init_atmarp(struct atm_vcc *vcc) +{ + struct net_device *dev; + + if (atmarpd) return -EADDRINUSE; + if (start_timer) { + start_timer = 0; + idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; + idle_timer.function = idle_timer_check; + add_timer(&idle_timer); + } + atmarpd = vcc; + vcc->flags |= ATM_VF_READY | ATM_VF_META; + /* allow replies and avoid getting closed if signaling dies */ + bind_vcc(vcc,&atmarpd_dev); + vcc->push = NULL; + vcc->pop = NULL; /* crash */ + vcc->push_oam = NULL; /* crash */ + if (register_netdevice_notifier(&clip_dev_notifier)) + printk(KERN_ERR "register_netdevice_notifier failed\n"); + if (register_inetaddr_notifier(&clip_inet_notifier)) + printk(KERN_ERR "register_inetaddr_notifier failed\n"); + for (dev = clip_devs; dev; dev = PRIV(dev)->next) + if (dev->flags & IFF_UP) + (void) to_atmarpd(act_up,PRIV(dev)->number,0); + return 0; +} diff -u --recursive --new-file v2.3.14/linux/net/atm/common.c linux/net/atm/common.c --- v2.3.14/linux/net/atm/common.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/common.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,937 @@ +/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include /* struct socket, struct net_proto, struct + proto_ops */ +#include /* ATM stuff */ +#include +#include /* CLIP_*ENCAP */ +#include /* manifest constants */ +#include /* for ioctls */ +#include /* SOL_SOCKET */ +#include /* error codes */ +#include +#include /* verify_area */ +#include +#include /* struct timeval */ +#include +#include /* struct sock */ + +#include +#include + +#ifdef CONFIG_MMU_HACKS +#include +#include +#endif + +#ifdef CONFIG_AREQUIPA +#include +#endif + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +#include +#include "lec.h" +#include "lec_arpc.h" +struct atm_lane_ops atm_lane_ops; +#endif +#ifdef CONFIG_ATM_LANE_MODULE +EXPORT_SYMBOL(atm_lane_ops); +#endif + +#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) +#include +#include "mpc.h" +struct atm_mpoa_ops atm_mpoa_ops; +#endif +#ifdef CONFIG_ATM_MPOA_MODULE +EXPORT_SYMBOL(atm_mpoa_ops); +#ifndef CONFIG_ATM_LANE_MODULE +EXPORT_SYMBOL(atm_lane_ops); +#endif +#endif + +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) +#include +#ifdef CONFIG_ATM_TCP_MODULE +struct atm_tcp_ops atm_tcp_ops; +EXPORT_SYMBOL(atm_tcp_ops); +#endif +#endif + +#include "resources.h" /* atm_find_dev */ +#include "common.h" /* prototypes */ +#include "protocols.h" /* atm_init_ */ +#include "tunable.h" /* tunable parameters */ +#include "addr.h" /* address registry */ +#ifdef CONFIG_ATM_CLIP +#include /* for clip_create */ +#endif +#include "signaling.h" /* for WAITING and sigd_attach */ + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) +{ + struct sk_buff *skb; + + if (atomic_read(&vcc->tx_inuse) && size+atomic_read(&vcc->tx_inuse)+ + ATM_PDU_OVHD > vcc->tx_quota) { + DPRINTK("Sorry: tx_inuse = %d, size = %d, tx_quota = %ld\n", + atomic_read(&vcc->tx_inuse),size,vcc->tx_quota); + return NULL; + } + while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); + DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse),skb->truesize); + atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); + return skb; +} + + +int atm_create(struct socket *sock,int protocol,int family) +{ + struct sock *sk; + struct atm_vcc *vcc; + + sock->sk = NULL; + if (sock->type == SOCK_STREAM) return -EINVAL; + if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; + vcc = sk->protinfo.af_atm; +#ifdef CONFIG_AREQUIPA + vcc->upper = NULL; + vcc->sock = sock; +#endif + vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX; + vcc->dev = NULL; + vcc->family = sock->ops->family; + vcc->alloc_tx = alloc_tx; + vcc->callback = NULL; + memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); + memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); + vcc->tx_quota = ATM_TXBQ_DEF; + vcc->rx_quota = ATM_RXBQ_DEF; + atomic_set(&vcc->tx_inuse,0); + atomic_set(&vcc->rx_inuse,0); + vcc->push = NULL; + vcc->pop = NULL; + vcc->push_oam = NULL; + vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ + vcc->atm_options = vcc->aal_options = 0; + vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0; + init_waitqueue_head(&vcc->sleep); + init_waitqueue_head(&vcc->wsleep); + skb_queue_head_init(&vcc->recvq); + skb_queue_head_init(&vcc->listenq); + sock->sk = sk; + return 0; +} + + +void atm_release_vcc_sk(struct sock *sk,int free_sk) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + + vcc = sk->protinfo.af_atm; + vcc->flags &= ~ATM_VF_READY; + if (vcc->dev) { + if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); + if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ + while ((skb = skb_dequeue(&vcc->recvq))) { + atm_return(vcc,skb->truesize); + if (vcc->dev->ops->free_rx_skb) + vcc->dev->ops->free_rx_skb(vcc,skb); + else kfree_skb(skb); + } + if (atomic_read(&vcc->rx_inuse)) + printk(KERN_WARNING "atm_release_vcc: strange ... " + "rx_inuse == %d after closing\n", + atomic_read(&vcc->rx_inuse)); + bind_vcc(vcc,NULL); + } + if (free_sk) free_atm_vcc_sk(sk); +} + + +int atm_release(struct socket *sock) +{ + if (sock->sk) + atm_release_vcc_sk(sock->sk,1); + return 0; +} + + +void atm_async_release_vcc(struct atm_vcc *vcc,int reply) +{ + vcc->flags |= ATM_VF_CLOSE; + vcc->reply = reply; + /*vcc->flags &= ~ATM_VF_READY;*/ + wake_up(&vcc->sleep); +} + + +EXPORT_SYMBOL(atm_async_release_vcc); + + +static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) +{ + int max_sdu; + + if (!tp->traffic_class) return 0; + switch (aal) { + case ATM_AAL0: + max_sdu = ATM_CELL_SIZE-1; + break; + case ATM_AAL34: + max_sdu = ATM_MAX_AAL34_PDU; + break; + default: + printk(KERN_WARNING "ATM: AAL problems ... " + "(%d)\n",aal); + /* fall through */ + case ATM_AAL5: + max_sdu = ATM_MAX_AAL5_PDU; + } + if (!tp->max_sdu) tp->max_sdu = max_sdu; + else if (tp->max_sdu > max_sdu) return -EINVAL; + if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV; + return 0; +} + + +static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, + int vci) +{ + int error; + + if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY && + vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC && + vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits)) + return -EINVAL; + if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) + return -EPERM; + error = 0; + switch (vcc->qos.aal) { + case ATM_AAL0: + error = atm_init_aal0(vcc); + vcc->stats = &dev->stats.aal0; + break; + case ATM_AAL34: + error = atm_init_aal34(vcc); + vcc->stats = &dev->stats.aal34; + break; + case ATM_NO_AAL: + /* ATM_AAL5 is also used in the "0 for default" case */ + vcc->qos.aal = ATM_AAL5; + /* fall through */ + case ATM_AAL5: + error = atm_init_aal5(vcc); + vcc->stats = &dev->stats.aal5; + break; + default: + error = -EPROTOTYPE; + } + if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal); + if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); + if (error) return error; + bind_vcc(vcc,dev); + DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); + DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, + vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); + DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, + vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu); + if (dev->ops->open) { + error = dev->ops->open(vcc,vpi,vci); + if (error) { + bind_vcc(vcc,NULL); + return error; + } + } + return 0; +} + + +static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) +{ + struct atm_dev *dev; + + dev = atm_find_dev(itf); + if (!dev) return -ENODEV; + return atm_do_connect_dev(vcc,dev,vpi,vci); +} + + +int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) +{ + if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) + vcc->flags &= ~ATM_VF_PARTIAL; + else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL; + printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; " + "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", + vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, + vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, + vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr, + vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, + vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : + " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); + if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || + vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) + return -EINVAL; + if (itf != ATM_ITF_ANY) { + int error; + + error = atm_do_connect(vcc,itf,vpi,vci); + if (error) return error; + } + else { + struct atm_dev *dev; + + for (dev = atm_devs; dev; dev = dev->next) + if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break; + if (!dev) return -ENODEV; + } + if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) + vcc->flags |= ATM_VF_PARTIAL; + return 0; +} + + +int atm_connect(struct socket *sock,int itf,short vpi,int vci) +{ + int error; + + DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci); + if (sock->state == SS_CONNECTED) return -EISCONN; + if (sock->state != SS_UNCONNECTED) return -EINVAL; + if (!(vpi || vci)) return -EINVAL; + error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci); + if (error) return error; + if (ATM_SD(sock)->flags & ATM_VF_READY) sock->state = SS_CONNECTED; + return 0; +} + + +int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, + int flags,struct scm_cookie *scm) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + unsigned long cpu_flags; + int eff_len,error; + + void *buff; + int size; + + if (sock->state != SS_CONNECTED) return -ENOTCONN; + if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP; + if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ + buff = m->msg_iov->iov_base; + size = m->msg_iov->iov_len; + vcc = ATM_SD(sock); + save_flags(cpu_flags); + cli(); + while (!(skb = skb_dequeue(&vcc->recvq))) { + if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) { + restore_flags(cpu_flags); + return vcc->reply; + } + if (!(vcc->flags & ATM_VF_READY)) { + restore_flags(cpu_flags); + return 0; + } + if (flags & MSG_DONTWAIT) { + restore_flags(cpu_flags); + return -EAGAIN; + } + interruptible_sleep_on(&vcc->sleep); + if (signal_pending(current)) { + restore_flags(cpu_flags); + return -ERESTARTSYS; + } + } + restore_flags(cpu_flags); + vcc->timestamp = skb->stamp; + eff_len = skb->len > size ? size : skb->len; + if (vcc->dev->ops->feedback) + vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, + (unsigned long) buff,eff_len); + DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->rx_inuse),skb->truesize); + atm_return(vcc,skb->truesize); + if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */ + /* iovcnt set, use scatter-gather for receive */ + int el, cnt; + struct iovec *iov = (struct iovec *)skb->data; + unsigned char *p = (unsigned char *)buff; + + el = eff_len; + error = 0; + for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) { +/*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/ + error = copy_to_user(p,iov->iov_base, + (iov->iov_len > el) ? el : iov->iov_len) ? + -EFAULT : 0; + if (error) break; + p += iov->iov_len; + el -= (iov->iov_len > el)?el:iov->iov_len; + iov++; + } + if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); + else vcc->dev->ops->free_rx_skb(vcc, skb); + return error ? error : eff_len; + } +#ifdef CONFIG_MMU_HACKS + if (vcc->flags & ATM_VF_SCRX) { + mmucp_tofs((unsigned long) buff,eff_len,skb, + (unsigned long) skb->data); + return eff_len; + } + else +#endif + { + error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; + if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); + else vcc->dev->ops->free_rx_skb(vcc, skb); + } + return error ? error : eff_len; +} + + +int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, + struct scm_cookie *scm) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + int eff,error; + + const void *buff; + int size; + + if (sock->state != SS_CONNECTED) return -ENOTCONN; + if (m->msg_name) return -EISCONN; + if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ + buff = m->msg_iov->iov_base; + size = m->msg_iov->iov_len; + vcc = ATM_SD(sock); + if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) return vcc->reply; + if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; + if (!size) return 0; + /* verify_area is done by net/socket.c */ +#ifdef CONFIG_MMU_HACKS + if ((vcc->flags & ATM_VF_SCTX) && vcc->dev->ops->sg_send && + vcc->dev->ops->sg_send(vcc,(unsigned long) buff,size)) { + int res,max_iov; + + max_iov = 2+size/PAGE_SIZE; + /* + * Doesn't use alloc_tx yet - this will change later. @@@ + */ + while (!(skb = alloc_skb(sizeof(struct iovec)*max_iov, + GFP_KERNEL))) { + if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN; + interruptible_sleep_on(&vcc->wsleep); + if (signal_pending(current)) return -ERESTARTSYS; + } + skb_put(skb,size); + res = lock_user((unsigned long) buff,size,max_iov, + (struct iovec *) skb->data); + if (res < 0) { + kfree_skb(skb); + if (res != -EAGAIN) return res; + } + else { + DPRINTK("res is %d\n",res); + DPRINTK("Asnd %d += %d\n",vcc->tx_inuse,skb->truesize); + atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = res; + error = vcc->dev->ops->send(vcc,skb); + /* FIXME: security: may send up to 3 "garbage" bytes */ + return error ? error : size; + } + } +#endif + eff = (size+3) & ~3; /* align to word boundary */ + while (!(skb = vcc->alloc_tx(vcc,eff))) { + if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN; + interruptible_sleep_on(&vcc->wsleep); + if (signal_pending(current)) return -ERESTARTSYS; + if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) + return vcc->reply; + if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; + } + ATM_SKB(skb)->iovcnt = 0; + ATM_SKB(skb)->atm_options = vcc->atm_options; + if (copy_from_user(skb_put(skb,size),buff,size)) { + kfree_skb(skb); + return -EFAULT; + } + if (eff != size) memset(skb->data+size,0,eff-size); + error = vcc->dev->ops->send(vcc,skb); + return error ? error : size; +} + + +unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait) +{ + struct atm_vcc *vcc; + unsigned int mask; + + vcc = ATM_SD(sock); + poll_wait(file,&vcc->sleep,wait); + poll_wait(file,&vcc->wsleep,wait); + mask = 0; + if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq)) + mask |= POLLIN | POLLRDNORM; + if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) mask |= POLLHUP; + if (sock->state != SS_CONNECTING) { + if (vcc->qos.txtp.traffic_class != ATM_NONE && + vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+ + ATM_PDU_OVHD <= vcc->tx_quota) + mask |= POLLOUT | POLLWRNORM; + } + else if (vcc->reply != WAITING) { + mask |= POLLOUT | POLLWRNORM; + if (vcc->reply) mask |= POLLERR; + } + return mask; +} + + +static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) +{ + unsigned long flags; + int error; + + error = 0; + save_flags(flags); + cli(); + if (arg) + error = copy_to_user(arg,&dev->stats, + sizeof(struct atm_dev_stats)); + if (zero && !error) + memset(&dev->stats,0,sizeof(struct atm_dev_stats)); + restore_flags(flags); + return error ? -EFAULT : 0; +} + + +int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) +{ + struct atm_dev *dev; + struct atm_vcc *vcc; + int *tmp_buf; + void *buf; + int error,len,size,number; + + vcc = ATM_SD(sock); + switch (cmd) { + case TIOCOUTQ: + if (sock->state != SS_CONNECTED || + !(vcc->flags & ATM_VF_READY)) return -EINVAL; + return put_user(vcc->tx_quota- + atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD, + (int *) arg) ? -EFAULT : 0; + case TIOCINQ: + { + struct sk_buff *skb; + + if (sock->state != SS_CONNECTED) + return -EINVAL; + skb = skb_peek(&vcc->recvq); + return put_user(skb ? skb->len : 0,(int *) arg) + ? -EFAULT : 0; + } + case ATM_GETNAMES: + if (get_user(buf, + &((struct atm_iobuf *) arg)->buffer)) + return -EFAULT; + if (get_user(len, + &((struct atm_iobuf *) arg)->length)) + return -EFAULT; + size = 0; + for (dev = atm_devs; dev; dev = dev->next) + size += sizeof(int); + if (size > len) return -E2BIG; + tmp_buf = kmalloc(size,GFP_KERNEL); + if (!tmp_buf) return -ENOMEM; + for (dev = atm_devs; dev; dev = dev->next) + *tmp_buf++ = dev->number; + if (copy_to_user(buf,(char *) tmp_buf-size,size)) + return -EFAULT; + return put_user(size, + &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0; + case SIOCGSTAMP: /* borrowed from IP */ + if (!vcc->timestamp.tv_sec) return -ENOENT; + vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000; + vcc->timestamp.tv_usec %= 1000000; + return copy_to_user((void *) arg,&vcc->timestamp, + sizeof(struct timeval)) ? -EFAULT : 0; + case ATM_SETSC: + if (arg & ~(ATM_VF_SCRX | ATM_VF_SCTX)) return -EINVAL; + /* @@@ race condition - should split flags into + "volatile" and non-volatile part */ + vcc->flags = (vcc->flags & ~(ATM_VF_SCRX | + ATM_VF_SCTX)) | arg; + return 0; + case ATMSIGD_CTRL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + error = sigd_attach(vcc); + if (!error) sock->state = SS_CONNECTED; + return error; +#ifdef WE_DONT_SUPPORT_P2MP_YET + case ATM_CREATE_LEAF: + { + struct socket *session; + + if (!(session = sockfd_lookup(arg,&error))) + return error; + if (sock->ops->family != PF_ATMSVC || + session->ops->family != PF_ATMSVC) + return -EPROTOTYPE; + return create_leaf(sock,session); + } +#endif +#ifdef CONFIG_ATM_CLIP + case SIOCMKCLIP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return clip_create(arg); + case ATMARPD_CTRL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + error = atm_init_atmarp(vcc); + if (!error) sock->state = SS_CONNECTED; + return error; + case ATMARP_MKIP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return clip_mkip(vcc,arg); + case ATMARP_SETENTRY: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return clip_setentry(vcc,arg); + case ATMARP_ENCAP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return clip_encap(vcc,arg); +#endif +#ifdef CONFIG_AREQUIPA + case AREQUIPA_PRESET: + { + struct socket *upper; + + if (!(upper = sockfd_lookup(arg,&error))) + return error; + if (upper->ops->family != PF_INET) + return -EPROTOTYPE; + return arequipa_preset(sock,upper->sk); + } + case AREQUIPA_INCOMING: + return arequipa_incoming(sock); + case AREQUIPA_CTRL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + error = arequipad_attach(vcc); + if (!error) sock->state = SS_CONNECTED; + return error; + case AREQUIPA_WORK: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + arequipa_work(); + return 0; +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + case ATMLEC_CTRL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (atm_lane_ops.lecd_attach == NULL) + atm_lane_init(); + if (atm_lane_ops.lecd_attach == NULL) /* try again */ + return -ENOSYS; + error = atm_lane_ops.lecd_attach(vcc, (int)arg); + if (error >= 0) sock->state = SS_CONNECTED; + return error; + case ATMLEC_MCAST: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return atm_lane_ops.mcast_attach(vcc, (int)arg); + case ATMLEC_DATA: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return atm_lane_ops.vcc_attach(vcc, (void*)arg); +#endif +#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) + case ATMMPC_CTRL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (atm_mpoa_ops.mpoad_attach == NULL) + atm_mpoa_init(); + if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */ + return -ENOSYS; + error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg); + if (error >= 0) sock->state = SS_CONNECTED; + return error; + case ATMMPC_DATA: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return atm_mpoa_ops.vcc_attach(vcc, arg); +#endif +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) + case SIOCSIFATMTCP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!atm_tcp_ops.attach) return -ENOPKG; + error = atm_tcp_ops.attach(vcc,(int) arg); + if (error >= 0) sock->state = SS_CONNECTED; + return error; + case ATMTCP_CREATE: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!atm_tcp_ops.create_persistent) return -ENOPKG; + return atm_tcp_ops.create_persistent((int) arg); + case ATMTCP_REMOVE: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!atm_tcp_ops.remove_persistent) return -ENOPKG; + return atm_tcp_ops.remove_persistent((int) arg); +#endif + default: + break; + } + if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT; + if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT; + if (get_user(number,&((struct atmif_sioc *) arg)->number)) + return -EFAULT; + if (!(dev = atm_find_dev(number))) return -ENODEV; + size = 0; + switch (cmd) { + case ATM_GETTYPE: + size = strlen(dev->type)+1; + if (copy_to_user(buf,dev->type,size)) return -EFAULT; + break; + case ATM_GETESI: + size = ESI_LEN; + if (copy_to_user(buf,dev->esi,size)) return -EFAULT; + break; + case ATM_SETESI: + { + int i; + + for (i = 0; i < ESI_LEN; i++) + if (dev->esi[i]) return -EEXIST; + } + /* fall through */ + case ATM_SETESIF: + { + unsigned char esi[ESI_LEN]; + + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (copy_from_user(esi,buf,ESI_LEN)) + return -EFAULT; + memcpy(dev->esi,esi,ESI_LEN); + return ESI_LEN; + } + case ATM_GETSTATZ: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* fall through */ + case ATM_GETSTAT: + size = sizeof(struct atm_dev_stats); + error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ); + if (error) return error; + break; + case ATM_GETCIRANGE: + size = sizeof(struct atm_cirange); + if (copy_to_user(buf,&dev->ci_range,size)) + return -EFAULT; + break; + case ATM_GETLINKRATE: + size = sizeof(int); + if (copy_to_user(buf,&dev->link_rate,size)) + return -EFAULT; + break; + case ATM_RSTADDR: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + reset_addr(dev); + break; + case ATM_ADDADDR: + case ATM_DELADDR: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + { + struct sockaddr_atmsvc addr; + + if (copy_from_user(&addr,buf,sizeof(addr))) + return -EFAULT; + if (cmd == ATM_ADDADDR) + return add_addr(dev,&addr); + else return del_addr(dev,&addr); + } + case ATM_GETADDR: + size = get_addr(dev,buf,len); + if (size < 0) return size; + /* may return 0, but later on size == 0 means "don't + write the length" */ + return put_user(size, + &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; + case ATM_SETCIRANGE: + case SONET_GETSTATZ: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* fall through */ + default: + if (!dev->ops->ioctl) return -EINVAL; + size = dev->ops->ioctl(dev,cmd,buf); + if (size < 0) return size; + } + if (!size) return 0; + return put_user(size,&((struct atmif_sioc *) arg)->length) ? + -EFAULT : 0; +} + + +int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) +{ + if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; + if (vcc->family == AF_ATMPVC) + return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET); + return svc_change_qos(vcc,qos); +} + + +static int check_tp(struct atm_trafprm *tp) +{ + /* @@@ Should be merged with adjust_tp */ + if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0; + if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr && + !tp->max_pcr) return -EINVAL; + if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL; + if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && + tp->min_pcr > tp->max_pcr) return -EINVAL; + /* + * We allow pcr to be outside [min_pcr,max_pcr], because later + * adjustment may still push it in the valid range. + */ + return 0; +} + + +static int check_qos(struct atm_qos *qos) +{ + int error; + + if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class) + return -EINVAL; + if (qos->txtp.traffic_class != qos->rxtp.traffic_class && + qos->txtp.traffic_class && qos->rxtp.traffic_class && + qos->txtp.traffic_class != ATM_ANYCLASS && + qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL; + error = check_tp(&qos->txtp); + if (error) return error; + return check_tp(&qos->rxtp); +} + + +static int atm_do_setsockopt(struct socket *sock,int level,int optname, + void *optval,int optlen) +{ + struct atm_vcc *vcc; + unsigned long value; + int error; + + vcc = ATM_SD(sock); + switch (optname) { + case SO_SNDBUF: + if (get_user(value,(unsigned long *) optval)) + return -EFAULT; + if (!value) value = ATM_TXBQ_DEF; + if (value < ATM_TXBQ_MIN) value = ATM_TXBQ_MIN; + if (value > ATM_TXBQ_MAX) value = ATM_TXBQ_MAX; + vcc->tx_quota = value; + return 0; + case SO_RCVBUF: + if (get_user(value,(unsigned long *) optval)) + return -EFAULT; + if (!value) value = ATM_RXBQ_DEF; + if (value < ATM_RXBQ_MIN) value = ATM_RXBQ_MIN; + if (value > ATM_RXBQ_MAX) value = ATM_RXBQ_MAX; + vcc->rx_quota = value; + return 0; + case SO_ATMQOS: + { + struct atm_qos qos; + + if (copy_from_user(&qos,optval,sizeof(qos))) + return -EFAULT; + error = check_qos(&qos); + if (error) return error; + if (sock->state == SS_CONNECTED) + return atm_change_qos(vcc,&qos); + if (sock->state != SS_UNCONNECTED) + return -EBADFD; + vcc->qos = qos; + vcc->flags |= ATM_VF_HASQOS; + return 0; + } + case SO_SETCLP: + if (get_user(value,(unsigned long *) optval)) + return -EFAULT; + if (value) vcc->atm_options |= ATM_ATMOPT_CLP; + else vcc->atm_options &= ~ATM_ATMOPT_CLP; + return 0; + default: + if (level == SOL_SOCKET) return -EINVAL; + break; + } + if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL; + return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen); +} + + +static int atm_do_getsockopt(struct socket *sock,int level,int optname, + void *optval,int optlen) +{ + struct atm_vcc *vcc; + + vcc = ATM_SD(sock); + switch (optname) { + case SO_SNDBUF: + return put_user(vcc->tx_quota,(unsigned long *) optval) + ? -EFAULT : 0; + case SO_RCVBUF: + return put_user(vcc->rx_quota,(unsigned long *) optval) + ? -EFAULT : 0; + case SO_BCTXOPT: + /* fall through */ + case SO_BCRXOPT: + break; + case SO_ATMQOS: + if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL; + return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ? + -EFAULT : 0; + case SO_SETCLP: + return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : + 0,(unsigned long *) optval) ? -EFAULT : 0; + default: + if (level == SOL_SOCKET) return -EINVAL; + break; + } + if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; + return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); +} + + +int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, + int optlen) +{ + if (level == __SO_LEVEL(optname) && optlen != __SO_SIZE(optname)) + return -EINVAL; + return atm_do_setsockopt(sock,level,optname,optval,optlen); +} + + +int atm_getsockopt(struct socket *sock,int level,int optname, + char *optval,int *optlen) +{ + int len; + + if (get_user(len,optlen)) return -EFAULT; + if (level == __SO_LEVEL(optname) && len != __SO_SIZE(optname)) + return -EINVAL; + return atm_do_getsockopt(sock,level,optname,optval,len); +} diff -u --recursive --new-file v2.3.14/linux/net/atm/common.h linux/net/atm/common.h --- v2.3.14/linux/net/atm/common.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/common.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,46 @@ +/* net/atm/common.h - ATM sockets (common part for PVC and SVC) */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_COMMON_H +#define NET_ATM_COMMON_H + +#include +#include /* for poll_table */ + + +int atm_create(struct socket *sock,int protocol,int family); +int atm_release(struct socket *sock); +int atm_connect(struct socket *sock,int itf,short vpi,int vci); +int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, + int flags,struct scm_cookie *scm); +int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, + struct scm_cookie *scm); +unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait); +int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); +int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, + int optlen); +int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, + int *optlen); + +int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci); +void atm_release_vcc_sk(struct sock *sk,int free_sk); +int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); +/* -- now in atmdev.h: +void atm_async_release_vcc(struct atm_vcc *vcc,int reply); +*/ +void atm_shutdown_dev(struct atm_dev *dev); + +int atm_proc_init(void); + +/* SVC */ + +void svc_callback(struct atm_vcc *vcc); +int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); + +/* p2mp */ + +int create_leaf(struct socket *leaf,struct socket *session); + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/ipcommon.c linux/net/atm/ipcommon.c --- v2.3.14/linux/net/atm/ipcommon.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/ipcommon.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,51 @@ +/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ + +/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ + + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "ipcommon.h" + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +const unsigned char llc_oui[] = { + 0xaa, /* DSAP: non-ISO */ + 0xaa, /* SSAP: non-ISO */ + 0x03, /* Ctrl: Unnumbered Information Command PDU */ + 0x00, /* OUI: EtherType */ + 0x00, + 0x00 }; + + +/* + * skb_migrate moves the list at FROM to TO, emptying FROM in the process. + * This function should live in skbuff.c or skbuff.h. Note that skb_migrate + * is not atomic, so turn off interrupts when using it. + */ + + +void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) +{ + struct sk_buff *skb,*prev; + + for (skb = ((struct sk_buff *) from)->next; + skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; + prev = from->prev; + from->next->prev = (struct sk_buff *) to; + prev->next = (struct sk_buff *) to; + *to = *from; + skb_queue_head_init(from); +} diff -u --recursive --new-file v2.3.14/linux/net/atm/ipcommon.h linux/net/atm/ipcommon.h --- v2.3.14/linux/net/atm/ipcommon.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/ipcommon.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,21 @@ +/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + +/* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_IPCOMMON_H +#define NET_ATM_IPCOMMON_H + + +#include +#include +#include +#include + + +extern struct net_device *clip_devs; + + +void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/lane_mpoa_init.c linux/net/atm/lane_mpoa_init.c --- v2.3.14/linux/net/atm/lane_mpoa_init.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/lane_mpoa_init.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,48 @@ +#include +#include + +#include "mpc.h" +#include "lec.h" + +/* + * lane_mpoa_init.c: A couple of helper functions + * to make modular LANE and MPOA client easier to implement + */ + +/* + * This is how it goes: + * + * if xxxx is not compiled as module, call atm_xxxx_init_ops() + * from here + * else call atm_mpoa_init_ops() from init_module() within + * the kernel when xxxx module is loaded + * + * In either case function pointers in struct atm_xxxx_ops + * are initialized to their correct values. Either they + * point to functions in the module or in the kernel + */ + +extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */ +extern struct atm_lane_ops atm_lane_ops; /* in common.c */ + +#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) +void atm_mpoa_init(void) +{ +#ifndef CONFIG_ATM_MPOA_MODULE /* not module */ + atm_mpoa_init_ops(&atm_mpoa_ops); +#endif + + return; +} +#endif + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +void atm_lane_init(void) +{ +#ifndef CONFIG_ATM_LANE_MODULE /* not module */ + atm_lane_init_ops(&atm_lane_ops); +#endif + + return; +} +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/lec.c linux/net/atm/lec.c --- v2.3.14/linux/net/atm/lec.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/lec.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,2186 @@ +/* + * lec.c: Lan Emulation driver + * Marko Kiiskila carnil@cs.tut.fi + * + */ + +#include +#include + +/* We are ethernet device */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TokenRing if needed */ +#ifdef CONFIG_TR +#include +#endif + +/* And atm device */ +#include +#include + +/* Bridge */ +#ifdef CONFIG_BRIDGE +#include +#endif + +/* Modular too */ +#include + +#include "lec.h" +#include "lec_arpc.h" +#include "tunable.h" +#include "resources.h" /* for bind_vcc() */ + +#if 0 +#define DPRINTK printk +#else +#define DPRINTK(format,args...) +#endif + +#define DUMP_PACKETS 0 /* 0 = None, + * 1 = 30 first bytes + * 2 = Whole packet + */ + +#define LEC_UNRES_QUE_LEN 8 /* number of tx packets to queue for a + single destination while waiting for SVC */ + +static int lec_open(struct net_device *dev); +static int lec_send_packet(struct sk_buff *skb, struct net_device *dev); +static int lec_close(struct net_device *dev); +static struct enet_statistics *lec_get_stats(struct net_device *dev); +static int lec_init(struct net_device *dev); +static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv, + unsigned char *mac_addr); +static __inline__ int lec_arp_remove(struct lec_arp_table **lec_arp_tables, + struct lec_arp_table *to_remove); +/* LANE2 functions */ +static void lane2_associate_ind (struct net_device *dev, u8 *mac_address, + u8 *tlvs, u32 sizeoftlvs); +static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, + u8 **tlvs, u32 *sizeoftlvs); +static int lane2_associate_req (struct net_device *dev, u8 *lan_dst, + u8 *tlvs, u32 sizeoftlvs); + +static struct lane2_ops lane2_ops = { + lane2_resolve, /* resolve, spec 3.1.3 */ + lane2_associate_req, /* associate_req, spec 3.1.4 */ + NULL /* associate indicator, spec 3.1.5 */ +}; + +/* will be lec0, lec1, lec2 etc. */ +static char myname[] = "lecxx"; + +static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + +/* Device structures */ +static struct net_device *dev_lec[MAX_LEC_ITF]; + +/* This will be called from proc.c via function pointer */ +struct net_device **get_dev_lec (void) { + return &dev_lec[0]; +} + +#ifdef CONFIG_BRIDGE +static void handle_bridge(struct sk_buff *skb, struct net_device *dev) +{ + struct ethhdr *eth; + char *buff; + struct lec_priv *priv; + unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; + + /* Check if this is a BPDU. If so, ask zeppelin to send + * LE_TOPOLOGY_REQUEST with the value of Topology Change bit + * in the Config BPDU*/ + eth = (struct ethhdr *)skb->data; + buff = skb->data + skb->dev->hard_header_len; + if ((memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) && + *buff++ == BRIDGE_LLC1_DSAP && + *buff++ == BRIDGE_LLC1_SSAP && + *buff++ == BRIDGE_LLC1_CTRL) { + struct sk_buff *skb2; + struct atmlec_msg *mesg; + + skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); + if (skb2 == NULL) return; + skb2->len = sizeof(struct atmlec_msg); + mesg = (struct atmlec_msg *)skb2->data; + mesg->type = l_topology_change; + mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE; + + priv = (struct lec_priv *)dev->priv; + atm_force_charge(priv->lecd, skb2->truesize); + skb_queue_tail(&priv->lecd->recvq, skb2); + wake_up(&priv->lecd->sleep); + } + + return; +} +#endif /* CONFIG_BRIDGE */ + +/* + * Modelled after tr_type_trans + * All multicast and ARE or STE frames go to BUS. + * Non source routed frames go by destination address. + * Last hop source routed frames go by destination address. + * Not last hop source routed frames go by _next_ route descriptor. + * Returns pointer to destination MAC address or fills in rdesc + * and returns NULL. + */ +#ifdef CONFIG_TR +unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) +{ + struct trh_hdr *trh; + int riflen, num_rdsc; + + trh = (struct trh_hdr *)packet; + if (trh->daddr[0] & (uint8_t)0x80) + return bus_mac; /* multicast */ + + if (trh->saddr[0] & TR_RII) { + riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; + if ((ntohs(trh->rcf) >> 13) != 0) + return bus_mac; /* ARE or STE */ + } + else + return trh->daddr; /* not source routed */ + + if (riflen < 6) + return trh->daddr; /* last hop, source routed */ + + /* riflen is 6 or more, packet has more than one route descriptor */ + num_rdsc = (riflen/2) - 1; + memset(rdesc, 0, ETH_ALEN); + /* offset 4 comes from LAN destination field in LE control frames */ + if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT)) + memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t)); + else + memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t)); + + return NULL; +} +#endif /* CONFIG_TR */ + +/* + * Open/initialize the netdevice. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int +lec_open(struct net_device *dev) +{ + struct lec_priv *priv = (struct lec_priv *)dev->priv; + + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = 1; + memset(&priv->stats,0,sizeof(struct enet_statistics)); + + return 0; +} + +static int +lec_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff *skb2; + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lecdatahdr_8023 *lec_h; + struct atm_vcc *send_vcc; + struct lec_arp_table *entry; + unsigned char *nb, *dst; +#ifdef CONFIG_TR + unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */ +#endif + int is_rdesc; +#if DUMP_PACKETS > 0 + char buf[300]; + int i=0; +#endif /* DUMP_PACKETS >0 */ + + DPRINTK("Lec_send_packet called\n"); + if (!priv->lecd) { + printk("%s:No lecd attached\n",dev->name); + priv->stats.tx_errors++; + dev->tbusy = 1; + return -EUNATCH; + } + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + printk("%s: transmit timed out\n", dev->name); + dev->tbusy = 0; + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", + dev->name); + } else { + DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n", + (long)skb->head, (long)skb->data, (long)skb->tail, + (long)skb->end); +#ifdef CONFIG_BRIDGE + if (skb->pkt_bridged == IS_BRIDGED) + handle_bridge(skb, dev); +#endif /* CONFIG_BRIDGE */ + + /* Make sure we have room for lec_id */ + if (skb_headroom(skb) < 2) { + + DPRINTK("lec_send_packet: reallocating skb\n"); + skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); + kfree_skb(skb); + if (skb2 == NULL) return 0; + skb = skb2; + } + skb_push(skb, 2); + + /* Put le header to place, works for TokenRing too */ + lec_h = (struct lecdatahdr_8023*)skb->data; + lec_h->le_header = htons(priv->lecid); + +#if DUMP_PACKETS > 0 + printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name, + skb->len, priv->lecid); +#if DUMP_PACKETS >= 2 + for(i=0;ilen && i <99;i++) { + sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]); + } +#elif DUMP_PACKETS >= 1 + for(i=0;ilen && i < 30;i++) { + sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]); + } +#endif /* DUMP_PACKETS >= 1 */ + if (i==skb->len) + printk("%s\n",buf); + else + printk("%s...\n",buf); +#endif /* DUMP_PACKETS > 0 */ + + /* Minimum ethernet-frame size */ + if (skb->len <62) { + if (skb->truesize < 62) { + printk("%s:data packet %d / %d\n", + dev->name, + skb->len,skb->truesize); + nb=(unsigned char*)kmalloc(64, GFP_ATOMIC); + memcpy(nb,skb->data,skb->len); + kfree(skb->head); + skb->head = skb->data = nb; + skb->tail = nb+62; + skb->end = nb+64; + skb->len=62; + skb->truesize = 64; + } else { + skb->len = 62; + } + } + + /* Send to right vcc */ + is_rdesc = 0; + dst = lec_h->h_dest; +#ifdef CONFIG_TR + if (priv->is_trdev) { + dst = get_tr_dst(skb->data+2, rdesc); + if (dst == NULL) { + dst = rdesc; + is_rdesc = 1; + } + } +#endif + entry = NULL; + send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); + DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name, + send_vcc, send_vcc?send_vcc->flags:0, entry); + if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { + if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { + DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name); + DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + skb_queue_tail(&entry->tx_wait, skb); + } else { + DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name); + DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + priv->stats.tx_dropped++; + dev_kfree_skb(skb); + } + dev->tbusy=0; + return 0; + } + +#if DUMP_PACKETS > 0 + printk("%s:sending to vpi:%d vci:%d\n", dev->name, + send_vcc->vpi, send_vcc->vci); +#endif /* DUMP_PACKETS > 0 */ + + while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { + DPRINTK("lec.c: emptying tx queue, "); + DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + ATM_SKB(skb2)->vcc = send_vcc; + atomic_add(skb2->truesize, &send_vcc->tx_inuse); + ATM_SKB(skb2)->iovcnt = 0; + ATM_SKB(skb2)->atm_options = send_vcc->atm_options; + DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name, + send_vcc->vpi, send_vcc->vci); + send_vcc->dev->ops->send(send_vcc, skb2); + priv->stats.tx_packets++; + } + + ATM_SKB(skb)->vcc = send_vcc; + atomic_add(skb->truesize, &send_vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + ATM_SKB(skb)->atm_options = send_vcc->atm_options; + send_vcc->dev->ops->send(send_vcc, skb); + priv->stats.tx_packets++; + } + /* Should we wait for card's device driver to notify us? */ + dev->tbusy=0; + + return 0; +} + +/* The inverse routine to net_open(). */ +static int +lec_close(struct net_device *dev) +{ + dev->tbusy = 1; + dev->start = 0; + return 0; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct enet_statistics * +lec_get_stats(struct net_device *dev) +{ + struct lec_priv *priv = (struct lec_priv *)dev->priv; + + return (struct enet_statistics *)&priv->stats; +} + +static int +lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct net_device *dev = (struct net_device*)vcc->proto_data; + struct lec_priv *priv = (struct lec_priv*)dev->priv; + struct atmlec_msg *mesg; + struct lec_arp_table *entry; + int i; + char *tmp; /* FIXME */ + + atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); + mesg = (struct atmlec_msg *)skb->data; + tmp = skb->data; + tmp += sizeof(struct atmlec_msg); + DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type); + switch(mesg->type) { + case l_set_mac_addr: + for (i=0;i<6;i++) { + dev->dev_addr[i] = mesg->content.normal.mac_addr[i]; + } + break; + case l_del_mac_addr: + for(i=0;i<6;i++) { + dev->dev_addr[i] = 0; + } + break; + case l_addr_delete: + lec_addr_delete(priv, mesg->content.normal.atm_addr, + mesg->content.normal.flag); + break; + case l_topology_change: + priv->topology_change = mesg->content.normal.flag; + break; + case l_flush_complete: + lec_flush_complete(priv, mesg->content.normal.flag); + break; + case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */ + entry = lec_arp_find(priv, mesg->content.normal.mac_addr); + lec_arp_remove(priv->lec_arp_tables, entry); + + if (mesg->content.normal.no_source_le_narp) + break; + /* FALL THROUGH */ + case l_arp_update: + lec_arp_update(priv, mesg->content.normal.mac_addr, + mesg->content.normal.atm_addr, + mesg->content.normal.flag, + mesg->content.normal.targetless_le_arp); + DPRINTK("lec: in l_arp_update\n"); + if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ + DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs); + lane2_associate_ind(dev, + mesg->content.normal.mac_addr, + tmp, mesg->sizeoftlvs); + } + break; + case l_config: + priv->maximum_unknown_frame_count = + mesg->content.config.maximum_unknown_frame_count; + priv->max_unknown_frame_time = + (mesg->content.config.max_unknown_frame_time*HZ); + priv->max_retry_count = + mesg->content.config.max_retry_count; + priv->aging_time = (mesg->content.config.aging_time*HZ); + priv->forward_delay_time = + (mesg->content.config.forward_delay_time*HZ); + priv->arp_response_time = + (mesg->content.config.arp_response_time*HZ); + priv->flush_timeout = (mesg->content.config.flush_timeout*HZ); + priv->path_switching_delay = + (mesg->content.config.path_switching_delay*HZ); + priv->lane_version = mesg->content.config.lane_version; /* LANE2 */ + priv->lane2_ops = NULL; + if (priv->lane_version > 1) + priv->lane2_ops = &lane2_ops; + if (dev->change_mtu(dev, mesg->content.config.mtu)) + printk("%s: change_mtu to %d failed\n", dev->name, + mesg->content.config.mtu); + break; + case l_flush_tran_id: + lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, + mesg->content.normal.flag); + break; + case l_set_lecid: + priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag); + break; + case l_should_bridge: { +#ifdef CONFIG_BRIDGE + struct fdb *f; + extern Port_data port_info[]; + + DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1], + mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3], + mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]); + f = br_avl_find_addr(mesg->content.proxy.mac_addr); /* bridge/br.c */ + if (f != NULL && + port_info[f->port].dev != dev && + port_info[f->port].state == Forwarding) { + /* hit from bridge table, send LE_ARP_RESPONSE */ + struct sk_buff *skb2; + + DPRINTK("%s: entry found, responding to zeppelin\n", dev->name); + skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); + if (skb2 == NULL) break; + skb2->len = sizeof(struct atmlec_msg); + memcpy(skb2->data, mesg, sizeof(struct atmlec_msg)); + atm_force_charge(priv->lecd, skb2->truesize); + skb_queue_tail(&priv->lecd->recvq, skb2); + wake_up(&priv->lecd->sleep); + } +#endif /* CONFIG_BRIDGE */ + } + break; + default: + printk("%s: Unknown message type %d\n", dev->name, mesg->type); + dev_kfree_skb(skb); + return -EINVAL; + } + dev_kfree_skb(skb); + return 0; +} + +static void +lec_atm_close(struct atm_vcc *vcc) +{ + struct sk_buff *skb; + struct net_device *dev = (struct net_device *)vcc->proto_data; + struct lec_priv *priv = (struct lec_priv *)dev->priv; + + priv->lecd = NULL; + /* Do something needful? */ + + dev->tbusy = 1; + dev->start = 0; + + lec_arp_destroy(priv); + + if (skb_peek(&vcc->recvq)) + printk("%s lec_atm_close: closing with messages pending\n", + dev->name); + while ((skb = skb_dequeue(&vcc->recvq))) { + atm_return(vcc, skb->truesize); + dev_kfree_skb(skb); + } + + printk("%s: Shut down!\n", dev->name); + MOD_DEC_USE_COUNT; +} + +static struct atmdev_ops lecdev_ops = { + NULL, /*dev_close*/ + NULL, /*open*/ + lec_atm_close, /*close*/ + NULL, /*ioctl*/ + NULL, /*getsockopt */ + NULL, /*setsockopt */ + lec_atm_send, /*send */ + NULL, /*sg_send */ +#if 0 /* these are disabled in too */ + NULL, /*poll */ + NULL, /*send_iovec*/ +#endif + NULL, /*send_oam*/ + NULL, /*phy_put*/ + NULL, /*phy_get*/ + NULL, /*feedback*/ + NULL, /* change_qos*/ + NULL /* free_rx_skb*/ +}; + +static struct atm_dev lecatm_dev = { + &lecdev_ops, + NULL, /*PHY*/ + "lec", /*type*/ + 999, /*dummy device number*/ + NULL,NULL, /*no VCCs*/ + NULL,NULL, /*no data*/ + 0, /*no flags*/ + NULL, /* no local address*/ + { 0 } /*no ESI or rest of the atm_dev struct things*/ +}; + +/* + * LANE2: new argument struct sk_buff *data contains + * the LE_ARP based TLVs introduced in the LANE2 spec + */ +int +send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, + unsigned char *mac_addr, unsigned char *atm_addr, + struct sk_buff *data) +{ + struct sk_buff *skb; + struct atmlec_msg *mesg; + + if (!priv || !priv->lecd) { + return -1; + } + skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); + if (!skb) + return -1; + skb->len = sizeof(struct atmlec_msg); + mesg = (struct atmlec_msg *)skb->data; + memset(mesg, 0, sizeof(struct atmlec_msg)); + mesg->type = type; + if (data != NULL) + mesg->sizeoftlvs = data->len; + if (mac_addr) + memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); + else + mesg->content.normal.targetless_le_arp = 1; + if (atm_addr) + memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); + + atm_force_charge(priv->lecd, skb->truesize); + skb_queue_tail(&priv->lecd->recvq, skb); + wake_up(&priv->lecd->sleep); + + if (data != NULL) { + DPRINTK("lec: about to send %d bytes of data\n", data->len); + atm_force_charge(priv->lecd, data->truesize); + skb_queue_tail(&priv->lecd->recvq, data); + wake_up(&priv->lecd->sleep); + } + + return 0; +} + +/* shamelessly stolen from drivers/net/net_init.c */ +static int lec_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 18190)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static int +lec_init(struct net_device *dev) +{ + struct lec_priv *priv; + + priv = (struct lec_priv *)dev->priv; + if (priv->is_trdev) { +#ifdef CONFIG_TR + init_trdev(dev, 0); +#endif + } else ether_setup(dev); + dev->change_mtu = lec_change_mtu; + dev->open = lec_open; + dev->stop = lec_close; + dev->hard_start_xmit = lec_send_packet; + + dev->get_stats = lec_get_stats; + dev->set_multicast_list = NULL; + dev->do_ioctl = NULL; + printk("%s: Initialized!\n",dev->name); + return 0; +} + +static unsigned char lec_ctrl_magic[] = { + 0xff, + 0x00, + 0x01, + 0x01 }; + +void +lec_push(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct net_device *dev = (struct net_device *)vcc->proto_data; + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lecdatahdr_8023 *hdr; + +#if DUMP_PACKETS >0 + int i=0; + char buf[300]; + + printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name, + vcc->vpi, vcc->vci); +#endif + if (!skb) { + DPRINTK("%s: null skb\n",dev->name); + lec_vcc_close(priv, vcc); + return; + } +#if DUMP_PACKETS > 0 + printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name, + skb->len, priv->lecid); +#if DUMP_PACKETS >= 2 + for(i=0;ilen && i <99;i++) { + sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]); + } +#elif DUMP_PACKETS >= 1 + for(i=0;ilen && i < 30;i++) { + sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]); + } +#endif /* DUMP_PACKETS >= 1 */ + if (i==skb->len) + printk("%s\n",buf); + else + printk("%s...\n",buf); +#endif /* DUMP_PACKETS > 0 */ + if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/ + DPRINTK("%s: To daemon\n",dev->name); + skb_queue_tail(&vcc->recvq, skb); + wake_up(&vcc->sleep); + } else { /* Data frame, queue to protocol handlers */ + atm_return(vcc,skb->truesize); + hdr = (struct lecdatahdr_8023 *)skb->data; + if (hdr->le_header == htons(priv->lecid) || + !priv->lecd) { + /* Probably looping back, or if lecd is missing, + lecd has gone down */ + DPRINTK("Ignoring loopback frame...\n"); + dev_kfree_skb(skb); + return; + } + if (priv->lec_arp_empty_ones) { /* FILTER DATA!!!! */ + lec_arp_check_empties(priv, vcc, skb); + } + skb->dev = dev; + skb->data += 2; /* skip lec_id */ +#ifdef CONFIG_TR + if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev); + else +#endif + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + priv->stats.rx_packets++; + } +} + +int +lec_vcc_attach(struct atm_vcc *vcc, void *arg) +{ + int bytes_left; + struct atmlec_ioc ioc_data; + + /* Lecd must be up in this case */ + bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); + if (bytes_left != 0) { + printk("lec: lec_vcc_attach, copy from user failed for %d bytes\n", + bytes_left); + } + if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || + !dev_lec[ioc_data.dev_num]) + return -EINVAL; + lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, + &ioc_data, vcc, vcc->push); + vcc->push = lec_push; + vcc->proto_data = dev_lec[ioc_data.dev_num]; + return 0; +} + +int +lec_mcast_attach(struct atm_vcc *vcc, int arg) +{ + if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) + return -EINVAL; + vcc->proto_data = dev_lec[arg]; + return (lec_mcast_make((struct lec_priv*)dev_lec[arg]->priv, vcc)); +} + +/* Initialize device. */ +int +lecd_attach(struct atm_vcc *vcc, int arg) +{ + int i, result; + struct lec_priv *priv; + + if (arg<0) + i = 0; + else + i = arg; +#ifdef CONFIG_TR + if (arg >= MAX_LEC_ITF) + return -EINVAL; +#else /* Reserve the top NUM_TR_DEVS for TR */ + if (arg >= (MAX_LEC_ITF-NUM_TR_DEVS)) + return -EINVAL; +#endif + if (!dev_lec[i]) { + dev_lec[i] = (struct net_device*)kmalloc(sizeof(struct net_device)+ + sizeof(myname)+1, + GFP_KERNEL); + if (!dev_lec[i]) + return -ENOMEM; + memset(dev_lec[i],0, sizeof(struct net_device)+sizeof(myname)+1); + + dev_lec[i]->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL); + if (!dev_lec[i]->priv) + return -ENOMEM; + memset(dev_lec[i]->priv,0,sizeof(struct lec_priv)); + priv = (struct lec_priv *)dev_lec[i]->priv; + + if (i >= (MAX_LEC_ITF - NUM_TR_DEVS)) + priv->is_trdev = 1; + + dev_lec[i]->name = (char*)(dev_lec[i]+1); + sprintf(dev_lec[i]->name, "lec%d",i); + dev_lec[i]->init = lec_init; + if ((result = register_netdev(dev_lec[i])) !=0) + return result; + sprintf(dev_lec[i]->name, "lec%d", i); /* init_trdev globbers device name */ + } else { + priv = (struct lec_priv *)dev_lec[i]->priv; + if (priv->lecd) + return -EADDRINUSE; + } + lec_arp_init(priv); + priv->itfnum = i; /* LANE2 addition */ + priv->lecd = vcc; + bind_vcc(vcc, &lecatm_dev); + + vcc->proto_data = dev_lec[i]; + vcc->flags |= ATM_VF_READY | ATM_VF_META; + + /* Set default values to these variables */ + priv->maximum_unknown_frame_count = 1; + priv->max_unknown_frame_time = (1*HZ); + priv->vcc_timeout_period = (1200*HZ); + priv->max_retry_count = 1; + priv->aging_time = (300*HZ); + priv->forward_delay_time = (15*HZ); + priv->topology_change = 0; + priv->arp_response_time = (1*HZ); + priv->flush_timeout = (4*HZ); + priv->path_switching_delay = (6*HZ); + + if (dev_lec[i]->flags & IFF_UP) { + dev_lec[i]->tbusy = 0; + dev_lec[i]->start = 1; + } + MOD_INC_USE_COUNT; + return i; +} + +void atm_lane_init_ops(struct atm_lane_ops *ops) +{ + ops->lecd_attach = lecd_attach; + ops->mcast_attach = lec_mcast_attach; + ops->vcc_attach = lec_vcc_attach; + ops->get_lecs = get_dev_lec; + + printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); + + return; +} + +#ifdef MODULE +int init_module(void) +{ + extern struct atm_lane_ops atm_lane_ops; + + atm_lane_init_ops(&atm_lane_ops); + + return 0; +} + +void cleanup_module(void) +{ + int i; + extern struct atm_lane_ops atm_lane_ops; + struct lec_priv *priv; + + if (MOD_IN_USE) { + printk(KERN_NOTICE "lec.c: module in use\n"); + return; + } + + atm_lane_ops.lecd_attach = NULL; + atm_lane_ops.mcast_attach = NULL; + atm_lane_ops.vcc_attach = NULL; + atm_lane_ops.get_lecs = NULL; + + for (i = 0; i < MAX_LEC_ITF; i++) { + if (dev_lec[i] != NULL) { + priv = (struct lec_priv *)dev_lec[i]->priv; + if (priv->is_trdev) { +#ifdef CONFIG_TR + unregister_trdev(dev_lec[i]); +#endif + } else + unregister_netdev(dev_lec[i]); + kfree(dev_lec[i]->priv); + kfree(dev_lec[i]); + dev_lec[i] = NULL; + } + } + + return; +} +#endif /* MODULE */ + +/* + * LANE2: 3.1.3, LE_RESOLVE.request + * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs. + * If sizeoftlvs == NULL the default TLVs associated with with this + * lec will be used. + * If dst_mac == NULL, targetless LE_ARP will be sent + */ +static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs) +{ + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_arp_table *table; + struct sk_buff *skb; + int retval; + + if (force == 0) { + table = lec_arp_find(priv, dst_mac); + if(table == NULL) + return -1; + + *tlvs = kmalloc(table->sizeoftlvs, GFP_KERNEL); + if (*tlvs == NULL) + return -1; + + memcpy(*tlvs, table->tlvs, table->sizeoftlvs); + *sizeoftlvs = table->sizeoftlvs; + + return 0; + } + + if (sizeoftlvs == NULL) + retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL); + + else { + skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC); + if (skb == NULL) + return -1; + skb->len = *sizeoftlvs; + memcpy(skb->data, *tlvs, *sizeoftlvs); + retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb); + } + return retval; +} + + +/* + * LANE2: 3.1.4, LE_ASSOCIATE.request + * Associate the *tlvs with the *lan_dst address. + * Will overwrite any previous association + * Returns 1 for success, 0 for failure (out of memory) + * + */ +static int lane2_associate_req (struct net_device *dev, u8 *lan_dst, + u8 *tlvs, u32 sizeoftlvs) +{ + int retval; + struct sk_buff *skb; + struct lec_priv *priv = (struct lec_priv*)dev->priv; + + if ( memcmp(lan_dst, dev->dev_addr, ETH_ALEN) != 0 ) + return (0); /* not our mac address */ + + kfree(priv->tlvs); /* NULL if there was no previous association */ + + priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL); + if (priv->tlvs == NULL) + return (0); + priv->sizeoftlvs = sizeoftlvs; + memcpy(priv->tlvs, tlvs, sizeoftlvs); + + skb = alloc_skb(sizeoftlvs, GFP_ATOMIC); + if (skb == NULL) + return 0; + skb->len = sizeoftlvs; + memcpy(skb->data, tlvs, sizeoftlvs); + retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb); + if (retval != 0) + printk("lec.c: lane2_associate_req() failed\n"); + /* If the previous association has changed we must + * somehow notify other LANE entities about the change + */ + return (1); +} + +/* + * LANE2: 3.1.5, LE_ASSOCIATE.indication + * + */ +static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs) +{ +#if 0 + int i = 0; +#endif + struct lec_priv *priv = (struct lec_priv *)dev->priv; +#if 0 /* Why have the TLVs in LE_ARP entries since we do not use them? When you + uncomment this code, make sure the TLVs get freed when entry is killed */ + struct lec_arp_table *entry = lec_arp_find(priv, mac_addr); + + if (entry == NULL) + return; /* should not happen */ + + kfree(entry->tlvs); + + entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL); + if (entry->tlvs == NULL) + return; + + entry->sizeoftlvs = sizeoftlvs; + memcpy(entry->tlvs, tlvs, sizeoftlvs); +#endif +#if 0 + printk("lec.c: lane2_associate_ind()\n"); + printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); + while (i < sizeoftlvs) + printk("%02x ", tlvs[i++]); + + printk("\n"); +#endif + + /* tell MPOA about the TLVs we saw */ + if (priv->lane2_ops && priv->lane2_ops->associate_indicator) { + priv->lane2_ops->associate_indicator(dev, mac_addr, + tlvs, sizeoftlvs); + } + else + printk("lane:(%s) lane2_associate_ind: could not notify MPOA\n", dev->name); + return; +} + +/* + * Here starts what used to lec_arpc.c + * + * lec_arpc.c was added here when making + * lane client modular. October 1997 + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#if 0 +#define DPRINTK(format,args...) +/* +#define DPRINTK printk +*/ +#endif +#define DEBUG_ARP_TABLE 0 + +#define LEC_ARP_REFRESH_INTERVAL (3*HZ) + +static void lec_arp_check_expire(unsigned long data); +static __inline__ void lec_arp_expire_arp(unsigned long data); +void dump_arp_table(struct lec_priv *priv); + +/* + * Arp table funcs + */ + +#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1)) + +static __inline__ void +lec_arp_lock(struct lec_priv *priv) +{ + atomic_inc(&priv->lec_arp_lock_var); +} + +static __inline__ void +lec_arp_unlock(struct lec_priv *priv) +{ + atomic_dec(&priv->lec_arp_lock_var); +} + +/* + * Initialization of arp-cache + */ +void +lec_arp_init(struct lec_priv *priv) +{ + unsigned short i; + + for (i=0;ilec_arp_tables[i] = NULL; + } + init_timer(&priv->lec_arp_timer); + priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL; + priv->lec_arp_timer.data = (unsigned long)priv; + priv->lec_arp_timer.function = lec_arp_check_expire; + add_timer(&priv->lec_arp_timer); +} + +void +lec_arp_clear_vccs(struct lec_arp_table *entry) +{ + if (entry->vcc) { + entry->vcc->push = entry->old_push; +#if 0 /* August 6, 1998 */ + entry->vcc->flags |= ATM_VF_RELEASED; + entry->vcc->flags &= ~ATM_VF_READY; + entry->vcc->push(entry->vcc, NULL); +#endif + atm_async_release_vcc(entry->vcc, -EPIPE); + entry->vcc = NULL; + } + if (entry->recv_vcc) { + entry->recv_vcc->push = entry->old_recv_push; +#if 0 + entry->recv_vcc->flags |= ATM_VF_RELEASED; + entry->recv_vcc->flags &= ~ATM_VF_READY; + entry->recv_vcc->push(entry->recv_vcc, NULL); +#endif + atm_async_release_vcc(entry->recv_vcc, -EPIPE); + entry->recv_vcc = NULL; + } +} + +/* + * Insert entry to lec_arp_table + * LANE2: Add to the end of the list to satisfy 8.1.13 + */ +static __inline__ void +lec_arp_put(struct lec_arp_table **lec_arp_tables, + struct lec_arp_table *to_put) +{ + unsigned short place; + unsigned long flags; + struct lec_arp_table *tmp; + + save_flags(flags); + cli(); + + place = HASH(to_put->mac_addr[ETH_ALEN-1]); + tmp = lec_arp_tables[place]; + to_put->next = NULL; + if (tmp == NULL) + lec_arp_tables[place] = to_put; + + else { /* add to the end */ + while (tmp->next) + tmp = tmp->next; + tmp->next = to_put; + } + + restore_flags(flags); + DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + 0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1], + 0xff&to_put->mac_addr[2], 0xff&to_put->mac_addr[3], + 0xff&to_put->mac_addr[4], 0xff&to_put->mac_addr[5]); +} + +/* + * Remove entry from lec_arp_table + */ +static __inline__ int +lec_arp_remove(struct lec_arp_table **lec_arp_tables, + struct lec_arp_table *to_remove) +{ + unsigned short place; + struct lec_arp_table *tmp; + unsigned long flags; + int remove_vcc=1; + + save_flags(flags); + cli(); + + if (!to_remove) { + restore_flags(flags); + return -1; + } + place = HASH(to_remove->mac_addr[ETH_ALEN-1]); + tmp = lec_arp_tables[place]; + if (tmp == to_remove) { + lec_arp_tables[place] = tmp->next; + } else { + while(tmp && tmp->next != to_remove) { + tmp = tmp->next; + } + if (!tmp) {/* Entry was not found */ + restore_flags(flags); + return -1; + } + } + tmp->next = to_remove->next; + del_timer(&to_remove->timer); + + /* If this is the only MAC connected to this VCC, also tear down + the VCC */ + if (to_remove->status >= ESI_FLUSH_PENDING) { + /* + * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT + */ + for(place=0;placenext){ + if (memcmp(tmp->atm_addr, to_remove->atm_addr, + ATM_ESA_LEN)==0) { + remove_vcc=0; + break; + } + } + } + if (remove_vcc) + lec_arp_clear_vccs(to_remove); + } + skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ + restore_flags(flags); + DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1], + 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], + 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]); + return 0; +} + +#if DEBUG_ARP_TABLE +static char* +get_status_string(unsigned char st) +{ + switch(st) { + case ESI_UNKNOWN: + return "ESI_UNKNOWN"; + case ESI_ARP_PENDING: + return "ESI_ARP_PENDING"; + case ESI_VC_PENDING: + return "ESI_VC_PENDING"; + case ESI_FLUSH_PENDING: + return "ESI_FLUSH_PENDING"; + case ESI_FORWARD_DIRECT: + return "ESI_FORWARD_DIRECT"; + default: + return ""; + } +} +#endif + +void +dump_arp_table(struct lec_priv *priv) +{ +#if DEBUG_ARP_TABLE + int i,j, offset; + struct lec_arp_table *rulla; + char buf[1024]; + struct lec_arp_table **lec_arp_tables = + (struct lec_arp_table **)priv->lec_arp_tables; + struct lec_arp_table *lec_arp_empty_ones = + (struct lec_arp_table *)priv->lec_arp_empty_ones; + struct lec_arp_table *lec_no_forward = + (struct lec_arp_table *)priv->lec_no_forward; + struct lec_arp_table *mcast_fwds = priv->mcast_fwds; + + + printk("Dump %p:\n",priv); + for (i=0;imac_addr[j]&0xff); + } + offset +=sprintf(buf+offset,"Atm:"); + for(j=0;jatm_addr[j]&0xff); + } + offset+=sprintf(buf+offset, + "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", + rulla->vcc?rulla->vcc->vpi:0, + rulla->vcc?rulla->vcc->vci:0, + rulla->recv_vcc?rulla->recv_vcc->vpi:0, + rulla->recv_vcc?rulla->recv_vcc->vci:0, + rulla->last_used, + rulla->timestamp, rulla->no_tries); + offset+=sprintf(buf+offset, + "Flags:%x, Packets_flooded:%x, Status: %s ", + rulla->flags, rulla->packets_flooded, + get_status_string(rulla->status)); + offset+=sprintf(buf+offset,"->%p\n",rulla->next); + rulla = rulla->next; + } + printk("%s",buf); + } + rulla = lec_no_forward; + if (rulla) + printk("No forward\n"); + while(rulla) { + offset=0; + offset += sprintf(buf+offset,"Mac:"); + for(j=0;jmac_addr[j]&0xff); + } + offset +=sprintf(buf+offset,"Atm:"); + for(j=0;jatm_addr[j]&0xff); + } + offset+=sprintf(buf+offset, + "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", + rulla->vcc?rulla->vcc->vpi:0, + rulla->vcc?rulla->vcc->vci:0, + rulla->recv_vcc?rulla->recv_vcc->vpi:0, + rulla->recv_vcc?rulla->recv_vcc->vci:0, + rulla->last_used, + rulla->timestamp, rulla->no_tries); + offset+=sprintf(buf+offset, + "Flags:%x, Packets_flooded:%x, Status: %s ", + rulla->flags, rulla->packets_flooded, + get_status_string(rulla->status)); + offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next); + rulla = rulla->next; + printk("%s",buf); + } + rulla = lec_arp_empty_ones; + if (rulla) + printk("Empty ones\n"); + while(rulla) { + offset=0; + offset += sprintf(buf+offset,"Mac:"); + for(j=0;jmac_addr[j]&0xff); + } + offset +=sprintf(buf+offset,"Atm:"); + for(j=0;jatm_addr[j]&0xff); + } + offset+=sprintf(buf+offset, + "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", + rulla->vcc?rulla->vcc->vpi:0, + rulla->vcc?rulla->vcc->vci:0, + rulla->recv_vcc?rulla->recv_vcc->vpi:0, + rulla->recv_vcc?rulla->recv_vcc->vci:0, + rulla->last_used, + rulla->timestamp, rulla->no_tries); + offset+=sprintf(buf+offset, + "Flags:%x, Packets_flooded:%x, Status: %s ", + rulla->flags, rulla->packets_flooded, + get_status_string(rulla->status)); + offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next); + rulla = rulla->next; + printk("%s",buf); + } + + rulla = mcast_fwds; + if (rulla) + printk("Multicast Forward VCCs\n"); + while(rulla) { + offset=0; + offset += sprintf(buf+offset,"Mac:"); + for(j=0;jmac_addr[j]&0xff); + } + offset +=sprintf(buf+offset,"Atm:"); + for(j=0;jatm_addr[j]&0xff); + } + offset+=sprintf(buf+offset, + "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", + rulla->vcc?rulla->vcc->vpi:0, + rulla->vcc?rulla->vcc->vci:0, + rulla->recv_vcc?rulla->recv_vcc->vpi:0, + rulla->recv_vcc?rulla->recv_vcc->vci:0, + rulla->last_used, + rulla->timestamp, rulla->no_tries); + offset+=sprintf(buf+offset, + "Flags:%x, Packets_flooded:%x, Status: %s ", + rulla->flags, rulla->packets_flooded, + get_status_string(rulla->status)); + offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next); + rulla = rulla->next; + printk("%s",buf); + } + +#endif +} + +/* + * Destruction of arp-cache + */ +void +lec_arp_destroy(struct lec_priv *priv) +{ + struct lec_arp_table *entry, *next; + unsigned long flags; + int i; + + save_flags(flags); + cli(); + + del_timer(&priv->lec_arp_timer); + + /* + * Remove all entries + */ + for (i=0;ilec_arp_tables[i];entry != NULL; entry=next) { + next = entry->next; + lec_arp_remove(priv->lec_arp_tables, entry); + kfree(entry); + } + } + entry = priv->lec_arp_empty_ones; + while(entry) { + next = entry->next; + del_timer(&entry->timer); + lec_arp_clear_vccs(entry); + kfree(entry); + entry = next; + } + priv->lec_arp_empty_ones = NULL; + entry = priv->lec_no_forward; + while(entry) { + next = entry->next; + del_timer(&entry->timer); + lec_arp_clear_vccs(entry); + kfree(entry); + entry = next; + } + priv->lec_no_forward = NULL; + entry = priv->mcast_fwds; + while(entry) { + next = entry->next; + del_timer(&entry->timer); + lec_arp_clear_vccs(entry); + kfree(entry); + entry = next; + } + priv->mcast_fwds = NULL; + priv->mcast_vcc = NULL; + memset(priv->lec_arp_tables, 0, + sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE); + restore_flags(flags); +} + + +/* + * Find entry by mac_address + */ +static __inline__ struct lec_arp_table* +lec_arp_find(struct lec_priv *priv, + unsigned char *mac_addr) +{ + unsigned short place; + struct lec_arp_table *to_return; + + DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff, + mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff); + lec_arp_lock(priv); + place = HASH(mac_addr[ETH_ALEN-1]); + + to_return = priv->lec_arp_tables[place]; + while(to_return) { + if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) { + lec_arp_unlock(priv); + return to_return; + } + to_return = to_return->next; + } + lec_arp_unlock(priv); + return NULL; +} + +static struct lec_arp_table* +make_entry(struct lec_priv *priv, unsigned char *mac_addr) +{ + struct lec_arp_table *to_return; + + to_return=(struct lec_arp_table *)kmalloc(sizeof(struct lec_arp_table), + GFP_ATOMIC); + if (!to_return) { + printk("LEC: Arp entry kmalloc failed\n"); + return NULL; + } + memset(to_return,0,sizeof(struct lec_arp_table)); + memcpy(to_return->mac_addr, mac_addr, ETH_ALEN); + init_timer(&to_return->timer); + to_return->timer.function = lec_arp_expire_arp; + to_return->timer.data = (unsigned long)to_return; + to_return->last_used = jiffies; + to_return->priv = priv; + skb_queue_head_init(&to_return->tx_wait); + return to_return; +} + +/* + * + * Arp sent timer expired + * + */ +static void +lec_arp_expire_arp(unsigned long data) +{ + struct lec_arp_table *entry; + + entry = (struct lec_arp_table *)data; + + del_timer(&entry->timer); + + DPRINTK("lec_arp_expire_arp\n"); + if (entry->status == ESI_ARP_PENDING) { + if (entry->no_tries <= entry->priv->max_retry_count) { + if (entry->is_rdesc) + send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL); + else + send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL); + entry->no_tries++; + } + entry->timer.expires = jiffies + (1*HZ); + add_timer(&entry->timer); + } +} + +/* + * + * Unknown/unused vcc expire, remove associated entry + * + */ +static void +lec_arp_expire_vcc(unsigned long data) +{ + struct lec_arp_table *to_remove = (struct lec_arp_table*)data; + struct lec_priv *priv = (struct lec_priv *)to_remove->priv; + struct lec_arp_table *entry = NULL; + + del_timer(&to_remove->timer); + + DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", + to_remove, priv, + to_remove->vcc?to_remove->recv_vcc->vpi:0, + to_remove->vcc?to_remove->recv_vcc->vci:0); + DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward); + if (to_remove == priv->lec_arp_empty_ones) + priv->lec_arp_empty_ones = to_remove->next; + else { + entry = priv->lec_arp_empty_ones; + while (entry && entry->next != to_remove) + entry = entry->next; + if (entry) + entry->next = to_remove->next; + } + if (!entry) + if (to_remove == priv->lec_no_forward) { + priv->lec_no_forward = to_remove->next; + } else { + entry = priv->lec_no_forward; + while (entry && entry->next != to_remove) + entry = entry->next; + if (entry) + entry->next = to_remove->next; + } + lec_arp_clear_vccs(to_remove); + kfree(to_remove); +} + +/* + * Expire entries. + * 1. Re-set timer + * 2. For each entry, delete entries that have aged past the age limit. + * 3. For each entry, depending on the status of the entry, perform + * the following maintenance. + * a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the + * tick_count is above the max_unknown_frame_time, clear + * the tick_count to zero and clear the packets_flooded counter + * to zero. This supports the packet rate limit per address + * while flooding unknowns. + * b. If the status is ESI_FLUSH_PENDING and the tick_count is greater + * than or equal to the path_switching_delay, change the status + * to ESI_FORWARD_DIRECT. This causes the flush period to end + * regardless of the progress of the flush protocol. + */ +static void +lec_arp_check_expire(unsigned long data) +{ + struct lec_priv *priv = (struct lec_priv *)data; + struct lec_arp_table **lec_arp_tables = + (struct lec_arp_table **)priv->lec_arp_tables; + struct lec_arp_table *entry, *next; + unsigned long now; + unsigned long time_to_check; + int i; + + del_timer(&priv->lec_arp_timer); + + DPRINTK("lec_arp_check_expire %p,%d\n",priv, + priv->lec_arp_lock_var.counter); + DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, + priv->lec_no_forward); + if (!priv->lec_arp_lock_var.counter) { + lec_arp_lock(priv); + now = jiffies; + for(i=0;iflags) & LEC_REMOTE_FLAG && + priv->topology_change) + time_to_check=priv->forward_delay_time; + else + time_to_check = priv->aging_time; + + DPRINTK("About to expire: %lx - %lx > %lx\n", + now,entry->last_used, time_to_check); + if( time_after(now, entry->last_used+ + time_to_check) && + !(entry->flags & LEC_PERMANENT_FLAG) && + !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */ + /* Remove entry */ + DPRINTK("LEC:Entry timed out\n"); + next = entry->next; + lec_arp_remove(lec_arp_tables, entry); + kfree(entry); + entry = next; + } else { + /* Something else */ + if ((entry->status == ESI_VC_PENDING || + entry->status == ESI_ARP_PENDING) + && time_after_eq(now, + entry->timestamp + + priv->max_unknown_frame_time)) { + entry->timestamp = jiffies; + entry->packets_flooded = 0; + if (entry->status == ESI_VC_PENDING) + send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL); + } + if (entry->status == ESI_FLUSH_PENDING + && + time_after_eq(now, entry->timestamp+ + priv->path_switching_delay)) { + entry->last_used = jiffies; + entry->status = + ESI_FORWARD_DIRECT; + } + entry = entry->next; + } + } + } + lec_arp_unlock(priv); + } + priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; + add_timer(&priv->lec_arp_timer); +} +/* + * Try to find vcc where mac_address is attached. + * + */ +struct atm_vcc* +lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc, + struct lec_arp_table **ret_entry) +{ + struct lec_arp_table *entry; + + if (mac_to_find[0]&0x01) { + switch (priv->lane_version) { + case 1: + return priv->mcast_vcc; + break; + case 2: /* LANE2 wants arp for multicast addresses */ + if ( memcmp(mac_to_find, bus_mac, ETH_ALEN) == 0) + return priv->mcast_vcc; + break; + default: + break; + } + } + + entry = lec_arp_find(priv, mac_to_find); + + if (entry) { + if (entry->status == ESI_FORWARD_DIRECT) { + /* Connection Ok */ + entry->last_used = jiffies; + *ret_entry = entry; + return entry->vcc; + } + /* Data direct VC not yet set up, check to see if the unknown + frame count is greater than the limit. If the limit has + not been reached, allow the caller to send packet to + BUS. */ + if (entry->status != ESI_FLUSH_PENDING && + entry->packets_floodedmaximum_unknown_frame_count) { + entry->packets_flooded++; + DPRINTK("LEC_ARP: Flooding..\n"); + return priv->mcast_vcc; + } + /* We got here because entry->status == ESI_FLUSH_PENDING + * or BUS flood limit was reached for an entry which is + * in ESI_ARP_PENDING or ESI_VC_PENDING state. + */ + *ret_entry = entry; + DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc); + return NULL; + } else { + /* No matching entry was found */ + entry = make_entry(priv, mac_to_find); + DPRINTK("LEC_ARP: Making entry\n"); + if (!entry) { + return priv->mcast_vcc; + } + lec_arp_put(priv->lec_arp_tables, entry); + /* We want arp-request(s) to be sent */ + entry->packets_flooded =1; + entry->status = ESI_ARP_PENDING; + entry->no_tries = 1; + entry->last_used = entry->timestamp = jiffies; + entry->is_rdesc = is_rdesc; + if (entry->is_rdesc) + send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL); + else + send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL); + entry->timer.expires = jiffies + (1*HZ); + entry->timer.function = lec_arp_expire_arp; + add_timer(&entry->timer); + return priv->mcast_vcc; + } +} + +int +lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, + unsigned long permanent) +{ + struct lec_arp_table *entry, *next; + int i; + + lec_arp_lock(priv); + DPRINTK("lec_addr_delete\n"); + for(i=0;ilec_arp_tables[i];entry != NULL; entry=next) { + next = entry->next; + if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) + && (permanent || + !(entry->flags & LEC_PERMANENT_FLAG))) { + lec_arp_remove(priv->lec_arp_tables, entry); + kfree(entry); + } + lec_arp_unlock(priv); + return 0; + } + } + lec_arp_unlock(priv); + return -1; +} + +/* + * Notifies: Response to arp_request (atm_addr != NULL) + */ +void +lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, + unsigned char *atm_addr, unsigned long remoteflag, + unsigned int targetless_le_arp) +{ + struct lec_arp_table *entry, *tmp; + int i; + + DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " "); + DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3], + mac_addr[4],mac_addr[5]); + + entry = lec_arp_find(priv, mac_addr); + if (entry == NULL && targetless_le_arp) + return; /* LANE2: ignore targetless LE_ARPs for which + * we have no entry in the cache. 7.1.30 + */ + lec_arp_lock(priv); + if (priv->lec_arp_empty_ones) { + entry = priv->lec_arp_empty_ones; + if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) { + priv->lec_arp_empty_ones = entry->next; + } else { + while(entry->next && memcmp(entry->next->atm_addr, + atm_addr, ATM_ESA_LEN)) + entry = entry->next; + if (entry->next) { + tmp = entry; + entry = entry->next; + tmp->next = entry->next; + } else + entry = NULL; + + } + if (entry) { + del_timer(&entry->timer); + tmp = lec_arp_find(priv, mac_addr); + if (tmp) { + del_timer(&tmp->timer); + tmp->status = ESI_FORWARD_DIRECT; + memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN); + tmp->vcc = entry->vcc; + tmp->old_push = entry->old_push; + tmp->last_used = jiffies; + del_timer(&entry->timer); + kfree(entry); + entry=tmp; + } else { + entry->status = ESI_FORWARD_DIRECT; + memcpy(entry->mac_addr, mac_addr, ETH_ALEN); + entry->last_used = jiffies; + lec_arp_put(priv->lec_arp_tables, entry); + } + if (remoteflag) + entry->flags|=LEC_REMOTE_FLAG; + else + entry->flags&=~LEC_REMOTE_FLAG; + lec_arp_unlock(priv); + DPRINTK("After update\n"); + dump_arp_table(priv); + return; + } + } + entry = lec_arp_find(priv, mac_addr); + if (!entry) { + entry = make_entry(priv, mac_addr); + entry->status = ESI_UNKNOWN; + lec_arp_put(priv->lec_arp_tables, entry); + /* Temporary, changes before end of function */ + } + memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); + del_timer(&entry->timer); + for(i=0;ilec_arp_tables[i];tmp;tmp=tmp->next) { + if (entry != tmp && + !memcmp(tmp->atm_addr, atm_addr, + ATM_ESA_LEN)) { + /* Vcc to this host exists */ + if (tmp->status > ESI_VC_PENDING) { + /* + * ESI_FLUSH_PENDING, + * ESI_FORWARD_DIRECT + */ + entry->vcc = tmp->vcc; + entry->old_push=tmp->old_push; + } + entry->status=tmp->status; + break; + } + } + } + if (remoteflag) + entry->flags|=LEC_REMOTE_FLAG; + else + entry->flags&=~LEC_REMOTE_FLAG; + if (entry->status == ESI_ARP_PENDING || + entry->status == ESI_UNKNOWN) { + entry->status = ESI_VC_PENDING; + send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL); + } + DPRINTK("After update2\n"); + dump_arp_table(priv); + lec_arp_unlock(priv); +} + +/* + * Notifies: Vcc setup ready + */ +void +lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, + struct atm_vcc *vcc, + void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)) +{ + struct lec_arp_table *entry; + int i, found_entry=0; + + lec_arp_lock(priv); + if (ioc_data->receive == 2) { + /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ + + DPRINTK("LEC_ARP: Attaching mcast forward\n"); +#if 0 + entry = lec_arp_find(priv, bus_mac); + if (!entry) { + printk("LEC_ARP: Multicast entry not found!\n"); + lec_arp_unlock(priv); + return; + } + memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); + entry->recv_vcc = vcc; + entry->old_recv_push = old_push; +#endif + entry = make_entry(priv, bus_mac); + if (entry == NULL) { + lec_arp_unlock(priv); + return; + } + del_timer(&entry->timer); + memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); + entry->recv_vcc = vcc; + entry->old_recv_push = old_push; + entry->next = priv->mcast_fwds; + priv->mcast_fwds = entry; + lec_arp_unlock(priv); + return; + } else if (ioc_data->receive == 1) { + /* Vcc which we don't want to make default vcc, attach it + anyway. */ + DPRINTK("LEC_ARP:Attaching data direct, not default :%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + ioc_data->atm_addr[0],ioc_data->atm_addr[1], + ioc_data->atm_addr[2],ioc_data->atm_addr[3], + ioc_data->atm_addr[4],ioc_data->atm_addr[5], + ioc_data->atm_addr[6],ioc_data->atm_addr[7], + ioc_data->atm_addr[8],ioc_data->atm_addr[9], + ioc_data->atm_addr[10],ioc_data->atm_addr[11], + ioc_data->atm_addr[12],ioc_data->atm_addr[13], + ioc_data->atm_addr[14],ioc_data->atm_addr[15], + ioc_data->atm_addr[16],ioc_data->atm_addr[17], + ioc_data->atm_addr[18],ioc_data->atm_addr[19]); + entry = make_entry(priv, bus_mac); + memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); + memset(entry->mac_addr, 0, ETH_ALEN); + entry->recv_vcc = vcc; + entry->old_recv_push = old_push; + entry->status = ESI_UNKNOWN; + entry->timer.expires = jiffies + priv->vcc_timeout_period; + entry->timer.function = lec_arp_expire_vcc; + add_timer(&entry->timer); + entry->next = priv->lec_no_forward; + priv->lec_no_forward = entry; + lec_arp_unlock(priv); + dump_arp_table(priv); + return; + } + DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + ioc_data->atm_addr[0],ioc_data->atm_addr[1], + ioc_data->atm_addr[2],ioc_data->atm_addr[3], + ioc_data->atm_addr[4],ioc_data->atm_addr[5], + ioc_data->atm_addr[6],ioc_data->atm_addr[7], + ioc_data->atm_addr[8],ioc_data->atm_addr[9], + ioc_data->atm_addr[10],ioc_data->atm_addr[11], + ioc_data->atm_addr[12],ioc_data->atm_addr[13], + ioc_data->atm_addr[14],ioc_data->atm_addr[15], + ioc_data->atm_addr[16],ioc_data->atm_addr[17], + ioc_data->atm_addr[18],ioc_data->atm_addr[19]); + for (i=0;ilec_arp_tables[i];entry;entry=entry->next) { + if (memcmp(ioc_data->atm_addr, entry->atm_addr, + ATM_ESA_LEN)==0) { + DPRINTK("LEC_ARP: Attaching data direct\n"); + DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n", + entry->vcc?entry->vcc->vci:0, + entry->recv_vcc?entry->recv_vcc->vci:0); + found_entry=1; + del_timer(&entry->timer); + entry->vcc = vcc; + entry->old_push = old_push; + if (entry->status == ESI_VC_PENDING) { + if(priv->maximum_unknown_frame_count + ==0) + entry->status = + ESI_FORWARD_DIRECT; + else { + entry->timestamp = jiffies; + entry->status = + ESI_FLUSH_PENDING; +#if 0 + send_to_lecd(priv,l_flush_xmt, + NULL, + entry->atm_addr, + NULL); +#endif + } + } else { + /* They were forming a connection + to us, and we to them. Our + ATM address is numerically lower + than theirs, so we make connection + we formed into default VCC (8.1.11). + Connection they made gets torn + down. This might confuse some + clients. Can be changed if + someone reports trouble... */ + ; + } + } + } + } + if (found_entry) { + lec_arp_unlock(priv); + DPRINTK("After vcc was added\n"); + dump_arp_table(priv); + return; + } + /* Not found, snatch address from first data packet that arrives from + this vcc */ + entry = make_entry(priv, bus_mac); + entry->vcc = vcc; + entry->old_push = old_push; + memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); + memset(entry->mac_addr, 0, ETH_ALEN); + entry->status = ESI_UNKNOWN; + entry->next = priv->lec_arp_empty_ones; + priv->lec_arp_empty_ones = entry; + entry->timer.expires = jiffies + priv->vcc_timeout_period; + entry->timer.function = lec_arp_expire_vcc; + add_timer(&entry->timer); + lec_arp_unlock(priv); + DPRINTK("After vcc was added\n"); + dump_arp_table(priv); +} + +void +lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) +{ + struct lec_arp_table *entry; + int i; + + DPRINTK("LEC:lec_flush_complete %lx\n",tran_id); + for (i=0;ilec_arp_tables[i];entry;entry=entry->next) { + if (entry->flush_tran_id == tran_id && + entry->status == ESI_FLUSH_PENDING) { + entry->status = ESI_FORWARD_DIRECT; + DPRINTK("LEC_ARP: Flushed\n"); + } + } + } + dump_arp_table(priv); +} + +void +lec_set_flush_tran_id(struct lec_priv *priv, + unsigned char *atm_addr, unsigned long tran_id) +{ + struct lec_arp_table *entry; + int i; + + for (i=0;ilec_arp_tables[i];entry;entry=entry->next) + if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { + entry->flush_tran_id = tran_id; + DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry); + } +} + +int +lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) +{ + unsigned char mac_addr[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct lec_arp_table *to_add; + + lec_arp_lock(priv); + to_add = make_entry(priv, mac_addr); + if (!to_add) { + lec_arp_unlock(priv); + return -ENOMEM; + } + memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN); + to_add->status = ESI_FORWARD_DIRECT; + to_add->flags |= LEC_PERMANENT_FLAG; + to_add->vcc = vcc; + to_add->old_push = vcc->push; + vcc->push = lec_push; + priv->mcast_vcc = vcc; + lec_arp_put(priv->lec_arp_tables, to_add); + lec_arp_unlock(priv); + return 0; +} + +void +lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) +{ + struct lec_arp_table *entry, *next; + int i; + + DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci); + dump_arp_table(priv); + lec_arp_lock(priv); + for(i=0;ilec_arp_tables[i];entry; entry=next) { + next = entry->next; + if (vcc == entry->vcc) { + lec_arp_remove(priv->lec_arp_tables,entry); + kfree(entry); + if (priv->mcast_vcc == vcc) { + priv->mcast_vcc = NULL; + } + } + } + } + + entry = priv->lec_arp_empty_ones; + priv->lec_arp_empty_ones = NULL; + while (entry != NULL) { + next = entry->next; + if (entry->vcc == vcc) { /* leave it out from the list */ + lec_arp_clear_vccs(entry); + del_timer(&entry->timer); + kfree(entry); + } + else { /* put it back to the list */ + entry->next = priv->lec_arp_empty_ones; + priv->lec_arp_empty_ones = entry; + } + entry = next; + } + + entry = priv->lec_no_forward; + priv->lec_no_forward = NULL; + while (entry != NULL) { + next = entry->next; + if (entry->recv_vcc == vcc) { + lec_arp_clear_vccs(entry); + del_timer(&entry->timer); + kfree(entry); + } + else { + entry->next = priv->lec_no_forward; + priv->lec_no_forward = entry; + } + entry = next; + } + + entry = priv->mcast_fwds; + priv->mcast_fwds = NULL; + while (entry != NULL) { + next = entry->next; + if (entry->recv_vcc == vcc) { + lec_arp_clear_vccs(entry); + /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ + kfree(entry); + } + else { + entry->next = priv->mcast_fwds; + priv->mcast_fwds = entry; + } + entry = next; + } + + lec_arp_unlock(priv); + dump_arp_table(priv); +} + +void +lec_arp_check_empties(struct lec_priv *priv, + struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct lec_arp_table *entry, *prev; + struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data; + unsigned long flags; + unsigned char *src; +#ifdef CONFIG_TR + struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data; + + if (priv->is_trdev) src = tr_hdr->h_source; + else +#endif + src = hdr->h_source; + + lec_arp_lock(priv); + entry = priv->lec_arp_empty_ones; + if (vcc == entry->vcc) { + save_flags(flags); + cli(); + del_timer(&entry->timer); + memcpy(entry->mac_addr, src, ETH_ALEN); + entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; + priv->lec_arp_empty_ones = entry->next; + restore_flags(flags); + /* We might have got an entry */ + if ((prev=lec_arp_find(priv,src))) { + lec_arp_remove(priv->lec_arp_tables, prev); + kfree(prev); + } + lec_arp_put(priv->lec_arp_tables, entry); + lec_arp_unlock(priv); + return; + } + prev = entry; + entry = entry->next; + while (entry && entry->vcc != vcc) { + prev= entry; + entry = entry->next; + } + if (!entry) { + DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); + lec_arp_unlock(priv); + return; + } + save_flags(flags); + cli(); + del_timer(&entry->timer); + memcpy(entry->mac_addr, src, ETH_ALEN); + entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; + prev->next = entry->next; + restore_flags(flags); + if ((prev = lec_arp_find(priv, src))) { + lec_arp_remove(priv->lec_arp_tables,prev); + kfree(prev); + } + lec_arp_put(priv->lec_arp_tables,entry); + lec_arp_unlock(priv); +} + diff -u --recursive --new-file v2.3.14/linux/net/atm/lec.h linux/net/atm/lec.h --- v2.3.14/linux/net/atm/lec.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/lec.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,150 @@ +/* + * + * Lan Emulation client header file + * + * Marko Kiiskila carnil@cs.tut.fi + * + */ + +#ifndef _LEC_H_ +#define _LEC_H_ + +#include +#include +#include + +#define LEC_HEADER_LEN 16 + +struct lecdatahdr_8023 { + unsigned short le_header; + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + unsigned short h_type; +}; + +struct lecdatahdr_8025 { + unsigned short le_header; + unsigned char ac_pad; + unsigned char fc; + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; +}; + +/* + * Operations that LANE2 capable device can do. Two first functions + * are used to make the device do things. See spec 3.1.3 and 3.1.4. + * + * The third function is intented for the MPOA component sitting on + * top of the LANE device. The MPOA component assigns it's own function + * to (*associate_indicator)() and the LANE device will use that + * function to tell about TLVs it sees floating through. + * + */ +struct lane2_ops { + int (*resolve)(struct net_device *dev, u8 *dst_mac, int force, + u8 **tlvs, u32 *sizeoftlvs); + int (*associate_req)(struct net_device *dev, u8 *lan_dst, + u8 *tlvs, u32 sizeoftlvs); + void (*associate_indicator)(struct net_device *dev, u8 *mac_addr, + u8 *tlvs, u32 sizeoftlvs); +}; + +struct atm_lane_ops { + int (*lecd_attach)(struct atm_vcc *vcc, int arg); + int (*mcast_attach)(struct atm_vcc *vcc, int arg); + int (*vcc_attach)(struct atm_vcc *vcc, void *arg); + struct net_device **(*get_lecs)(void); +}; + +/* + * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType + * frames. + * 1. Dix Ethernet EtherType frames encoded by placing EtherType + * field in h_type field. Data follows immediatelly after header. + * 2. LLC Data frames whose total length, including LLC field and data, + * but not padding required to meet the minimum data frame length, + * is less than 1536(0x0600) MUST be encoded by placing that length + * in the the h_type field. The LLC field follows header immediatelly. + * 3. LLC data frames longer than this maximum MUST be encoded by placing + * the value 0 in the h_type field. + * + */ + +/* Hash table size */ +#define LEC_ARP_TABLE_SIZE 16 + +struct lec_priv { + struct enet_statistics stats; + unsigned short lecid; /* Lecid of this client */ + struct lec_arp_table *lec_arp_empty_ones; + /* Used for storing VCC's that don't have a MAC address attached yet */ + struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE]; + /* Actual LE ARP table */ + struct lec_arp_table *lec_no_forward; + /* Used for storing VCC's (and forward packets from) which are to + age out by not using them to forward packets. + This is because to some LE clients there will be 2 VCCs. Only + one of them gets used. */ + struct lec_arp_table *mcast_fwds; + /* With LANEv2 it is possible that BUS (or a special multicast server) + establishes multiple Multicast Forward VCCs to us. This list + collects all those VCCs. LANEv1 client has only one item in this + list. These entries are not aged out. */ + atomic_t lec_arp_lock_var; + struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ + struct atm_vcc *lecd; + struct timer_list lec_arp_timer; + /* C10 */ + unsigned int maximum_unknown_frame_count; +/* Within the period of time defined by this variable, the client will send + no more than C10 frames to BUS for a given unicast destination. (C11) */ + unsigned long max_unknown_frame_time; +/* If no traffic has been sent in this vcc for this period of time, + vcc will be torn down (C12)*/ + unsigned long vcc_timeout_period; +/* An LE Client MUST not retry an LE_ARP_REQUEST for a + given frame's LAN Destination more than maximum retry count times, + after the first LEC_ARP_REQUEST (C13)*/ + unsigned short max_retry_count; +/* Max time the client will maintain an entry in its arp cache in + absence of a verification of that relationship (C17)*/ + unsigned long aging_time; +/* Max time the client will maintain an entry in cache when + topology change flag is true (C18) */ + unsigned long forward_delay_time; +/* Topology change flag (C19)*/ + int topology_change; +/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE + cycle to take (C20)*/ + unsigned long arp_response_time; +/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the + LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/ + unsigned long flush_timeout; +/* The time since sending a frame to the bus after which the + LE Client may assume that the frame has been either discarded or + delivered to the recipient (C22) */ + unsigned long path_switching_delay; + + u8 *tlvs; /* LANE2: TLVs are new */ + u32 sizeoftlvs; /* The size of the tlv array in bytes */ + int lane_version; /* LANE2 */ + int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ + struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ + int is_proxy; /* bridge between ATM and Ethernet */ + int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */ +}; + +int lecd_attach(struct atm_vcc *vcc, int arg); +int lec_vcc_attach(struct atm_vcc *vcc, void *arg); +int lec_mcast_attach(struct atm_vcc *vcc, int arg); +struct net_device **get_dev_lec(void); +int make_lec(struct atm_vcc *vcc); +int send_to_lecd(struct lec_priv *priv, + atmlec_msg_type type, unsigned char *mac_addr, + unsigned char *atm_addr, struct sk_buff *data); +void lec_push(struct atm_vcc *vcc, struct sk_buff *skb); + +void atm_lane_init(void); +void atm_lane_init_ops(struct atm_lane_ops *ops); +#endif _LEC_H_ + diff -u --recursive --new-file v2.3.14/linux/net/atm/lec_arpc.h linux/net/atm/lec_arpc.h --- v2.3.14/linux/net/atm/lec_arpc.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/lec_arpc.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,116 @@ +/* + * Lec arp cache + * Marko Kiiskila carnil@cs.tut.fi + * + */ +#ifndef _LEC_ARP_H +#define _LEC_ARP_H +#include +#include +#include +#include + +struct lec_arp_table { + struct lec_arp_table *next; /* Linked entry list */ + unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */ + unsigned char mac_addr[ETH_ALEN]; /* Mac address */ + int is_rdesc; /* Mac address is a route descriptor */ + struct atm_vcc *vcc; /* Vcc this entry is attached */ + struct atm_vcc *recv_vcc; /* Vcc we receive data from */ + void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); + /* Push that leads to daemon */ + void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb); + /* Push that leads to daemon */ + void (*old_close)(struct atm_vcc *vcc); + /* We want to see when this + * vcc gets closed */ + unsigned long last_used; /* For expiry */ + unsigned long timestamp; /* Used for various timestamping + * things: + * 1. FLUSH started + * (status=ESI_FLUSH_PENDING) + * 2. Counting to + * max_unknown_frame_time + * (status=ESI_ARP_PENDING|| + * status=ESI_VC_PENDING) + */ + unsigned char no_tries; /* No of times arp retry has been + tried */ + unsigned char status; /* Status of this entry */ + unsigned short flags; /* Flags for this entry */ + unsigned short packets_flooded; /* Data packets flooded */ + unsigned long flush_tran_id; /* Transaction id in flush protocol */ + struct timer_list timer; /* Arping timer */ + struct lec_priv *priv; /* Pointer back */ + + u8 *tlvs; /* LANE2: Each MAC address can have TLVs */ + u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */ + /* the length of the tlvs array */ + struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ +}; + +struct tlv { /* LANE2: Template tlv struct for accessing */ + /* the tlvs in the lec_arp_table->tlvs array*/ + u32 type; + u8 length; + u8 value[255]; +}; + +/* Status fields */ +#define ESI_UNKNOWN 0 /* + * Next packet sent to this mac address + * causes ARP-request to be sent + */ +#define ESI_ARP_PENDING 1 /* + * There is no ATM address associated with this + * 48-bit address. The LE-ARP protocol is in + * progress. + */ +#define ESI_VC_PENDING 2 /* + * There is a valid ATM address associated with + * this 48-bit address but there is no VC set + * up to that ATM address. The signaling + * protocol is in process. + */ +#define ESI_FLUSH_PENDING 4 /* + * The LEC has been notified of the FLUSH_START + * status and it is assumed that the flush + * protocol is in process. + */ +#define ESI_FORWARD_DIRECT 5 /* + * Either the Path Switching Delay (C22) has + * elapsed or the LEC has notified the Mapping + * that the flush protocol has completed. In + * either case, it is safe to forward packets + * to this address via the data direct VC. + */ + +/* Flag values */ +#define LEC_REMOTE_FLAG 0x0001 +#define LEC_PERMANENT_FLAG 0x0002 + +/* Protos */ +void lec_arp_init(struct lec_priv *priv); +int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc); +void lec_arp_destroy(struct lec_priv *priv); +void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); + +struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, + unsigned char *mac_to_addr, + int is_rdesc, + struct lec_arp_table **ret_entry); +void lec_vcc_added(struct lec_priv *dev, + struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, + void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)); +void lec_arp_check_empties(struct lec_priv *priv, + struct atm_vcc *vcc, struct sk_buff *skb); +int lec_addr_delete(struct lec_priv *priv, + unsigned char *mac_addr, unsigned long permanent); +void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); +void lec_arp_update(struct lec_priv *priv, + unsigned char *mac_addr, unsigned char *atm_addr, + unsigned long remoteflag, unsigned int targetless_le_arp); +void lec_set_flush_tran_id(struct lec_priv *priv, + unsigned char *mac_addr, unsigned long tran_id); + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/mpc.c linux/net/atm/mpc.c --- v2.3.14/linux/net/atm/mpc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/mpc.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,1470 @@ +#include +#include +#include +#include + +/* We are an ethernet device */ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for ip_fast_csum() */ +#include +#include +#include + +/* And atm device */ +#include +#include +#include +/* Modular too */ +#include +#include + +#include "lec.h" +#include "mpc.h" +#include "tunable.h" +#include "resources.h" /* for bind_vcc() */ + +/* + * mpc.c: Implementation of MPOA client kernel part + */ + +#if 0 +#define dprintk printk /* debug */ +#else +#define dprintk(format,args...) +#endif + +#if 0 +#define ddprintk printk /* more debug */ +#else +#define ddprintk(format,args...) +#endif + + + +#define MPOA_TAG_LEN 4 + +/* mpc_daemon -> kernel */ +static void MPOA_trigger_rcvd (struct k_message *msg, struct mpoa_client *mpc); +static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); +static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); +static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); +static void mps_death(struct k_message *msg, struct mpoa_client *mpc); +static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action); +static void MPOA_cache_impos_rcvd(struct k_message *msg, struct mpoa_client *mpc); +static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); +static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); + +static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac, + uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type); +static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry); + +static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc); +static void mpoad_close(struct atm_vcc *vcc); +static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb); + +static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb); +static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev); +static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev); +static void mpc_timer_refresh(void); +static void mpc_cache_check( unsigned long checking_time ); + +static struct llc_snap_hdr llc_snap_mpoa_ctrl = { + 0xaa, 0xaa, 0x03, + {0x00, 0x00, 0x5e}, + {0x00, 0x03} /* For MPOA control PDUs */ +}; +static struct llc_snap_hdr llc_snap_mpoa_data = { + 0xaa, 0xaa, 0x03, + {0x00, 0x00, 0x00}, + {0x08, 0x00} /* This is for IP PDUs only */ +}; +static struct llc_snap_hdr llc_snap_mpoa_data_tagged = { + 0xaa, 0xaa, 0x03, + {0x00, 0x00, 0x00}, + {0x88, 0x4c} /* This is for tagged data PDUs */ +}; + +static struct notifier_block mpoa_notifier = { + mpoa_event_listener, + NULL, + 0 +}; + +#ifdef CONFIG_PROC_FS +extern int mpc_proc_init(void); +extern void mpc_proc_clean(void); +#endif + +struct mpoa_client *mpcs = NULL; /* FIXME */ +static struct atm_mpoa_qos *qos_head = NULL; +static struct timer_list mpc_timer; + + +static struct mpoa_client *find_mpc_by_itfnum(int itf) +{ + struct mpoa_client *mpc; + + mpc = mpcs; /* our global linked list */ + while (mpc != NULL) { + if (mpc->dev_num == itf) + return mpc; + mpc = mpc->next; + } + + return NULL; /* not found */ +} + +static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc) +{ + struct mpoa_client *mpc; + + mpc = mpcs; /* our global linked list */ + while (mpc != NULL) { + if (mpc->mpoad_vcc == vcc) + return mpc; + mpc = mpc->next; + } + + return NULL; /* not found */ +} + +static struct mpoa_client *find_mpc_by_lec(struct net_device *dev) +{ + struct mpoa_client *mpc; + + mpc = mpcs; /* our global linked list */ + while (mpc != NULL) { + if (mpc->dev == dev) + return mpc; + mpc = mpc->next; + } + + return NULL; /* not found */ +} + +/* + * Functions for managing QoS list + */ + +/* + * Overwrites the old entry or makes a new one. + */ +struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) +{ + struct atm_mpoa_qos *entry; + + entry = atm_mpoa_search_qos(dst_ip); + if (entry != NULL) { + entry->qos = *qos; + return entry; + } + + entry = kmalloc(sizeof(struct atm_qos), GFP_KERNEL); + if (entry == NULL) { + printk("mpoa: atm_mpoa_add_qos: out of memory\n"); + return entry; + } + + entry->ipaddr = dst_ip; + entry->qos = *qos; + + entry->next = qos_head; + qos_head = entry; + + return entry; +} + +struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip) +{ + struct atm_mpoa_qos *qos; + + qos = qos_head; + while( qos != NULL ){ + if(qos->ipaddr == dst_ip) { + break; + } + qos = qos->next; + } + + return qos; +} + +/* + * Returns 0 for failure + */ +int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry) +{ + + struct atm_mpoa_qos *curr; + + if (entry == NULL) return 0; + if (entry == qos_head) { + qos_head = qos_head->next; + kfree(entry); + return 1; + } + + curr = qos_head; + while (curr != NULL) { + if (curr->next == entry) { + curr->next = entry->next; + kfree(entry); + return 1; + } + curr = curr->next; + } + + return 0; +} + +void atm_mpoa_disp_qos(char *page, int *len) +{ + + unsigned char *ip; + char ipaddr[16]; + struct atm_mpoa_qos *qos; + + qos = qos_head; + *len += sprintf(page + *len, "QoS entries for shortcuts:\n"); + *len += sprintf(page + *len, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n"); + + ipaddr[sizeof(ipaddr)-1] = '\0'; + while (qos != NULL) { + ip = (unsigned char *)&qos->ipaddr; + sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + *len += sprintf(page + *len, "%-16s\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", + ipaddr, + qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu, + qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu); + qos = qos->next; + } + + return; +} + +static struct net_device *find_lec_by_itfnum(int itf) +{ + extern struct atm_lane_ops atm_lane_ops; /* in common.c */ + + if (atm_lane_ops.get_lecs == NULL) + return NULL; + + return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */ +} + +static struct mpoa_client *alloc_mpc(void) +{ + struct mpoa_client *mpc; + + mpc = kmalloc(sizeof (struct mpoa_client), GFP_KERNEL); + if (mpc == NULL) + return NULL; + memset(mpc, 0, sizeof(struct mpoa_client)); +#if 0 /* compiler seems to barf on this */ + mpc->ingress_lock = RW_LOCK_UNLOCKED; + mpc->egress_lock = RW_LOCK_UNLOCKED; +#endif + mpc->next = mpcs; + atm_mpoa_init_cache(mpc); + + mpc->parameters.mpc_p1 = MPC_P1; + mpc->parameters.mpc_p2 = MPC_P2; + memset(mpc->parameters.mpc_p3,0,sizeof(mpc->parameters.mpc_p3)); + mpc->parameters.mpc_p4 = MPC_P4; + mpc->parameters.mpc_p5 = MPC_P5; + mpc->parameters.mpc_p6 = MPC_P6; + + mpcs = mpc; + + return mpc; +} + +/* + * + * start_mpc() puts the MPC on line. All the packets destined + * to the lec underneath us are now being monitored and + * shortcuts will be established. + * + */ +static void start_mpc(struct mpoa_client *mpc, struct net_device *dev) +{ + + dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); + if (dev->hard_start_xmit == NULL) { + printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n", + dev->name); + return; + } + mpc->old_hard_start_xmit = dev->hard_start_xmit; + dev->hard_start_xmit = mpc_send_packet; + + return; +} + +static void stop_mpc(struct mpoa_client *mpc) +{ + + dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name); + + /* Lets not nullify lec device's dev->hard_start_xmit */ + if (mpc->dev->hard_start_xmit != mpc_send_packet) { + dprintk(" mpc already stopped, not fatal\n"); + return; + } + dprintk("\n"); + mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit; + mpc->old_hard_start_xmit = NULL; + /* close_shortcuts(mpc); ??? FIXME */ + + return; +} + +static const char *mpoa_device_type_string (char type) +{ + switch(type) { + case NON_MPOA: + return "non-MPOA device"; + break; + case MPS: + return "MPS"; + break; + case MPC: + return "MPC"; + break; + case MPS_AND_MPC: + return "both MPS and MPC"; + break; + default: + return "unspecified (non-MPOA) device"; + break; + } + + return ""; /* not reached */ +} + +/* + * lec device calls this via its dev->priv->lane2_ops->associate_indicator() + * when it sees a TLV in LE_ARP packet. + * We fill in the pointer above when we see a LANE2 lec initializing + * See LANE2 spec 3.1.5 + * + * Quite a big and ugly function but when you look at it + * all it does is to try to locate and parse MPOA Device + * Type TLV. + * We give our lec a pointer to this function and when the + * lec sees a TLV it uses the pointer to call this function. + * + */ +static void lane2_assoc_ind(struct net_device *dev, uint8_t *mac_addr, + uint8_t *tlvs, uint32_t sizeoftlvs) +{ + uint32_t type; + uint8_t length, mpoa_device_type, number_of_mps_macs; + uint8_t *end_of_tlvs; + struct mpoa_client *mpc; + + mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */ + dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name); + dprintk("total length of all TLVs %d\n", sizeoftlvs); + mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */ + if (mpc == NULL) { + printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name); + return; + } + end_of_tlvs = tlvs + sizeoftlvs; + while (end_of_tlvs - tlvs >= 5) { + type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; + length = tlvs[4]; + tlvs += 5; + dprintk(" type 0x%x length %02x\n", type, length); + if (tlvs + length > end_of_tlvs) { + printk("TLV value extends past its buffer, aborting parse\n"); + return; + } + + if (type == 0) { + printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name); + return; + } + + if (type != TLV_MPOA_DEVICE_TYPE) { + tlvs += length; + continue; /* skip other TLVs */ + } + mpoa_device_type = *tlvs++; + number_of_mps_macs = *tlvs++; + dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type)); + if (mpoa_device_type == MPS_AND_MPC && + length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */ + printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", + dev->name); + continue; + } + if ((mpoa_device_type == MPS || mpoa_device_type == MPC) + && length < 22 + number_of_mps_macs*ETH_ALEN) { + printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", + dev->name); + continue; + } + if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) { + dprintk("ignoring non-MPS device\n"); + if (mpoa_device_type == MPC) tlvs += 20; + continue; /* we are only interested in MPSs */ + } + if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) { + printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name); + continue; /* someone should read the spec */ + } + dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs); + + /* ok, now we can go and tell our daemon the control address of MPS */ + send_set_mps_ctrl_addr(tlvs, mpc); + + tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type); + if (tlvs == NULL) return; + } + if (end_of_tlvs - tlvs != 0) + printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n", + dev->name, end_of_tlvs - tlvs); + return; +} + +/* + * Store at least advertizing router's MAC address + * plus the possible MAC address(es) to mpc->mps_macs. + * For a freshly allocated MPOA client mpc->mps_macs == 0. + */ +static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac, + uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type) +{ + int num_macs; + num_macs = (mps_macs > 1) ? mps_macs : 1; + + if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */ + if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs); + mpc->number_of_mps_macs = 0; + mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL); + if (mpc->mps_macs == NULL) { + printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name); + return NULL; + } + } + memcpy(mpc->mps_macs, router_mac, ETH_ALEN); + tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20; + if (mps_macs > 0) + memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); + tlvs += mps_macs*ETH_ALEN; + mpc->number_of_mps_macs = num_macs; + + return tlvs; +} + +/* FIXME: tarvitsee työtä */ +static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) +{ + in_cache_entry *entry; + struct iphdr *iph; + char *buff; + uint32_t ipaddr = 0; + + static struct { + struct llc_snap_hdr hdr; + uint32_t tag; + } tagged_llc_snap_hdr = { + {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, + 0 + }; + + buff = skb->data + mpc->dev->hard_header_len; + iph = (struct iphdr *)buff; + ipaddr = iph->daddr; + + ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr); + + entry = mpc->in_ops->search(ipaddr, mpc); + if (entry == NULL) { + mpc->in_ops->new_entry(ipaddr, mpc); + return 1; + } + if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){ /* threshold not exceeded or VCC not ready */ + ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name); + return 1; + } + + ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name); + /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ + if (iph->ttl <= 1) { + ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); + return 1; + } + iph->ttl--; + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + + if (entry->ctrl_info.tag != 0) { + ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); + tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; + skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ + skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ + memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); + } else { + skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ + skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ + memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); + } + + atomic_add(skb->truesize, &entry->shortcut->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */ + ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; + entry->shortcut->dev->ops->send(entry->shortcut, skb); + entry->packets_fwded++; + + return 0; +} + +/* + * Probably needs some error checks and locking, not sure... + */ +static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + int retval; + struct mpoa_client *mpc; + struct ethhdr *eth; + int i = 0; + + mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ + if(mpc == NULL) { + printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name); + goto non_ip; + } + + eth = (struct ethhdr *)skb->data; + if (eth->h_proto != htons(ETH_P_IP)) + goto non_ip; /* Multi-Protocol Over ATM :-) */ + + while (i < mpc->number_of_mps_macs) { + if (memcmp(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0) + if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ + return 0; /* success! */ + i++; + } + + non_ip: + retval = mpc->old_hard_start_xmit(skb,dev); + + return retval; +} + +int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg) +{ + int bytes_left; + struct mpoa_client *mpc; + struct atmmpc_ioc ioc_data; + in_cache_entry *in_entry; + uint32_t ipaddr; + unsigned char *ip; + + bytes_left = copy_from_user(&ioc_data, (void *)arg, sizeof(struct atmmpc_ioc)); + if (bytes_left != 0) { + printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left); + return -EFAULT; + } + ipaddr = ioc_data.ipaddr; + if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) + return -EINVAL; + + mpc = find_mpc_by_itfnum(ioc_data.dev_num); + if (mpc == NULL) + return -EINVAL; + + if (ioc_data.type == MPC_SOCKET_INGRESS) { + in_entry = mpc->in_ops->search(ipaddr, mpc); + if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) { + printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n", + mpc->dev->name); + return -EINVAL; + } + ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip; + printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n", + mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); + in_entry->shortcut = vcc; + } else { + printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name); + } + + vcc->proto_data = mpc->dev; + vcc->push = mpc_push; + + return 0; +} + +/* + * + */ +static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) +{ + struct mpoa_client *mpc; + in_cache_entry *in_entry; + eg_cache_entry *eg_entry; + + mpc = find_mpc_by_lec(dev); + if (mpc == NULL) { + printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name); + return; + } + + dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name); + in_entry = mpc->in_ops->search_by_vcc(vcc, mpc); + if (in_entry) { + unsigned char *ip = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; + dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n", + mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); + in_entry->shortcut = NULL; + } + eg_entry = mpc->eg_ops->search_by_vcc(vcc, mpc); + if (eg_entry) { + dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name); + eg_entry->shortcut = NULL; + } + + if (in_entry == NULL && eg_entry == NULL) + dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", dev->name); + + return; +} + +static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct net_device *dev = (struct net_device *)vcc->proto_data; + struct sk_buff *new_skb; + eg_cache_entry *eg; + struct mpoa_client *mpc; + uint32_t tag; + char *tmp; + + ddprintk("mpoa: (%s) mpc_push:\n", dev->name); + if (skb == NULL) { + dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name); + mpc_vcc_close(vcc, dev); + return; + } + + skb->dev = dev; + if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { + dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name); + skb_queue_tail(&vcc->recvq, skb); /* Pass control packets to daemon */ + wake_up(&vcc->sleep); + return; + } + + /* data coming over the shortcut */ + atm_return(vcc, skb->truesize); + + mpc = find_mpc_by_lec(dev); + if (mpc == NULL) { + printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name); + return; + } + + if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ + ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name); + + } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ + printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name); + printk(" mpc_push: non-tagged data unsupported, purging\n"); + kfree_skb(skb); + return; + } else { + printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name); + kfree_skb(skb); + return; + } + + tmp = skb->data + sizeof(struct llc_snap_hdr); + tag = *(uint32_t *)tmp; + + eg = mpc->eg_ops->search_by_tag(tag, mpc); + if (eg == NULL) { + printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n", + dev->name,tag); + purge_egress_shortcut(vcc, NULL); + kfree_skb(skb); + return; + } + + /* + * See if ingress MPC is using shortcut we opened as a return channel. + * This means we have a bi-directional vcc opened by us. + */ + if (eg->shortcut == NULL) { + eg->shortcut = vcc; + printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name); + } + + skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ + new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ + kfree_skb(skb); + if (new_skb == NULL) return; + skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ + memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length); + new_skb->protocol = eth_type_trans(new_skb, dev); + new_skb->nh.raw = new_skb->data; + + eg->latest_ip_addr = new_skb->nh.iph->saddr; + eg->packets_rcvd++; + + netif_rx(new_skb); + + return; +} + +static struct atmdev_ops mpc_ops = { /* only send is required */ + NULL, /* dev_close */ + NULL, /* open */ + mpoad_close, /* close */ + NULL, /* ioctl */ + NULL, /* getsockopt */ + NULL, /* setsockopt */ + msg_from_mpoad, /* send */ + NULL, /* sg_send */ + NULL, /* send_oam */ + NULL, /* phy_put */ + NULL, /* phy_get */ + NULL, /* feedback */ + NULL, /* change_qos */ + NULL, /* free_rx_skb */ + NULL /* proc_read */ +}; + +static struct atm_dev mpc_dev = { + &mpc_ops, /* device operations */ + NULL, /* PHY operations */ + "mpc", /* device type name */ + 42, /* device index (dummy) */ + NULL, /* VCC table */ + NULL, /* last VCC */ + NULL, /* per-device data */ + NULL, /* private PHY data */ + 0, /* device flags */ + NULL, /* local ATM address */ + { 0 } /* no ESI */ + /* rest of the members will be 0 */ +}; + +int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) +{ + struct mpoa_client *mpc; + struct lec_priv *priv; + + if (mpcs == NULL) { + init_timer(&mpc_timer); + mpc_timer_refresh(); + + /* This lets us now how our LECs are doing */ + register_netdevice_notifier(&mpoa_notifier); + } + + mpc = find_mpc_by_itfnum(arg); + if (mpc == NULL) { + dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg); + mpc = alloc_mpc(); + mpc->dev_num = arg; + mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */ + } + if (mpc->mpoad_vcc) { + printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg); + return -EADDRINUSE; + } + + if (mpc->dev) { /* check if the lec is LANE2 capable */ + priv = (struct lec_priv *)mpc->dev->priv; + if (priv->lane_version < 2) + mpc->dev = NULL; + else + priv->lane2_ops->associate_indicator = lane2_assoc_ind; + } + + mpc->mpoad_vcc = vcc; + bind_vcc(vcc, &mpc_dev); + vcc->flags |= ATM_VF_READY | ATM_VF_META; + + if (mpc->dev) { + char empty[ATM_ESA_LEN]; + memset(empty, 0, ATM_ESA_LEN); + + start_mpc(mpc, mpc->dev); + /* set address if mpcd e.g. gets killed and restarted. + * If we do not do it now we have to wait for the next LE_ARP + */ + if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 ) + send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); + } + + MOD_INC_USE_COUNT; + return arg; +} + +static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc) +{ + struct k_message mesg; + + memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); + + mesg.type = SET_MPS_CTRL_ADDR; + memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); + msg_to_mpoad(&mesg, mpc); + + return; +} + +static void mpoad_close(struct atm_vcc *vcc) +{ + unsigned long flags; + struct mpoa_client *mpc; + struct sk_buff *skb; + + mpc = find_mpc_by_vcc(vcc); + if (mpc == NULL) { + printk("mpoa: mpoad_close: did not find MPC\n"); + return; + } + if (!mpc->mpoad_vcc) { + printk("mpoa: mpoad_close: close for non-present mpoad\n"); + return; + } + + mpc->mpoad_vcc = NULL; + if (mpc->dev) { + struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; + priv->lane2_ops->associate_indicator = NULL; + stop_mpc(mpc); + } + + /* clear the caches */ + write_lock_irqsave(&mpc->ingress_lock, flags); + while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); + write_unlock_irqrestore(&mpc->ingress_lock, flags); + + write_lock_irqsave(&mpc->egress_lock, flags); + while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); + write_unlock_irqrestore(&mpc->egress_lock, flags); + + while ( (skb = skb_dequeue(&vcc->recvq)) ){ + atm_return(vcc, skb->truesize); + kfree_skb(skb); + } + + printk("mpoa: (%s) going down\n", + (mpc->dev) ? mpc->dev->name : ""); + MOD_DEC_USE_COUNT; + + return; +} + +/* + * + */ +static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) +{ + + struct mpoa_client *mpc = find_mpc_by_vcc(vcc); + struct k_message *mesg = (struct k_message*)skb->data; + atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); + + if (mpc == NULL) { + printk("mpoa: msg_from_mpoad: no mpc found\n"); + return 0; + } + dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : ""); + switch(mesg->type) { + case MPOA_RES_REPLY_RCVD: + dprintk(" mpoa_res_reply_rcvd\n"); + MPOA_res_reply_rcvd(mesg, mpc); + break; + case MPOA_TRIGGER_RCVD: + dprintk(" mpoa_trigger_rcvd\n"); + MPOA_trigger_rcvd(mesg, mpc); + break; + case INGRESS_PURGE_RCVD: + dprintk(" nhrp_purge_rcvd\n"); + ingress_purge_rcvd(mesg, mpc); + break; + case EGRESS_PURGE_RCVD: + dprintk(" egress_purge_reply_rcvd\n"); + egress_purge_rcvd(mesg, mpc); + break; + case MPS_DEATH: + dprintk(" mps_death\n"); + mps_death(mesg, mpc); + break; + case CACHE_IMPOS_RCVD: + dprintk(" cache_impos_rcvd\n"); + MPOA_cache_impos_rcvd(mesg, mpc); + break; + case SET_MPC_CTRL_ADDR: + dprintk(" set_mpc_ctrl_addr\n"); + set_mpc_ctrl_addr_rcvd(mesg, mpc); + break; + case SET_MPS_MAC_ADDR: + dprintk(" set_mps_mac_addr\n"); + set_mps_mac_addr_rcvd(mesg, mpc); + break; + case CLEAN_UP_AND_EXIT: + dprintk(" clean_up_and_exit\n"); + clean_up(mesg, mpc, DIE); + break; + case RELOAD: + dprintk(" reload\n"); + clean_up(mesg, mpc, RELOAD); + break; + case SET_MPC_PARAMS: + dprintk(" set_mpc_params\n"); + mpc->parameters = mesg->content.params; + break; + default: + dprintk(" unknown message %d\n", mesg->type); + break; + } + kfree_skb(skb); + + return 0; +} + +int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) +{ + struct sk_buff *skb; + + if (mpc == NULL || !mpc->mpoad_vcc) { + printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type); + return -ENXIO; + } + + skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + skb_put(skb, sizeof(struct k_message)); + memcpy(skb->data, mesg, sizeof(struct k_message)); + atm_force_charge(mpc->mpoad_vcc, skb->truesize); + skb_queue_tail(&mpc->mpoad_vcc->recvq, skb); + wake_up(&mpc->mpoad_vcc->sleep); + + return 0; +} + +static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr) +{ + struct net_device *dev; + struct mpoa_client *mpc; + struct lec_priv *priv; + + dev = (struct net_device *)dev_ptr; + if (dev->name == NULL || strncmp(dev->name, "lec", 3)) + return NOTIFY_DONE; /* we are only interested in lec:s */ + + switch (event) { + case NETDEV_REGISTER: /* a new lec device was allocated */ + priv = (struct lec_priv *)dev->priv; + if (priv->lane_version < 2) + break; + priv->lane2_ops->associate_indicator = lane2_assoc_ind; + mpc = find_mpc_by_itfnum(priv->itfnum); + if (mpc == NULL) { + dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n", + dev->name); + mpc = alloc_mpc(); + if (mpc == NULL) { + printk("mpoa: mpoa_event_listener: no new mpc"); + break; + } + } + mpc->dev_num = priv->itfnum; + mpc->dev = dev; + dprintk("mpoa: (%s) was initialized\n", dev->name); + break; + case NETDEV_UNREGISTER: + /* the lec device was deallocated */ + mpc = find_mpc_by_lec(dev); + if (mpc == NULL) + break; + dprintk("mpoa: device (%s) was deallocated\n", dev->name); + stop_mpc(mpc); + mpc->dev = NULL; + break; + case NETDEV_UP: + /* the dev was ifconfig'ed up */ + mpc = find_mpc_by_lec(dev); + if (mpc == NULL) + break; + if (mpc->mpoad_vcc != NULL) { + start_mpc(mpc, dev); + } + break; + case NETDEV_DOWN: + /* the dev was ifconfig'ed down */ + /* this means dev->start == 0 and + * the flow of packets from the + * upper layer stops + */ + mpc = find_mpc_by_lec(dev); + if (mpc == NULL) + break; + if (mpc->mpoad_vcc != NULL) { + stop_mpc(mpc); + } + break; + case NETDEV_REBOOT: + case NETDEV_CHANGE: + case NETDEV_CHANGEMTU: + case NETDEV_CHANGEADDR: + case NETDEV_GOING_DOWN: + break; + default: + break; + } + + return NOTIFY_DONE; +} + +/* + * Functions which are called after a message is received from mpcd. + * Msg is reused on purpose. + */ + + +static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *client) +{ + uint32_t dst_ip = msg->content.in_info.in_dst_ip; + in_cache_entry *entry; + + entry = client->in_ops->search(dst_ip, client); + if( entry == NULL ){ + entry = client->in_ops->new_entry(dst_ip, client); + entry->entry_state = INGRESS_RESOLVING; + msg->type = SND_MPOA_RES_RQST; + msg->content.in_info = entry->ctrl_info; + msg_to_mpoad(msg,client); + do_gettimeofday(&(entry->reply_wait)); + return; + } + + if( entry->entry_state == INGRESS_INVALID ){ + entry->entry_state = INGRESS_RESOLVING; + msg->type = SND_MPOA_RES_RQST; + msg->content.in_info = entry->ctrl_info; + msg_to_mpoad(msg,client); + do_gettimeofday(&(entry->reply_wait)); + return; + } + + printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n", + (client->dev) ? client->dev->name : ""); + return; +} + +/* + * Things get complicated because we have to check if there's an egress + * shortcut with suitable traffic parameters we could use. + */ +static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry){ + uint32_t dst_ip = msg->content.in_info.in_dst_ip; + unsigned char *ip = (unsigned char *)&dst_ip; + struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); + eg_cache_entry *eg_entry = client->eg_ops->search_by_src_ip(dst_ip, client); + if(eg_entry && eg_entry->shortcut){ + if(eg_entry->shortcut->qos.txtp.traffic_class & + msg->qos.txtp.traffic_class & + (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)){ + if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR) + entry->shortcut = eg_entry->shortcut; + else if(eg_entry->shortcut->qos.txtp.max_pcr > 0) + entry->shortcut = eg_entry->shortcut; + } + if(entry->shortcut){ + dprintk("mpoa: (%s) using egress SVC to reach %d.%d.%d.%d\n",client->dev->name, ip[0], ip[1], ip[2], ip[3]); + return; + } + } + /* No luck in the egress cache we must open an ingress SVC */ + msg->type = OPEN_INGRESS_SVC; + if (qos && (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) + { + msg->qos = qos->qos; + printk("mpoa: (%s) trying to get a CBR shortcut\n",client->dev->name); + } + else memset(&msg->qos,0,sizeof(struct atm_qos)); + msg_to_mpoad(msg, client); + return; +} + +static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *client) +{ + unsigned char *ip; + + uint32_t dst_ip = msg->content.in_info.in_dst_ip; + in_cache_entry *entry = client->in_ops->search(dst_ip, client); + ip = (unsigned char *)&dst_ip; + dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %d.%d.%d.%d\n", client->dev->name, ip[0], ip[1], ip[2], ip[3]); + ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client->dev->name, entry); + if(entry == NULL){ + printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", client->dev->name); + return; + } + ddprintk(" entry_state = %d ", entry->entry_state); + + if (entry->entry_state == INGRESS_RESOLVED) { + printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", client->dev->name); + return; + } + + entry->ctrl_info = msg->content.in_info; + do_gettimeofday(&(entry->tv)); + do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */ + entry->refresh_time = 0; + ddprintk("entry->shortcut = %p\n", entry->shortcut); + + if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){ + entry->entry_state = INGRESS_RESOLVED; + return; /* Shortcut already open... */ + } + + if (entry->shortcut != NULL) { + printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n", + client->dev->name); + return; + } + + check_qos_and_open_shortcut(msg, client, entry); + entry->entry_state = INGRESS_RESOLVED; + + return; + +} + +static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) +{ + uint32_t dst_ip = msg->content.in_info.in_dst_ip; + uint32_t mask = msg->ip_mask; + unsigned char *ip = (unsigned char *)&dst_ip; + + in_cache_entry *entry = mpc->in_ops->search_with_mask(dst_ip, mpc, mask); + if( entry == NULL ){ + printk("mpoa: (%s) ingress_purge_rcvd: recieved a purge for an entry that doesn't exist, ", mpc->dev->name); + printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); + return; + } + while(entry != NULL){ + dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" , + mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); + mpc->in_ops->cache_remove(entry, mpc); + entry = mpc->in_ops->search_with_mask(dst_ip, mpc, mask); + } + return; +} + +static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) +{ + unsigned long flags; + uint32_t cache_id = msg->content.eg_info.cache_id; + eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(cache_id, mpc); + + if( entry == NULL ){ + printk("mpoa: (%s) egress_purge_rcvd: received a purge reply for an entry that doesn't exist\n", mpc->dev->name); + return; + } + + write_lock_irqsave(&mpc->egress_lock, flags); + mpc->eg_ops->cache_remove(entry, mpc); + write_unlock_irqrestore(&mpc->egress_lock, flags); + + return; +} + +static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) +{ + struct k_message *purge_msg; + struct sk_buff *skb; + + dprintk("mpoa: purge_egress_shortcut: entering\n"); + if (vcc == NULL) { + printk("mpoa: purge_egress_shortcut: vcc == NULL\n"); + return; + } + + skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); + if (skb == NULL) { + printk("mpoa: purge_egress_shortcut: out of memory\n"); + return; + } + + skb_put(skb, sizeof(struct k_message)); + memset(skb->data, 0, sizeof(struct k_message)); + purge_msg = (struct k_message *)skb->data; + purge_msg->type = DATA_PLANE_PURGE; + if (entry != NULL) + purge_msg->content.eg_info = entry->ctrl_info; + + atm_force_charge(vcc, skb->truesize); + skb_queue_tail(&vcc->recvq, skb); + wake_up(&vcc->sleep); + dprintk("mpoa: purge_egress_shortcut: exiting:\n"); + + return; +} + +/* + * Our MPS died. Tell our daemon to send NHRP data plane purge to each + * of the egress shortcuts we have. + */ +static void mps_death( struct k_message * msg, struct mpoa_client * mpc ) +{ + + unsigned long flags; + eg_cache_entry *entry; + + dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name); + + if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){ + printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name); + return; + } + + entry = mpc->eg_cache; + while (entry != NULL) { + purge_egress_shortcut(entry->shortcut, entry); + entry = entry->next; + } + + write_lock_irqsave(&mpc->ingress_lock, flags); + while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); + write_unlock_irqrestore(&mpc->ingress_lock, flags); + + write_lock_irqsave(&mpc->egress_lock, flags); + while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); + write_unlock_irqrestore(&mpc->egress_lock, flags); + + return; +} + +static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc){ + + uint16_t holding_time; + unsigned long flags; + eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(msg->content.eg_info.cache_id, mpc); + + holding_time = msg->content.eg_info.holding_time; + dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n", + mpc->dev->name, entry, holding_time); + if(entry == NULL && holding_time) { + mpc->eg_ops->new_entry(msg, mpc); + return; + } + if(holding_time){ + mpc->eg_ops->update(entry, holding_time); + return; + } + + write_lock_irqsave(&mpc->egress_lock, flags); + mpc->eg_ops->cache_remove(entry, mpc); + write_unlock_irqrestore(&mpc->egress_lock, flags); + + + return; +} + +static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc) +{ + struct lec_priv *priv; + int i, retval ; + + uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN]; + + tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type */ + tlv[4] = 1 + 1 + ATM_ESA_LEN; /* length */ + tlv[5] = 0x02; /* MPOA client */ + tlv[6] = 0x00; /* number of MPS MAC addresses */ + + memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ + memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); + + dprintk("mpoa: (%s) setting MPC ctrl ATM address to ", + (mpc->dev) ? mpc->dev->name : ""); + for (i = 7; i < sizeof(tlv); i++) + dprintk("%02x ", tlv[i]); + dprintk("\n"); + + if (mpc->dev) { + priv = (struct lec_priv *)mpc->dev->priv; + retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv)); + if (retval == 0) + printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name); + retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL); + if (retval < 0) + printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name); + } + + return; +} + +static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client){ + + if(client->number_of_mps_macs) + kfree(client->mps_macs); + client->number_of_mps_macs = 0; + client->mps_macs = kmalloc(ETH_ALEN,GFP_KERNEL); + if (client->mps_macs == NULL) { + printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n"); + return; + } + client->number_of_mps_macs = 1; + memcpy(client->mps_macs, msg->MPS_ctrl, ETH_ALEN); + + return; +} + +/* + * purge egress cache and tell daemon to 'action' (DIE, RELOAD) + */ +static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action){ + + unsigned long flags; + eg_cache_entry *entry; + msg->type = SND_EGRESS_PURGE; + + + read_lock_irqsave(&mpc->egress_lock, flags); + entry = mpc->eg_cache; + while(entry != NULL){ + msg->content.eg_info = entry->ctrl_info; + dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id); + msg_to_mpoad(msg, mpc); + entry = entry->next; + } + read_unlock_irqrestore(&mpc->egress_lock, flags); + + msg->type = action; + msg_to_mpoad(msg, mpc); + return; +} + +static void mpc_timer_refresh() +{ + mpc_timer.expires = jiffies + (MPC_P2 * HZ); + mpc_timer.data = mpc_timer.expires; + mpc_timer.function = mpc_cache_check; + add_timer(&mpc_timer); + + return; +} + +static void mpc_cache_check( unsigned long checking_time ) +{ + struct mpoa_client *mpc = mpcs; + static unsigned long previous_resolving_check_time = 0; + static unsigned long previous_refresh_time = 0; + + while( mpc != NULL ){ + mpc->in_ops->clear_count(mpc); + mpc->eg_ops->clear_expired(mpc); + if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){ + mpc->in_ops->check_resolving(mpc); + previous_resolving_check_time = checking_time; + } + if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){ + mpc->in_ops->refresh(mpc); + previous_refresh_time = checking_time; + } + mpc = mpc->next; + } + mpc_timer_refresh(); + + return; +} + +void atm_mpoa_init_ops(struct atm_mpoa_ops *ops) +{ + ops->mpoad_attach = atm_mpoa_mpoad_attach; + ops->vcc_attach = atm_mpoa_vcc_attach; + +#ifdef CONFIG_PROC_FS + if(mpc_proc_init() != 0) + printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); + else + printk(KERN_INFO "mpoa: /proc/mpoa initialized\n"); +#endif + + printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); + + return; +} + +#ifdef MODULE +int init_module(void) +{ + extern struct atm_mpoa_ops atm_mpoa_ops; + + atm_mpoa_init_ops(&atm_mpoa_ops); + + return 0; +} + +void cleanup_module(void) +{ + extern struct atm_mpoa_ops atm_mpoa_ops; + struct mpoa_client *mpc, *tmp; + struct atm_mpoa_qos *qos, *nextqos; + struct lec_priv *priv; + + if (MOD_IN_USE) { + printk("mpc.c: module in use\n"); + return; + } +#ifdef CONFIG_PROC_FS + mpc_proc_clean(); +#endif + + del_timer(&mpc_timer); + unregister_netdevice_notifier(&mpoa_notifier); + atm_mpoa_ops.mpoad_attach = NULL; + atm_mpoa_ops.vcc_attach = NULL; + + mpc = mpcs; + mpcs = NULL; + while (mpc != NULL) { + tmp = mpc->next; + if (mpc->dev != NULL) { + stop_mpc(mpc); + priv = (struct lec_priv *)mpc->dev->priv; + if (priv->lane2_ops != NULL) + priv->lane2_ops->associate_indicator = NULL; + } + ddprintk("mpoa: cleanup_module: about to clear caches\n"); + while(mpc->in_ops->cache_remove(mpc->in_cache, mpc)); + while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc)); + ddprintk("mpoa: cleanup_module: caches cleared\n"); + kfree(mpc->mps_macs); + memset(mpc, 0, sizeof(struct mpoa_client)); + ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc); + kfree(mpc); + ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp); + mpc = tmp; + } + + qos = qos_head; + qos_head = NULL; + while (qos != NULL) { + nextqos = qos->next; + dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos); + kfree(qos); + qos = nextqos; + } + + return; +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.14/linux/net/atm/mpc.h linux/net/atm/mpc.h --- v2.3.14/linux/net/atm/mpc.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/mpc.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,65 @@ +#ifndef _MPC_H_ +#define _MPC_H_ + +#include +#include +#include +#include +#include "mpoa_caches.h" + +/* kernel -> mpc-daemon */ +int msg_to_mpoad(struct k_message *msg, struct mpoa_client *mpc); + +/* Functions for ioctl(ATMMPC_*) operations */ +int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg); +int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg); + +struct mpoa_client { + struct mpoa_client *next; + struct net_device *dev; /* lec in question */ + int dev_num; /* e.g. 2 for lec2 */ + int (*old_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); + struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ + uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */ + uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */ + + rwlock_t ingress_lock; + struct in_cache_ops *in_ops; /* ingress cache operations */ + in_cache_entry *in_cache; /* the ingress cache of this MPC */ + + rwlock_t egress_lock; + struct eg_cache_ops *eg_ops; /* egress cache operations */ + eg_cache_entry *eg_cache; /* the egress cache of this MPC */ + + uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */ + int number_of_mps_macs; /* number of the above MAC addresses */ + struct mpc_parameters parameters; /* parameters for this client */ +}; + + +struct atm_mpoa_qos { + struct atm_mpoa_qos *next; + uint32_t ipaddr; + struct atm_qos qos; +}; + + +/* Functions to call during ioctl(ATMMPC, ) */ +struct atm_mpoa_ops { + int (*mpoad_attach)(struct atm_vcc *vcc, int arg); /* attach mpoa daemon */ + int (*vcc_attach)(struct atm_vcc *vcc, long arg); /* attach shortcut vcc */ +}; + +/* Boot/module initialization function */ +void atm_mpoa_init(void); +void atm_mpoa_init_ops(struct atm_mpoa_ops *ops); + +/* MPOA QoS operations */ +struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); +struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip); +int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); + +/* Display QoS entries. This is for the procfs */ +void atm_mpoa_disp_qos(char *page, int *len); + +#endif /* _MPC_H_ */ diff -u --recursive --new-file v2.3.14/linux/net/atm/mpoa_caches.c linux/net/atm/mpoa_caches.c --- v2.3.14/linux/net/atm/mpoa_caches.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/mpoa_caches.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,557 @@ +#include +#include +#include + +#include "mpoa_caches.h" +#include "mpc.h" + +/* + * mpoa_caches.c: Implementation of ingress and egress cache + * handling functions + */ + +#if 0 +#define dprintk printk /* debug */ +#else +#define dprintk(format,args...) +#endif + +#if 0 +#define ddprintk printk /* more debug */ +#else +#define ddprintk(format,args...) +#endif + +static in_cache_entry *in_cache_search(uint32_t dst_ip, + struct mpoa_client *client) +{ + unsigned long flags; + in_cache_entry *entry; + + read_lock_irqsave(&client->ingress_lock, flags); + entry = client->in_cache; + while(entry != NULL){ + if( entry->ctrl_info.in_dst_ip == dst_ip ){ + read_unlock_irqrestore(&client->ingress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->ingress_lock, flags); + + return NULL; +} + +static in_cache_entry *in_cache_search_with_mask(uint32_t dst_ip, + struct mpoa_client *client, + uint32_t mask){ + unsigned long flags; + in_cache_entry *entry; + + read_lock_irqsave(&client->ingress_lock, flags); + entry = client->in_cache; + while(entry != NULL){ + if((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask )){ + read_unlock_irqrestore(&client->ingress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->ingress_lock, flags); + + return NULL; + +} + +static in_cache_entry *in_cache_search_by_vcc(struct atm_vcc *vcc, + struct mpoa_client *client ) +{ + unsigned long flags; + in_cache_entry *entry; + + read_lock_irqsave(&client->ingress_lock, flags); + entry = client->in_cache; + while(entry != NULL){ + if(entry->shortcut == vcc) { + read_unlock_irqrestore(&client->ingress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->ingress_lock, flags); + + return NULL; +} + +static in_cache_entry *new_in_cache_entry(uint32_t dst_ip, + struct mpoa_client *client) +{ + unsigned long flags; + unsigned char *ip = (unsigned char *)&dst_ip; + in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL); + + if (entry == NULL) { + printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); + return NULL; + } + + dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); + memset(entry,0,sizeof(in_cache_entry)); + + dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); + write_lock_irqsave(&client->ingress_lock, flags); + entry->next = client->in_cache; + entry->prev = NULL; + if (client->in_cache != NULL) + client->in_cache->prev = entry; + client->in_cache = entry; + write_unlock_irqrestore(&client->ingress_lock, flags); + dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n"); + + memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); + entry->ctrl_info.in_dst_ip = dst_ip; + do_gettimeofday(&(entry->tv)); + entry->retry_time = client->parameters.mpc_p4; + entry->count = 1; + entry->entry_state = INGRESS_INVALID; + entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT; + + return entry; +} + +static int cache_hit( in_cache_entry * entry, struct mpoa_client *mpc) +{ + struct atm_mpoa_qos *qos; + struct k_message msg; + + entry->count++; + if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) + return OPEN; + + if(entry->entry_state == INGRESS_REFRESHING){ + if(entry->count > mpc->parameters.mpc_p1){ + msg.type = SND_MPOA_RES_RQST; + msg.content.in_info = entry->ctrl_info; + memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; + msg_to_mpoad(&msg, mpc); + do_gettimeofday(&(entry->reply_wait)); + entry->entry_state = INGRESS_RESOLVING; + } + if(entry->shortcut != NULL) + return OPEN; + return CLOSED; + } + + if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) + return OPEN; + + if( entry->count > mpc->parameters.mpc_p1 && + entry->entry_state == INGRESS_INVALID){ + unsigned char *ip = (unsigned char *)&entry->ctrl_info.in_dst_ip; + + dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); + entry->entry_state = INGRESS_RESOLVING; + msg.type = SND_MPOA_RES_RQST; + memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); + msg.content.in_info = entry->ctrl_info; + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; + msg_to_mpoad( &msg, mpc); + do_gettimeofday(&(entry->reply_wait)); + } + + return CLOSED; +} + +/* + * If there are no more references to vcc in egress cache, + * we are ready to close it. + */ +static void close_unused_egress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) +{ + if (vcc == NULL) + return; + + dprintk("mpoa: mpoa_caches.c: close_unused_egress_vcc:\n"); + if (mpc->eg_ops->search_by_vcc(vcc, mpc) != NULL) + return; /* entry still in use */ + + atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */ + dprintk("mpoa: mpoa_caches.c: close_unused_egress_vcc, closed one:\n"); + + return; +} + +/* + * This should be called with write lock on + */ +static int in_cache_remove( in_cache_entry *entry, + struct mpoa_client *client ) +{ + struct atm_vcc *vcc; + struct k_message msg; + unsigned char *ip; + + if(entry == NULL) + return 0; + + vcc = entry->shortcut; + ip = (unsigned char *)&entry->ctrl_info.in_dst_ip; + dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]); + + if (entry->prev != NULL) + entry->prev->next = entry->next; + else + client->in_cache = entry->next; + if (entry->next != NULL) + entry->next->prev = entry->prev; + memset(entry, 0, sizeof(in_cache_entry)); + kfree(entry); + if(client->in_cache == NULL && client->eg_cache == NULL){ + msg.type = STOP_KEEP_ALIVE_SM; + msg_to_mpoad(&msg,client); + } + + close_unused_egress_vcc(vcc, client); + return 1; +} + + +/* Call this every MPC-p2 seconds... Not exactly correct solution, + but an easy one... */ + +static void clear_count_and_expired(struct mpoa_client *client) +{ + unsigned char *ip; + unsigned long flags; + in_cache_entry *entry, *next_entry; + struct timeval now; + + do_gettimeofday(&now); + + write_lock_irqsave(&client->ingress_lock, flags); + entry = client->in_cache; + while(entry != NULL){ + entry->count=0; + next_entry = entry->next; + if((now.tv_sec - entry->tv.tv_sec) + > entry->ctrl_info.holding_time){ + ip = (unsigned char*)&entry->ctrl_info.in_dst_ip; + dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + in_cache_remove(entry, client); + } + entry = next_entry; + } + write_unlock_irqrestore(&client->ingress_lock, flags); + + return; +} + +/* Call this every MPC-p4 seconds. */ + +static void check_resolving_entries( struct mpoa_client * client ) +{ + + struct atm_mpoa_qos *qos; + unsigned long flags; + in_cache_entry *entry; + struct timeval now; + struct k_message msg; + + do_gettimeofday( &now ); + + read_lock_irqsave(&client->ingress_lock, flags); + entry = client->in_cache; + while( entry != NULL ){ + if(entry->entry_state == INGRESS_RESOLVING){ + if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){ + entry = entry->next; /* Entry in hold down */ + continue; + } + if( (now.tv_sec - entry->reply_wait.tv_sec) > + entry->retry_time ){ + entry->retry_time = MPC_C1*( entry->retry_time ); + if(entry->retry_time > client->parameters.mpc_p5){ + /* Retry time maximum exceeded, put entry in hold down. */ + do_gettimeofday(&(entry->hold_down)); + entry->retry_time = client->parameters.mpc_p4; + entry = entry->next; + continue; + } + /* Ask daemon to send a resolution request. */ + memset(&(entry->hold_down),0,sizeof(struct timeval)); + msg.type = SND_MPOA_RES_RTRY; + memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); + msg.content.in_info = entry->ctrl_info; + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; + msg_to_mpoad(&msg, client); + do_gettimeofday(&(entry->reply_wait)); + } + } + entry = entry->next; + } + read_unlock_irqrestore(&client->ingress_lock, flags); +} + +/* Call this every MPC-p5 seconds. */ + +static void refresh_entries( struct mpoa_client * client ) +{ + unsigned long flags; + struct timeval now; + struct in_cache_entry *entry = client->in_cache; + + ddprintk("mpoa: mpoa_caches.c: refresh_entries\n"); + do_gettimeofday(&now); + + read_lock_irqsave(&client->ingress_lock, flags); + while( entry != NULL ){ + if( entry->entry_state == INGRESS_RESOLVED ){ + if(!(entry->refresh_time)) + entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3; + if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){ + dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); + entry->entry_state = INGRESS_REFRESHING; + + } + } + entry = entry->next; + } + read_unlock_irqrestore(&client->ingress_lock, flags); +} + +static eg_cache_entry *eg_cache_search_by_cache_id(uint32_t cache_id, + struct mpoa_client *client) +{ + eg_cache_entry *entry; + unsigned long flags; + + read_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while(entry != NULL){ + if( entry->ctrl_info.cache_id == cache_id){ + read_unlock_irqrestore(&client->egress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->egress_lock, flags); + + return NULL; +} + +static eg_cache_entry *eg_cache_search_by_tag(uint32_t tag, + struct mpoa_client *client) +{ + unsigned long flags; + eg_cache_entry *entry; + + read_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while(entry != NULL){ + if( entry->ctrl_info.tag == tag){ + read_unlock_irqrestore(&client->egress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->egress_lock, flags); + + return NULL; +} + +static eg_cache_entry *eg_cache_search_by_vcc(struct atm_vcc *vcc, + struct mpoa_client *client ) +{ + unsigned long flags; + eg_cache_entry *entry; + + read_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while( entry != NULL ){ + if( entry->shortcut == vcc ) { + read_unlock_irqrestore(&client->egress_lock, flags); + return entry; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->egress_lock, flags); + + return NULL; +} + +static eg_cache_entry *eg_cache_search_by_src_ip(uint32_t ipaddr, + struct mpoa_client *client) +{ + unsigned long flags; + eg_cache_entry *entry; + + read_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while( entry != NULL ){ + if(entry->latest_ip_addr == ipaddr) { + break; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->egress_lock, flags); + + return entry; +} + +/* + * If there are no more references to vcc in ingress cache, + * we are ready to close it. + */ +static void close_unused_ingress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) +{ + if (vcc == NULL) + return; + + dprintk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:\n"); + if (mpc->in_ops->search_by_vcc(vcc, mpc) != NULL) + return; /* entry still in use */ + + atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */ + dprintk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:, closed one\n"); + + return; +} +/* + * This should be called with write lock on + */ +static int eg_cache_remove(eg_cache_entry *entry, + struct mpoa_client *client) +{ + struct atm_vcc *vcc; + struct k_message msg; + if(entry == NULL) + return 0; + + vcc = entry->shortcut; + dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n"); + if (entry->prev != NULL) + entry->prev->next = entry->next; + else + client->eg_cache = entry->next; + if (entry->next != NULL) + entry->next->prev = entry->prev; + memset(entry, 0, sizeof(eg_cache_entry)); + kfree(entry); + if(client->in_cache == NULL && client->eg_cache == NULL){ + msg.type = STOP_KEEP_ALIVE_SM; + msg_to_mpoad(&msg,client); + } + + close_unused_ingress_vcc(vcc, client); + + return 1; +} + +static eg_cache_entry *new_eg_cache_entry(struct k_message *msg, struct mpoa_client *client) +{ + unsigned long flags; + unsigned char *ip; + eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL); + + if (entry == NULL) { + printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n"); + return NULL; + } + + ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip; + dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %d.%d.%d.%d, this should be our IP\n", ip[0], ip[1], ip[2], ip[3]); + memset(entry, 0, sizeof(eg_cache_entry)); + + dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); + write_lock_irqsave(&client->egress_lock, flags); + entry->next = client->eg_cache; + entry->prev = NULL; + if (client->eg_cache != NULL) + client->eg_cache->prev = entry; + client->eg_cache = entry; + write_unlock_irqrestore(&client->egress_lock, flags); + dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n"); + + memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); + entry->ctrl_info = msg->content.eg_info; + do_gettimeofday(&(entry->tv)); + entry->entry_state = EGRESS_RESOLVED; + dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); + ip = (unsigned char *)&entry->ctrl_info.mps_ip; + dprintk("mpoa: mpoa_caches.c: mps_ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + return entry; +} + +static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time) +{ + do_gettimeofday(&(entry->tv)); + entry->entry_state = EGRESS_RESOLVED; + entry->ctrl_info.holding_time = holding_time; + + return; +} + +static void clear_expired(struct mpoa_client *client){ + eg_cache_entry *entry, *next_entry; + unsigned long flags; + struct timeval now; + struct k_message msg; + + do_gettimeofday(&now); + + write_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while(entry != NULL){ + next_entry = entry->next; + if((now.tv_sec - entry->tv.tv_sec) + > entry->ctrl_info.holding_time){ + msg.type = SND_EGRESS_PURGE; + msg.content.eg_info = entry->ctrl_info; + dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); + msg_to_mpoad(&msg, client); + eg_cache_remove(entry, client); + } + entry = next_entry; + } + write_unlock_irqrestore(&client->egress_lock, flags); + + return; +} + + + +static struct in_cache_ops ingress_ops = { + new_in_cache_entry, /* new_entry */ + in_cache_search, /* search */ + in_cache_search_with_mask, /* search_with_mask */ + in_cache_search_by_vcc, /* search_by_vcc */ + cache_hit, /* cache_hit */ + in_cache_remove, /* cache_remove */ + clear_count_and_expired, /* clear_count */ + check_resolving_entries, /* check_resolving */ + refresh_entries, /* refresh */ +}; + +static struct eg_cache_ops egress_ops = { + new_eg_cache_entry, /* new_entry */ + eg_cache_search_by_cache_id, /* search_by_cache_id */ + eg_cache_search_by_tag, /* search_by_tag */ + eg_cache_search_by_vcc, /* search_by_vcc */ + eg_cache_search_by_src_ip, /* search_by_src_ip */ + eg_cache_remove, /* cache_remove */ + update_eg_cache_entry, /* update */ + clear_expired /* clear_expired */ +}; + + +void atm_mpoa_init_cache(struct mpoa_client *mpc) +{ + mpc->in_ops = &ingress_ops; + mpc->eg_ops = &egress_ops; + + return; +} diff -u --recursive --new-file v2.3.14/linux/net/atm/mpoa_caches.h linux/net/atm/mpoa_caches.h --- v2.3.14/linux/net/atm/mpoa_caches.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/mpoa_caches.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,90 @@ +#ifndef MPOA_CACHES_H +#define MPOA_CACHES_H + +#include +#include +#include +#include +#include + +struct mpoa_client; + +void atm_mpoa_init_cache(struct mpoa_client *mpc); + +typedef struct in_cache_entry { + struct in_cache_entry *next; + struct in_cache_entry *prev; + struct timeval tv; + struct timeval reply_wait; + struct timeval hold_down; + uint32_t packets_fwded; + uint16_t entry_state; + uint32_t retry_time; + uint32_t refresh_time; + uint32_t count; + struct atm_vcc *shortcut; + uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; + struct in_ctrl_info ctrl_info; +} in_cache_entry; + +struct in_cache_ops{ + in_cache_entry *(*new_entry)(uint32_t dst_ip, + struct mpoa_client *client); + in_cache_entry *(*search)(uint32_t dst_ip, struct mpoa_client *client); + in_cache_entry *(*search_with_mask)(uint32_t dst_ip, + struct mpoa_client *client, + uint32_t mask); + in_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, + struct mpoa_client *client); + int (*cache_hit)(in_cache_entry *entry, + struct mpoa_client *client); + int (*cache_remove)(in_cache_entry *delEntry, + struct mpoa_client *client ); + void (*clear_count)(struct mpoa_client *client); + void (*check_resolving)(struct mpoa_client *client); + void (*refresh)(struct mpoa_client *client); +}; + +typedef struct eg_cache_entry{ + struct eg_cache_entry *next; + struct eg_cache_entry *prev; + struct timeval tv; + uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; + struct atm_vcc *shortcut; + uint32_t packets_rcvd; + uint16_t entry_state; + uint32_t latest_ip_addr; /* The src IP address of the last packet */ + struct eg_ctrl_info ctrl_info; +} eg_cache_entry; + +struct eg_cache_ops{ + eg_cache_entry *(*new_entry)(struct k_message *msg, struct mpoa_client *client); + eg_cache_entry *(*search_by_cache_id)(uint32_t cache_id, struct mpoa_client *client); + eg_cache_entry *(*search_by_tag)(uint32_t cache_id, struct mpoa_client *client); + eg_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); + eg_cache_entry *(*search_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client); + int (*cache_remove)(eg_cache_entry *entry, struct mpoa_client *client); + void (*update)(eg_cache_entry *entry, uint16_t holding_time); + void (*clear_expired)(struct mpoa_client *client); +}; + + +/* Ingress cache entry states */ + +#define INGRESS_REFRESHING 3 +#define INGRESS_RESOLVED 2 +#define INGRESS_RESOLVING 1 +#define INGRESS_INVALID 0 + +/* VCC states */ + +#define OPEN 1 +#define CLOSED 0 + +/* Egress cache entry states */ + +#define EGRESS_RESOLVED 2 +#define EGRESS_PURGE 1 +#define EGRESS_INVALID 0 + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/mpoa_proc.c linux/net/atm/mpoa_proc.c --- v2.3.14/linux/net/atm/mpoa_proc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/mpoa_proc.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,391 @@ +#include + +#ifdef CONFIG_PROC_FS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpc.h" +#include "mpoa_caches.h" + +/* + * mpoa_proc.c: Implementation MPOA client's proc + * file system statistics + */ + +#if 1 +#define dprintk printk /* debug */ +#else +#define dprintk(format,args...) +#endif + +#define STAT_FILE_NAME "mpc" /* Our statistic file's name */ + +extern struct mpoa_client *mpcs; +extern struct proc_dir_entry atm_proc_root; /* from proc.c. */ + +static ssize_t proc_mpc_read(struct file *file, char *buff, + size_t count, loff_t *pos); + +static ssize_t proc_mpc_write(struct file *file, const char *buff, + size_t nbytes, loff_t *ppos); + +static int parse_qos(const char *buff, int len); + +/* + * Define allowed FILE OPERATIONS + */ +static struct file_operations mpc_file_operations = { + NULL, /* lseek */ + proc_mpc_read, /* read */ + proc_mpc_write, /* write */ + NULL, /* readdir */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* no fsync */ +}; + +/* + * Define allowed INODE OPERATIONS + */ +static struct inode_operations mpc_inode_operations = { + &mpc_file_operations, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* + * Our statistics file + */ +static struct proc_dir_entry mpc_stats = { + 0, /* low_ino */ + sizeof(STAT_FILE_NAME)-1, /* name length */ + STAT_FILE_NAME, /* name */ + S_IFREG | S_IRUGO, /* mode */ + 1, /* 1=file */ + 0, /* UID */ + 0, /* GID */ + 0, /* size */ + &mpc_inode_operations, /* inode operations */ + NULL /* get_info func-ptr */ + +}; + +static int print_header(char *buff,struct mpoa_client *mpc){ + if(mpc != NULL){ + return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num); + + } + return 0; +} + +/* + * Returns the state of an ingress cache entry as a string + */ +static const char *ingress_state_string(int state){ + switch(state) { + case INGRESS_RESOLVING: + return "resolving "; + break; + case INGRESS_RESOLVED: + return "resolved "; + break; + case INGRESS_INVALID: + return "invalid "; + break; + case INGRESS_REFRESHING: + return "refreshing "; + break; + default: + return ""; + } +} + +/* + * Returns the state of an egress cache entry as a string + */ +static const char *egress_state_string(int state){ + switch(state) { + case EGRESS_RESOLVED: + return "resolved "; + break; + case EGRESS_PURGE: + return "purge "; + break; + case EGRESS_INVALID: + return "invalid "; + break; + default: + return ""; + } +} + +/* + * READING function - called when the /proc/atm/mpoa file is read from. + */ +static ssize_t proc_mpc_read(struct file *file, char *buff, + size_t count, loff_t *pos){ + unsigned long page = 0; + unsigned char *temp; + ssize_t length = 0; + int i = 0; + struct mpoa_client *mpc = mpcs; + in_cache_entry *in_entry; + eg_cache_entry *eg_entry; + struct timeval now; + unsigned char ip_string[16]; + if(count < 0) + return -EINVAL; + if(count == 0) + return 0; + page = get_free_page(GFP_KERNEL); + if(!page) + return -ENOMEM; + atm_mpoa_disp_qos((char *)page, &length); + while(mpc != NULL){ + length += print_header((char *)page + length, mpc); + length += sprintf((char *)page + length,"Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); + in_entry = mpc->in_cache; + do_gettimeofday(&now); + while(in_entry != NULL){ + temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); + length += sprintf((char *)page + length,"%-16s%s%-14lu%-12u", ip_string, ingress_state_string(in_entry->entry_state), (in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec)), in_entry->packets_fwded); + if(in_entry->shortcut) + length += sprintf((char *)page + length," %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci); + length += sprintf((char *)page + length,"\n"); + in_entry = in_entry->next; + } + length += sprintf((char *)page + length,"\n"); + eg_entry = mpc->eg_cache; + length += sprintf((char *)page + length,"Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); + while(eg_entry != NULL){ + for(i=0;ictrl_info.in_MPC_data_ATM_addr[i]);} + length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-15u",ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd); + + /* latest IP address */ + temp = (unsigned char *)&eg_entry->latest_ip_addr; + sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); + length += sprintf((char *)page + length, "%-16s", ip_string); + + if(eg_entry->shortcut) + length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); + length += sprintf((char *)page + length,"\n"); + eg_entry = eg_entry->next; + } + length += sprintf((char *)page + length,"\n"); + mpc = mpc->next; + } + + if (*pos >= length) length = 0; + else { + if ((count + *pos) > length) count = length - *pos; + copy_to_user(buff, (char *)page , count); + *pos += count; + } + + free_page(page); + return length; +} + +static ssize_t proc_mpc_write(struct file *file, const char *buff, + size_t nbytes, loff_t *ppos) +{ + int incoming, error, retval; + char *page, c; + const char *tmp; + + if (nbytes < 0) return -EINVAL; + if (nbytes == 0) return 0; + if (nbytes > PAGE_SIZE) nbytes = PAGE_SIZE-1; + + error = verify_area(VERIFY_READ, buff, nbytes); + if (error) return error; + + page = (char *)__get_free_page(GFP_KERNEL); + if (page == NULL) return -ENOMEM; + + incoming = 0; + tmp = buff; + while(incoming < nbytes){ + if (get_user(c, tmp++)) return -EFAULT; + incoming++; + if (c == '\0' || c == '\n') + break; + } + + retval = copy_from_user(page, buff, incoming); + if (retval != 0) { + printk("mpoa: proc_mpc_write: copy_from_user() failed\n"); + return -EFAULT; + } + + *ppos += incoming; + + page[incoming] = '\0'; + retval = parse_qos(buff, incoming); + if (retval == 0) + printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); + + free_page((unsigned long)page); + + return nbytes; +} + +static int parse_qos(const char *buff, int len) +{ + /* possible lines look like this + * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu + */ + + int pos, i; + uint32_t ipaddr; + unsigned char ip[4]; + char cmd[4], temp[256]; + const char *tmp, *prev; + struct atm_qos qos; + int value[5]; + + memset(&qos, 0, sizeof(struct atm_qos)); + strncpy(cmd, buff, 3); + if( strncmp(cmd,"add", 3) && strncmp(cmd,"del", 3)) + return 0; /* not add or del */ + + pos = 4; + /* next parse ip */ + prev = buff + pos; + for (i = 0; i < 3; i++) { + tmp = strchr(prev, '.'); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + ip[i] = (char)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, ' '); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + ip[i] = (char)simple_strtoul(temp, NULL, 0); + ipaddr = *(uint32_t *)ip; + + if(!strncmp(cmd, "del", 3)) + return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); + + /* next transmit values */ + tmp = strstr(buff, "tx="); + if(tmp == NULL) return 0; + tmp += 3; + prev = tmp; + for( i = 0; i < 1; i++){ + tmp = strchr(prev, ','); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, ' '); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + qos.txtp.traffic_class = ATM_CBR; + qos.txtp.max_pcr = value[0]; + qos.txtp.max_sdu = value[1]; + + /* next receive values */ + tmp = strstr(buff, "rx="); + if(tmp == NULL) return 0; + if (strstr(buff, "rx=tx")) { /* rx == tx */ + qos.rxtp.traffic_class = qos.txtp.traffic_class; + qos.rxtp.max_pcr = qos.txtp.max_pcr; + qos.rxtp.max_cdv = qos.txtp.max_cdv; + qos.rxtp.max_sdu = qos.txtp.max_sdu; + } else { + tmp += 3; + prev = tmp; + for( i = 0; i < 1; i++){ + tmp = strchr(prev, ','); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, '\0'); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + qos.rxtp.traffic_class = ATM_CBR; + qos.rxtp.max_pcr = value[0]; + qos.rxtp.max_sdu = value[1]; + } + qos.aal = ATM_AAL5; + dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", + qos.txtp.max_pcr, + qos.txtp.max_sdu, + qos.rxtp.max_pcr, + qos.rxtp.max_sdu + ); + + atm_mpoa_add_qos(ipaddr, &qos); + return 1; +} + +/* + * INITIALIZATION function - called when module is initialized/loaded. + */ +int mpc_proc_init(void) +{ + int retval = 0; + + if ( (retval = proc_register(&atm_proc_root,&mpc_stats)) != 0 ) { + printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); + return retval; + } + return 0; +} + +/* + * DELETING function - called when module is removed. + */ +void mpc_proc_clean(void) +{ + proc_unregister(&atm_proc_root,mpc_stats.low_ino); +} + + +#endif /* CONFIG_PROC_FS */ + + + + + + diff -u --recursive --new-file v2.3.14/linux/net/atm/proc.c linux/net/atm/proc.c --- v2.3.14/linux/net/atm/proc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/proc.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,617 @@ +/* net/atm/proc.c - ATM /proc interface */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + +/* + * The mechanism used here isn't designed for speed but rather for convenience + * of implementation. We only return one entry per read system call, so we can + * be reasonably sure not to overrun the page and race conditions may lead to + * the addition or omission of some lines but never to any corruption of a + * line's internal structure. + * + * Making the whole thing slightly more efficient is left as an exercise to the + * reader. (Suggestions: wrapper which loops to get several entries per system + * call; or make --left slightly more clever to avoid O(n^2) characteristics.) + * I find it fast enough on my unloaded 266 MHz Pentium 2 :-) + */ + + +#include +#include /* for EXPORT_SYMBOL */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for __initfunc */ +#include +#include /* for HZ */ +#include "resources.h" +#include "common.h" /* atm_proc_init prototype */ +#include "signaling.h" /* to get sigd - ugly too */ + +#ifdef CONFIG_AREQUIPA +#include +void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); +#endif + +#ifdef CONFIG_ATM_CLIP +#include +#include "ipcommon.h" +extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb); +#endif + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +#include "lec.h" +#include "lec_arpc.h" +extern struct atm_lane_ops atm_lane_ops; /* in common.c */ +#endif + + +static ssize_t proc_atm_read(struct file *file,char *buf,size_t count, + loff_t *pos); + + +static struct file_operations proc_atm_operations = { + NULL, /* lseek */ + proc_atm_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_atm_inode_operations = { + &proc_atm_operations, /* default ATM directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + + +#define ENTRY(name) static struct proc_dir_entry atm_proc_entry_##name = \ + { 0, sizeof(#name)-1, #name, S_IFREG | S_IRUGO, 1, 0, 0, 0, \ + &proc_atm_inode_operations, NULL } +#define REG(name) if (!error) error = proc_register(&atm_proc_root, \ + &atm_proc_entry_##name) +#define INO(name) (atm_proc_entry_##name.low_ino) + + +ENTRY(devices); +ENTRY(pvc); +ENTRY(svc); +#ifdef CONFIG_ATM_CLIP +ENTRY(arp); +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +ENTRY(lec); +#endif +#ifdef CONFIG_AREQUIPA +ENTRY(arequipa); +#endif + + +static int atm_header(ino_t ino,char *buf) +{ + if (ino == INO(devices)) + return sprintf(buf,"Itf Type ESI/\"MAC\"addr " + "AAL(TX,err,RX,err,drop) ...\n"); + if (ino == INO(pvc)) + return sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) " + "TX(PCR,Class)\n"); + if (ino == INO(svc)) + return sprintf(buf,"Itf VPI VCI State Remote\n"); +#ifdef CONFIG_ATM_CLIP + if (ino == INO(arp)) + return sprintf(buf,"IPitf TypeEncp Idle IP address " + "ATM address\n"); +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + if (ino == INO(lec)) + return sprintf(buf,"Itf MAC ATM destination" + " Status Flags " + "VPI/VCI Recv VPI/VCI\n"); +#endif +#ifdef CONFIG_AREQUIPA + if (ino == INO(arequipa)) + return sprintf(buf,"Itf VPI VCI State Sock# Inode\n"); +#endif + return -EINVAL; +} + + +static void add_stats(char *buf,const char *aal, + const struct atm_aal_stats *stats) +{ + sprintf(strchr(buf,0),"%s ( %ld %ld %ld %ld %ld )",aal,stats->tx, + stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop); +} + + +static void dev_info(const struct atm_dev *dev,char *buf) +{ + int off,i; + + off = sprintf(buf,"%3d %-8s",dev->number,dev->type); + for (i = 0; i < ESI_LEN; i++) + off += sprintf(buf+off,"%02x",dev->esi[i]); + strcat(buf," "); + add_stats(buf,"0",&dev->stats.aal0); + strcat(buf," "); + add_stats(buf,"5",&dev->stats.aal5); + strcat(buf,"\n"); +} + + +#ifdef CONFIG_ATM_CLIP + + +static int svc_addr(char *buf,struct sockaddr_atmsvc *addr) +{ + static int code[] = { 1,2,10,6,1,0 }; + static int e164[] = { 1,8,4,6,1,0 }; + int *fields; + int len,i,j,pos; + + len = 0; + if (*addr->sas_addr.pub) { + strcpy(buf,addr->sas_addr.pub); + len = strlen(addr->sas_addr.pub); + buf += len; + if (*addr->sas_addr.pub) { + *buf += '+'; + len++; + } + } + else if (!*addr->sas_addr.prv) { + strcpy(buf,"(none)"); + return strlen(buf); + } + if (*addr->sas_addr.prv) { + len += 44; + pos = 0; + fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code; + for (i = 0; fields[i]; i++) { + for (j = fields[i]; j; j--) { + sprintf(buf,"%02X",addr->sas_addr.prv[pos++]); + buf += 2; + } + if (fields[i+1]) *buf++ = '.'; + } + } + return len; +} + + +static void atmarp_info(struct net_device *dev,struct atmarp_entry *entry, + struct clip_vcc *clip_vcc,char *buf) +{ + unsigned char *ip; + int svc,off,ip_len; + + svc = !clip_vcc || clip_vcc->vcc->family == AF_ATMSVC; + off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC", + !clip_vcc || clip_vcc->encap ? "LLC" : "NULL", + (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/ + HZ); + ip = (unsigned char *) &entry->ip; + ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); + off += ip_len; + while (ip_len++ < 16) buf[off++] = ' '; + if (!clip_vcc) + if (time_before(jiffies, entry->expires)) + strcpy(buf+off,"(resolving)\n"); + else sprintf(buf+off,"(expired, ref %d)\n", + atomic_read(&entry->neigh->refcnt)); + else if (!svc) + sprintf(buf+off,"%d.%d.%d\n",clip_vcc->vcc->dev->number, + clip_vcc->vcc->vpi,clip_vcc->vcc->vci); + else { + off += svc_addr(buf+off,&clip_vcc->vcc->remote); + strcpy(buf+off,"\n"); + } +} + + +#endif + + +static void pvc_info(struct atm_vcc *vcc,char *buf) +{ + static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" }; + static const char *aal_name[] = { + "---", "1", "2", "3/4", /* 0- 3 */ + "???", "5", "???", "???", /* 4- 7 */ + "???", "???", "???", "???", /* 8-11 */ + "???", "0", "???", "???"}; /* 12-15 */ + int off; + + off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s", + vcc->dev->number,vcc->vpi,vcc->vci, + vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" : + aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr, + class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr, + class_name[vcc->qos.txtp.traffic_class]); +#ifdef CONFIG_ATM_CLIP + if (vcc->push == clip_push) { + struct clip_vcc *clip_vcc = CLIP_VCC(vcc); + struct net_device *dev; + + dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL; + off += sprintf(buf+off,"CLIP, Itf:%s, Encap:", + dev ? dev->name : "none?"); + if (clip_vcc->encap) off += sprintf(buf+off,"LLC/SNAP"); + else off += sprintf(buf+off,"None"); + } +#endif + strcpy(buf+off,"\n"); +} + + +static const char *vcc_state(struct atm_vcc *vcc) +{ + static const char *map[] = { ATM_VS2TXT_MAP }; + + return map[ATM_VF2VS(vcc->flags)]; +} + + +static void svc_info(struct atm_vcc *vcc,char *buf) +{ + char *here; + int i; + + if (!vcc->dev) sprintf(buf,"Unassigned "); + else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); + here = strchr(buf,0); + here += sprintf(here,"%-10s ",vcc_state(vcc)); + here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub, + *vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : ""); + if (*vcc->remote.sas_addr.prv) + for (i = 0; i < ATM_ESA_LEN; i++) + here += sprintf(here,"%02x", + vcc->remote.sas_addr.prv[i]); + strcat(here,"\n"); +} + + +#ifdef CONFIG_AREQUIPA + + +static const char *arequipa_state(const struct atm_vcc *vcc) +{ + if (!(vcc->flags & ATM_VF_REGIS) && vcc->family != PF_ATMPVC) + return "DOOMED"; + if (vcc->upper) return "ATTACHED"; + return "DANGLING"; +} + + +static void arequipa_info(struct atm_vcc *vcc,char *buf) +{ + char *here; + + if (!vcc->dev) sprintf(buf,"Unassigned "); + else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); + here = strchr(buf,0); + here += sprintf(here,"%-8s ",arequipa_state(vcc)); + if (vcc->upper) + here += sprintf(here,"%5d %ld",vcc->upper->num, + vcc->upper->socket && SOCK_INODE(vcc->upper->socket) ? + SOCK_INODE(vcc->upper->socket)->i_ino : 0); + strcat(here,"\n"); +} + + +#endif + + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + +static char* +lec_arp_get_status_string(unsigned char status) +{ + switch(status) { + case ESI_UNKNOWN: + return "ESI_UNKNOWN "; + case ESI_ARP_PENDING: + return "ESI_ARP_PENDING "; + case ESI_VC_PENDING: + return "ESI_VC_PENDING "; + case ESI_FLUSH_PENDING: + return "ESI_FLUSH_PENDING "; + case ESI_FORWARD_DIRECT: + return "ESI_FORWARD_DIRECT"; + default: + return " "; + } +} + +static void +lec_info(struct lec_arp_table *entry, char *buf) +{ + int j, offset=0; + + + for(j=0;jmac_addr[j]); + } + offset+=sprintf(buf+offset, " "); + for(j=0;jatm_addr[j]); + } + offset+=sprintf(buf+offset, " %s %4.4x", + lec_arp_get_status_string(entry->status), + entry->flags&0xffff); + if (entry->vcc) { + offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, + entry->vcc->vci); + } else + offset+=sprintf(buf+offset, " "); + if (entry->recv_vcc) { + offset+=sprintf(buf+offset, " %3d %3d", + entry->recv_vcc->vpi, entry->recv_vcc->vci); + } + + sprintf(buf+offset,"\n"); +} + +#endif + + +/* + * FIXME: it isn't safe to walk the VCC list without turning off interrupts. + * What is really needed is some lock on the devices. Ditto for ATMARP. + */ + +static int atm_info(ino_t ino,loff_t *pos,char *buf) +{ + struct atm_dev *dev; + struct atm_vcc *vcc; + int left; + + if (ino == INO(devices)) { + left = *pos-1; + for (dev = atm_devs; dev && left; dev = dev->next) left--; + if (!dev) return 0; + dev_info(dev,buf); + return strlen(buf); + } + if (ino == INO(pvc)) { + left = *pos-1; + for (dev = atm_devs; dev; dev = dev->next) + for (vcc = dev->vccs; vcc; vcc = vcc->next) + if (vcc->family == PF_ATMPVC && + vcc->dev && !left--) { + pvc_info(vcc,buf); + return strlen(buf); + } + return 0; + } + if (ino == INO(svc)) { + left = *pos-1; + for (dev = atm_devs; dev; dev = dev->next) + for (vcc = dev->vccs; vcc; vcc = vcc->next) + if (vcc->family == PF_ATMSVC && !left--) { + svc_info(vcc,buf); + return strlen(buf); + } + for (vcc = nodev_vccs; vcc; vcc = vcc->next) + if (vcc->family == PF_ATMSVC && !left--) { + svc_info(vcc,buf); + return strlen(buf); + } + return 0; + } +#ifdef CONFIG_ATM_CLIP + if (ino == INO(arp)) { + struct neighbour *n; + int i,count; + + count = *pos; + read_lock_bh(&clip_tbl.lock); + for (i = 0; i <= NEIGH_HASHMASK; i++) + for (n = clip_tbl.hash_buckets[i]; n; n = n->next) { + struct atmarp_entry *entry = NEIGH2ENTRY(n); + struct clip_vcc *vcc; + + if (!entry->vccs) { + if (--count) continue; + atmarp_info(n->dev,entry,NULL,buf); + read_unlock_bh(&clip_tbl.lock); + return strlen(buf); + } + for (vcc = entry->vccs; vcc; + vcc = vcc->next) { + if (--count) continue; + atmarp_info(n->dev,entry,vcc,buf); + read_unlock_bh(&clip_tbl.lock); + return strlen(buf); + } + } + read_unlock_bh(&clip_tbl.lock); + return 0; + } +#endif +#ifdef CONFIG_AREQUIPA + if (ino == INO(arequipa)) { + left = *pos-1; + for (dev = atm_devs; dev; dev = dev->next) + for (vcc = dev->vccs; vcc; vcc = vcc->next) + if (vcc->push == atm_push_arequipa && !left--) { + arequipa_info(vcc,buf); + return strlen(buf); + } + return 0; + } +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + if (ino == INO(lec)) { + struct lec_priv *priv; + struct lec_arp_table *entry; + int i, count, d, e; + struct net_device **dev_lec; + + if (atm_lane_ops.get_lecs == NULL) + return 0; /* the lane module is not there yet */ + else + dev_lec = atm_lane_ops.get_lecs(); + + count = *pos; + for(d=0;dpriv)) continue; + for(i=0;ilec_arp_tables[i]; + for(;entry;entry=entry->next) { + if (--count) continue; + e=sprintf(buf,"%s ", + dev_lec[d]->name); + lec_info(entry,buf+e); + return strlen(buf); + } + } + for(entry=priv->lec_arp_empty_ones; entry; + entry=entry->next) { + if (--count) continue; + e=sprintf(buf,"%s ",dev_lec[d]->name); + lec_info(entry, buf+e); + return strlen(buf); + } + for(entry=priv->lec_no_forward; entry; + entry=entry->next) { + if (--count) continue; + e=sprintf(buf,"%s ",dev_lec[d]->name); + lec_info(entry, buf+e); + return strlen(buf); + } + for(entry=priv->mcast_fwds; entry; + entry=entry->next) { + if (--count) continue; + e=sprintf(buf,"%s ",dev_lec[d]->name); + lec_info(entry, buf+e); + return strlen(buf); + } + } + return 0; + } +#endif + return -EINVAL; +} + + +static ssize_t proc_atm_read(struct file *file,char *buf,size_t count, + loff_t *pos) +{ + struct atm_dev *dev; + unsigned long page; + int ino = file->f_dentry->d_inode->i_ino; + int length; + + if (count < 0) return -EINVAL; + page = get_free_page(GFP_KERNEL); + if (!page) return -ENOMEM; + for (dev = atm_devs; dev; dev = dev->next) + if (dev->ops->proc_read && dev->proc_entry->low_ino == ino) + break; + if (dev) length = dev->ops->proc_read(dev,pos,(char *) page); + else if (*pos) length = atm_info(ino,pos,(char *) page); + else length = atm_header(ino,(char *) page); + if (length > count) length = -EINVAL; + if (length >= 0) { + if (copy_to_user(buf,(char *) page,length)) length = -EFAULT; + (*pos)++; + } + free_page(page); + return length; +} + + +struct proc_dir_entry atm_proc_root = { 0, 3, "atm", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, 0, &proc_dir_inode_operations, + NULL, NULL, NULL, NULL, NULL }; + + +EXPORT_SYMBOL(atm_proc_root); + + +int atm_proc_dev_register(struct atm_dev *dev) +{ + ENTRY(template); + int digits,num; + int error; + + error = -ENOMEM; + digits = 0; + for (num = dev->number; num; num /= 10) digits++; + if (!digits) digits++; + dev->proc_entry = kmalloc(sizeof(*dev->proc_entry),GFP_KERNEL); + if (!dev->proc_entry) goto fail0; + dev->proc_name = kmalloc(strlen(dev->type)+digits+2,GFP_KERNEL); + if (!dev->proc_name) goto fail1; + *dev->proc_entry = atm_proc_entry_template; + dev->proc_entry->name = dev->proc_name; + dev->proc_entry->namelen = sprintf(dev->proc_name,"%s:%d",dev->type, + dev->number); + error = proc_register(&atm_proc_root,dev->proc_entry); + if (!error) return 0; + kfree(dev->proc_name); +fail1: + kfree(dev->proc_entry); +fail0: + return error; +} + + +void atm_proc_dev_deregister(struct atm_dev *dev) +{ + proc_unregister(&atm_proc_root,dev->proc_entry->low_ino); + kfree(dev->proc_entry); + kfree(dev->proc_name); +} + + +__initfunc(int atm_proc_init(void)) +{ + int error; + + error = proc_register(&proc_root,&atm_proc_root); + REG(devices); + REG(pvc); + REG(svc); +#ifdef CONFIG_ATM_CLIP + REG(arp); +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + REG(lec); +#endif +#ifdef CONFIG_AREQUIPA + REG(arequipa); +#endif + return error; +} diff -u --recursive --new-file v2.3.14/linux/net/atm/protocols.h linux/net/atm/protocols.h --- v2.3.14/linux/net/atm/protocols.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/protocols.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,16 @@ +/* net/atm/protocols.h - ATM protocol handler entry points */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + +#ifndef NET_ATM_PROTOCOLS_H +#define NET_ATM_PROTOCOLS_H + +void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb); + +int atm_init_aal0(struct atm_vcc *vcc); /* "raw" AAL0 */ +int atm_init_aal34(struct atm_vcc *vcc);/* "raw" AAL3/4 transport */ +int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ +int atm_init_atmarp(struct atm_vcc *vcc);/* ATM ARP */ + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/pvc.c linux/net/atm/pvc.c --- v2.3.14/linux/net/atm/pvc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/pvc.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,166 @@ +/* net/atm/pvc.c - ATM PVC sockets */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include /* struct socket, struct net_proto, + struct proto_ops */ +#include /* ATM stuff */ +#include /* ATM devices */ +#include /* Classical IP over ATM */ +#include /* error codes */ +#include /* printk */ +#include +#include +#include /* for sock_no_* */ +#ifdef CONFIG_AREQUIPA +#include +#endif +#ifdef CONFIG_ATM_CLIP +#include +#endif + +#include "resources.h" /* devs and vccs */ +#include "common.h" /* common for PVCs and SVCs */ + +#ifndef NULL +#define NULL 0 +#endif + + +static int pvc_shutdown(struct socket *sock,int how) +{ + return 0; +} + + +static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, + int sockaddr_len) +{ + struct sockaddr_atmpvc *addr; + struct atm_vcc *vcc; + + if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; + addr = (struct sockaddr_atmpvc *) sockaddr; + if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; + vcc = ATM_SD(sock); + if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (vcc->flags & ATM_VF_PARTIAL) { + if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; + if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; + } + return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, + addr->sap_addr.vci); +} + + +static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, + int sockaddr_len,int flags) +{ + return pvc_bind(sock,sockaddr,sockaddr_len); +} + + +static int pvc_listen(struct socket *sock,int backlog) +{ + return -EOPNOTSUPP; +} + + +static int pvc_accept(struct socket *sock,struct socket *newsock,int flags) +{ + return -EOPNOTSUPP; +} + + +static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, + int *sockaddr_len,int peer) +{ + struct sockaddr_atmpvc *addr; + struct atm_vcc *vcc; + +#if 0 /* add some sanity checks later ... @@@ */ + if (sock->state != SS_CONNECTED) return -EINVAL; +#endif + *sockaddr_len = sizeof(struct sockaddr_atmpvc); + addr = (struct sockaddr_atmpvc *) sockaddr; + vcc = ATM_SD(sock); + addr->sap_family = AF_ATMPVC; + addr->sap_addr.itf = vcc->dev->number; + addr->sap_addr.vpi = vcc->vpi; + addr->sap_addr.vci = vcc->vci; + return 0; +} + + +static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { + PF_ATMPVC, + atm_release, + pvc_bind, + pvc_connect, + sock_no_socketpair, + pvc_accept, + pvc_getname, + atm_poll, + atm_ioctl, + pvc_listen, + pvc_shutdown, + atm_setsockopt, + atm_getsockopt, + sock_no_fcntl, + atm_sendmsg, + atm_recvmsg, + sock_no_mmap +}; + +#include +SOCKOPS_WRAP(pvc_proto, PF_ATMPVC); + + +static int pvc_create(struct socket *sock,int protocol) +{ + sock->ops = &pvc_proto_ops; + return atm_create(sock,protocol,PF_ATMPVC); +} + + +static struct net_proto_family pvc_family_ops = { + PF_ATMPVC, + pvc_create, + 0, /* no authentication */ + 0, /* no encryption */ + 0 /* no encrypt_net */ +}; + + +/* + * Initialize the ATM PVC protocol family + */ + + +__initfunc(void atmpvc_proto_init(struct net_proto *pro)) +{ + int error; + + error = sock_register(&pvc_family_ops); + if (error < 0) { + printk(KERN_ERR "ATMPVC: can't register (%d)",error); + return; + } +#ifdef CONFIG_ATM_CLIP + clip_tbl.lock = RW_LOCK_UNLOCKED; + if (clip_tbl.kmem_cachep == NULL) + clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id, + clip_tbl.entry_size, + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); +#endif +#ifdef CONFIG_AREQUIPA + (void) atm_init_arequipa(); +#endif +#ifdef CONFIG_PROC_FS + error = atm_proc_init(); + if (error) printk("atm_proc_init fails with %d\n",error); +#endif +} diff -u --recursive --new-file v2.3.14/linux/net/atm/raw.c linux/net/atm/raw.c --- v2.3.14/linux/net/atm/raw.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/raw.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,80 @@ +/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC */ + + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MMU_HACKS +#include +#include +#endif + +#include "common.h" +#include "protocols.h" +#include "tunable.h" /* tunable parameters */ + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +/* + * SKB == NULL indicates that the link is being closed + */ + +void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) +{ + if (skb) { + skb_queue_tail(&vcc->recvq,skb); + wake_up(&vcc->sleep); + } +} + + +static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) +{ +#ifdef CONFIG_MMU_HACKS + if (ATM_SKB(skb)->iovcnt) + unlock_user(ATM_SKB(skb)->iovcnt,(struct iovec *) skb->data); +#endif + DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize); + atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); + dev_kfree_skb(skb); + wake_up(&vcc->wsleep); +} + + +int atm_init_aal0(struct atm_vcc *vcc) +{ + vcc->push = atm_push_raw; + vcc->pop = atm_pop_raw; + vcc->push_oam = NULL; + return 0; +} + + +int atm_init_aal34(struct atm_vcc *vcc) +{ + vcc->push = atm_push_raw; + vcc->pop = atm_pop_raw; + vcc->push_oam = NULL; + return 0; +} + + +int atm_init_aal5(struct atm_vcc *vcc) +{ + vcc->push = atm_push_raw; + vcc->pop = atm_pop_raw; + vcc->push_oam = NULL; + return 0; +} diff -u --recursive --new-file v2.3.14/linux/net/atm/resources.c linux/net/atm/resources.c --- v2.3.14/linux/net/atm/resources.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/resources.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,202 @@ +/* net/atm/resources.c - Staticly allocated resources */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include /* for barrier */ +#include +#include /* for struct sock */ +#include /* for get_fs_long and put_fs_long */ + +#include "common.h" +#include "resources.h" + + +#ifndef NULL +#define NULL 0 +#endif + + +struct atm_dev *atm_devs = NULL; +static struct atm_dev *last_dev = NULL; +struct atm_vcc *nodev_vccs = NULL; + + +static struct atm_dev *alloc_atm_dev(const char *type) +{ + struct atm_dev *dev; + + dev = kmalloc(sizeof(*dev),GFP_KERNEL); + if (!dev) return NULL; + memset(dev,0,sizeof(*dev)); + dev->type = type; + dev->prev = last_dev; + dev->signal = ATM_PHY_SIG_UNKNOWN; + dev->link_rate = ATM_OC3_PCR; + dev->next = NULL; + if (atm_devs) last_dev->next = dev; + else atm_devs = dev; + last_dev = dev; + return dev; +} + + +static void free_atm_dev(struct atm_dev *dev) +{ + if (dev->prev) dev->prev->next = dev->next; + else atm_devs = dev->next; + if (dev->next) dev->next->prev = dev->prev; + else last_dev = dev->prev; + kfree(dev); +} + + +struct atm_dev *atm_find_dev(int number) +{ + struct atm_dev *dev; + + for (dev = atm_devs; dev; dev = dev->next) + if (dev->ops && dev->number == number) return dev; + return NULL; +} + + +struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, + int number,unsigned long flags) +{ + struct atm_dev *dev; + + dev = alloc_atm_dev(type); + if (!dev) { + printk(KERN_ERR "atm_dev_register: no space for dev %s\n", + type); + return NULL; + } + if (number != -1) { + if (atm_find_dev(number)) { + free_atm_dev(dev); + return NULL; + } + dev->number = number; + } + else { + dev->number = 0; + while (atm_find_dev(dev->number)) dev->number++; + } + dev->vccs = dev->last = NULL; + dev->dev_data = NULL; + barrier(); + dev->ops = ops; + dev->flags = flags; + memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats)); +#ifdef CONFIG_PROC_FS + if (ops->proc_read) + if (atm_proc_dev_register(dev) < 0) { + printk(KERN_ERR "atm_dev_register: " + "atm_proc_dev_register failed for dev %s\n",type); + free_atm_dev(dev); + return NULL; + } +#endif + return dev; +} + + +void atm_dev_deregister(struct atm_dev *dev) +{ +#ifdef CONFIG_PROC_FS + if (dev->ops->proc_read) atm_proc_dev_deregister(dev); +#endif + free_atm_dev(dev); +} + + +void shutdown_atm_dev(struct atm_dev *dev) +{ + if (dev->vccs) { + dev->flags |= ATM_DF_CLOSE; + return; + } + if (dev->ops->dev_close) dev->ops->dev_close(dev); + atm_dev_deregister(dev); +} + + +/* Handler for sk->destruct, invoked by sk_free() */ +static void atm_free_sock(struct sock *sk) +{ + kfree(sk->protinfo.af_atm); +} + + +struct sock *alloc_atm_vcc_sk(int family) +{ + struct sock *sk; + struct atm_vcc *vcc; + + sk = sk_alloc(family, GFP_KERNEL, 1); + if (!sk) return NULL; + vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL); + if (!vcc) { + sk_free(sk); + return NULL; + } + sk->destruct = atm_free_sock; + memset(vcc,0,sizeof(*vcc)); + if (nodev_vccs) nodev_vccs->prev = vcc; + vcc->prev = NULL; + vcc->next = nodev_vccs; + nodev_vccs = vcc; + return sk; +} + + +static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev) +{ + if (vcc->prev) vcc->prev->next = vcc->next; + else if (vcc->dev) vcc->dev->vccs = vcc->next; + else nodev_vccs = vcc->next; + if (vcc->next) vcc->next->prev = vcc->prev; + else if (vcc->dev) vcc->dev->last = vcc->prev; + if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs && + (vcc->dev->flags & ATM_DF_CLOSE)) + shutdown_atm_dev(vcc->dev); +} + + +void free_atm_vcc_sk(struct sock *sk) +{ + unlink_vcc(sk->protinfo.af_atm,NULL); + sk_free(sk); +} + + +void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev) +{ + unlink_vcc(vcc,dev); + vcc->dev = dev; + if (dev) { + vcc->next = NULL; + vcc->prev = dev->last; + if (dev->vccs) dev->last->next = vcc; + else dev->vccs = vcc; + dev->last = vcc; + } + else { + if (nodev_vccs) nodev_vccs->prev = vcc; + vcc->next = nodev_vccs; + vcc->prev = NULL; + nodev_vccs = vcc; + } +} + + +EXPORT_SYMBOL(atm_dev_register); +EXPORT_SYMBOL(atm_dev_deregister); +EXPORT_SYMBOL(atm_find_dev); +EXPORT_SYMBOL(shutdown_atm_dev); +EXPORT_SYMBOL(bind_vcc); diff -u --recursive --new-file v2.3.14/linux/net/atm/resources.h linux/net/atm/resources.h --- v2.3.14/linux/net/atm/resources.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/resources.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,32 @@ +/* net/atm/resources.h - ATM-related resources */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_RESOURCES_H +#define NET_ATM_RESOURCES_H + +#include +#include + + +extern struct atm_dev *atm_devs; +extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */ + + +struct sock *alloc_atm_vcc_sk(int family); +void free_atm_vcc_sk(struct sock *sk); + + +#ifdef CONFIG_PROC_FS + +#include + +extern struct proc_dir_entry atm_proc_root; /* @@@ move elsewhere */ + +int atm_proc_dev_register(struct atm_dev *dev); +void atm_proc_dev_deregister(struct atm_dev *dev); + +#endif + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/signaling.c linux/net/atm/signaling.c --- v2.3.14/linux/net/atm/signaling.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/signaling.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,258 @@ +/* net/atm/signaling.c - ATM signaling */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include /* error codes */ +#include /* printk */ +#include +#include +#include /* jiffies and HZ */ +#include /* ATM stuff */ +#include +#include +#include + +#include "tunable.h" +#include "resources.h" +#include "signaling.h" + + +#undef WAIT_FOR_DEMON /* #define this if system calls on SVC sockets + should block until the demon runs. + Danger: may cause nasty hangs if the demon + crashes. */ + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +struct atm_vcc *sigd = NULL; +static wait_queue_head_t sigd_sleep; + + +static void sigd_put_skb(struct sk_buff *skb) +{ +#ifdef WAIT_FOR_DEMON + static unsigned long silence = 0; +#endif + + while (!sigd) { +#ifdef WAIT_FOR_DEMON + if (time_after(jiffies, silence) || silence == 0) { + printk(KERN_INFO "atmsvc: waiting for signaling demon " + "...\n"); + silence = (jiffies+30*HZ)|1; + } + sleep_on(&sigd_sleep); +#else + printk(KERN_WARNING "atmsvc: no signaling demon\n"); + kfree_skb(skb); + return; +#endif + } + atm_force_charge(sigd,skb->truesize); + skb_queue_tail(&sigd->recvq,skb); + wake_up(&sigd->sleep); +} + + +static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg) +{ + struct sk_buff *skb; + + if ((vcc->flags & ATM_VF_RELEASED) || !(vcc->flags & ATM_VF_READY)) + return; + msg->type = as_error; + if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP; + else { + /* should lock VCC */ + msg->reply = vcc->dev->ops->change_qos(vcc,&msg->qos, + msg->reply); + if (!msg->reply) msg->type = as_okay; + } + /* + * Should probably just turn around the old skb. But the, the buffer + * space accounting needs to follow the change too. Maybe later. + */ + while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) + schedule(); + *(struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)) = *msg; + sigd_put_skb(skb); +} + + +static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ + struct atmsvc_msg *msg; + struct atm_vcc *session_vcc; + + msg = (struct atmsvc_msg *) skb->data; + atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); + DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,msg->vcc); + vcc = (struct atm_vcc *) msg->vcc; + switch (msg->type) { + case as_okay: + vcc->reply = msg->reply; + if (!*vcc->local.sas_addr.prv && + !*vcc->local.sas_addr.pub) { + vcc->local.sas_family = AF_ATMSVC; + memcpy(vcc->local.sas_addr.prv, + msg->local.sas_addr.prv,ATM_ESA_LEN); + memcpy(vcc->local.sas_addr.pub, + msg->local.sas_addr.pub,ATM_E164_LEN+1); + } + session_vcc = vcc->session ? vcc->session : vcc; + if (session_vcc->vpi || session_vcc->vci) break; + session_vcc->itf = msg->pvc.sap_addr.itf; + session_vcc->vpi = msg->pvc.sap_addr.vpi; + session_vcc->vci = msg->pvc.sap_addr.vci; + if (session_vcc->vpi || session_vcc->vci) + session_vcc->qos = msg->qos; + break; + case as_error: + vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY); + vcc->reply = msg->reply; + break; + case as_indicate: + vcc = (struct atm_vcc *) msg->listen_vcc; + DPRINTK("as_indicate!!!\n"); + if (!vcc->backlog_quota) { + sigd_enq(0,as_reject,vcc,NULL,NULL); + return 0; + } + vcc->backlog_quota--; + skb_queue_tail(&vcc->listenq,skb); + if (vcc->callback) { + DPRINTK("waking vcc->sleep 0x%p\n", + &vcc->sleep); + vcc->callback(vcc); + } + return 0; + case as_close: + vcc->flags |= ATM_VF_RELEASED; + vcc->flags &= ~ATM_VF_READY; + vcc->reply = msg->reply; + break; + case as_modify: + modify_qos(vcc,msg); + break; + default: + printk(KERN_ALERT "sigd_send: bad message type %d\n", + (int) msg->type); + return -EINVAL; + } + if (vcc->callback) vcc->callback(vcc); + dev_kfree_skb(skb); + return 0; +} + + +void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, + const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, + const struct sockaddr_atmsvc *svc) +{ + struct sk_buff *skb; + struct atmsvc_msg *msg; + + DPRINTK("sigd_enq %d (0x%p)\n",(int) type,vcc); + while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) + schedule(); + msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)); + msg->type = type; + msg->vcc = (unsigned long) vcc; + msg->listen_vcc = (unsigned long) listen_vcc; + msg->reply = 0; /* other ISP applications may use this field */ + if (vcc) { + msg->qos = vcc->qos; + msg->sap = vcc->sap; + } + if (!svc) msg->svc.sas_family = 0; + else msg->svc = *svc; + if (vcc) msg->local = vcc->local; + if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc)); + else msg->pvc = *pvc; + sigd_put_skb(skb); + if (vcc) vcc->flags |= ATM_VF_REGIS; +} + + +static void purge_vccs(struct atm_vcc *vcc) +{ + while (vcc) { + if (vcc->family == PF_ATMSVC && + !(vcc->flags & ATM_VF_META)) { + vcc->flags |= ATM_VF_RELEASED; + vcc->reply = -EUNATCH; + wake_up(&vcc->sleep); + } + vcc = vcc->next; + } +} + + +static void sigd_close(struct atm_vcc *vcc) +{ + struct sk_buff *skb; + struct atm_dev *dev; + + DPRINTK("sigd_close\n"); + sigd = NULL; + if (skb_peek(&vcc->recvq)) + printk(KERN_ERR "sigd_close: closing with requests pending\n"); + while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb); + purge_vccs(nodev_vccs); + for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs); +} + + +static struct atmdev_ops sigd_dev_ops = { + NULL, /* no dev_close */ + NULL, /* no open */ + sigd_close, /* close */ + NULL, /* no ioctl */ + NULL, /* no getsockopt */ + NULL, /* no setsockopt */ + sigd_send, /* send */ + NULL, /* no sg_send */ + NULL, /* no send_oam */ + NULL, /* no phy_put */ + NULL, /* no phy_get */ + NULL, /* no feedback */ + NULL, /* no change_qos */ + NULL /* no free_rx_skb */ +}; + + +static struct atm_dev sigd_dev = { + &sigd_dev_ops, + NULL, /* no PHY */ + "sig", /* type */ + 999, /* dummy device number */ + NULL,NULL, /* pretend not to have any VCCs */ + NULL,NULL, /* no data */ + 0, /* no flags */ + NULL, /* no local address */ + { 0 } /* no ESI, no statistics */ +}; + + +int sigd_attach(struct atm_vcc *vcc) +{ + if (sigd) return -EADDRINUSE; + DPRINTK("sigd_attach\n"); + sigd = vcc; + bind_vcc(vcc,&sigd_dev); + vcc->flags |= ATM_VF_READY | ATM_VF_META; + wake_up(&sigd_sleep); + return 0; +} + + +void signaling_init(void) +{ + init_waitqueue_head(&sigd_sleep); +} diff -u --recursive --new-file v2.3.14/linux/net/atm/signaling.h linux/net/atm/signaling.h --- v2.3.14/linux/net/atm/signaling.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/signaling.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,26 @@ +/* net/atm/signaling.h - ATM signaling */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_SIGNALING_H +#define NET_ATM_SIGNALING_H + +#include +#include +#include + + +#define WAITING 1 /* for reply: 0: no error, < 0: error, ... */ + + +extern struct atm_vcc *sigd; /* needed in svc_release */ + + +void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, + const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, + const struct sockaddr_atmsvc *svc); +int sigd_attach(struct atm_vcc *vcc); +void signaling_init(void); + +#endif diff -u --recursive --new-file v2.3.14/linux/net/atm/svc.c linux/net/atm/svc.c --- v2.3.14/linux/net/atm/svc.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/svc.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,397 @@ +/* net/atm/svc.c - ATM SVC sockets */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include /* struct socket, struct net_proto, + struct proto_ops */ +#include /* error codes */ +#include /* printk */ +#include +#include +#include /* jiffies and HZ */ +#include /* O_NONBLOCK */ +#include +#include /* ATM stuff */ +#include +#include +#include +#include /* for sock_no_* */ +#include + +#include "resources.h" +#include "common.h" /* common for PVCs and SVCs */ +#include "signaling.h" +#include "addr.h" + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +static int svc_create(struct socket *sock,int protocol); + + +/* + * Note: since all this is still nicely synchronized with the signaling demon, + * there's no need to protect sleep loops with clis. If signaling is + * moved into the kernel, that would change. + */ + + +void svc_callback(struct atm_vcc *vcc) +{ + wake_up(&vcc->sleep); +} + + + + +static int svc_shutdown(struct socket *sock,int how) +{ + return 0; +} + + +static void svc_disconnect(struct atm_vcc *vcc) +{ + struct sk_buff *skb; + + DPRINTK("svc_disconnect %p\n",vcc); + if (vcc->flags & ATM_VF_REGIS) { + sigd_enq(vcc,as_close,NULL,NULL,NULL); + while (!(vcc->flags & ATM_VF_RELEASED) && sigd) + sleep_on(&vcc->sleep); + } + /* beware - socket is still in use by atmsigd until the last + as_indicate has been answered */ + while ((skb = skb_dequeue(&vcc->listenq))) { + DPRINTK("LISTEN REL\n"); + sigd_enq(NULL,as_reject,vcc,NULL,NULL); /* @@@ should include + the reason */ + dev_kfree_skb(skb); + } + vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED | ATM_VF_CLOSE); + /* may retry later */ +} + + +static int svc_release(struct socket *sock) +{ + struct atm_vcc *vcc; + + if (!sock->sk) return 0; + vcc = ATM_SD(sock); + DPRINTK("svc_release %p\n",vcc); + vcc->flags &= ~ATM_VF_READY; + atm_release_vcc_sk(sock->sk,0); + svc_disconnect(vcc); + /* VCC pointer is used as a reference, so we must not free it + (thereby subjecting it to re-use) before all pending connections + are closed */ + free_atm_vcc_sk(sock->sk); + return 0; +} + + +static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, + int sockaddr_len) +{ + struct sockaddr_atmsvc *addr; + struct atm_vcc *vcc; + + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; + if (sock->state == SS_CONNECTED) return -EISCONN; + if (sock->state != SS_UNCONNECTED) return -EINVAL; + vcc = ATM_SD(sock); + if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + addr = (struct sockaddr_atmsvc *) sockaddr; + if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; + vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */ + /* @@@ check memory (de)allocation on rebind */ + if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + vcc->local = *addr; + vcc->reply = WAITING; + sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); + while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); + vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */ + if (!sigd) return -EUNATCH; + if (!vcc->reply) vcc->flags |= ATM_VF_BOUND; + return vcc->reply; +} + + +static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, + int sockaddr_len,int flags) +{ + struct sockaddr_atmsvc *addr; + struct atm_vcc *vcc = ATM_SD(sock); + int error; + + DPRINTK("svc_connect %p\n",vcc); + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; + if (sock->state == SS_CONNECTED) return -EISCONN; + if (sock->state == SS_CONNECTING) { + if (vcc->reply == WAITING) return -EALREADY; + sock->state = SS_UNCONNECTED; + if (vcc->reply) return vcc->reply; + } + else { + if (sock->state != SS_UNCONNECTED) return -EINVAL; + if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + addr = (struct sockaddr_atmsvc *) sockaddr; + if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; + if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || + vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) + return -EINVAL; + if (!vcc->qos.txtp.traffic_class && + !vcc->qos.rxtp.traffic_class) return -EINVAL; + vcc->remote = *addr; + vcc->reply = WAITING; + sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); + if (flags & O_NONBLOCK) { + sock->state = SS_CONNECTING; + return -EINPROGRESS; + } + while (vcc->reply == WAITING && sigd) { + interruptible_sleep_on(&vcc->sleep); + if (signal_pending(current)) { + DPRINTK("*ABORT*\n"); + /* + * This is tricky: + * Kernel ---close--> Demon + * Kernel <--close--- Demon + * or + * Kernel ---close--> Demon + * Kernel <--error--- Demon + * or + * Kernel ---close--> Demon + * Kernel <--okay---- Demon + * Kernel <--close--- Demon + */ + sigd_enq(vcc,as_close,NULL,NULL,NULL); + while (vcc->reply == WAITING && sigd) + sleep_on(&vcc->sleep); + if (!vcc->reply) + while (!(vcc->flags & ATM_VF_RELEASED) + && sigd) sleep_on(&vcc->sleep); + vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED + | ATM_VF_CLOSE); + /* we're gone now but may connect later */ + return -EINTR; + } + } + if (!sigd) return -EUNATCH; + if (vcc->reply) return vcc->reply; + } +/* + * Not supported yet + * + * #ifndef CONFIG_SINGLE_SIGITF + */ + vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); + vcc->qos.txtp.pcr = 0; + vcc->qos.txtp.min_pcr = 0; +/* + * #endif + */ + if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) + sock->state = SS_CONNECTED; + else (void) svc_disconnect(vcc); + return error; +} + + +static int svc_listen(struct socket *sock,int backlog) +{ + struct atm_vcc *vcc = ATM_SD(sock); + + DPRINTK("svc_listen %p\n",vcc); + /* let server handle listen on unbound sockets */ + if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + vcc->reply = WAITING; + sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); + while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); + if (!sigd) return -EUNATCH; + vcc->flags |= ATM_VF_LISTEN; + vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; + return vcc->reply; +} + + +static int svc_accept(struct socket *sock,struct socket *newsock,int flags) +{ + struct sk_buff *skb; + struct atmsvc_msg *msg; + struct atm_vcc *old_vcc = ATM_SD(sock); + struct atm_vcc *new_vcc; + int error; + + error = svc_create(newsock,0); + if (error) + return error; + + new_vcc = ATM_SD(newsock); + + DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); + while (1) { + while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { + if (old_vcc->flags & ATM_VF_RELEASED) break; + if (old_vcc->flags & ATM_VF_CLOSE) + return old_vcc->reply; + if (flags & O_NONBLOCK) return -EAGAIN; + interruptible_sleep_on(&old_vcc->sleep); + if (signal_pending(current)) return -ERESTARTSYS; + } + if (!skb) return -EUNATCH; + msg = (struct atmsvc_msg *) skb->data; + new_vcc->qos = msg->qos; + new_vcc->flags |= ATM_VF_HASQOS; + new_vcc->remote = msg->svc; + new_vcc->sap = msg->sap; + error = atm_connect(newsock,msg->pvc.sap_addr.itf, + msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); + dev_kfree_skb(skb); + old_vcc->backlog_quota++; + if (error) { + sigd_enq(NULL,as_reject,old_vcc,NULL,NULL); + /* @@@ should include the reason */ + return error == -EAGAIN ? -EBUSY : error; + } + /* wait should be short, so we ignore the non-blocking flag */ + new_vcc->reply = WAITING; + sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); + while (new_vcc->reply == WAITING && sigd) + sleep_on(&new_vcc->sleep); + if (!sigd) return -EUNATCH; + if (!new_vcc->reply) break; + if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; + } + newsock->state = SS_CONNECTED; + return 0; +} + + +static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, + int *sockaddr_len,int peer) +{ + struct sockaddr_atmsvc *addr; + + *sockaddr_len = sizeof(struct sockaddr_atmsvc); + addr = (struct sockaddr_atmsvc *) sockaddr; + memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, + sizeof(struct sockaddr_atmsvc)); + return 0; +} + + +int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) +{ + struct atm_qos save_qos; + + vcc->reply = WAITING; + save_qos = vcc->qos; /* @@@ really gross hack ... */ + vcc->qos = *qos; + sigd_enq(vcc,as_modify,NULL,NULL,&vcc->local); + vcc->qos = save_qos; + while (vcc->reply == WAITING && !(vcc->flags & ATM_VF_RELEASED) && + sigd) sleep_on(&vcc->sleep); + if (!sigd) return -EUNATCH; + return vcc->reply; +} + + +static int svc_setsockopt(struct socket *sock,int level,int optname, + char *optval,int optlen) +{ + struct atm_vcc *vcc; + + if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP || + optlen != sizeof(struct atm_sap)) + return atm_setsockopt(sock,level,optname,optval,optlen); + vcc = ATM_SD(sock); + if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT; + vcc->flags |= ATM_VF_HASSAP; + return 0; +} + + +static int svc_getsockopt(struct socket *sock,int level,int optname, + char *optval,int *optlen) +{ + int len; + + if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP) + return atm_getsockopt(sock,level,optname,optval,optlen); + if (get_user(len,optlen)) return -EFAULT; + if (len != sizeof(struct atm_sap)) return -EINVAL; + return copy_to_user(optval,&ATM_SD(sock)->sap,sizeof(struct atm_sap)) ? + -EFAULT : 0; +} + + +static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { + PF_ATMSVC, + svc_release, + svc_bind, + svc_connect, + sock_no_socketpair, + svc_accept, + svc_getname, + atm_poll, + atm_ioctl, + svc_listen, + svc_shutdown, + svc_setsockopt, + svc_getsockopt, + sock_no_fcntl, + atm_sendmsg, + atm_recvmsg, + sock_no_mmap +}; + + +#include +SOCKOPS_WRAP(svc_proto, PF_ATMSVC); + +static int svc_create(struct socket *sock,int protocol) +{ + int error; + + sock->ops = &svc_proto_ops; + error = atm_create(sock,protocol,AF_ATMSVC); + if (error) return error; + ATM_SD(sock)->callback = svc_callback; + ATM_SD(sock)->local.sas_family = AF_ATMSVC; + ATM_SD(sock)->remote.sas_family = AF_ATMSVC; + return 0; +} + + +static struct net_proto_family svc_family_ops = { + PF_ATMSVC, + svc_create, + 0, /* no authentication */ + 0, /* no encryption */ + 0 /* no encrypt_net */ +}; + + +/* + * Initialize the ATM SVC protocol family + */ + +__initfunc(void atmsvc_proto_init(struct net_proto *pro)) +{ + if (sock_register(&svc_family_ops) < 0) { + printk(KERN_ERR "ATMSVC: can't register"); + return; + } + signaling_init(); + init_addr(); +} diff -u --recursive --new-file v2.3.14/linux/net/atm/tunable.h linux/net/atm/tunable.h --- v2.3.14/linux/net/atm/tunable.h Wed Dec 31 16:00:00 1969 +++ linux/net/atm/tunable.h Mon Aug 23 09:56:32 1999 @@ -0,0 +1,23 @@ +/* net/atm/tunable.h - Tunable parameters of ATM support */ + +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_TUNABLE_H +#define NET_ATM_TUNABLE_H + +#if 0 +/* this is just a reminder - TTS is a device-specific parameter and shall be + used inside device drivers only */ +#define ATM_TTS 1000 /* worst-case time to service of device + drivers, in microseconds */ +#endif + +#define ATM_RXBQ_DEF ( 64*1024) /* default RX buffer quota, in bytes */ +#define ATM_TXBQ_DEF ( 64*1024) /* default TX buffer quota, in bytes */ +#define ATM_RXBQ_MIN ( 1*1024) /* RX buffer minimum, in bytes */ +#define ATM_TXBQ_MIN ( 1*1024) /* TX buffer minimum, in bytes */ +#define ATM_RXBQ_MAX (1024*1024) /* RX buffer quota limit, in bytes */ +#define ATM_TXBQ_MAX (1024*1024) /* TX buffer quota limit, in bytes */ + +#endif diff -u --recursive --new-file v2.3.14/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.3.14/linux/net/ax25/af_ax25.c Wed Aug 18 11:38:48 1999 +++ linux/net/ax25/af_ax25.c Wed Aug 25 14:45:50 1999 @@ -125,7 +125,7 @@ #include #include #include -#include +#include #include #include #include @@ -928,7 +928,7 @@ return sk; } -static int ax25_release(struct socket *sock, struct socket *peer) +static int ax25_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -1226,15 +1226,6 @@ if (sock->state != SS_UNCONNECTED) return -EINVAL; - /* - * sys_accept has already allocated a struct sock. we need to free it, - * since we want to use the one provided by ax25_make_new. - */ - if (newsock->sk != NULL) { - sk_free(newsock->sk); - newsock->sk = NULL; - } - if ((sk = sock->sk) == NULL) return -EINVAL; @@ -1716,10 +1707,9 @@ ax25_create }; -static struct proto_ops ax25_proto_ops = { +static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = { PF_AX25, - sock_no_dup, ax25_release, ax25_bind, ax25_connect, @@ -1734,9 +1724,13 @@ ax25_getsockopt, sock_no_fcntl, ax25_sendmsg, - ax25_recvmsg + ax25_recvmsg, + sock_no_mmap }; +#include +SOCKOPS_WRAP(ax25_proto, PF_AX25); + /* * Called by socket.c on kernel start up */ @@ -1793,7 +1787,7 @@ }; #endif -__initfunc(void ax25_proto_init(struct net_proto *pro)) +void __init ax25_proto_init(struct net_proto *pro) { sock_register(&ax25_family_ops); ax25_packet_type.type = htons(ETH_P_AX25); diff -u --recursive --new-file v2.3.14/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.3.14/linux/net/ax25/ax25_in.c Wed Aug 18 11:38:48 1999 +++ linux/net/ax25/ax25_in.c Mon Aug 23 10:01:02 1999 @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include /* For ip_rcv */ #include /* For arp_rcv */ @@ -234,11 +234,6 @@ skb->h.raw = skb->data; if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - kfree_skb(skb); - return 0; - } - - if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb); return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c --- v2.3.14/linux/net/ax25/ax25_ip.c Wed Aug 18 11:38:48 1999 +++ linux/net/ax25/ax25_ip.c Mon Aug 23 10:01:02 1999 @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.14/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.3.14/linux/net/ax25/ax25_out.c Wed Aug 18 11:38:48 1999 +++ linux/net/ax25/ax25_out.c Mon Aug 23 10:01:02 1999 @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -378,11 +378,6 @@ void ax25_queue_xmit(struct sk_buff *skb) { unsigned char *ptr; - - if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { - kfree_skb(skb); - return; - } skb->protocol = htons(ETH_P_AX25); skb->dev = ax25_fwd_dev(skb->dev); diff -u --recursive --new-file v2.3.14/linux/net/ax25/ax25_uid.c linux/net/ax25/ax25_uid.c --- v2.3.14/linux/net/ax25/ax25_uid.c Mon Jul 7 08:19:59 1997 +++ linux/net/ax25/ax25_uid.c Mon Aug 23 10:01:02 1999 @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.14/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.3.14/linux/net/bridge/br.c Wed Aug 18 11:38:49 1999 +++ linux/net/bridge/br.c Mon Aug 23 10:18:38 1999 @@ -39,6 +39,8 @@ * Alan Cox: Merged Jean-Rene's stuff, reformatted stuff a bit * so blame me first if its broken ;) * + * Robert Pintarelli: fixed bug in bpdu time values + * * Todo: * Don't bring up devices automatically. Start ports disabled * and use a netlink notifier so a daemon can maintain the bridge @@ -284,13 +286,13 @@ config_bpdu.message_age = Zero; /* (4.6.1.3.2(5)) */ } else { config_bpdu.message_age - = message_age_timer[bridge_info.root_port].value - + Message_age_increment; /* (4.6.1.3.2(6)) */ + = (message_age_timer[bridge_info.root_port].value + + Message_age_increment) << 8; /* (4.6.1.3.2(6)) */ } - config_bpdu.max_age = bridge_info.max_age;/* (4.6.1.3.2(7)) */ - config_bpdu.hello_time = bridge_info.hello_time; - config_bpdu.forward_delay = bridge_info.forward_delay; + config_bpdu.max_age = bridge_info.max_age << 8;/* (4.6.1.3.2(7)) */ + config_bpdu.hello_time = bridge_info.hello_time << 8; + config_bpdu.forward_delay = bridge_info.forward_delay << 8; config_bpdu.top_change_ack = port_info[port_no].top_change_ack; /* (4.6.1.3.2(8)) */ @@ -363,10 +365,10 @@ static void record_config_timeout_values(Config_bpdu *config) /* (4.6.3) */ { - bridge_info.max_age = config->max_age; /* (4.6.3.3) */ - bridge_info.hello_time = config->hello_time; - bridge_info.forward_delay = config->forward_delay; - bridge_info.top_change = config->top_change; + bridge_info.max_age = config->max_age >> 8; /* (4.6.3.3) */ + bridge_info.hello_time = config->hello_time >> 8; + bridge_info.forward_delay = config->forward_delay >> 8; + bridge_info.top_change = config->top_change >> 8; } static void config_bpdu_generation(void) diff -u --recursive --new-file v2.3.14/linux/net/core/Makefile linux/net/core/Makefile --- v2.3.14/linux/net/core/Makefile Tue Dec 29 11:21:49 1998 +++ linux/net/core/Makefile Mon Aug 23 09:56:58 1999 @@ -25,8 +25,8 @@ O_OBJS += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o -ifdef CONFIG_FIREWALL -OX_OBJS += firewall.o +ifdef CONFIG_NETFILTER +OX_OBJS += netfilter.o endif endif diff -u --recursive --new-file v2.3.14/linux/net/core/datagram.c linux/net/core/datagram.c --- v2.3.14/linux/net/core/datagram.c Wed Jun 2 11:29:13 1999 +++ linux/net/core/datagram.c Mon Aug 23 10:01:02 1999 @@ -46,33 +46,64 @@ /* + * Is a socket 'connection oriented' ? + */ + +static inline int connection_based(struct sock *sk) +{ + return (sk->type==SOCK_SEQPACKET || sk->type==SOCK_STREAM); +} + + +/* * Wait for a packet.. - * - * Interrupts off so that no packet arrives before we begin sleeping. - * Otherwise we might miss our wake up */ -static inline void wait_for_packet(struct sock * sk) +static int wait_for_packet(struct sock * sk, int *err) { + int error; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(sk->sleep, &wait); current->state = TASK_INTERRUPTIBLE; - if (skb_peek(&sk->receive_queue) == NULL) - schedule(); + barrier(); + + /* Socket errors? */ + error = sock_error(sk); + if (error) + goto out; + + if (!skb_queue_empty(&sk->receive_queue)) + goto ready; + + /* Socket shut down? */ + if (sk->shutdown & RCV_SHUTDOWN) + goto out; + + /* Sequenced packets can come disconnected. If so we report the problem */ + error = -ENOTCONN; + if(connection_based(sk) && sk->state!=TCP_ESTABLISHED) + goto out; + /* handle signals */ + error = -ERESTARTSYS; + if (signal_pending(current)) + goto out; + + schedule(); + +ready: current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); -} + return 0; -/* - * Is a socket 'connection oriented' ? - */ - -static inline int connection_based(struct sock *sk) -{ - return (sk->type==SOCK_SEQPACKET || sk->type==SOCK_STREAM); +out: + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); + *err = error; + return error; } /* @@ -108,64 +139,36 @@ if (error) goto no_packet; -restart: - while(skb_queue_empty(&sk->receive_queue)) /* No data */ - { - /* Socket errors? */ - error = sock_error(sk); - if (error) - goto no_packet; - - /* Socket shut down? */ - if (sk->shutdown & RCV_SHUTDOWN) - goto no_packet; + do { + /* Again only user level code calls this function, so nothing interrupt level + will suddenly eat the receive_queue. - /* Sequenced packets can come disconnected. If so we report the problem */ - error = -ENOTCONN; - if(connection_based(sk) && sk->state!=TCP_ESTABLISHED) - goto no_packet; + Look at current nfs client by the way... + However, this function was corrent in any case. 8) + */ + if (flags & MSG_PEEK) + { + unsigned long cpu_flags; + + spin_lock_irqsave(&sk->receive_queue.lock, cpu_flags); + skb = skb_peek(&sk->receive_queue); + if(skb!=NULL) + atomic_inc(&skb->users); + spin_unlock_irqrestore(&sk->receive_queue.lock, cpu_flags); + } else + skb = skb_dequeue(&sk->receive_queue); - /* handle signals */ - error = -ERESTARTSYS; - if (signal_pending(current)) - goto no_packet; + if (skb) + return skb; /* User doesn't want to wait */ error = -EAGAIN; if (noblock) goto no_packet; - wait_for_packet(sk); - } + } while (wait_for_packet(sk, err) == 0); - /* Again only user level code calls this function, so nothing interrupt level - will suddenly eat the receive_queue */ - if (flags & MSG_PEEK) - { - unsigned long cpu_flags; - - /* It is the only POTENTIAL race condition - in this function. skb may be stolen by - another receiver after peek, but before - incrementing use count, provided kernel - is reentearble (it is not) or this function - is called by interrupts. - - Protect it with skb queue spinlock, - though for now even this is overkill. - --ANK (980728) - */ - spin_lock_irqsave(&sk->receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->receive_queue); - if(skb!=NULL) - atomic_inc(&skb->users); - spin_unlock_irqrestore(&sk->receive_queue.lock, cpu_flags); - } else - skb = skb_dequeue(&sk->receive_queue); - - if (!skb) /* Avoid race if someone beats us to the data */ - goto restart; - return skb; + return NULL; no_packet: *err = error; diff -u --recursive --new-file v2.3.14/linux/net/core/dev.c linux/net/core/dev.c --- v2.3.14/linux/net/core/dev.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/dev.c Wed Aug 25 14:45:50 1999 @@ -134,13 +134,6 @@ static rwlock_t ptype_lock = RW_LOCK_UNLOCKED; /* - * Device list lock. Setting it provides that interface - * will not disappear unexpectedly while kernel sleeps. - */ - -atomic_t dev_lockct = ATOMIC_INIT(0); - -/* * Our notifier list */ @@ -256,50 +249,101 @@ ******************************************************************************************/ /* - * Find an interface by name. + * Find an interface by name. May be called under rtnl semaphore + * or dev_base_lock. */ -struct net_device *dev_get(const char *name) + +struct net_device *__dev_get_by_name(const char *name) { struct net_device *dev; - read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { if (strcmp(dev->name, name) == 0) - goto out; + return dev; } -out: + return NULL; +} + +/* + * Find an interface by name. Any context, dev_put() to release. + */ + +struct net_device *dev_get_by_name(const char *name) +{ + struct net_device *dev; + + read_lock(&dev_base_lock); + dev = __dev_get_by_name(name); + if (dev) + dev_hold(dev); read_unlock(&dev_base_lock); return dev; } -struct net_device * dev_get_by_index(int ifindex) +/* + Return value is changed to int to prevent illegal usage in future. + It is still legal to use to check for device existance. + */ + +int dev_get(const char *name) { struct net_device *dev; read_lock(&dev_base_lock); + dev = __dev_get_by_name(name); + read_unlock(&dev_base_lock); + return dev != NULL; +} + +/* + * Find an interface by index. May be called under rtnl semaphore + * or dev_base_lock. + */ + +struct net_device * __dev_get_by_index(int ifindex) +{ + struct net_device *dev; + for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->ifindex == ifindex) - goto out; + return dev; } -out: + return NULL; +} + +/* + * Find an interface by index. Any context, dev_put() to release. + */ + +struct net_device * dev_get_by_index(int ifindex) +{ + struct net_device *dev; + + read_lock(&dev_base_lock); + dev = __dev_get_by_index(ifindex); + if (dev) + dev_hold(dev); read_unlock(&dev_base_lock); return dev; } +/* + * Find an interface by ll addr. May be called only under rtnl semaphore. + */ + struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) { struct net_device *dev; - read_lock(&dev_base_lock); + ASSERT_RTNL(); + for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->type == type && memcmp(dev->dev_addr, ha, dev->addr_len) == 0) - goto out; + return dev; } -out: - read_unlock(&dev_base_lock); - return dev; + return NULL; } /* @@ -316,7 +360,7 @@ for(i=0;i<100;i++) { sprintf(dev->name,name,i); - if(dev_get(dev->name)==NULL) + if(__dev_get_by_name(dev->name)==NULL) return i; } return -ENFILE; /* Over 100 of the things .. bail out! */ @@ -355,7 +399,7 @@ void dev_load(const char *name) { - if(!dev_get(name) && capable(CAP_SYS_MODULE)) + if(!__dev_get_by_name(name) && capable(CAP_SYS_MODULE)) request_module(name); } @@ -434,13 +478,21 @@ #ifdef CONFIG_NET_FASTROUTE -static __inline__ void dev_do_clear_fastroute(struct net_device *dev) +static void dev_do_clear_fastroute(struct net_device *dev) { if (dev->accept_fastpath) { int i; - for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++) - dst_release_irqwait(xchg(dev->fastpath+i, NULL)); + for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++) { + struct dst_entry *dst; + + write_lock_irq(&dev->fastpath_lock); + dst = dev->fastpath[i]; + dev->fastpath[i] = NULL; + write_unlock_irq(&dev->fastpath_lock); + + dst_release(dst); + } } } @@ -468,8 +520,6 @@ dev_deactivate(dev); - dev_lock_wait(); - /* * Call the device specific close. This cannot fail. * Only if device is UP @@ -538,16 +588,7 @@ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) break; - /* Code, following below is wrong. - - The only reason, why it does work is that - ONLY packet sockets receive outgoing - packets. If such a packet will be (occasionally) - received by normal packet handler, which expects - that mac header is pulled... - */ - - /* More sensible variant. skb->nh should be correctly + /* skb->nh should be correctly set by sender, so that the second statement is just protection against buggy protocols. */ @@ -563,6 +604,8 @@ skb2->h.raw = skb2->nh.raw; skb2->pkt_type = PACKET_OUTGOING; + skb2->rx_dev = skb->dev; + dev_hold(skb2->rx_dev); ptype->func(skb2, skb->dev, ptype); } } @@ -597,19 +640,18 @@ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; if (q->enqueue) { - q->enqueue(skb, q); + int ret = q->enqueue(skb, q); /* If the device is not busy, kick it. * Otherwise or if queue is not empty after kick, * add it to run list. */ - if (dev->tbusy || qdisc_restart(dev)) - qdisc_run(dev->qdisc); + if (dev->tbusy || __qdisc_wakeup(dev)) + qdisc_run(q); spin_unlock_bh(&dev->queue_lock); - return 0; + return ret; } - spin_unlock_bh(&dev->queue_lock); /* The device has no queue. Common case for software devices: loopback, all the sorts of tunnels... @@ -623,13 +665,13 @@ Either shot noqueue qdisc, it is even simpler 8) */ if (dev->flags&IFF_UP) { - if (netdev_nit) - dev_queue_xmit_nit(skb,dev); - - local_bh_disable(); if (dev->xmit_lock_owner != smp_processor_id()) { + spin_unlock(&dev->queue_lock); spin_lock(&dev->xmit_lock); dev->xmit_lock_owner = smp_processor_id(); + + if (netdev_nit) + dev_queue_xmit_nit(skb,dev); if (dev->hard_start_xmit(skb, dev) == 0) { dev->xmit_lock_owner = -1; spin_unlock_bh(&dev->xmit_lock); @@ -639,16 +681,18 @@ spin_unlock_bh(&dev->xmit_lock); if (net_ratelimit()) printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name); + kfree_skb(skb); + return -ENETDOWN; } else { /* Recursion is detected! It is possible, unfortunately */ - local_bh_enable(); if (net_ratelimit()) printk(KERN_DEBUG "Dead loop on virtual device %s, fix it urgently!\n", dev->name); } } + spin_unlock_bh(&dev->queue_lock); kfree_skb(skb); - return 0; + return -ENETDOWN; } @@ -664,6 +708,7 @@ int netdev_throttle_events; static unsigned long netdev_fc_mask = 1; unsigned long netdev_fc_xoff = 0; +spinlock_t netdev_fc_lock = SPIN_LOCK_UNLOCKED; static struct { @@ -676,8 +721,7 @@ int bit = 0; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&netdev_fc_lock, flags); if (netdev_fc_mask != ~0UL) { bit = ffz(netdev_fc_mask); netdev_fc_slots[bit].stimul = stimul; @@ -685,7 +729,7 @@ set_bit(bit, &netdev_fc_mask); clear_bit(bit, &netdev_fc_xoff); } - restore_flags(flags); + spin_unlock_irqrestore(&netdev_fc_lock, flags); return bit; } @@ -693,22 +737,21 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&netdev_fc_lock, flags); if (bit > 0) { netdev_fc_slots[bit].stimul = NULL; netdev_fc_slots[bit].dev = NULL; clear_bit(bit, &netdev_fc_mask); clear_bit(bit, &netdev_fc_xoff); } - restore_flags(flags); + spin_unlock_irqrestore(&netdev_fc_lock, flags); } static void netdev_wakeup(void) { unsigned long xoff; - cli(); + spin_lock_irq(&netdev_fc_lock); xoff = netdev_fc_xoff; netdev_fc_xoff = 0; netdev_dropping = 0; @@ -718,47 +761,46 @@ xoff &= ~(1<next; - if ( curr->prev->dev == dev ) { + if (curr->prev->dev == dev) { prev = curr->prev; - spin_lock_irqsave(&backlog.lock, flags); __skb_unlink(prev, &backlog); - spin_unlock_irqrestore(&backlog.lock, flags); - kfree_skb(prev); + __skb_queue_tail(&garbage, prev); } } - end_bh_atomic(); + } + spin_unlock_irq(&backlog.lock); + + if (garbage.qlen) { #ifdef CONFIG_NET_HW_FLOWCONTROL if (netdev_dropping) netdev_wakeup(); #else netdev_dropping = 0; #endif + skb_queue_purge(&garbage); } } @@ -769,12 +811,8 @@ void netif_rx(struct sk_buff *skb) { -#ifndef CONFIG_CPU_IS_SLOW if(skb->stamp.tv_sec==0) get_fast_time(&skb->stamp); -#else - skb->stamp = xtime; -#endif /* The code is rearranged so that the path is the most short when CPU is congested, but is still operating. @@ -783,6 +821,10 @@ if (backlog.qlen <= netdev_max_backlog) { if (backlog.qlen) { if (netdev_dropping == 0) { + if (skb->rx_dev) + dev_put(skb->rx_dev); + skb->rx_dev = skb->dev; + dev_hold(skb->rx_dev); skb_queue_tail(&backlog,skb); mark_bh(NET_BH); return; @@ -797,6 +839,10 @@ #else netdev_dropping = 0; #endif + if (skb->rx_dev) + dev_put(skb->rx_dev); + skb->rx_dev = skb->dev; + dev_hold(skb->rx_dev); skb_queue_tail(&backlog,skb); mark_bh(NET_BH); return; @@ -938,9 +984,15 @@ if (!ptype->dev || ptype->dev == skb->dev) { if(pt_prev) { - struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC); + struct sk_buff *skb2; + if (pt_prev->data == NULL) + skb2 = skb_clone(skb, GFP_ATOMIC); + else { + skb2 = skb; + atomic_inc(&skb2->users); + } if(skb2) - pt_prev->func(skb2,skb->dev, pt_prev); + pt_prev->func(skb2, skb->dev, pt_prev); } pt_prev=ptype; } @@ -958,7 +1010,12 @@ { struct sk_buff *skb2; - skb2=skb_clone(skb, GFP_ATOMIC); + if (pt_prev->data == NULL) + skb2 = skb_clone(skb, GFP_ATOMIC); + else { + skb2 = skb; + atomic_inc(&skb2->users); + } /* * Kick the protocol handler. This should be fast @@ -988,7 +1045,7 @@ } read_unlock(&ptype_lock); } /* End of queue loop */ - + /* * We have emptied the queue */ @@ -1043,24 +1100,27 @@ { struct net_device *dev; struct ifreq ifr; - int err; /* * Fetch the caller's info block. */ - err = copy_from_user(&ifr, arg, sizeof(struct ifreq)); - if (err) + if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; - dev = dev_get_by_index(ifr.ifr_ifindex); - if (!dev) + read_lock(&dev_base_lock); + dev = __dev_get_by_index(ifr.ifr_ifindex); + if (!dev) { + read_unlock(&dev_base_lock); return -ENODEV; + } strcpy(ifr.ifr_name, dev->name); + read_unlock(&dev_base_lock); - err = copy_to_user(arg, &ifr, sizeof(struct ifreq)); - return (err)?-EFAULT:0; + if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) + return -EFAULT; + return 0; } /* @@ -1085,20 +1145,14 @@ if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; + pos = ifc.ifc_buf; len = ifc.ifc_len; - if (ifc.ifc_buf) { - pos = (char *) kmalloc(len, GFP_KERNEL); - if(pos == NULL) - return -ENOBUFS; - } else - pos = NULL; /* * Loop over the interfaces, and write an info block for each. */ total = 0; - read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { for (i=0; iget_stats ? dev->get_stats(dev): NULL); @@ -1206,11 +1255,13 @@ break; } read_unlock(&dev_base_lock); - + *start=buffer+(offset-begin); /* Start of wanted data */ len-=(offset-begin); /* Start slop */ if(len>length) len=length; /* Ending slop */ + if (len<0) + len=0; return len; } @@ -1326,6 +1377,8 @@ len -= (offset - begin); /* Start slop */ if(len > length) len = length; /* Ending slop */ + if (len<0) + len=0; return len; } @@ -1431,7 +1484,7 @@ struct net_device *dev; int err; - if ((dev = dev_get(ifr->ifr_name)) == NULL) + if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) return -ENODEV; switch(cmd) @@ -1543,7 +1596,7 @@ case SIOCSIFNAME: if (dev->flags&IFF_UP) return -EBUSY; - if (dev_get(ifr->ifr_newname)) + if (__dev_get_by_name(ifr->ifr_newname)) return -EEXIST; memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); dev->name[IFNAMSIZ-1] = 0; @@ -1632,7 +1685,9 @@ case SIOCGIFINDEX: case SIOCGIFTXQLEN: dev_load(ifr.ifr_name); + read_lock(&dev_base_lock); ret = dev_ifsioc(&ifr, cmd); + read_unlock(&dev_base_lock); if (!ret) { if (colon) *colon = ':'; @@ -1716,7 +1771,7 @@ for (;;) { if (++ifindex <= 0) ifindex=1; - if (dev_get_by_index(ifindex) == NULL) + if (__dev_get_by_index(ifindex) == NULL) return ifindex; } } @@ -1731,6 +1786,9 @@ spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1; +#ifdef CONFIG_NET_FASTROUTE + dev->fastpath_lock=RW_LOCK_UNLOCKED; +#endif if (dev_boot_phase) { /* This is NOT bug, but I am not sure, that all the @@ -1755,6 +1813,7 @@ dev->next = NULL; write_lock_bh(&dev_base_lock); *dp = dev; + dev_hold(dev); write_unlock_bh(&dev_base_lock); return 0; } @@ -1775,10 +1834,20 @@ return -EEXIST; } } + /* + * nil rebuild_header routine, + * that should be never called and used as just bug trap. + */ + + if (dev->rebuild_header == NULL) + dev->rebuild_header = default_rebuild_header; + dev->next = NULL; dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); *dp = dev; + dev_hold(dev); + dev->deadbeaf = 0; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ @@ -1787,37 +1856,51 @@ return 0; } +int netdev_finish_unregister(struct net_device *dev) +{ + BUG_TRAP(dev->ip_ptr==NULL); + BUG_TRAP(dev->ip6_ptr==NULL); + BUG_TRAP(dev->dn_ptr==NULL); + + if (!dev->deadbeaf) { + printk("Freeing alive device %p, %s\n", dev, dev->name); + return 0; + } +#ifdef NET_REFCNT_DEBUG + printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name, dev->new_style?"":", old style"); +#endif + if (dev->destructor) + dev->destructor(dev); + if (dev->new_style) + kfree(dev); + return 0; +} + int unregister_netdevice(struct net_device *dev) { + unsigned long now; struct net_device *d, **dp; /* If device is running, close it first. */ if (dev->flags & IFF_UP) dev_close(dev); + BUG_TRAP(dev->deadbeaf==0); + dev->deadbeaf = 1; + /* And unlink it from device chain. */ for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) { if (d == dev) { write_lock_bh(&dev_base_lock); *dp = d->next; write_unlock_bh(&dev_base_lock); - - /* Sorry. It is known "feature". The race is clear. - Keep it after device reference counting will - be complete. - */ - synchronize_bh(); break; } } - if (d == NULL) + if (d == NULL) { + printk(KERN_DEBUG "unregister_netdevice: device %s/%p never was registered\n", dev->name, dev); return -ENODEV; - - /* It is "synchronize_bh" to those of guys, who overslept - in skb_alloc/page fault etc. that device is off-line. - Again, it can be removed only if devices are refcounted. - */ - dev_lock_wait(); + } if (dev_boot_phase == 0) { #ifdef CONFIG_NET_FASTROUTE @@ -1838,8 +1921,37 @@ dev_mc_discard(dev); } - if (dev->destructor) - dev->destructor(dev); + if (dev->uninit) + dev->uninit(dev); + + if (dev->new_style) { +#ifdef NET_REFCNT_DEBUG + if (atomic_read(&dev->refcnt) != 1) + printk(KERN_DEBUG "unregister_netdevice: holding %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)-1); +#endif + dev_put(dev); + return 0; + } + + if (atomic_dec_and_test(&dev->refcnt)) { + netdev_finish_unregister(dev); + return 0; + } + +#ifdef NET_REFCNT_DEBUG + printk("unregister_netdevice: waiting %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)); +#endif + + now = jiffies; + while (atomic_read(&dev->refcnt)) { + schedule_timeout(HZ/10); + if ((jiffies - now) > 10*HZ) + break; + } + + if (atomic_read(&dev->refcnt)) + printk("unregister_netdevice: Old style device %s leaked(refcnt=%d). Wait for crash.\n", dev->name, atomic_read(&dev->refcnt)); + return 0; } @@ -1884,7 +1996,7 @@ #endif /* CONFIG_PROC_FS */ #endif /* CONFIG_NET_RADIO */ -__initfunc(int net_dev_init(void)) +int __init net_dev_init(void) { struct net_device *dev, **dp; @@ -1976,18 +2088,23 @@ spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1; dev->iflink = -1; + dev_hold(dev); if (dev->init && dev->init(dev)) { /* * It failed to come up. Unhook it. */ write_lock_bh(&dev_base_lock); *dp = dev->next; + dev->deadbeaf = 1; write_unlock_bh(&dev_base_lock); + dev_put(dev); } else { dp = &dev->next; dev->ifindex = dev_new_index(); if (dev->iflink == -1) dev->iflink = dev->ifindex; + if (dev->rebuild_header == NULL) + dev->rebuild_header = default_rebuild_header; dev_init_scheduler(dev); } } diff -u --recursive --new-file v2.3.14/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c --- v2.3.14/linux/net/core/dev_mcast.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/dev_mcast.c Wed Aug 25 14:45:50 1999 @@ -123,13 +123,14 @@ */ *dmip = dmi->next; dev->mc_count--; + write_unlock_bh(&dev_mc_lock); + kfree_s(dmi,sizeof(*dmi)); + /* * We have altered the list, so the card * loaded filter is now wrong. Fix it */ - write_unlock_bh(&dev_mc_lock); - dev_mc_upload(dev); return 0; } @@ -149,10 +150,7 @@ int err = 0; struct dev_mc_list *dmi, *dmi1; - /* RED-PEN: does gfp_any() work now? It requires - true local_bh_disable rather than global. - */ - dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any()); + dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC); write_lock_bh(&dev_mc_lock); for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) { @@ -257,7 +255,7 @@ } #endif -__initfunc(void dev_mcast_init(void)) +void __init dev_mcast_init(void) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *ent; diff -u --recursive --new-file v2.3.14/linux/net/core/dst.c linux/net/core/dst.c --- v2.3.14/linux/net/core/dst.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/dst.c Wed Aug 25 14:45:50 1999 @@ -51,10 +51,11 @@ return; } + del_timer(&dst_gc_timer); dstp = &dst_garbage_list; while ((dst = *dstp) != NULL) { - if (atomic_read(&dst->use)) { + if (atomic_read(&dst->__refcnt)) { dstp = &dst->next; delayed++; continue; @@ -92,7 +93,7 @@ return 0; } -void * dst_alloc(int size, struct dst_ops * ops) +void * dst_alloc(struct dst_ops * ops) { struct dst_entry * dst; @@ -100,12 +101,11 @@ if (ops->gc()) return NULL; } - dst = kmalloc(size, GFP_ATOMIC); + dst = kmem_cache_alloc(ops->kmem_cachep, SLAB_ATOMIC); if (!dst) return NULL; - memset(dst, 0, size); + memset(dst, 0, ops->entry_size); dst->ops = ops; - atomic_set(&dst->refcnt, 0); dst->lastuse = jiffies; dst->input = dst_discard; dst->output = dst_blackhole; @@ -124,7 +124,6 @@ if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) { dst->input = dst_discard; dst->output = dst_blackhole; - dst->dev = &loopback_dev; } dst->obsolete = 2; dst->next = dst_garbage_list; @@ -158,8 +157,10 @@ if (dst->ops->destroy) dst->ops->destroy(dst); + if (dst->dev) + dev_put(dst->dev); atomic_dec(&dst_total); - kfree(dst); + kmem_cache_free(dst->ops->kmem_cachep, dst); } static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -175,7 +176,6 @@ if (dst->dev == dev) { dst->input = dst_discard; dst->output = dst_blackhole; - dst->dev = &loopback_dev; } } spin_unlock_bh(&dst_lock); @@ -190,7 +190,7 @@ 0 }; -__initfunc(void dst_init(void)) +void __init dst_init(void) { register_netdevice_notifier(&dst_dev_notifier); } diff -u --recursive --new-file v2.3.14/linux/net/core/filter.c linux/net/core/filter.c --- v2.3.14/linux/net/core/filter.c Sat May 15 17:43:46 1999 +++ linux/net/core/filter.c Mon Aug 23 10:01:02 1999 @@ -440,9 +440,12 @@ fp->len = fprog->len; if ((err = sk_chk_filter(fp->insns, fp->len))==0) { - struct sk_filter *old_fp = sk->filter; + struct sk_filter *old_fp; + + spin_lock_bh(&sk->lock.slock); + old_fp = sk->filter; sk->filter = fp; - synchronize_bh(); + spin_unlock_bh(&sk->lock.slock); fp = old_fp; } diff -u --recursive --new-file v2.3.14/linux/net/core/firewall.c linux/net/core/firewall.c --- v2.3.14/linux/net/core/firewall.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/firewall.c Wed Dec 31 16:00:00 1969 @@ -1,160 +0,0 @@ -/* - * Generic loadable firewalls. At the moment only IP will actually - * use these, but people can add the others as they are needed. - * - * Authors: Dave Bonn (for IP) - * much hacked by: Alan Cox - */ - -#include -#include -#include -#include -#include -#include - -DECLARE_MUTEX(firewall_sem); -static int firewall_policy[NPROTO]; -static struct firewall_ops *firewall_chain[NPROTO]; - -/* - * Register a firewall - */ - -int register_firewall(int pf, struct firewall_ops *fw) -{ - struct firewall_ops **p; - - if(pf<0||pf>=NPROTO) - return -EINVAL; - - /* - * Don't allow two people to adjust at once. - */ - - down(&firewall_sem); - - p=&firewall_chain[pf]; - - while(*p) - { - if(fw->fw_priority > (*p)->fw_priority) - break; - p=&((*p)->next); - } - - /* - * We need to use a memory barrier to make sure that this - * works correctly even in SMP with weakly ordered writes. - * - * This is atomic wrt interrupts (and generally walking the - * chain), but not wrt itself (so you can't call this from - * an interrupt. Not that you'd want to). - */ - - fw->next=*p; - mb(); - *p = fw; - - /* - * And release the sleep lock - */ - - up(&firewall_sem); - return 0; -} - -/* - * Unregister a firewall - */ - -int unregister_firewall(int pf, struct firewall_ops *fw) -{ - struct firewall_ops **nl; - - if(pf<0||pf>=NPROTO) - return -EINVAL; - - /* - * Don't allow two people to adjust at once. - */ - - down(&firewall_sem); - - nl=&firewall_chain[pf]; - - while(*nl!=NULL) - { - if(*nl==fw) - { - struct firewall_ops *f=fw->next; - *nl = f; - up(&firewall_sem); - synchronize_bh(); - return 0; - } - nl=&((*nl)->next); - } - up(&firewall_sem); - return -ENOENT; -} - -int call_fw_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - struct firewall_ops *fw=firewall_chain[pf]; - - while(fw!=NULL) - { - int rc=fw->fw_forward(fw,pf,dev,phdr,arg,skb); - if(rc!=FW_SKIP) - return rc; - fw=fw->next; - } - return firewall_policy[pf]; -} - -/* - * Actual invocation of the chains - */ - -int call_in_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - struct firewall_ops *fw=firewall_chain[pf]; - - while(fw!=NULL) - { - int rc=fw->fw_input(fw,pf,dev,phdr,arg,skb); - if(rc!=FW_SKIP) - return rc; - fw=fw->next; - } - return firewall_policy[pf]; -} - -int call_out_firewall(int pf, struct net_device *dev, void *phdr, void *arg, struct sk_buff **skb) -{ - struct firewall_ops *fw=firewall_chain[pf]; - - while(fw!=NULL) - { - int rc=fw->fw_output(fw,pf,dev,phdr,arg,skb); - if(rc!=FW_SKIP) - return rc; - fw=fw->next; - } - /* alan, is this right? */ - return firewall_policy[pf]; -} - -EXPORT_SYMBOL(register_firewall); -EXPORT_SYMBOL(unregister_firewall); -EXPORT_SYMBOL(call_in_firewall); -EXPORT_SYMBOL(call_out_firewall); -EXPORT_SYMBOL(call_fw_firewall); - -__initfunc(void fwchain_init(void)) -{ - int i; - for(i=0;ilock); - if (atomic_read(&n->refcnt) == 0 && + if (atomic_read(&n->refcnt) == 1 && !(n->nud_state&NUD_PERMANENT) && (n->nud_state != NUD_INCOMPLETE || jiffies - n->used > n->parms->retrans_time)) { *np = n->next; - n->tbl = NULL; - tbl->entries--; + n->dead = 1; shrunk = 1; write_unlock(&n->lock); - neigh_destroy(n); + neigh_release(n); continue; } write_unlock(&n->lock); @@ -156,6 +154,17 @@ return shrunk; } +static int neigh_del_timer(struct neighbour *n) +{ + if (n->nud_state & NUD_IN_TIMER) { + if (del_timer(&n->timer)) { + neigh_release(n); + return 1; + } + } + return 0; +} + int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) { int i; @@ -173,9 +182,10 @@ } *np = n->next; write_lock(&n->lock); - n->tbl = NULL; - tbl->entries--; - if (atomic_read(&n->refcnt)) { + neigh_del_timer(n); + n->dead = 1; + + if (atomic_read(&n->refcnt) != 1) { /* The most unpleasant situation. We must destroy neighbour entry, but someone still uses it. @@ -185,8 +195,6 @@ we must kill timers etc. and move it to safe state. */ - if (n->nud_state & NUD_IN_TIMER) - del_timer(&n->timer); n->parms = &tbl->parms; skb_queue_purge(&n->arp_queue); n->output = neigh_blackhole; @@ -195,11 +203,9 @@ else n->nud_state = NUD_NONE; NEIGH_PRINTK2("neigh %p is stray.\n", n); - write_unlock(&n->lock); - } else { - write_unlock(&n->lock); - neigh_destroy(n); } + write_unlock(&n->lock); + neigh_release(n); } } @@ -223,7 +229,7 @@ return NULL; } - n = kmalloc(tbl->entry_size, GFP_ATOMIC); + n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC); if (n == NULL) return NULL; @@ -240,6 +246,10 @@ n->timer.data = (unsigned long)n; tbl->stats.allocs++; neigh_glbl_allocs++; + tbl->entries++; + n->tbl = tbl; + atomic_set(&n->refcnt, 1); + n->dead = 1; return n; } @@ -250,17 +260,13 @@ u32 hash_val; int key_len = tbl->key_len; - hash_val = *(u32*)(pkey + key_len - 4); - hash_val ^= (hash_val>>16); - hash_val ^= hash_val>>8; - hash_val ^= hash_val>>3; - hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + hash_val = tbl->hash(pkey, dev); read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (dev == n->dev && memcmp(n->primary_key, pkey, key_len) == 0) { - atomic_inc(&n->refcnt); + neigh_hold(n); break; } } @@ -281,43 +287,39 @@ memcpy(n->primary_key, pkey, key_len); n->dev = dev; + dev_hold(dev); /* Protocol specific setup. */ if (tbl->constructor && tbl->constructor(n) < 0) { - neigh_destroy(n); + neigh_release(n); return NULL; } /* Device specific setup. */ if (n->parms && n->parms->neigh_setup && n->parms->neigh_setup(n) < 0) { - neigh_destroy(n); + neigh_release(n); return NULL; } n->confirmed = jiffies - (n->parms->base_reachable_time<<1); - hash_val = *(u32*)(pkey + key_len - 4); - hash_val ^= (hash_val>>16); - hash_val ^= hash_val>>8; - hash_val ^= hash_val>>3; - hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + hash_val = tbl->hash(pkey, dev); write_lock_bh(&tbl->lock); for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) { if (dev == n1->dev && memcmp(n1->primary_key, pkey, key_len) == 0) { - atomic_inc(&n1->refcnt); + neigh_hold(n1); write_unlock_bh(&tbl->lock); - neigh_destroy(n); + neigh_release(n); return n1; } } - tbl->entries++; - n->tbl = tbl; - atomic_set(&n->refcnt, 1); n->next = tbl->hash_buckets[hash_val]; tbl->hash_buckets[hash_val] = n; + n->dead = 0; + neigh_hold(n); write_unlock_bh(&tbl->lock); NEIGH_PRINTK2("neigh %p is created.\n", n); return n; @@ -336,11 +338,16 @@ hash_val ^= hash_val>>4; hash_val &= PNEIGH_HASHMASK; + read_lock_bh(&tbl->lock); + for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { if (memcmp(n->key, pkey, key_len) == 0 && - (n->dev == dev || !n->dev)) + (n->dev == dev || !n->dev)) { + read_unlock_bh(&tbl->lock); return n; + } } + read_unlock_bh(&tbl->lock); if (!creat) return NULL; @@ -356,8 +363,10 @@ return NULL; } + write_lock_bh(&tbl->lock); n->next = tbl->phash_buckets[hash_val]; tbl->phash_buckets[hash_val] = n; + write_unlock_bh(&tbl->lock); return n; } @@ -376,8 +385,9 @@ for (np = &tbl->phash_buckets[hash_val]; (n=*np) != NULL; np = &n->next) { if (memcmp(n->key, pkey, key_len) == 0 && n->dev == dev) { + write_lock_bh(&tbl->lock); *np = n->next; - synchronize_bh(); + write_unlock_bh(&tbl->lock); if (tbl->pdestructor) tbl->pdestructor(n); kfree(n); @@ -397,7 +407,6 @@ for (np = &tbl->phash_buckets[h]; (n=*np) != NULL; np = &n->next) { if (n->dev == dev || dev == NULL) { *np = n->next; - synchronize_bh(); if (tbl->pdestructor) tbl->pdestructor(n); kfree(n); @@ -418,14 +427,14 @@ { struct hh_cache *hh; - if (neigh->tbl || atomic_read(&neigh->refcnt)) { - NEIGH_PRINTK1("neigh_destroy: neighbour is use tbl=%p, ref=%d: " - "called from %p\n", neigh->tbl, atomic_read(&neigh->refcnt), __builtin_return_address(0)); + if (!neigh->dead) { + printk("Destroying alive neighbour %p from %08lx\n", neigh, + *(((unsigned long*)&neigh)-1)); return; } - if (neigh->nud_state&NUD_IN_TIMER) - del_timer(&neigh->timer); + if (neigh_del_timer(neigh)) + printk("Impossible event.\n"); while ((hh = neigh->hh) != NULL) { neigh->hh = hh->hh_next; @@ -442,10 +451,13 @@ skb_queue_purge(&neigh->arp_queue); + dev_put(neigh->dev); + NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); neigh_glbl_allocs--; - kfree(neigh); + neigh->tbl->entries--; + kmem_cache_free(neigh->tbl->kmem_cachep, neigh); } /* Neighbour state is suspicious; @@ -514,8 +526,7 @@ } } else if (state&NUD_VALID) { if (now - n->confirmed < n->parms->reachable_time) { - if (state&NUD_IN_TIMER) - del_timer(&n->timer); + neigh_del_timer(n); n->nud_state = NUD_REACHABLE; neigh_connect(n); } @@ -560,14 +571,12 @@ if ((long)(n->used - n->confirmed) < 0) n->used = n->confirmed; - if (atomic_read(&n->refcnt) == 0 && + if (atomic_read(&n->refcnt) == 1 && (state == NUD_FAILED || now - n->used > n->parms->gc_staletime)) { *np = n->next; - n->tbl = NULL; - n->next = NULL; - tbl->entries--; + n->dead = 1; write_unlock(&n->lock); - neigh_destroy(n); + neigh_release(n); continue; } @@ -605,12 +614,13 @@ int notify = 0; write_lock(&neigh->lock); - atomic_inc(&neigh->refcnt); state = neigh->nud_state; if (!(state&NUD_IN_TIMER)) { - NEIGH_PRINTK1("neigh: timer & !nud_in_timer\n"); +#ifndef __SMP__ + printk("neigh: timer & !nud_in_timer\n"); +#endif goto out; } @@ -655,7 +665,6 @@ neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue)); atomic_inc(&neigh->probes); - neigh_release(neigh); return; out: @@ -672,16 +681,10 @@ write_lock_bh(&neigh->lock); if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) { if (!(neigh->nud_state&(NUD_STALE|NUD_INCOMPLETE))) { - if (neigh->tbl == NULL) { - NEIGH_PRINTK2("neigh %p used after death.\n", neigh); - if (skb) - kfree_skb(skb); - write_unlock_bh(&neigh->lock); - return 1; - } if (neigh->parms->mcast_probes + neigh->parms->app_probes) { atomic_set(&neigh->probes, neigh->parms->ucast_probes); neigh->nud_state = NUD_INCOMPLETE; + neigh_hold(neigh); neigh->timer.expires = jiffies + neigh->parms->retrans_time; add_timer(&neigh->timer); write_unlock_bh(&neigh->lock); @@ -712,6 +715,7 @@ } if (neigh->nud_state == NUD_STALE) { NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); + neigh_hold(neigh); neigh->nud_state = NUD_DELAY; neigh->timer.expires = jiffies + neigh->parms->delay_probe_time; add_timer(&neigh->timer); @@ -747,7 +751,7 @@ Caller MUST hold reference count on the entry. */ -int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp) +int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp) { u8 old; int err; @@ -762,8 +766,7 @@ goto out; if (!(new&NUD_VALID)) { - if (old&NUD_IN_TIMER) - del_timer(&neigh->timer); + neigh_del_timer(neigh); if (old&NUD_CONNECTED) neigh_suspect(neigh); neigh->nud_state = new; @@ -813,8 +816,7 @@ if (new == old || (new == NUD_STALE && (old&NUD_CONNECTED))) goto out; } - if (old&NUD_IN_TIMER) - del_timer(&neigh->timer); + neigh_del_timer(neigh); neigh->nud_state = new; if (lladdr != neigh->ha) { memcpy(&neigh->ha, lladdr, dev->addr_len); @@ -1073,7 +1075,7 @@ } } write_unlock_bh(&tbl->lock); - NEIGH_PRINTK1("neigh_release_parms: not found\n"); + NEIGH_PRINTK1("neigh_parms_release: not found\n"); } @@ -1083,6 +1085,12 @@ tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time); + if (tbl->kmem_cachep == NULL) + tbl->kmem_cachep = kmem_cache_create(tbl->id, + (tbl->entry_size+15)&~15, + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + init_timer(&tbl->gc_timer); tbl->lock = RW_LOCK_UNLOCKED; tbl->gc_timer.data = (unsigned long)tbl; @@ -1136,6 +1144,7 @@ struct rtattr **nda = arg; struct neigh_table *tbl; struct net_device *dev = NULL; + int err = 0; if (ndm->ndm_ifindex) { if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) @@ -1144,19 +1153,21 @@ read_lock(&neigh_tbl_lock); for (tbl=neigh_tables; tbl; tbl = tbl->next) { - int err = 0; struct neighbour *n; if (tbl->family != ndm->ndm_family) continue; read_unlock(&neigh_tbl_lock); + err = -EINVAL; if (nda[NDA_DST-1] == NULL || nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len)) - return -EINVAL; + goto out; - if (ndm->ndm_flags&NTF_PROXY) - return pneigh_delete(tbl, RTA_DATA(nda[NDA_DST-1]), dev); + if (ndm->ndm_flags&NTF_PROXY) { + err = pneigh_delete(tbl, RTA_DATA(nda[NDA_DST-1]), dev); + goto out; + } if (dev == NULL) return -EINVAL; @@ -1166,10 +1177,16 @@ err = neigh_update(n, NULL, NUD_FAILED, 1, 0); neigh_release(n); } +out: + if (dev) + dev_put(dev); return err; } read_unlock(&neigh_tbl_lock); + if (dev) + dev_put(dev); + return -EADDRNOTAVAIL; } @@ -1194,19 +1211,22 @@ continue; read_unlock(&neigh_tbl_lock); + err = -EINVAL; if (nda[NDA_DST-1] == NULL || nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len)) - return -EINVAL; + goto out; if (ndm->ndm_flags&NTF_PROXY) { + err = -ENOBUFS; if (pneigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1)) - return 0; - return -ENOBUFS; + err = 0; + goto out; } if (dev == NULL) return -EINVAL; + err = -EINVAL; if (nda[NDA_LLADDR-1] != NULL && nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len)) - return -EINVAL; + goto out; n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev); if (n) { if (nlh->nlmsg_flags&NLM_F_EXCL) @@ -1225,10 +1245,15 @@ } if (n) neigh_release(n); +out: + if (dev) + dev_put(dev); return err; } read_unlock(&neigh_tbl_lock); + if (dev) + dev_put(dev); return -EADDRNOTAVAIL; } @@ -1241,6 +1266,7 @@ struct nlmsghdr *nlh; unsigned char *b = skb->tail; struct nda_cacheinfo ci; + int locked = 0; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ndm)); ndm = NLMSG_DATA(nlh); @@ -1250,20 +1276,24 @@ ndm->ndm_ifindex = n->dev->ifindex; RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key); read_lock_bh(&n->lock); + locked=1; ndm->ndm_state = n->nud_state; if (n->nud_state&NUD_VALID) RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha); ci.ndm_used = now - n->used; ci.ndm_confirmed = now - n->confirmed; ci.ndm_updated = now - n->updated; - ci.ndm_refcnt = atomic_read(&n->refcnt); + ci.ndm_refcnt = atomic_read(&n->refcnt) - 1; read_unlock_bh(&n->lock); + locked=0; RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len; nlmsg_failure: rtattr_failure: + if (locked) + read_unlock_bh(&n->lock); skb_trim(skb, b - skb->data); return -1; } diff -u --recursive --new-file v2.3.14/linux/net/core/netfilter.c linux/net/core/netfilter.c --- v2.3.14/linux/net/core/netfilter.c Wed Dec 31 16:00:00 1969 +++ linux/net/core/netfilter.c Mon Aug 23 13:44:03 1999 @@ -0,0 +1,593 @@ +/* netfilter.c: look after the filters for various protocols. + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox. + * + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any + * way. + * + * Rusty Russell (C)1998 -- This code is GPL. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __KERNEL_SYSCALLS__ +#include + +/* In this code, we can be waiting indefinitely for userspace to + * service a packet if a hook returns NF_QUEUE. We could keep a count + * of skbuffs queued for userspace, and not deregister a hook unless + * this is zero, but that sucks. Now, we simply check when the + * packets come back: if the hook is gone, the packet is discarded. */ +#ifdef CONFIG_NETFILTER_DEBUG +#define NFDEBUG(format, args...) printk(format , ## args) +#else +#define NFDEBUG(format, args...) +#endif + +/* Each queued (to userspace) skbuff has one of these. */ +struct nf_info +{ + /* The ops struct which sent us to userspace. */ + struct nf_hook_ops *elem; + + /* If we're sent to userspace, this keeps housekeeping info */ + int pf; + unsigned long mark; + unsigned int hook; + struct net_device *indev, *outdev; + int (*okfn)(struct sk_buff *); +}; + +static rwlock_t nf_lock = RW_LOCK_UNLOCKED; + +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; +static LIST_HEAD(nf_sockopts); +static LIST_HEAD(nf_interested); + +int nf_register_hook(struct nf_hook_ops *reg) +{ + struct list_head *i; + +#ifdef CONFIG_NETFILTER_DEBUG + if (reg->pf<0 || reg->pf>=NPROTO || reg->hooknum >= NF_MAX_HOOKS) { + NFDEBUG("nf_register_hook: bad vals: pf=%i, hooknum=%u.\n", + reg->pf, reg->hooknum); + return -EINVAL; + } +#endif + NFDEBUG("nf_register_hook: pf=%i hook=%u.\n", reg->pf, reg->hooknum); + + write_lock_bh(&nf_lock); + for (i = nf_hooks[reg->pf][reg->hooknum].next; + i != &nf_hooks[reg->pf][reg->hooknum]; + i = i->next) { + if (reg->priority < ((struct nf_hook_ops *)i)->priority) + break; + } + list_add(®->list, i->prev); + write_unlock_bh(&nf_lock); + return 0; +} + +void nf_unregister_hook(struct nf_hook_ops *reg) +{ +#ifdef CONFIG_NETFILTER_DEBUG + if (reg->pf<0 || reg->pf>=NPROTO || reg->hooknum >= NF_MAX_HOOKS) { + NFDEBUG("nf_unregister_hook: bad vals: pf=%i, hooknum=%u.\n", + reg->pf, reg->hooknum); + return; + } +#endif + write_lock_bh(&nf_lock); + list_del(®->list); + write_unlock_bh(&nf_lock); +} + +/* Do inclusive ranges overlap? */ +static inline int overlap(int min1, int max1, int min2, int max2) +{ + return (min1 >= min2 && min1 <= max2) + || (max1 >= min2 && max1 <= max2); +} + +/* Functions to register setsockopt ranges (inclusive). */ +int nf_register_sockopt(struct nf_setsockopt_ops *reg) +{ + struct list_head *i; + int ret = 0; + +#ifdef CONFIG_NETFILTER_DEBUG + if (reg->pf<0 || reg->pf>=NPROTO) { + NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf); + return -EINVAL; + } + if (reg->optmin > reg->optmax) { + NFDEBUG("nf_register_sockopt: bad val: min=%i max=%i.\n", + reg->optmin, reg->optmax); + return -EINVAL; + } +#endif + write_lock_bh(&nf_lock); + for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { + struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i; + if (ops->pf == reg->pf + && overlap(ops->optmin, ops->optmax, + reg->optmin, reg->optmax)) { + NFDEBUG("nf_register_sockopt overlap: %u-%u v %u-%u\n", + ops->optmin, ops->optmax, + reg->optmin, reg->optmax); + ret = -EBUSY; + goto out; + } + } + + list_add(®->list, &nf_sockopts); +out: + write_unlock_bh(&nf_lock); + return ret; +} + +void nf_unregister_sockopt(struct nf_setsockopt_ops *reg) +{ +#ifdef CONFIG_NETFILTER_DEBUG + if (reg->pf<0 || reg->pf>=NPROTO) { + NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf); + return; + } +#endif + write_lock_bh(&nf_lock); + list_del(®->list); + write_unlock_bh(&nf_lock); +} + +#ifdef CONFIG_NETFILTER_DEBUG +#include +#include +#include +#include + +void nf_dump_skb(int pf, struct sk_buff *skb) +{ + printk("skb: pf=%i %s dev=%s len=%u\n", + pf, + skb->sk ? "(owned)" : "(unowned)", + skb->dev ? skb->dev->name : "(no dev)", + skb->len); + switch (pf) { + case PF_INET: { + const struct iphdr *ip = skb->nh.iph; + __u32 *opt = (__u32 *) (ip + 1); + int opti; + __u16 src_port = 0, dst_port = 0; + + if (ip->protocol == IPPROTO_TCP + || ip->protocol == IPPROTO_UDP) { + struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); + src_port = ntohs(tcp->source); + dst_port = ntohs(tcp->dest); + } + + printk("PROTO=%d %ld.%ld.%ld.%ld:%hu %ld.%ld.%ld.%ld:%hu" + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", + ip->protocol, + (ntohl(ip->saddr)>>24)&0xFF, + (ntohl(ip->saddr)>>16)&0xFF, + (ntohl(ip->saddr)>>8)&0xFF, + (ntohl(ip->saddr))&0xFF, + src_port, + (ntohl(ip->daddr)>>24)&0xFF, + (ntohl(ip->daddr)>>16)&0xFF, + (ntohl(ip->daddr)>>8)&0xFF, + (ntohl(ip->daddr))&0xFF, + dst_port, + ntohs(ip->tot_len), ip->tos, ntohs(ip->id), + ntohs(ip->frag_off), ip->ttl); + + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) + printk(" O=0x%8.8X", *opt++); + printk("\n"); + } + } +} + +void nf_debug_ip_local_deliver(struct sk_buff *skb) +{ + /* If it's a loopback packet, it must have come through + * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and + * NF_IP_LOCAL_IN. Otherwise, must have gone through + * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */ + if (!skb->dev) { + printk("ip_local_deliver: skb->dev is NULL.\n"); + } + else if (strcmp(skb->dev->name, "lo") == 0) { + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING) + | (1 << NF_IP_PRE_ROUTING) + | (1 << NF_IP_LOCAL_IN))) { + printk("ip_local_deliver: bad loopback skb: "); + debug_print_hooks_ip(skb->nf_debug); + nf_dump_skb(PF_INET, skb); + } + } + else { + if (skb->nf_debug != ((1<nf_debug); + nf_dump_skb(PF_INET, skb); + } + } +} + +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb) +{ + if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) { + printk("ip_dev_loopback_xmit: bad owned skb = %p: ", + newskb); + debug_print_hooks_ip(newskb->nf_debug); + nf_dump_skb(PF_INET, newskb); + } + /* Clear to avoid confusing input check */ + newskb->nf_debug = 0; +} + +void nf_debug_ip_finish_output2(struct sk_buff *skb) +{ + /* If it's owned, it must have gone through the + * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING. + * Otherwise, must have gone through NF_IP_RAW_INPUT, + * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING. + */ + if (skb->sk) { + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) { + printk("ip_finish_output: bad owned skb = %p: ", skb); + debug_print_hooks_ip(skb->nf_debug); + nf_dump_skb(PF_INET, skb); + } + } else { + if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING) +#ifdef CONFIG_IP_NETFILTER_RAW_INPUT + | (1 << NF_IP_RAW_INPUT) +#endif + | (1 << NF_IP_FORWARD) + | (1 << NF_IP_POST_ROUTING))) { + printk("ip_finish_output: bad unowned skb = %p: ",skb); + debug_print_hooks_ip(skb->nf_debug); + nf_dump_skb(PF_INET, skb); + } + } +} + + +#endif /*CONFIG_NETFILTER_DEBUG*/ + +void nf_cacheflush(int pf, unsigned int hook, const void *packet, + const struct net_device *indev, const struct net_device *outdev, + __u32 packetcount, __u32 bytecount) +{ + struct list_head *i; + + read_lock_bh(&nf_lock); + for (i = nf_hooks[pf][hook].next; + i != &nf_hooks[pf][hook]; + i = i->next) { + if (((struct nf_hook_ops *)i)->flush) + ((struct nf_hook_ops *)i)->flush(packet, indev, + outdev, + packetcount, + bytecount); + } + read_unlock_bh(&nf_lock); +} + +/* Call setsockopt() */ +int nf_setsockopt(int pf, int val, char *opt, unsigned int len) +{ + struct list_head *i; + int ret; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + read_lock_bh(&nf_lock); + for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { + struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i; + if (ops->pf == pf + && val >= ops->optmin && val <= ops->optmax) { + ret = ops->fn(val, opt, len); + goto out; + } + } + ret = -ENOPROTOOPT; + out: + read_unlock_bh(&nf_lock); + return ret; +} + +static unsigned int nf_iterate(struct list_head *head, + struct sk_buff **skb, + int hook, + const struct net_device *indev, + const struct net_device *outdev, + struct list_head **i) +{ + for (*i = (*i)->next; *i != head; *i = (*i)->next) { + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; + switch (elem->hook(hook, skb, indev, outdev)) { + case NF_QUEUE: + NFDEBUG("nf_iterate: NF_QUEUE for %p.\n", *skb); + return NF_QUEUE; + + case NF_STOLEN: + NFDEBUG("nf_iterate: NF_STOLEN for %p.\n", *skb); + return NF_STOLEN; + + case NF_DROP: + NFDEBUG("nf_iterate: NF_DROP for %p.\n", *skb); + return NF_DROP; + +#ifdef CONFIG_NETFILTER_DEBUG + case NF_ACCEPT: + break; + + default: + NFDEBUG("Evil return from %p(%u).\n", + elem->hook, hook); +#endif + } + } + return NF_ACCEPT; +} + +static void nf_queue(struct sk_buff *skb, + struct list_head *elem, + int pf, unsigned int hook, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + struct list_head *i; + + struct nf_info *info = kmalloc(sizeof(*info), GFP_ATOMIC); + if (!info) { + NFDEBUG("nf_hook: OOM.\n"); + kfree_skb(skb); + return; + } + + /* Can't do struct assignments with arrays in them. Damn. */ + info->elem = (struct nf_hook_ops *)elem; + info->mark = skb->nfmark; + info->pf = pf; + info->hook = hook; + info->okfn = okfn; + info->indev = indev; + info->outdev = outdev; + skb->nfmark = (unsigned long)info; + + /* Bump dev refs so they don't vanish while packet is out */ + if (indev) dev_hold(indev); + if (outdev) dev_hold(outdev); + + for (i = nf_interested.next; i != &nf_interested; i = i->next) { + struct nf_interest *recip = (struct nf_interest *)i; + + if ((recip->hookmask & (1 << info->hook)) + && info->pf == recip->pf + && (!recip->mark || info->mark == recip->mark) + && (!recip->reason || skb->nfreason == recip->reason)) { + /* FIXME: Andi says: use netlink. Hmmm... --RR */ + if (skb_queue_len(&recip->wake->skbq) >= 100) { + NFDEBUG("nf_hook: queue to long.\n"); + goto free_discard; + } + /* Hand it to userspace for collection */ + skb_queue_tail(&recip->wake->skbq, skb); + NFDEBUG("Waking up pf=%i hook=%u mark=%lu reason=%u\n", + pf, hook, skb->nfmark, skb->nfreason); + wake_up_interruptible(&recip->wake->sleep); + + return; + } + } + NFDEBUG("nf_hook: noone wants the packet.\n"); + + free_discard: + if (indev) dev_put(indev); + if (outdev) dev_put(outdev); + + kfree_s(info, sizeof(*info)); + kfree_skb(skb); +} + +/* nf_hook() doesn't have lock, so may give false positive. */ +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + struct list_head *elem; + unsigned int verdict; + int ret = 0; + +#ifdef CONFIG_NETFILTER_DEBUG + if (pf < 0 || pf >= NPROTO || hook >= NF_MAX_HOOKS) { + NFDEBUG("nf_hook: bad vals: pf=%i, hook=%u.\n", + pf, hook); + kfree_skb(skb); + return -EINVAL; /* -ECODERFUCKEDUP ?*/ + } + + if (skb->nf_debug & (1 << hook)) { + NFDEBUG("nf_hook: hook %i already set.\n", hook); + nf_dump_skb(pf, skb); + } + skb->nf_debug |= (1 << hook); +#endif + read_lock_bh(&nf_lock); + elem = &nf_hooks[pf][hook]; + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, + outdev, &elem); + if (verdict == NF_QUEUE) { + NFDEBUG("nf_hook: Verdict = QUEUE.\n"); + nf_queue(skb, elem, pf, hook, indev, outdev, okfn); + } + read_unlock_bh(&nf_lock); + + switch (verdict) { + case NF_ACCEPT: + ret = okfn(skb); + break; + + case NF_DROP: + kfree_skb(skb); + ret = -EPERM; + break; + } + + return ret; +} + +struct nf_waitinfo { + unsigned int verdict; + struct task_struct *owner; +}; + +/* For netfilter device. */ +void nf_register_interest(struct nf_interest *interest) +{ + /* First in, best dressed. */ + write_lock_bh(&nf_lock); + list_add(&interest->list, &nf_interested); + write_unlock_bh(&nf_lock); +} + +void nf_unregister_interest(struct nf_interest *interest) +{ + struct sk_buff *skb; + + write_lock_bh(&nf_lock); + list_del(&interest->list); + write_unlock_bh(&nf_lock); + + /* Blow away any queued skbs; this is overzealous. */ + while ((skb = skb_dequeue(&interest->wake->skbq)) != NULL) + nf_reinject(skb, 0, NF_DROP); +} + +void nf_getinfo(const struct sk_buff *skb, + struct net_device **indev, + struct net_device **outdev, + unsigned long *mark) +{ + const struct nf_info *info = (const struct nf_info *)skb->nfmark; + + *indev = info->indev; + *outdev = info->outdev; + *mark = info->mark; +} + +void nf_reinject(struct sk_buff *skb, unsigned long mark, unsigned int verdict) +{ + struct nf_info *info = (struct nf_info *)skb->nfmark; + struct list_head *elem = &info->elem->list; + struct list_head *i; + + read_lock_bh(&nf_lock); + + for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) { + if (i == &nf_hooks[info->pf][info->hook]) { + /* The module which sent it to userspace is gone. */ + verdict = NF_DROP; + break; + } + } + + /* Continue traversal iff userspace said ok, and devices still + exist... */ + if (verdict == NF_ACCEPT) { + skb->nfmark = mark; + verdict = nf_iterate(&nf_hooks[info->pf][info->hook], + &skb, info->hook, + info->indev, info->outdev, &elem); + } + + if (verdict == NF_QUEUE) { + nf_queue(skb, elem, info->pf, info->hook, + info->indev, info->outdev, info->okfn); + } + read_unlock_bh(&nf_lock); + + switch (verdict) { + case NF_ACCEPT: + local_bh_disable(); + info->okfn(skb); + local_bh_enable(); + break; + + case NF_DROP: + kfree_skb(skb); + break; + } + + /* Release those devices we held, or Alexey will kill me. */ + if (info->indev) dev_put(info->indev); + if (info->outdev) dev_put(info->outdev); + + kfree_s(info, sizeof(*info)); + return; +} + +/* FIXME: Before cache is ever used, this must be implemented for real. */ +void nf_invalidate_cache(int pf) +{ +} + +#ifdef CONFIG_NETFILTER_DEBUG + +void debug_print_hooks_ip(unsigned int nf_debug) +{ + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) { + printk("PRE_ROUTING "); + nf_debug ^= (1 << NF_IP_PRE_ROUTING); + } + if (nf_debug & (1 << NF_IP_LOCAL_IN)) { + printk("LOCAL_IN "); + nf_debug ^= (1 << NF_IP_LOCAL_IN); + } + if (nf_debug & (1 << NF_IP_FORWARD)) { + printk("FORWARD "); + nf_debug ^= (1 << NF_IP_FORWARD); + } + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) { + printk("LOCAL_OUT "); + nf_debug ^= (1 << NF_IP_LOCAL_OUT); + } + if (nf_debug & (1 << NF_IP_POST_ROUTING)) { + printk("POST_ROUTING "); + nf_debug ^= (1 << NF_IP_POST_ROUTING); + } + if (nf_debug) + printk("Crap bits: 0x%04X", nf_debug); + printk("\n"); +} +#endif /* CONFIG_NETFILTER_DEBUG */ + +__initfunc(void netfilter_init(void)) +{ + int i, h; + + for (i = 0; i < NPROTO; i++) + for (h = 0; h < NF_MAX_HOOKS; h++) + INIT_LIST_HEAD(&nf_hooks[i][h]); +} diff -u --recursive --new-file v2.3.14/linux/net/core/profile.c linux/net/core/profile.c --- v2.3.14/linux/net/core/profile.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/profile.c Wed Aug 25 14:46:02 1999 @@ -126,10 +126,8 @@ len-=(offset-begin); if(len>length) len=length; - if (len < 0) { + if (len < 0) len = 0; - printk(KERN_CRIT "Yep, guys... our template for proc_*_read is crappy :-)\n"); - } if (offset == 0) { cli(); net_prof_total.active = 0; @@ -212,7 +210,7 @@ return stats; } -__initfunc(int whitehole_init(struct net_device *dev)) +int __init whitehole_init(struct net_device *dev) { dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) @@ -262,7 +260,7 @@ } -__initfunc(int net_profile_init(void)) +int __init net_profile_init(void) { int i; @@ -282,7 +280,6 @@ return -1; } #endif - start_bh_atomic(); #ifdef __alpha__ alpha_tick(0); #endif @@ -298,7 +295,6 @@ } net_prof_total.hits = 0; net_profile_stamp(&net_prof_total.entered); - end_bh_atomic(); return 0; } diff -u --recursive --new-file v2.3.14/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c --- v2.3.14/linux/net/core/rtnetlink.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/rtnetlink.c Wed Aug 25 14:46:02 1999 @@ -64,8 +64,6 @@ rtnl_shunlock(); } - - int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr*)*maxattr); @@ -136,8 +134,29 @@ return err; } +int rtnetlink_put_metrics(struct sk_buff *skb, unsigned *metrics) +{ + struct rtattr *mx = (struct rtattr*)skb->tail; + int i; + + RTA_PUT(skb, RTA_METRICS, 0, NULL); + for (i=0; irta_len = skb->tail - (u8*)mx; + if (mx->rta_len == RTA_LENGTH(0)) + skb_trim(skb, (u8*)mx - skb->data); + return 0; + +rtattr_failure: + skb_trim(skb, (u8*)mx - skb->data); + return -1; +} + + static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, - int type, u32 pid, u32 seq) + int type, u32 pid, u32 seq, u32 change) { struct ifinfomsg *r; struct nlmsghdr *nlh; @@ -150,7 +169,7 @@ r->ifi_type = dev->type; r->ifi_index = dev->ifindex; r->ifi_flags = dev->flags; - r->ifi_change = ~0U; + r->ifi_change = change; RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); if (dev->addr_len) { @@ -191,7 +210,7 @@ for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; - if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) + if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 0) <= 0) break; } read_unlock(&dev_base_lock); @@ -233,7 +252,7 @@ if (!skb) return; - if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0) < 0) { + if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, ~0U) < 0) { kfree_skb(skb); return; } @@ -414,23 +433,25 @@ static void rtnetlink_rcv(struct sock *sk, int len) { - struct sk_buff *skb; + do { + struct sk_buff *skb; - if (rtnl_shlock_nowait()) - return; + if (rtnl_shlock_nowait()) + return; - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { - if (rtnetlink_rcv_skb(skb)) { - if (skb->len) - skb_queue_head(&sk->receive_queue, skb); - else - kfree_skb(skb); - break; + while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + if (rtnetlink_rcv_skb(skb)) { + if (skb->len) + skb_queue_head(&sk->receive_queue, skb); + else + kfree_skb(skb); + break; + } + kfree_skb(skb); } - kfree_skb(skb); - } - rtnl_shunlock(); + up(&rtnl_sem); + } while (rtnl && rtnl->receive_queue.qlen); } static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = @@ -483,7 +504,7 @@ }; -__initfunc(void rtnetlink_init(void)) +void __init rtnetlink_init(void) { #ifdef RTNL_DEBUG printk("Initializing RT netlink socket\n"); diff -u --recursive --new-file v2.3.14/linux/net/core/scm.c linux/net/core/scm.c --- v2.3.14/linux/net/core/scm.c Sat Jul 3 10:43:11 1999 +++ linux/net/core/scm.c Mon Aug 23 10:01:02 1999 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -162,11 +161,6 @@ kfree(p->fp); p->fp = NULL; } - - err = -EINVAL; - if (msg->msg_flags & MSG_CTLFLAGS) - goto error; - return 0; error: diff -u --recursive --new-file v2.3.14/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.3.14/linux/net/core/skbuff.c Mon May 31 22:07:43 1999 +++ linux/net/core/skbuff.c Mon Aug 23 10:01:02 1999 @@ -4,7 +4,7 @@ * Authors: Alan Cox * Florian La Roche * - * Version: $Id: skbuff.c,v 1.56 1999/05/29 23:20:42 davem Exp $ + * Version: $Id: skbuff.c,v 1.60 1999/08/23 07:02:01 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -61,6 +61,10 @@ #include #include +#ifdef CONFIG_ATM +#include +#endif + /* * Resource tracking variables */ @@ -81,14 +85,16 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here) { - panic("skput:over: %p:%d put:%d dev:%s", + printk("skput:over: %p:%d put:%d dev:%s", here, skb->len, sz, skb->dev ? skb->dev->name : ""); + *(int*)0 = 0; } void skb_under_panic(struct sk_buff *skb, int sz, void *here) { - panic("skput:under: %p:%d put:%d dev:%s", + printk("skput:under: %p:%d put:%d dev:%s", here, skb->len, sz, skb->dev ? skb->dev->name : ""); + *(int*)0 = 0; } void show_net_buffers(void) @@ -120,7 +126,8 @@ static int count = 0; if (++count < 5) { printk(KERN_ERR "alloc_skb called nonatomically " - "from interrupt %p\n", __builtin_return_address(0)); + "from interrupt %p\n", NET_CALLER(size)); + *(int*)0 = 0; } gfp_mask &= ~__GFP_WAIT; } @@ -142,7 +149,8 @@ */ atomic_inc(&net_allocs); - skb->truesize = size; + /* XXX: does not include slab overhead */ + skb->truesize = size + sizeof(struct sk_buff); atomic_inc(&net_skbcount); @@ -157,6 +165,10 @@ skb->is_clone = 0; skb->cloned = 0; +#ifdef CONFIG_ATM + ATM_SKB(skb)->iovcnt = 0; +#endif + atomic_set(&skb->users, 1); atomic_set(skb_datarefp(skb), 1); return skb; @@ -187,8 +199,12 @@ skb->ip_summed = 0; skb->security = 0; /* By default packets are insecure */ skb->dst = NULL; -#ifdef CONFIG_IP_FIREWALL - skb->fwmark = 0; + skb->rx_dev = NULL; +#ifdef CONFIG_NETFILTER + skb->nfmark = skb->nfreason = skb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif #endif memset(skb->cb, 0, sizeof(skb->cb)); skb->priority = 0; @@ -212,13 +228,17 @@ void __kfree_skb(struct sk_buff *skb) { - if (skb->list) + if (skb->list) { printk(KERN_WARNING "Warning: kfree_skb passed an skb still " - "on a list (from %p).\n", __builtin_return_address(0)); + "on a list (from %p).\n", NET_CALLER(skb)); + *(int*)0 = 0; + } dst_release(skb->dst); if(skb->destructor) skb->destructor(skb); + if(skb->rx_dev) + dev_put(skb->rx_dev); skb_headerinit(skb, NULL, 0); /* clean state */ kfree_skbmem(skb); } @@ -242,6 +262,7 @@ atomic_inc(&net_allocs); atomic_inc(&net_skbcount); dst_clone(n->dst); + n->rx_dev = NULL; n->cloned = 1; n->next = n->prev = NULL; n->list = NULL; @@ -285,6 +306,7 @@ n->list=NULL; n->sk=NULL; n->dev=skb->dev; + n->rx_dev=NULL; n->priority=skb->priority; n->protocol=skb->protocol; n->dst=dst_clone(skb->dst); @@ -299,8 +321,13 @@ n->stamp=skb->stamp; n->destructor = NULL; n->security=skb->security; -#ifdef CONFIG_IP_FIREWALL - n->fwmark = skb->fwmark; +#ifdef CONFIG_NETFILTER + n->nfmark=skb->nfmark; + n->nfreason=skb->nfreason; + n->nfcache=skb->nfcache; +#ifdef CONFIG_NETFILTER_DEBUG + n->nf_debug=skb->nf_debug; +#endif #endif return n; } @@ -309,13 +336,12 @@ { struct sk_buff *n; unsigned long offset; - int headroom = skb_headroom(skb); /* * Allocate the copy buffer */ - n=alloc_skb(skb->truesize+newheadroom-headroom, GFP_ATOMIC); + n=alloc_skb((skb->end-skb->data)+newheadroom, GFP_ATOMIC); if(n==NULL) return NULL; @@ -336,6 +362,7 @@ n->priority=skb->priority; n->protocol=skb->protocol; n->dev=skb->dev; + n->rx_dev=NULL; n->dst=dst_clone(skb->dst); n->h.raw=skb->h.raw+offset; n->nh.raw=skb->nh.raw+offset; @@ -348,10 +375,14 @@ n->stamp=skb->stamp; n->destructor = NULL; n->security=skb->security; -#ifdef CONFIG_IP_FIREWALL - n->fwmark = skb->fwmark; +#ifdef CONFIG_NETFILTER + n->nfmark=skb->nfmark; + n->nfreason=skb->nfreason; + n->nfcache=skb->nfcache; +#ifdef CONFIG_NETFILTER_DEBUG + n->nf_debug=skb->nf_debug; +#endif #endif - return n; } diff -u --recursive --new-file v2.3.14/linux/net/core/sock.c linux/net/core/sock.c --- v2.3.14/linux/net/core/sock.c Wed Aug 18 11:38:48 1999 +++ linux/net/core/sock.c Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.82 1999/05/27 00:37:03 davem Exp $ + * Version: $Id: sock.c,v 1.85 1999/08/23 05:16:08 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -116,7 +116,6 @@ #include #include #include -#include #include #include #include @@ -180,7 +179,9 @@ return err; valbool = val?1:0; - + + lock_sock(sk); + switch(optname) { case SO_DEBUG: @@ -257,14 +258,15 @@ if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN)) sk->priority = val; else - return(-EPERM); + ret = -EPERM; break; case SO_LINGER: - if(optlen IFNAMSIZ) optlen = IFNAMSIZ; - if (copy_from_user(devname, optval, optlen)) - return -EFAULT; + if (copy_from_user(devname, optval, optlen)) { + ret = -EFAULT; + break; + } /* Remove any cached route for this socket. */ - lock_sock(sk); - dst_release(xchg(&sk->dst_cache, NULL)); - release_sock(sk); + sk_dst_reset(sk); if (devname[0] == '\0') { sk->bound_dev_if = 0; } else { - struct net_device *dev = dev_get(devname); - if (!dev) - return -EINVAL; + struct net_device *dev = dev_get_by_name(devname); + if (!dev) { + ret = -ENODEV; + break; + } sk->bound_dev_if = dev->ifindex; + dev_put(dev); } - return 0; } + break; } #endif @@ -344,20 +351,25 @@ break; case SO_DETACH_FILTER: + spin_lock_bh(&sk->lock.slock); filter = sk->filter; - if(filter) { + if (filter) { sk->filter = NULL; - synchronize_bh(); + spin_unlock_bh(&sk->lock.slock); sk_filter_release(sk, filter); - return 0; + break; } - return -ENOENT; + spin_unlock_bh(&sk->lock.slock); + ret = -ENONET; + break; #endif /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: - return(-ENOPROTOOPT); + ret = -ENOPROTOOPT; + break; } + release_sock(sk); return ret; } @@ -501,6 +513,7 @@ #ifdef CONFIG_FILTER struct sk_filter *filter; #endif + if (sk->destruct) sk->destruct(sk); @@ -540,6 +553,7 @@ /* In case it might be waiting for more memory. */ atomic_sub(skb->truesize, &sk->wmem_alloc); sk->write_space(sk); + sock_put(sk); } /* @@ -552,6 +566,10 @@ atomic_sub(skb->truesize, &sk->rmem_alloc); } +void sock_cfree(struct sk_buff *skb) +{ + sock_put(skb->sk); +} /* * Allocate a skb from the socket's send buffer. @@ -561,9 +579,7 @@ if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); if (skb) { - atomic_add(skb->truesize, &sk->wmem_alloc); - skb->destructor = sock_wfree; - skb->sk = sk; + skb_set_owner_w(skb, sk); return skb; } } @@ -578,9 +594,7 @@ if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) { - atomic_add(skb->truesize, &sk->rmem_alloc); - skb->destructor = sock_rfree; - skb->sk = sk; + skb_set_owner_r(skb, sk); return skb; } } @@ -592,7 +606,8 @@ */ void *sock_kmalloc(struct sock *sk, int size, int priority) { - if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) { + if ((unsigned)size <= sysctl_optmem_max && + atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) { void *mem; /* First do the add, to avoid the race if kmalloc * might sleep. @@ -736,62 +751,57 @@ return NULL; } -void lock_sock(struct sock *sk) +void __lock_sock(struct sock *sk) { - spin_lock_bh(&sk->lock.slock); - if(sk->lock.users != 0) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue_exclusive(&sk->lock.wq, &wait); - for(;;) { - current->state = TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE; - spin_unlock_bh(&sk->lock.slock); - schedule(); - spin_lock_bh(&sk->lock.slock); - if(!sk->lock.users) - break; - } - current->state = TASK_RUNNING; - remove_wait_queue(&sk->lock.wq, &wait); + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(&sk->lock.wq, &wait); + for(;;) { + current->state = TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE; + spin_unlock_bh(&sk->lock.slock); + schedule(); + spin_lock_bh(&sk->lock.slock); + if(!sk->lock.users) + break; } - sk->lock.users = 1; - spin_unlock_bh(&sk->lock.slock); + current->state = TASK_RUNNING; + remove_wait_queue(&sk->lock.wq, &wait); } -void release_sock(struct sock *sk) +void __release_sock(struct sock *sk) { - spin_lock_bh(&sk->lock.slock); - sk->lock.users = 0; - if(sk->backlog.tail != NULL) { - struct sk_buff *skb = sk->backlog.head; - do { struct sk_buff *next = skb->next; - skb->next = NULL; - sk->backlog_rcv(sk, skb); - skb = next; - } while(skb != NULL); - sk->backlog.head = sk->backlog.tail = NULL; - } - wake_up(&sk->lock.wq); - spin_unlock_bh(&sk->lock.slock); + struct sk_buff *skb = sk->backlog.head; + do { + struct sk_buff *next = skb->next; + skb->next = NULL; + sk->backlog_rcv(sk, skb); + skb = next; + } while(skb != NULL); + sk->backlog.head = sk->backlog.tail = NULL; } /* * Generic socket manager library. Most simpler socket families * use this to manage their socket lists. At some point we should * hash these. By making this generic we get the lot hashed for free. + * + * It is broken by design. All the protocols using it must be fixed. --ANK */ + +rwlock_t net_big_sklist_lock = RW_LOCK_UNLOCKED; void sklist_remove_socket(struct sock **list, struct sock *sk) { struct sock *s; - start_bh_atomic(); + write_lock_bh(&net_big_sklist_lock); s= *list; if(s==sk) { *list = s->next; - end_bh_atomic(); + write_unlock_bh(&net_big_sklist_lock); + sock_put(sk); return; } while(s && s->next) @@ -803,15 +813,16 @@ } s=s->next; } - end_bh_atomic(); + write_unlock_bh(&net_big_sklist_lock); } void sklist_insert_socket(struct sock **list, struct sock *sk) { - start_bh_atomic(); + write_lock_bh(&net_big_sklist_lock); sk->next= *list; *list=sk; - end_bh_atomic(); + sock_hold(sk); + write_unlock_bh(&net_big_sklist_lock); } /* @@ -853,7 +864,7 @@ atomic_read(&sk->rmem_alloc) == 0 && sk->dead) { - sk_free(sk); + sock_put(sk); } else { @@ -875,14 +886,7 @@ * function, some default processing is provided. */ -int sock_no_dup(struct socket *newsock, struct socket *oldsock) -{ - struct sock *sk = oldsock->sk; - - return net_families[sk->family]->create(newsock, sk->protocol); -} - -int sock_no_release(struct socket *sock, struct socket *peersock) +int sock_no_release(struct socket *sock) { return 0; } @@ -986,7 +990,11 @@ return -EOPNOTSUPP; } - +int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) +{ + /* Mirror missing mmap method error code */ + return -ENODEV; +} /* * Default Socket Callbacks @@ -994,28 +1002,36 @@ void sock_def_wakeup(struct sock *sk) { + read_lock(&sk->callback_lock); if(!sk->dead) wake_up_interruptible(sk->sleep); + read_unlock(&sk->callback_lock); } void sock_def_error_report(struct sock *sk) { + read_lock(&sk->callback_lock); if (!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,0); } + read_unlock(&sk->callback_lock); } void sock_def_readable(struct sock *sk, int len) { + read_lock(&sk->callback_lock); if(!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,1); } + read_unlock(&sk->callback_lock); } void sock_def_write_space(struct sock *sk) { + read_lock(&sk->callback_lock); + /* Do not wake up a writer until he can make "significant" * progress. --DaveM */ @@ -1027,6 +1043,7 @@ if (sock_writeable(sk)) sock_wake_async(sk->socket, 2); } + read_unlock(&sk->callback_lock); } void sock_def_destruct(struct sock *sk) @@ -1040,7 +1057,8 @@ skb_queue_head_init(&sk->receive_queue); skb_queue_head_init(&sk->write_queue); skb_queue_head_init(&sk->error_queue); - + + spin_lock_init(&sk->timer_lock); init_timer(&sk->timer); sk->allocation = GFP_KERNEL; @@ -1058,6 +1076,8 @@ } else sk->sleep = NULL; + sk->callback_lock = RW_LOCK_UNLOCKED; + sk->state_change = sock_def_wakeup; sk->data_ready = sock_def_readable; sk->write_space = sock_def_write_space; @@ -1068,4 +1088,5 @@ sk->peercred.uid = -1; sk->peercred.gid = -1; + atomic_set(&sk->refcnt, 1); } diff -u --recursive --new-file v2.3.14/linux/net/core/utils.c linux/net/core/utils.c --- v2.3.14/linux/net/core/utils.c Sun Mar 1 14:40:40 1998 +++ linux/net/core/utils.c Mon Aug 23 10:01:02 1999 @@ -46,21 +46,28 @@ */ int net_ratelimit(void) { + static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; static unsigned long toks = 10*5*HZ; static unsigned long last_msg; static int missed; + unsigned long flags; unsigned long now = jiffies; - toks += now - xchg(&last_msg, now); + spin_lock_irqsave(&ratelimit_lock, flags); + toks += now - last_msg; + last_msg = now; if (toks > net_msg_burst) toks = net_msg_burst; if (toks >= net_msg_cost) { - toks -= net_msg_cost; - if (missed) - printk(KERN_WARNING "NET: %d messages suppressed.\n", missed); + int lost = missed; missed = 0; + toks -= net_msg_cost; + spin_unlock_irqrestore(&ratelimit_lock, flags); + if (lost) + printk(KERN_WARNING "NET: %d messages suppressed.\n", lost); return 1; } - missed++; + missed++; + spin_unlock_irqrestore(&ratelimit_lock, flags); return 0; } diff -u --recursive --new-file v2.3.14/linux/net/decnet/Config.in linux/net/decnet/Config.in --- v2.3.14/linux/net/decnet/Config.in Sat May 29 11:09:54 1999 +++ linux/net/decnet/Config.in Mon Aug 23 10:01:02 1999 @@ -4,10 +4,3 @@ bool 'DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF bool 'DECnet: router support (VERY VERY EXPERIMENTAL)' CONFIG_DECNET_ROUTER bool 'DECnet: raw socket support' CONFIG_DECNET_RAW -#bool 'DECnet: MOP support' CONFIG_DECNET_MOP -#if [ "$CONFIG_FIREWALL" = "y" ]; then -# bool 'DECnet: firewall support' CONFIG_DECNET_FW -# if [ "$CONFIG_DECNET_FW" = "y" ]; then -# bool 'DECnet: firewall netlink support' CONFIG_DECNET_FIREWALL_NETLINK -# fi -#fi diff -u --recursive --new-file v2.3.14/linux/net/decnet/TODO linux/net/decnet/TODO --- v2.3.14/linux/net/decnet/TODO Wed May 26 09:36:36 1999 +++ linux/net/decnet/TODO Mon Aug 23 10:01:02 1999 @@ -4,8 +4,6 @@ o Proper timeouts on each neighbour (in routing mode) rather than just the 60 second On-Ethernet cache value. - o MOP support (probably as part of Raw sockets) [hooks in] - o Routing stuff in dn_fib.c o Misc. get/set_sockopt() functions [done for the time being, more later] @@ -33,8 +31,6 @@ send/recvmsg() calls should simply be a vector of set/getsockopt() calls] - o recvmsg() to optionally report remote address. - o check MSG_TRUNC, MSG_CTRUNC are set where they should be. o Work out if I really need support for rtnetlink "link" messages and if @@ -45,11 +41,7 @@ o Routing ioctl() support o Start to hack together user level software and add more DECnet support - in ifconfig for example. Also a DECnet equivalent to Alexey's ip config - tool is required. Hopefully I can steal some code from that. - - o Sort out MSG_EOR in sendmsg.... should it be used, or is each transmission - a seperate message ? What about when you get interrupted by a signal ? + in ifconfig for example. o Fix conninit_rx to check out each CI before queuing it diff -u --recursive --new-file v2.3.14/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.3.14/linux/net/decnet/af_decnet.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/af_decnet.c Mon Aug 23 10:01:02 1999 @@ -30,6 +30,8 @@ * Steve Whitehouse: Fixes to username2sockaddr & sockaddr2username. * Steve Whitehouse: Fixes to connect() error returns. * Patrick Caulfield: Fixes to delayed acceptance logic. + * David S. Miller: New socket locking + * Steve Whitehouse: Socket list hashing/locking */ @@ -136,11 +138,99 @@ int decnet_node_type = DN_RT_INFO_ENDN; static struct proto_ops dn_proto_ops; +rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED; static struct sock *dn_sklist = NULL; static struct sock *dn_wild_sk = NULL; -static int _dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags); -static int _dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen, int flags); +static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags); +static int __dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen, int flags); + +static struct sock **dn_find_list(struct sock *sk) +{ + struct dn_scp *scp = &sk->protinfo.dn; + + if (scp->addr.sdn_flags & SDF_WILD) + return dn_wild_sk ? NULL : &dn_wild_sk; + + return &dn_sklist; +} + +static unsigned short port_alloc(struct sock *sk) +{ + struct dn_scp *scp = &sk->protinfo.dn; +static unsigned short port = 0x2000; + + if (port == 0) + port++; + + scp->addrloc = port++; + + return 1; +} + +/* + * Since this is only ever called from user + * level, we don't need a write_lock() version + * of this. + */ +static int dn_hash_sock(struct sock *sk) +{ + struct dn_scp *scp = &sk->protinfo.dn; + struct sock **skp; + int rv = -EUSERS; + + write_lock_bh(&dn_hash_lock); + + if (!scp->addrloc && !port_alloc(sk)) + goto out; + + rv = -EADDRINUSE; + if ((skp = dn_find_list(sk)) == NULL) + goto out; + + sk->next = *skp; + sk->pprev = skp; + *skp = sk; + rv = 0; +out: + write_unlock_bh(&dn_hash_lock); + return rv; +} + +static void dn_unhash_sock(struct sock *sk) +{ + struct sock **skp = sk->pprev; + + if (skp == NULL) + return; + + write_lock(&dn_hash_lock); + while(*skp != sk) + skp = &((*skp)->next); + *skp = sk->next; + write_unlock(&dn_hash_lock); + + sk->next = NULL; + sk->pprev = NULL; +} + +static void dn_unhash_sock_bh(struct sock *sk) +{ + struct sock **skp = sk->pprev; + + if (skp == NULL) + return; + + write_lock_bh(&dn_hash_lock); + while(*skp != sk) + skp = &((*skp)->next); + *skp = sk->next; + write_unlock_bh(&dn_hash_lock); + + sk->next = NULL; + sk->pprev = NULL; +} + int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type) { @@ -154,16 +244,16 @@ break; case 1: *buf++ = 0; - *buf++ = sdn->sdn_objnamel; - memcpy(buf, sdn->sdn_objname, sdn->sdn_objnamel); - len = 3 + sdn->sdn_objnamel; + *buf++ = dn_ntohs(sdn->sdn_objnamel); + memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel)); + len = 3 + dn_ntohs(sdn->sdn_objnamel); break; case 2: memset(buf, 0, 5); buf += 5; - *buf++ = sdn->sdn_objnamel; - memcpy(buf, sdn->sdn_objname, sdn->sdn_objnamel); - len = 7 + sdn->sdn_objnamel; + *buf++ = dn_ntohs(sdn->sdn_objnamel); + memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel)); + len = 7 + dn_ntohs(sdn->sdn_objnamel); break; } @@ -184,7 +274,7 @@ int namel = 12; sdn->sdn_objnum = 0; - sdn->sdn_objnamel = 0; + sdn->sdn_objnamel = dn_htons(0); memset(sdn->sdn_objname, 0, DN_MAXOBJL); if (len < 2) @@ -196,7 +286,7 @@ switch(*fmt) { case 0: - sdn->sdn_objnum = type; + sdn->sdn_objnum = dn_htons(type); return 2; case 1: namel = 16; @@ -218,13 +308,13 @@ if (len < 0) return -1; - sdn->sdn_objnamel = *data++; - len -= sdn->sdn_objnamel; + sdn->sdn_objnamel = dn_htons(*data++); + len -= dn_ntohs(sdn->sdn_objnamel); - if ((len < 0) || (sdn->sdn_objnamel > namel)) + if ((len < 0) || (dn_ntohs(sdn->sdn_objnamel) > namel)) return -1; - memcpy(sdn->sdn_objname, data, sdn->sdn_objnamel); + memcpy(sdn->sdn_objname, data, dn_ntohs(sdn->sdn_objnamel)); return size - len; } @@ -233,6 +323,7 @@ { struct sock *sk; + read_lock(&dn_hash_lock); for(sk = dn_sklist; sk != NULL; sk = sk->next) { struct dn_scp *scp = &sk->protinfo.dn; if (sk->state != TCP_LISTEN) @@ -245,64 +336,28 @@ continue; if (scp->addr.sdn_objnamel != addr->sdn_objnamel) continue; - if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, addr->sdn_objnamel) != 0) + if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, dn_ntohs(addr->sdn_objnamel)) != 0) continue; } + sock_hold(sk); + read_unlock(&dn_hash_lock); return sk; } - return (dn_wild_sk && (dn_wild_sk->state == TCP_LISTEN)) ? dn_wild_sk : NULL; -} - -struct sock *dn_sklist_find(unsigned short port) -{ - struct sock *s; - - for (s = dn_sklist; s != NULL; s = s->next) { - if (s->protinfo.dn.addrloc == port) { - return s; - } - } - - return NULL; -} - -static struct sock *dn_sklist_find_by_objnum(unsigned char objnum) -{ - struct sock *s; - - for (s = dn_sklist; s != NULL; s = s->next) { - if ((s->protinfo.dn.addr.sdn_objnum == objnum) && - (s->state == TCP_LISTEN)) { - return s; - } - } - return NULL; -} + if (dn_wild_sk && (dn_wild_sk->state == TCP_LISTEN)) + sock_hold((sk = dn_wild_sk)); -static struct sock *dn_sklist_find_by_name(char *name) -{ - struct sock *s; - - for (s = dn_sklist; s != NULL; s = s->next) { - if (s->protinfo.dn.addr.sdn_objnum) - continue; - if ((memcmp(s->protinfo.dn.addr.sdn_objname,name, - s->protinfo.dn.addr.sdn_objnamel) == 0) - && (s->state == TCP_LISTEN)) { - return s; - } - } - return NULL; + read_unlock(&dn_hash_lock); + return sk; } - struct sock *dn_find_by_skb(struct sk_buff *skb) { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; struct sock *sk; struct dn_scp *scp; + read_lock(&dn_hash_lock); for(sk = dn_sklist; sk != NULL; sk = sk->next) { scp = &sk->protinfo.dn; if (cb->src != dn_saddr2dn(&scp->peer)) @@ -314,27 +369,14 @@ break; } - return sk; -} - - -unsigned short dn_alloc_port(void) -{ - struct sock *sk; - static unsigned short dn_port = 0x2000; - short port; + if (sk) + sock_hold(sk); - start_bh_atomic(); + read_unlock(&dn_hash_lock); - do { - port = dn_port++; - sk = dn_sklist_find(port); - } while((sk != NULL) || (port == 0)); - - end_bh_atomic(); + return sk; +} - return dn_htons(port); -}; static void dn_destruct(struct sock *sk) @@ -453,14 +495,12 @@ switch(scp->state) { case DN_DI: - /* printk(KERN_DEBUG "dn_destroy_timer: DI\n"); */ dn_send_disc(sk, NSP_DISCINIT, 0); if (scp->nsp_rxtshift >= decnet_di_count) scp->state = DN_CN; return 0; case DN_DR: - /* printk(KERN_DEBUG "dn_destroy_timer: DR\n"); */ dn_send_disc(sk, NSP_DISCINIT, 0); if (scp->nsp_rxtshift >= decnet_dr_count) scp->state = DN_DRC; @@ -476,19 +516,16 @@ scp->persist = (HZ * decnet_time_wait); -/* printk(KERN_DEBUG "dn_destroy_timer: testing dead\n"); */ - if (sk->socket) return 0; dn_stop_fast_timer(sk); /* unlikely, but possible that this is runninng */ if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) { - sklist_destroy_socket(&dn_sklist, sk); + dn_unhash_sock(sk); + sock_put(sk); return 1; } - /*printk(KERN_DEBUG "dn_destroy_timer: dead 'n' waiting...\n"); */ - return 0; } @@ -538,18 +575,12 @@ default: printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n"); case DN_O: - start_bh_atomic(); dn_stop_fast_timer(sk); dn_stop_slow_timer(sk); - if (sk == dn_wild_sk) { - dn_wild_sk = NULL; - sklist_destroy_socket(NULL, sk); - } else { - sklist_destroy_socket(&dn_sklist, sk); - } + dn_unhash_sock_bh(sk); + sock_put(sk); - end_bh_atomic(); break; } } @@ -606,52 +637,6 @@ return "????"; } -static int dn_get_info(char *buffer, char **start, off_t offset, - int length, int dummy) -{ - struct sock *sk; - int len = 0; - off_t pos = 0; - off_t begin = 0; - char buf[DN_ASCBUF_LEN]; - - len += sprintf(buffer+len,"%-8s%-7s%-7s%-7s%-5s%-13s%-13s\n", - "Remote","Source","Remote","Object","Link ", - " Data Packets ","Link Packets"); - len += sprintf(buffer+len,"%-8s%-7s%-7s%-7s%-5s%-13s%-13s\n\n", - "Node ","Port ","Port ","Number","State", - " Out In "," Out In"); - start_bh_atomic(); - for (sk = dn_sklist; sk != NULL; sk = sk->next) { - len += sprintf(buffer+len, - "%6s %04X %04X %6d %4s %6d %6d %6d %6d\n", - - dn_addr2asc(dn_ntohs(dn_saddr2dn(&sk->protinfo.dn.peer)), buf), - sk->protinfo.dn.addrloc,sk->protinfo.dn.addrrem, - sk->protinfo.dn.addr.sdn_objnum, - dn_state2asc(sk->protinfo.dn.state), - sk->protinfo.dn.numdat, sk->protinfo.dn.numdat_rcv, - sk->protinfo.dn.numoth, sk->protinfo.dn.numoth_rcv); - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset+length) - break; - } - end_bh_atomic(); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) - len = length; - - return len; -} - static int dn_create(struct socket *sock, int protocol) { struct sock *sk; @@ -688,7 +673,7 @@ static int -dn_release(struct socket *sock, struct socket *peer) +dn_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -705,8 +690,11 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { - struct sock *sk = sock->sk; + struct sock *sk = sock->sk; + struct dn_scp *scp = &sk->protinfo.dn; struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr; + struct net_device *dev; + int rv; if (sk->zapped == 0) return -EINVAL; @@ -717,50 +705,47 @@ if (saddr->sdn_family != AF_DECnet) return -EINVAL; + if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2)) + return -EINVAL; + if (saddr->sdn_objnum && !suser()) return -EPERM; - if (!saddr->sdn_objname && (saddr->sdn_objnamel > DN_MAXOBJL)) + if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL) return -EINVAL; if (saddr->sdn_flags & ~SDF_WILD) return -EINVAL; - if ((saddr->sdn_flags & SDF_WILD) && !suser()) - return -EPERM; - - start_bh_atomic(); - if (saddr->sdn_flags & SDF_WILD) { - if (dn_wild_sk) { - end_bh_atomic(); - return -EADDRINUSE; - } - dn_wild_sk = sk; - sk->zapped = 0; - memcpy(&sk->protinfo.dn.addr, saddr, addr_len); - end_bh_atomic(); - return 0; - } - - if (saddr->sdn_objnum && dn_sklist_find_by_objnum(saddr->sdn_objnum)) { - end_bh_atomic(); - return -EADDRINUSE; - } - - if (!saddr->sdn_objnum) { - if (dn_sklist_find_by_name(saddr->sdn_objname)) { - end_bh_atomic(); - return -EADDRINUSE; + if (!suser()) + return -EPERM; + } else { + if (dn_ntohs(saddr->sdn_nodeaddrl)) { + read_lock(&dev_base_lock); + for(dev = dev_base; dev; dev = dev->next) { + if (!dev->dn_ptr) + continue; + if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) + break; + } + read_unlock(&dev_base_lock); + if (dev == NULL) + return -EADDRNOTAVAIL; } } - memcpy(&sk->protinfo.dn.addr, saddr, addr_len); + + memcpy(&scp->addr, saddr, addr_len); sk->zapped = 0; - sklist_insert_socket(&dn_sklist, sk); - end_bh_atomic(); - return 0; + if ((rv = dn_hash_sock(sk)) == 0) + goto out; + + sk->zapped = 1; +out: + + return rv; } @@ -781,17 +766,17 @@ if ((scp->accessdata.acc_accl != 0) && (scp->accessdata.acc_accl <= 12)) { - scp->addr.sdn_objnamel = scp->accessdata.acc_accl; - memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, scp->addr.sdn_objnamel); + scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl); + memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel)); scp->accessdata.acc_accl = 0; memset(scp->accessdata.acc_acc, 0, 40); } - scp->addr.sdn_add.a_len = 2; + scp->addr.sdn_add.a_len = dn_htons(2); *(dn_address *)scp->addr.sdn_add.a_addr = decnet_address; - sklist_insert_socket(&dn_sklist, sk); + dn_hash_sock(sk); return 0; } @@ -801,6 +786,7 @@ { struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr; struct sock *sk = sock->sk; + struct dn_scp *scp = &sk->protinfo.dn; int err = -EISCONN; lock_sock(sk); @@ -835,10 +821,10 @@ if (sk->zapped && (err = dn_auto_bind(sock))) goto out; - memcpy(&sk->protinfo.dn.peer, addr, addr_len); + memcpy(&scp->peer, addr, addr_len); err = -EHOSTUNREACH; - if (dn_route_output(sk) < 0) + if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer), dn_saddr2dn(&scp->addr), 0) < 0) goto out; sk->state = TCP_SYN_SENT; @@ -925,8 +911,6 @@ { struct sock *sk = sock->sk; - /* printk(KERN_DEBUG "dn_wait_accept: in\n"); */ - while(sk->state == TCP_LISTEN) { if (flags & O_NONBLOCK) { return -EAGAIN; @@ -939,10 +923,8 @@ SOCK_SLEEP_POST(sk) - if (signal_pending(current)) { - /* printk(KERN_DEBUG "dn_wait_accept: signal\n"); */ + if (signal_pending(current)) return -ERESTARTSYS; /* But of course you don't! */ - } } if ((sk->protinfo.dn.state != DN_RUN) && (sk->protinfo.dn.state != DN_DRC)) { @@ -951,16 +933,15 @@ } sock->state = SS_CONNECTED; - /* printk(KERN_DEBUG "dn_wait_accept: out\n"); */ return 0; } -static int dn_accept(struct socket *sock, struct socket *newsock,int flags) +static int dn_accept(struct socket *sock, struct socket *newsock, int flags) { - struct sock *sk=sock->sk, *newsk; - struct sk_buff *skb = NULL; + struct sock *sk = sock->sk, *newsk; + struct sk_buff *skb = NULL; struct dn_skb_cb *cb; unsigned char menuver; int err = 0; @@ -978,15 +959,8 @@ return -EINVAL; } - if (newsock->sk != NULL) { - newsock->sk->socket = NULL; - dn_destroy_sock(newsock->sk); - newsock->sk = NULL; - } - do { - /* printk(KERN_DEBUG "dn_accept: loop top\n"); */ if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if (flags & O_NONBLOCK) @@ -1023,9 +997,7 @@ dst_release(xchg(&newsk->dst_cache, skb->dst)); skb->dst = NULL; - newsk->protinfo.dn.state = DN_CR; - newsk->protinfo.dn.addrloc = dn_alloc_port(); newsk->protinfo.dn.addrrem = cb->src_port; newsk->protinfo.dn.mss = cb->segsize; newsk->protinfo.dn.accept_mode = sk->protinfo.dn.accept_mode; @@ -1041,6 +1013,7 @@ skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.addr, &type)); skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.peer, &type)); *(dn_address *)newsk->protinfo.dn.peer.sdn_add.a_addr = cb->src; + *(dn_address *)newsk->protinfo.dn.addr.sdn_add.a_addr = cb->dst; menuver = *skb->data; skb_pull(skb, 1); @@ -1065,7 +1038,7 @@ sizeof(struct optdata_dn)); lock_sock(newsk); - sklist_insert_socket(&dn_sklist, newsk); + dn_hash_sock(newsk); dn_send_conn_ack(newsk); @@ -1091,7 +1064,7 @@ lock_sock(sk); if (peer) { - if (sock->state != SS_CONNECTED && sk->protinfo.dn.accept_mode == ACC_IMMED) + if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED) return -ENOTCONN; memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn)); @@ -1259,12 +1232,15 @@ static int dn_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + int err = -EINVAL; + + lock_sock(sk); if (sk->zapped) - return -EINVAL; + goto out; if ((sk->protinfo.dn.state != DN_O) || (sk->state == TCP_LISTEN)) - return -EINVAL; + goto out; if (backlog > SOMAXCONN) backlog = SOMAXCONN; @@ -1272,8 +1248,12 @@ sk->max_ack_backlog = backlog; sk->ack_backlog = 0; sk->state = TCP_LISTEN; + err = 0; - return 0; +out: + release_sock(sk); + + return err; } @@ -1312,10 +1292,17 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { - return _dn_setsockopt(sock, level, optname, optval, optlen, 0); + struct sock *sk = sock->sk; + int err; + + lock_sock(sk); + err = __dn_setsockopt(sock, level, optname, optval, optlen, 0); + release_sock(sk); + + return err; } -static int _dn_setsockopt(struct socket *sock, int level,int optname, char *optval, int optlen, int flags) +static int __dn_setsockopt(struct socket *sock, int level,int optname, char *optval, int optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; @@ -1406,7 +1393,6 @@ break; case DSO_CONACCEPT: - lock_sock(sk); if (scp->state != DN_CR) return -EINVAL; @@ -1414,11 +1400,9 @@ scp->state = DN_CC; dn_send_conn_conf(sk); err = dn_wait_accept(sock, sock->file->f_flags); - release_sock(sk); return err; case DSO_CONREJECT: - lock_sock(sk); if (scp->state != DN_CR) return -EINVAL; @@ -1426,11 +1410,9 @@ scp->state = DN_DR; sk->shutdown = SHUTDOWN_MASK; dn_send_disc(sk, 0x38, 0); - release_sock(sk); break; #ifdef CONFIG_DECNET_FW - case DN_FW_MASQ_TIMEOUTS: case DN_FW_APPEND: case DN_FW_REPLACE: case DN_FW_DELETE: @@ -1465,11 +1447,17 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { - return _dn_getsockopt(sock, level, optname, optval, optlen, 0); + struct sock *sk = sock->sk; + int err; + + lock_sock(sk); + err = __dn_getsockopt(sock, level, optname, optval, optlen, 0); + release_sock(sk); + + return err; } -static int -_dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *optlen, int flags) +static int __dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; @@ -1552,8 +1540,6 @@ struct dn_scp *scp = &sk->protinfo.dn; int err = 0; - /* printk(KERN_DEBUG "dn_wait_run %d\n", scp->state); */ - switch(scp->state) { case DN_RUN: return 0; @@ -1567,7 +1553,6 @@ break; default: return -ENOTCONN; - goto out; } if (flags & MSG_DONTWAIT) @@ -1575,11 +1560,11 @@ do { if ((err = sock_error(sk)) != 0) - goto out; + break; if (signal_pending(current)) { err = -ERESTARTSYS; - goto out; + break; } SOCK_SLEEP_PRE(sk) @@ -1591,8 +1576,6 @@ } while(scp->state != DN_RUN); -out: - return 0; } @@ -1621,6 +1604,8 @@ /* minimum data length for read exceeded */ if (len >= target) return 1; + + skb = skb->next; } return 0; @@ -1636,8 +1621,9 @@ int target = size > 1 ? 1 : 0; int copied = 0; int rv = 0; - struct sk_buff *skb = NULL, **pskb; + struct sk_buff *skb, *nskb; struct dn_skb_cb *cb = NULL; + unsigned char eor = 0; lock_sock(sk); @@ -1710,8 +1696,7 @@ sock->flags &= ~SO_WAITDATA; } - pskb = &((struct sk_buff *)queue)->next; - while((skb = *pskb) != (struct sk_buff *)queue) { + for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) { int chunk = skb->len; cb = (struct dn_skb_cb *)skb->cb; @@ -1727,27 +1712,29 @@ if (!(flags & MSG_PEEK)) skb->len -= chunk; + eor = cb->nsp_flags & 0x40; + nskb = skb->next; + if (skb->len == 0) { skb_unlink(skb); kfree_skb(skb); + /* + * N.B. Don't refer to skb or cb after this point + * in loop. + */ if ((scp->flowloc_sw == DN_DONTSEND) && !dn_congested(sk)) { scp->flowloc_sw = DN_SEND; dn_nsp_send_lnk(sk, DN_SEND); } } - pskb = &skb->next; - - if (cb->nsp_flags & 0x40) { - if (sk->type == SOCK_SEQPACKET) { - msg->msg_flags |= MSG_EOR; + if (eor) { + if (sk->type == SOCK_SEQPACKET) + break; + if (!(flags & MSG_WAITALL)) break; - } } - if (!(flags & MSG_WAITALL)) - break; - if (flags & MSG_OOB) break; @@ -1756,10 +1743,19 @@ } rv = copied; + + if (eor && (sk->type == SOCK_SEQPACKET)) + msg->msg_flags |= MSG_EOR; + out: if (rv == 0) rv = (flags & MSG_PEEK) ? -sk->err : sock_error(sk); + if ((rv >= 0) && msg->msg_name) { + memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn)); + msg->msg_namelen = sizeof(struct sockaddr_dn); + } + release_sock(sk); return rv; @@ -1787,7 +1783,7 @@ unsigned short ack; int len; - if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT)) + if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR)) return -EOPNOTSUPP; if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) @@ -1913,14 +1909,18 @@ } else { cb->segnum = scp->numdat++; scp->numdat &= 0x0fff; + msgflg = 0x00; if (sock->type == SOCK_STREAM) msgflg = 0x60; - else - msgflg = 0x00; - if (numseg == 0) + if (scp->seg_size == 0) msgflg |= 0x20; - if ((sent + len) == size) + + scp->seg_size += len; + + if (((sent + len) == size) && (flags & MSG_EOR)) { msgflg |= 0x40; + scp->seg_size = 0; + } ack = scp->ackxmt_dat | 0x8000; } @@ -1987,6 +1987,61 @@ }; #ifdef CONFIG_PROC_FS + +static int dn_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + struct sock *sk; + struct dn_scp *scp; + int len = 0; + off_t pos = 0; + off_t begin = 0; + char buf1[DN_ASCBUF_LEN]; + char buf2[DN_ASCBUF_LEN]; + + len += sprintf(buffer + len, "Local Remote\n"); + + read_lock(&dn_hash_lock); + for(sk = dn_sklist; sk != NULL; sk = sk->next) { + scp = &sk->protinfo.dn; + + len += sprintf(buffer + len, + "%6s/%04X %04d:%04d %04d:%04d %01d %6s/%04X %04d:%04d %04d:%04d %01d %4s %s\n", + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), + scp->addrloc, + scp->numdat, + scp->numoth, + scp->ackxmt_dat, + scp->ackxmt_oth, + scp->flowloc_sw, + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), + scp->addrrem, + scp->numdat_rcv, + scp->numoth_rcv, + scp->ackrcv_dat, + scp->ackrcv_oth, + scp->flowrem_sw, + dn_state2asc(scp->state), + ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); + + pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > (offset + length)) + break; + } + read_unlock(&dn_hash_lock); + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) + len = length; + + return len; +} + struct proc_dir_entry decnet_linkinfo = { PROC_NET_DN_SKT, 6, "decnet", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, dn_get_info @@ -2011,7 +2066,6 @@ static struct proto_ops dn_proto_ops = { AF_DECnet, - sock_no_dup, dn_release, dn_bind, dn_connect, @@ -2026,7 +2080,8 @@ dn_getsockopt, sock_no_fcntl, dn_sendmsg, - dn_recvmsg + dn_recvmsg, + sock_no_mmap }; #ifdef CONFIG_SYSCTL @@ -2061,46 +2116,41 @@ #ifdef CONFIG_SYSCTL dn_register_sysctl(); #endif /* CONFIG_SYSCTL */ - printk(KERN_INFO "DECnet for Linux: V.2.2.5s (C) 1995-1999 Linux DECnet Project Team\n"); + printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.13s (C) 1995-1999 Linux DECnet Project Team\n"); } -void __init decnet_setup(char *str, int *ints) +#ifndef MODULE +static int __init decnet_setup(char *str) { + unsigned short area = simple_strtoul(str, &str, 0); + unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0); + unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); - if ((ints[0] == 2) || (ints[0] == 3)) { - - if (ints[1] < 0) - ints[1] = 0; - if (ints[1] > 63) - ints[1] = 63; - - if (ints[2] < 0) - ints[2] = 0; - if (ints[2] > 1023) - ints[2] = 1023; + decnet_address = dn_htons(area << 10 | node); + dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); - decnet_address = dn_htons(ints[1] << 10 | ints[2]); - dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); - - if (ints[0] == 3) { - switch(ints[3]) { + switch(type) { + default: + printk(KERN_INFO "Invalid DECnet node type, switching to EndNode\n"); + case 0: + decnet_node_type = DN_RT_INFO_ENDN; + break; #ifdef CONFIG_DECNET_ROUTER - case 1: - decnet_node_type = DN_RT_INFO_L1RT; - break; - case 2: - decnet_node_type = DN_RT_INFO_L2RT; - break; + case 1: + decnet_node_type = DN_RT_INFO_L1RT; + break; + case 2: + decnet_node_type = DN_RT_INFO_L2RT; + break; #endif /* CONFIG_DECNET_ROUTER */ - default: - decnet_node_type = DN_RT_INFO_ENDN; - } - } - } else { - printk(KERN_ERR "DECnet: Invalid command line options\n"); } + + return 0; } + +__setup("decnet=", decnet_setup); +#endif #ifdef MODULE EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c --- v2.3.14/linux/net/decnet/dn_dev.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/dn_dev.c Mon Aug 23 10:01:02 1999 @@ -60,10 +60,6 @@ static int dn_eth_up(struct net_device *); static void dn_send_brd_hello(struct net_device *dev); static void dn_send_ptp_hello(struct net_device *dev); -static int dn_dev_eth_setsrc(struct sk_buff *skb); -static int dn_dev_lo_setsrc(struct sk_buff *skb); -static int dn_dev_ptp_setsrc(struct sk_buff *skb); -static int dn_dev_eth_neigh_setup(struct neighbour *n); static struct dn_dev_parms dn_dev_list[] = { { @@ -82,8 +78,6 @@ NULL, NULL, dn_send_brd_hello, - dn_dev_eth_setsrc, - dn_dev_eth_neigh_setup, NULL }, { @@ -102,8 +96,6 @@ NULL, NULL, dn_send_brd_hello, - NULL, - NULL, NULL }, #if 0 @@ -123,8 +115,6 @@ NULL, NULL, dn_send_ptp_hello, - dn_dev_ptp_setsrc, - NULL, NULL }, #endif @@ -145,8 +135,6 @@ NULL, NULL, dn_send_brd_hello, - dn_dev_ptp_setsrc, - NULL, NULL }, #endif @@ -167,8 +155,6 @@ NULL, NULL, dn_send_ptp_hello, - dn_dev_ptp_setsrc, - NULL, NULL }, #endif @@ -188,8 +174,6 @@ NULL, NULL, dn_send_brd_hello, - dn_dev_lo_setsrc, - dn_dev_eth_neigh_setup, NULL } }; @@ -383,11 +367,14 @@ static struct dn_dev *dn_dev_by_index(int ifindex) { struct net_device *dev; + struct dn_dev *dn_dev = NULL; dev = dev_get_by_index(ifindex); - if (dev) - return dev->dn_ptr; + if (dev) { + dn_dev = dev->dn_ptr; + dev_put(dev); + } - return NULL; + return dn_dev; } @@ -425,7 +412,7 @@ return -EINVAL; } - if ((dev = dev_get(ifr->ifr_name)) == NULL) { + if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) { ret = -ENODEV; goto done; } @@ -511,7 +498,7 @@ if (rta[IFA_LOCAL-1] == NULL) return -EINVAL; - if ((dev = dev_get_by_index(ifm->ifa_index)) == NULL) + if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) return -ENODEV; if ((dn_db = dev->dn_ptr) == NULL) { @@ -547,7 +534,7 @@ ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_DECnet; - ifm->ifa_prefixlen = 0; + ifm->ifa_prefixlen = 16; ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; @@ -556,6 +543,7 @@ RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); nlh->nlmsg_len = skb->tail - b; return skb->len; + nlmsg_failure: rtattr_failure: skb_trim(skb, b - skb->data); @@ -624,7 +612,11 @@ s_idx = cb->args[0]; s_dn_idx = dn_idx = cb->args[1]; - for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { + read_lock(&dev_base_lock); + for(dev = dev_base, idx = 0; dev; dev = dev->next) { + if ((dn_db = dev->dn_ptr) == NULL) + continue; + idx++; if (idx < s_idx) continue; if (idx > s_idx) @@ -641,6 +633,7 @@ } } done: + read_unlock(&dev_base_lock); cb->args[0] = idx; cb->args[1] = dn_idx; @@ -653,6 +646,7 @@ int s_idx = cb->args[0]; struct net_device *dev; + read_lock(&dev_base_lock); for(dev=dev_base, idx=0; dev; dev = dev->next) { if (!dev->dn_ptr) continue; @@ -662,6 +656,7 @@ if (dn_dev_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) break; } + read_unlock(&dev_base_lock); cb->args[0] = idx; return skb->len; @@ -711,7 +706,7 @@ if (dn_db->router) { struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; - memcpy(msg->neighbor, dn->addr, ETH_ALEN); + dn_dn2eth(msg->neighbor, dn->addr); } msg->timer = dn_htons((unsigned short)dn_db->parms.t3); @@ -724,11 +719,7 @@ skb->nh.raw = skb->data; - if (dev->hard_header(skb,dev, ETH_P_DNA_RT,dn_rt_all_rt_mcast, - decnet_ether_address, skb->len) >= 0) - dn_send_skb(skb); - else - kfree_skb(skb); + dn_rt_finish_output(skb, dn_rt_all_rt_mcast); } @@ -754,7 +745,7 @@ if (dn->priority != dn_db->parms.priority) return 0; - if (dn_ntohs(dn_eth2dn(dn->addr)) < dn_ntohs(decnet_address)) + if (dn_ntohs(dn->addr) < dn_ntohs(decnet_address)) return 1; return 0; @@ -821,21 +812,11 @@ if (dn_am_i_a_router(dn, dn_db)) { struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); if (skb2) { - if (dev->hard_header(skb2, dev, ETH_P_DNA_RT, - dn_rt_all_end_mcast, - decnet_ether_address, - skb2->len) >= 0) - dn_send_skb(skb2); - else - kfree_skb(skb2); + dn_rt_finish_output(skb2, dn_rt_all_end_mcast); } } - if (dev->hard_header(skb, dev, ETH_P_DNA_RT, dn_rt_all_rt_mcast, - decnet_ether_address, skb->len) >= 0) - dn_send_skb(skb); - else - kfree_skb(skb); + dn_rt_finish_output(skb, dn_rt_all_rt_mcast); } static void dn_send_brd_hello(struct net_device *dev) @@ -857,7 +838,7 @@ int tdlen = 16; int size = dev->hard_header_len + 2 + 4 + tdlen; struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC); - struct dn_dev *dn_db = dev->dn_ptr; + /* struct dn_dev *dn_db = dev->dn_ptr; */ unsigned char *ptr; int i; @@ -876,25 +857,17 @@ for(i = 0; i < tdlen; i++) *ptr++ = 0252; +#if 0 if (dn_db->router) { struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; if (memcmp(dn->addr, decnet_ether_address, ETH_ALEN) == 0) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 && dev->hard_header(skb2, dev, ETH_P_DNA_RT, - dn_rt_all_end_mcast, - decnet_ether_address, - skb->len) >= 0) { - - dn_send_skb(skb2); - } + dn_rt_finish_output(skb2, dn_rt_all_end_mcast); } } +#endif - if (dev->hard_header(skb, dev, ETH_P_DNA_RT, dn_rt_all_rt_mcast, - decnet_ether_address, skb->len) < 0); - return; - - dn_send_skb(skb); + dn_rt_finish_output(skb, dn_rt_all_rt_mcast); } static int dn_eth_up(struct net_device *dev) @@ -914,51 +887,6 @@ return 0; } -static int dn_dev_eth_setsrc(struct sk_buff *skb) -{ - struct ethhdr *h = skb->mac.ethernet; - struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - - if (h == NULL) - return -1; - - cb->neigh = dn_eth2dn(h->h_source); - - return 0; -} - -static int dn_dev_lo_setsrc(struct sk_buff *skb) -{ - struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - - cb->neigh = decnet_address; - - return 0; -} - -static int dn_dev_eth_neigh_setup(struct neighbour *n) -{ - struct dn_neigh *dn = (struct dn_neigh *)n; - - memcpy(n->ha, dn->addr, ETH_ALEN); - - return 0; -} - -static int dn_dev_ptp_setsrc(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct dn_dev *dn_db = dev->dn_ptr; - struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - - if (!dn_db->peer) - return -1; - - cb->neigh = dn_eth2dn(((struct dn_neigh *)dn_db->peer)->addr); - - return 0; -} - static void dn_dev_set_timer(struct net_device *dev); static void dn_dev_timer_func(unsigned long arg) @@ -1045,7 +973,7 @@ } dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); - dn_db->neigh_parms->neigh_setup = dn_db->parms.neigh_setup; + /* dn_db->neigh_parms->neigh_setup = dn_db->parms.neigh_setup; */ dn_dev_sysctl_register(dev, &dn_db->parms); @@ -1091,15 +1019,12 @@ static void dn_dev_delete(struct net_device *dev) { struct dn_dev *dn_db = dev->dn_ptr; - unsigned long cpuflags; if (dn_db == NULL) return; - save_flags(cpuflags); - cli(); del_timer(&dn_db->timer); - restore_flags(cpuflags); + synchronize_bh(); #ifdef CONFIG_RTNETLINK dn_dev_ifinfo(RTM_DELLINK, dev); @@ -1249,10 +1174,10 @@ char peer_buf[DN_ASCBUF_LEN]; char router_buf[DN_ASCBUF_LEN]; - cli(); len += sprintf(buffer, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n"); + read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL) continue; @@ -1279,7 +1204,7 @@ break; } - sti(); + read_unlock(&dev_base_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -1313,12 +1238,12 @@ #ifdef CONFIG_DECNET_ROUTER { dn_fib_rtm_newroute, NULL, }, { dn_fib_rtm_delroute, NULL, }, - { dn_fib_rtm_getroute, dn_fib_dump, }, + { dn_cache_getroute, dn_fib_dump, }, { NULL, NULL, }, #else { NULL, NULL, }, { NULL, NULL, }, - { NULL, NULL, }, + { dn_cache_getroute, dn_cache_dump, }, { NULL, NULL, }, #endif { NULL, NULL, }, diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c --- v2.3.14/linux/net/decnet/dn_fib.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/dn_fib.c Mon Aug 23 10:01:02 1999 @@ -9,6 +9,7 @@ * * * Changes: + * Alexey Kuznetsov : SMP locking changes * */ #include @@ -46,6 +47,7 @@ #ifdef CONFIG_RTNETLINK static int dn_fib_table_dump(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb); static void dn_rtmsg_fib(int event, int table, struct dn_fib_action *fa, struct nlmsghdr *nlh, struct netlink_skb_parms *req); +extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); #endif /* CONFIG_RTNETLINK */ static void dn_fib_del_tree(struct dn_fib_table *t); @@ -448,7 +450,7 @@ struct dn_fib_table *t = dn_fib_get_tree(table, 0); if (t == NULL) - return -ENOBUFS; + return -ENOENT; if ((err = t->lookup(t, res)) < 0) return err; @@ -465,7 +467,13 @@ return -ENOENT; } - return (fa->fa_type == RTN_PROHIBIT) ? -fa->fa_error : 0; + switch(fa->fa_type) { + case RTN_PROHIBIT: + case RTN_UNREACHABLE: + return -fa->fa_error; + } + + return 0; } /* @@ -487,7 +495,7 @@ struct netlink_skb_parms *req) { dn_address dst, gw, mask = 0xffff; - int ifindex; + int ifindex = 0; struct neighbour *neigh; struct net_device *dev; unsigned char addr[ETH_ALEN]; @@ -505,16 +513,16 @@ memcpy(&gw, RTA_DATA(rta[RTA_GATEWAY-1]), 2); fa->fa_key = dn_ntohs(dst); - fa->fa_mask = mask; + fa->fa_mask = dn_ntohs(mask); fa->fa_ifindex = ifindex; fa->fa_proto = r->rtm_protocol; fa->fa_type = r->rtm_type; switch(fa->fa_type) { case RTN_UNICAST: - if ((dev = dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(ifindex)) == NULL) return -ENODEV; - dn_dn2eth(addr, gw); + dn_dn2eth(addr, dn_ntohs(gw)); if ((neigh = __neigh_lookup(&dn_neigh_table, &addr, dev, 1)) == NULL) return -EHOSTUNREACH; fa->fa_neigh = neigh; @@ -523,11 +531,14 @@ fa->fa_table = 0; break; case RTN_PROHIBIT: - fa->fa_error = 0; + fa->fa_error = EPERM; break; case RTN_UNREACHABLE: fa->fa_error = EHOSTUNREACH; break; + case RTN_BLACKHOLE: + fa->fa_error = EINVAL; + break; } return 0; @@ -662,20 +673,31 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) { + int t; int s_t; - struct dn_fib_table *t; + struct dn_fib_table *tb; - for(s_t = cb->args[0]; s_t < DN_NUM_TABLES; s_t++) { - if (s_t > cb->args[0]) + if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && + ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) + return dn_cache_dump(skb, cb); + + s_t = cb->args[0]; + if (s_t == 0) + s_t = cb->args[0] = DN_MIN_TABLE; + + for(t = s_t; t < DN_NUM_TABLES; t++) { + if (t < s_t) + continue; + if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int)); - t = dn_fib_get_tree(s_t, 0); - if (t == NULL) + tb = dn_fib_get_tree(t, 0); + if (tb == NULL) continue; - if (t->dump(t, skb, cb) < 0) + if (tb->dump(tb, skb, cb) < 0) break; } - cb->args[0] = s_t; + cb->args[0] = t; return skb->len; } @@ -696,6 +718,8 @@ return -EINVAL; } +#ifdef CONFIG_PROC_FS + struct dn_fib_procfs { int len; off_t pos; @@ -780,6 +804,8 @@ 0, &proc_net_inode_operations, decnet_rt_get_info }; + +#endif /* CONFIG_PROC_FS */ #ifdef CONFIG_DECNET_MODULE void dn_fib_cleanup(void) diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c --- v2.3.14/linux/net/decnet/dn_neigh.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/dn_neigh.c Mon Aug 23 10:01:02 1999 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev); static int dn_neigh_construct(struct neighbour *); static void dn_long_error_report(struct neighbour *, struct sk_buff *); static void dn_short_error_report(struct neighbour *, struct sk_buff *); @@ -92,11 +94,13 @@ NULL, PF_DECnet, sizeof(struct dn_neigh), - ETH_ALEN, + sizeof(dn_address), + dn_neigh_hash, dn_neigh_construct, NULL, /* pconstructor */ NULL, /* pdestructor */ NULL, /* proxyredo */ + "dn_neigh_cache", { NULL, NULL, @@ -125,6 +129,17 @@ }; +static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) +{ + u32 hash_val; + + hash_val = *(dn_address *)pkey; + hash_val ^= (hash_val >> 10); + hash_val ^= (hash_val >> 3); + + return hash_val & NEIGH_HASHMASK; +} + static int dn_neigh_construct(struct neighbour *neigh) { struct net_device *dev = neigh->dev; @@ -148,6 +163,16 @@ neigh->nud_state = NUD_NOARP; neigh->output = neigh->ops->connected_output; + if ((dev->type == ARPHRD_IPGRE) || (dev->flags & IFF_POINTOPOINT)) + memcpy(neigh->ha, dev->broadcast, dev->addr_len); + else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK)) + dn_dn2eth(neigh->ha, dn->addr); + else { + if (net_ratelimit()) + printk(KERN_DEBUG "Trying to create neigh for hw %d\n", dev->type); + return -EINVAL; + } + dn->blksize = 230; return 0; @@ -217,13 +242,27 @@ skb->dst->neighbour->ops->queue_xmit(skb); } +static int dn_neigh_output_packet(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct neighbour *neigh = dst->neighbour; + struct net_device *dev = neigh->dev; + + if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len) >= 0) + return neigh->ops->queue_xmit(skb); + + if (net_ratelimit()) + printk(KERN_DEBUG "dn_neigh_output_packet: oops, can't send packet\n"); + + kfree_skb(skb); + return -EINVAL; +} static int dn_long_output(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; - struct dn_dev *dn_db = dev->dn_ptr; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; unsigned char *data; struct dn_long_packet *lp; @@ -252,9 +291,9 @@ lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS)); lp->d_area = lp->d_subarea = 0; - dn_dn2eth(lp->d_id, cb->dst); + dn_dn2eth(lp->d_id, dn_ntohs(cb->dst)); lp->s_area = lp->s_subarea = 0; - dn_dn2eth(lp->s_id, cb->src); + dn_dn2eth(lp->s_id, dn_ntohs(cb->src)); lp->nl2 = 0; lp->visit_ct = cb->hops & 0x3f; lp->s_class = 0; @@ -262,15 +301,7 @@ skb->nh.raw = skb->data; - if (dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, - dn_db->addr, skb->len) >= 0) - return neigh->ops->queue_xmit(skb); - - if (net_ratelimit()) - printk(KERN_DEBUG "dn_long_output: oops, can't sent packet\n"); - - kfree_skb(skb); - return -EINVAL; + return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet); } static int dn_short_output(struct sk_buff *skb) @@ -309,12 +340,7 @@ skb->nh.raw = skb->data; - if (dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, - NULL, skb->len) >= 0) - return neigh->ops->queue_xmit(skb); - - kfree_skb(skb); - return -EINVAL; + return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet); } /* @@ -350,18 +376,13 @@ sp = (struct dn_short_packet *)(data + 2); sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); - sp->dstnode = cb->dst & __constant_htons(0x03ff); - sp->srcnode = cb->src & __constant_htons(0x03ff); + sp->dstnode = cb->dst & dn_htons(0x03ff); + sp->srcnode = cb->src & dn_htons(0x03ff); sp->forward = cb->hops & 0x3f; skb->nh.raw = skb->data; - if (dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, - NULL, skb->len) >= 0) - return neigh->ops->queue_xmit(skb); - - kfree_skb(skb); - return -EINVAL; + return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet); } /* @@ -372,20 +393,20 @@ */ struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr) { - int i; struct neighbour *neigh; + u32 hash_val; - start_bh_atomic(); - for(i = 0; i < NEIGH_HASHMASK; i++) { - for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) { - if (memcmp(neigh->primary_key, ptr, ETH_ALEN) == 0) { - atomic_inc(&neigh->refcnt); - end_bh_atomic(); - return neigh; - } + hash_val = tbl->hash(ptr, NULL); + + read_lock_bh(&tbl->lock); + for(neigh = tbl->hash_buckets[hash_val]; neigh != NULL; neigh = neigh->next) { + if (memcmp(neigh->primary_key, ptr, tbl->key_len) == 0) { + atomic_inc(&neigh->refcnt); + read_unlock_bh(&tbl->lock); + return neigh; } } - end_bh_atomic(); + read_unlock_bh(&tbl->lock); return NULL; } @@ -418,30 +439,39 @@ struct neighbour *neigh; struct dn_neigh *dn; struct dn_dev *dn_db; + dn_address src; + + src = dn_eth2dn(msg->id); - start_bh_atomic(); - neigh = __neigh_lookup(&dn_neigh_table, msg->id, skb->dev, 1); - end_bh_atomic(); + neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); dn = (struct dn_neigh *)neigh; if (neigh) { - neigh_update(neigh, msg->id, NUD_NOARP, 1, 0); - neigh->used = jiffies; + write_lock(&neigh->lock); + neigh->used = jiffies; dn_db = (struct dn_dev *)neigh->dev->dn_ptr; - dn->blksize = dn_ntohs(msg->blksize); - dn->priority = msg->priority; + if (!(neigh->nud_state & NUD_PERMANENT)) { + neigh->updated = jiffies; + + if (neigh->dev->type == ARPHRD_ETHER) + memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN); - dn->flags &= ~DN_NDFLAG_P3; + dn->blksize = dn_ntohs(msg->blksize); + dn->priority = msg->priority; - switch(msg->iinfo & DN_RT_INFO_TYPE) { - case DN_RT_INFO_L1RT: - dn->flags &=~DN_NDFLAG_R2; - dn->flags |= DN_NDFLAG_R1; - case DN_RT_INFO_L2RT: - dn->flags |= DN_NDFLAG_R2; + dn->flags &= ~DN_NDFLAG_P3; + + switch(msg->iinfo & DN_RT_INFO_TYPE) { + case DN_RT_INFO_L1RT: + dn->flags &=~DN_NDFLAG_R2; + dn->flags |= DN_NDFLAG_R1; + break; + case DN_RT_INFO_L2RT: + dn->flags |= DN_NDFLAG_R2; + } } if (!dn_db->router) { @@ -450,7 +480,7 @@ if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority) neigh_release(xchg(&dn_db->router, neigh_clone(neigh))); } - + write_unlock(&neigh->lock); neigh_release(neigh); } @@ -465,21 +495,30 @@ struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data; struct neighbour *neigh; struct dn_neigh *dn; + dn_address src; + + src = dn_eth2dn(msg->id); - start_bh_atomic(); - neigh = __neigh_lookup(&dn_neigh_table, msg->id, skb->dev, 1); - end_bh_atomic(); + neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); dn = (struct dn_neigh *)neigh; if (neigh) { - neigh_update(neigh, msg->id, NUD_NOARP, 1, 0); + write_lock(&neigh->lock); + neigh->used = jiffies; - dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2); - dn->blksize = dn_ntohs(msg->blksize); - dn->priority = 0; + if (!(neigh->nud_state & NUD_PERMANENT)) { + neigh->updated = jiffies; + + if (neigh->dev->type == ARPHRD_ETHER) + memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN); + dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2); + dn->blksize = dn_ntohs(msg->blksize); + dn->priority = 0; + } + write_unlock(&neigh->lock); neigh_release(neigh); } @@ -516,7 +555,7 @@ struct neigh_table *tbl = &dn_neigh_table; unsigned char *rs = ptr; - start_bh_atomic(); + read_lock_bh(&tbl->lock); for(i = 0; i < NEIGH_HASHMASK; i++) { for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) { @@ -533,7 +572,7 @@ t++; if (rs == NULL) continue; - memcpy(rs, dn->addr, ETH_ALEN); + dn_dn2eth(rs, dn->addr); rs += 6; *rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0; *rs |= dn->priority; @@ -541,7 +580,7 @@ } } - end_bh_atomic(); + read_unlock_bh(&tbl->lock); return t; } @@ -569,7 +608,7 @@ read_lock(&n->lock); len += sprintf(buffer+len, "%-7s %s%s%s %02x %02d %07ld %-8s\n", - dn_addr2asc(dn_ntohs(dn_eth2dn(dn->addr)), buf), + dn_addr2asc(dn_ntohs(dn->addr), buf), (dn->flags&DN_NDFLAG_R1) ? "1" : "-", (dn->flags&DN_NDFLAG_R2) ? "2" : "-", (dn->flags&DN_NDFLAG_P3) ? "3" : "-", diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c --- v2.3.14/linux/net/decnet/dn_nsp_in.c Sat May 29 11:09:54 1999 +++ linux/net/decnet/dn_nsp_in.c Mon Aug 23 10:01:02 1999 @@ -19,6 +19,7 @@ * Steve Whitehouse: More checks on skb->len to catch bogus packets * Fixed various race conditions and possible nasties. * Steve Whitehouse: Now handles returned conninit frames. + * David S. Miller: New socket locking */ /****************************************************************************** @@ -60,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -149,9 +151,8 @@ * to find its sockets, since it searches on object name/number * rather than port numbers */ -static int dn_conninit_rx(struct sk_buff *skb) +static struct sock *dn_find_listener(struct sk_buff *skb) { - struct sock *sk; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data; struct sockaddr_dn addr; @@ -169,29 +170,29 @@ /* printk(KERN_DEBUG "username2sockaddr 1\n"); */ if (dn_username2sockaddr(skb->data, skb->len, &addr, &type) < 0) - goto free_out; + goto err_out; if (type > 1) - goto free_out; + goto err_out; /* printk(KERN_DEBUG "looking for listener...\n"); */ - if ((sk = dn_sklist_find_listener(&addr)) == NULL) - return 1; + return dn_sklist_find_listener(&addr); +err_out: + return NULL; +} +static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb) +{ /* printk(KERN_DEBUG "checking backlog...\n"); */ - if (sk->ack_backlog >= sk->max_ack_backlog) - goto free_out; + if (sk->ack_backlog >= sk->max_ack_backlog) { + kfree_skb(skb); + return; + } /* printk(KERN_DEBUG "waking up socket...\n"); */ sk->ack_backlog++; skb_queue_tail(&sk->receive_queue, skb); sk->state_change(sk); - - return 0; - -free_out: - kfree_skb(skb); - return 0; } static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) @@ -393,13 +394,17 @@ } /* - * Copy of sock_queue_rcv_skb (from net/core/datagram.c) to + * Copy of sock_queue_rcv_skb (from sock.h) to * queue other data segments. Also we send SIGURG here instead * of the normal SIGIO, 'cos its out of band data. */ static __inline__ int dn_queue_other_skb(struct sock *sk, struct sk_buff *skb) { +#ifdef CONFIG_FILTER + struct sk_filter *filter; +#endif struct dn_scp *scp = &sk->protinfo.dn; + unsigned long flags; /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK @@ -409,22 +414,28 @@ return -ENOMEM; #ifdef CONFIG_FILTER - if (sk->filter) - { - if (sk_filter(skb, sk->filter)) - return -EPERM; /* Toss packet */ + if (sk->filter) { + int err = 0; + bh_lock_sock(sk); + if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter)) + err = -EPERM; /* Toss packet */ + bh_unlock_sock(sk); + if (err) + return err; } #endif /* CONFIG_FILTER */ skb_set_owner_r(skb, sk); skb_queue_tail(&scp->other_receive_queue, skb); + read_lock_irqsave(&sk->callback_lock, flags); if (!sk->dead) { struct socket *sock = sk->socket; wake_up_interruptible(sk->sleep); if (!(sock->flags & SO_WAITDATA) && sock->fasync_list) kill_fasync(sock->fasync_list, SIGURG); } + read_unlock_irqrestore(&sk->callback_lock, flags); return 0; } @@ -495,28 +506,21 @@ * deals with it. It puts the socket into the NO_COMMUNICATION * state. */ -static void dn_returned_conninit(struct sk_buff *skb) +static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb) { - struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - struct sock *sk; - - cb->dst_port = cb->src_port; - cb->src_port = 0; + struct dn_scp *scp = &sk->protinfo.dn; - if ((sk = dn_find_by_skb(skb)) != NULL) { - struct dn_scp *scp = &sk->protinfo.dn; - if (scp->state == DN_CI) { - scp->state = DN_NC; - sk->state = TCP_CLOSE; - if (!sk->dead) - sk->state_change(sk); - } + if (scp->state == DN_CI) { + scp->state = DN_NC; + sk->state = TCP_CLOSE; + if (!sk->dead) + sk->state_change(sk); } kfree_skb(skb); } -int dn_nsp_rx(struct sk_buff *skb) +static int dn_nsp_rx_packet(struct sk_buff *skb) { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; struct sock *sk = NULL; @@ -525,7 +529,7 @@ skb->h.raw = skb->data; cb->nsp_flags = *ptr++; - if (decnet_debug_level & 1) + if (decnet_debug_level & 2) printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags); #ifdef CONFIG_DECNET_RAW @@ -540,17 +544,17 @@ /* * Returned packets... + * Swap src & dst and look up in the normal way. */ if (cb->rt_flags & DN_RT_F_RTS) { - if ((cb->nsp_flags & 0x0c) == 0x08) { - switch(cb->nsp_flags & 0x70) { - case 0x10: - case 0x60: - dn_returned_conninit(skb); - goto out; - } - } - goto free_out; + unsigned short tmp = cb->dst_port; + cb->dst_port = cb->src_port; + cb->src_port = tmp; + tmp = cb->dst; + cb->dst = cb->src; + cb->src = tmp; + sk = dn_find_by_skb(skb); + goto got_it; } /* @@ -564,7 +568,8 @@ goto free_out; case 0x10: case 0x60: - return dn_conninit_rx(skb); + sk = dn_find_listener(skb); + goto got_it; } } @@ -590,7 +595,9 @@ /* * Find the socket to which this skb is destined. */ - if ((sk = dn_find_by_skb(skb)) != NULL) { + sk = dn_find_by_skb(skb); +got_it: + if (sk != NULL) { struct dn_scp *scp = &sk->protinfo.dn; int ret; /* printk(KERN_DEBUG "dn_nsp_rx: Found a socket\n"); */ @@ -605,6 +612,7 @@ else sk_add_backlog(sk, skb); bh_unlock_sock(sk); + sock_put(sk); return ret; } @@ -612,10 +620,14 @@ free_out: kfree_skb(skb); -out: return 0; } +int dn_nsp_rx(struct sk_buff *skb) +{ + return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->rx_dev, NULL, dn_nsp_rx_packet); +} + /* * This is the main receive routine for sockets. It is called * from the above when the socket is not busy, and also from @@ -626,12 +638,21 @@ struct dn_scp *scp = &sk->protinfo.dn; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; + if (cb->rt_flags & DN_RT_F_RTS) { + dn_returned_conn_init(sk, skb); + return 0; + } + /* * Control packet. */ if ((cb->nsp_flags & 0x0c) == 0x08) { /* printk(KERN_DEBUG "control type\n"); */ switch(cb->nsp_flags & 0x70) { + case 0x10: + case 0x60: + dn_nsp_conn_init(sk, skb); + break; case 0x20: dn_nsp_conn_conf(sk, skb); break; diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c --- v2.3.14/linux/net/decnet/dn_nsp_out.c Wed Jun 30 11:24:55 1999 +++ linux/net/decnet/dn_nsp_out.c Mon Aug 23 10:01:02 1999 @@ -71,8 +71,7 @@ /* * If sk == NULL, then we assume that we are supposed to be making * a routing layer skb. If sk != NULL, then we are supposed to be - * creating an skb for the NSP layer. The dn_send_skb() function will - * recognise skbs on the same basis. + * creating an skb for the NSP layer. * * The eventual aim is for each socket to have a cached header size * for its outgoing packets, and to set hdr from this when sk != NULL. @@ -86,9 +85,11 @@ return NULL; skb->protocol = __constant_htons(ETH_P_DNA_RT); - skb->sk = sk; skb->pkt_type = PACKET_OUTGOING; + if (sk) + skb_set_owner_w(skb, sk); + skb_reserve(skb, hdr); return skb; @@ -149,9 +150,6 @@ if ((skb = dn_alloc_skb(sk, len, GFP_KERNEL)) == NULL) continue; - skb->destructor = sock_wfree; - atomic_add(skb->truesize, &sk->wmem_alloc); - *size = len - 11; } @@ -253,7 +251,7 @@ cb->stamp = jiffies; cb->xmit_count++; skb2->sk = sk; - dn_send_skb(skb2); + dn_nsp_send(skb2); } skb = skb->next; win--; @@ -277,7 +275,7 @@ cb->stamp = jiffies; cb->xmit_count++; skb2->sk = sk; - dn_send_skb(skb2); + dn_nsp_send(skb2); } skb = skb->next; win--; @@ -340,7 +338,7 @@ cb->stamp = jiffies; cb->xmit_count++; skb2->sk = sk; - dn_send_skb(skb2); + dn_nsp_send(skb2); } } @@ -399,8 +397,8 @@ void dn_nsp_send_data_ack(struct sock *sk) { - struct sk_buff *skb = NULL; - struct nsp_data_ack_msg *msg; + struct sk_buff *skb = NULL; + struct nsp_data_ack_msg *msg; if ((skb = dn_alloc_skb(sk, 200, GFP_ATOMIC)) == NULL) return; @@ -414,29 +412,27 @@ sk->protinfo.dn.ackxmt_dat = sk->protinfo.dn.numdat_rcv; - dn_send_skb(skb); + dn_nsp_send(skb); } void dn_nsp_send_oth_ack(struct sock *sk) { - struct sk_buff *skb = NULL; - struct nsp_data_ack_msg *msg; + struct sk_buff *skb = NULL; + struct nsp_data_ack_msg *msg; if ((skb = dn_alloc_skb(sk, 200, GFP_ATOMIC)) == NULL) return; - /* printk(KERN_DEBUG "dn_send_oth_ack\n"); */ - msg = (struct nsp_data_ack_msg *)skb_put(skb,sizeof(*msg)); - msg->msgflg = 0x14; /* oth ack message */ + msg->msgflg = 0x14; /* oth ack message */ msg->dstaddr = sk->protinfo.dn.addrrem; msg->srcaddr = sk->protinfo.dn.addrloc; msg->acknum = dn_htons((sk->protinfo.dn.numoth_rcv & 0x0FFF) | 0x8000); sk->protinfo.dn.ackxmt_oth = sk->protinfo.dn.numoth_rcv; - dn_send_skb(skb); + dn_nsp_send(skb); } @@ -453,7 +449,7 @@ msg->msgflg = 0x24; msg->dstaddr = scp->addrrem; - dn_send_skb(skb); + dn_nsp_send(skb); } void dn_nsp_delayed_ack(struct sock *sk) @@ -492,7 +488,7 @@ } - dn_send_skb(skb); + dn_nsp_send(skb); } void dn_send_disc (struct sock *sk, unsigned char msgflg, unsigned short reason) @@ -522,7 +518,7 @@ memcpy(msg, scp->discdata_out.opt_data, scp->discdata_out.opt_optl); } - dn_send_skb(skb); + dn_nsp_send(skb); } void dn_nsp_send_lnk(struct sock *sk, unsigned short flgs) @@ -587,9 +583,6 @@ msg->msgflg = msgflg; msg->dstaddr = 0x0000; /* Remote Node will assign it*/ - if (msgflg == NSP_CI) - sk->protinfo.dn.addrloc = dn_alloc_port(); - msg->srcaddr = sk->protinfo.dn.addrloc; msg->services = 1 | NSP_FC_NONE; /* Requested flow control */ msg->info = 0x03; /* Version Number */ @@ -634,6 +627,6 @@ cb->rt_flags = DN_RT_F_RQR; - dn_send_skb(skb); + dn_nsp_send(skb); } diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_raw.c linux/net/decnet/dn_raw.c --- v2.3.14/linux/net/decnet/dn_raw.c Wed May 26 09:36:36 1999 +++ linux/net/decnet/dn_raw.c Mon Aug 23 10:01:02 1999 @@ -10,6 +10,8 @@ * * Changes: * Steve Whitehouse - connect() function. + * Steve Whitehouse - SMP changes, removed MOP stubs. MOP will + * be userland only. */ #include @@ -19,38 +21,62 @@ #include #include #include +#include #include #include +#include +static rwlock_t dn_raw_hash_lock = RW_LOCK_UNLOCKED; static struct sock *dn_raw_nsp_sklist = NULL; static struct sock *dn_raw_routing_sklist = NULL; -#ifdef CONFIG_DECNET_MOP -static struct sock *dn_raw_mop_sklist = NULL; -#endif /* CONFIG_DECNET_MOP */ -static void dn_raw_autobind(struct sock *sk) +static void dn_raw_hash(struct sock *sk) { + struct sock **skp; switch(sk->protocol) { case DNPROTO_NSP: - sklist_insert_socket(&dn_raw_nsp_sklist, sk); + skp = &dn_raw_nsp_sklist; break; case DNPROTO_ROU: - sklist_insert_socket(&dn_raw_routing_sklist, sk); + skp = &dn_raw_routing_sklist; break; -#ifdef CONFIG_DECNET_MOP - case DNPROTO_MOP: - sklist_insert_socket(&dn_raw_mop_sklist, sk); -#endif /* CONFIG_DECNET_MOP */ default: - printk(KERN_DEBUG "dn_raw_autobind: Unknown protocol\n"); + printk(KERN_DEBUG "dn_raw_hash: Unknown protocol\n"); return; } + write_lock_bh(&dn_raw_hash_lock); + sk->next = *skp; + sk->pprev = skp; + *skp = sk; + write_unlock_bh(&dn_raw_hash_lock); +} + +static void dn_raw_unhash(struct sock *sk) +{ + struct sock **skp = sk->pprev; + + if (skp == NULL) + return; + + write_lock_bh(&dn_raw_hash_lock); + while(*skp != sk) + skp = &((*skp)->next); + *skp = sk->next; + write_unlock_bh(&dn_raw_hash_lock); + + sk->next = NULL; + sk->pprev = NULL; +} + +static void dn_raw_autobind(struct sock *sk) +{ + dn_raw_hash(sk); sk->zapped = 0; } -static int dn_raw_release(struct socket *sock, struct socket *peer) +static int dn_raw_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -63,32 +89,21 @@ sk->socket = NULL; sock->sk = NULL; - switch(sk->protocol) { - case DNPROTO_NSP: - sklist_destroy_socket(&dn_raw_nsp_sklist, sk); - break; - case DNPROTO_ROU: - sklist_destroy_socket(&dn_raw_routing_sklist, sk); - break; -#ifdef CONFIG_DECNET_MOP - case DNPROTO_MOP: - sklist_destroy_socket(&dn_raw_mop_sklist, sk); - break; -#endif /* CONFIG_DECNET_MOP */ - } + dn_raw_unhash(sk); + sock_put(sk); return 0; } /* * Bind does odd things with raw sockets. Its basically used to filter - * the incomming packets, but this differs with the different layers + * the incoming packets, but this differs with the different layers * at which you extract packets. * * For Routing layer sockets, the object name is a host ordered unsigned * short which is a mask for the 16 different types of possible routing * packet. I'd like to also select by destination address of the packets - * but alas, this is rather too dificult to do at the moment. + * but alas, this is rather too difficult to do at the moment. */ static int dn_raw_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { @@ -103,24 +118,23 @@ switch(sk->protocol) { case DNPROTO_ROU: - if (addr->sdn_objnamel && (addr->sdn_objnamel != 2)) + if (dn_ntohs(addr->sdn_objnamel) && (dn_ntohs(addr->sdn_objnamel) != 2)) return -EINVAL; /* Fall through here */ case DNPROTO_NSP: - if (addr->sdn_add.a_len && (addr->sdn_add.a_len != 2)) + if (dn_ntohs(addr->sdn_add.a_len) && (dn_ntohs(addr->sdn_add.a_len) != 2)) return -EINVAL; break; default: return -EPROTONOSUPPORT; } - if (addr->sdn_objnamel > (DN_MAXOBJL-1)) + if (dn_ntohs(addr->sdn_objnamel) > (DN_MAXOBJL-1)) return -EINVAL; - if (addr->sdn_add.a_len > DN_MAXADDL) + if (dn_ntohs(addr->sdn_add.a_len) > DN_MAXADDL) return -EINVAL; - memcpy(&sk->protinfo.dn.addr, addr, sizeof(struct sockaddr_dn)); dn_raw_autobind(sk); @@ -137,25 +151,34 @@ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr; + int err; + lock_sock(sk); + + err = -EINVAL; if (addr_len != sizeof(struct sockaddr_dn)) - return -EINVAL; + goto out; if (saddr->sdn_family != AF_DECnet) - return -EINVAL; + goto out; - if (saddr->sdn_objnamel > (DN_MAXOBJL-1)) - return -EINVAL; + if (dn_ntohs(saddr->sdn_objnamel) > (DN_MAXOBJL-1)) + goto out; - if (saddr->sdn_add.a_len > DN_MAXADDL) - return -EINVAL; + if (dn_ntohs(saddr->sdn_add.a_len) > DN_MAXADDL) + goto out; if (sk->zapped) dn_raw_autobind(sk); + if ((err = dn_route_output(&sk->dst_cache, dn_saddr2dn(saddr), dn_saddr2dn(&scp->addr), 0)) < 0) + goto out; + memcpy(&scp->peer, saddr, sizeof(struct sockaddr_dn)); +out: + release_sock(sk); - return 0; + return err; } /* @@ -187,6 +210,8 @@ int err = 0; int copied = 0; + lock_sock(sk); + if (sk->zapped) dn_raw_autobind(sk); @@ -212,13 +237,14 @@ skb_free_datagram(sk, skb); out: + release_sock(sk); + return copied ? copied : err; } struct proto_ops dn_raw_proto_ops = { AF_DECnet, - sock_no_dup, dn_raw_release, dn_raw_bind, dn_raw_connect, @@ -233,7 +259,8 @@ sock_no_getsockopt, sock_no_fcntl, dn_raw_sendmsg, - dn_raw_recvmsg + dn_raw_recvmsg, + sock_no_mmap }; #ifdef CONFIG_PROC_FS @@ -244,7 +271,7 @@ off_t begin = 0; struct sock *sk; - cli(); + read_lock_bh(&dn_raw_hash_lock); for(sk = dn_raw_nsp_sklist; sk; sk = sk->next) { len += sprintf(buffer+len, "NSP\n"); @@ -274,24 +301,8 @@ goto all_done; } -#ifdef CONFIG_DECNET_MOP - for(sk = dn_raw_mop_sklist; sk; sk = sk->next) { - len += sprintf(buffer+len, "MOP\n"); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - goto all_done; - } -#endif /* CONFIG_DECNET_MOP */ - all_done: - sti(); + read_unlock_bh(&dn_raw_hash_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -306,10 +317,8 @@ { struct sock *sk; struct sk_buff *skb2; - unsigned long cpuflags; - save_flags(cpuflags); - cli(); + read_lock(&dn_raw_hash_lock); for(sk = dn_raw_nsp_sklist; sk != NULL; sk = sk->next) { if (skb->len > sock_rspace(sk)) continue; @@ -317,11 +326,11 @@ continue; if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { skb_set_owner_r(skb2, sk); - __skb_queue_tail(&sk->receive_queue, skb2); + skb_queue_tail(&sk->receive_queue, skb2); sk->data_ready(sk, skb->len); } } - restore_flags(cpuflags); + read_unlock(&dn_raw_hash_lock); } void dn_raw_rx_routing(struct sk_buff *skb) @@ -329,13 +338,11 @@ struct sock *sk; struct sk_buff *skb2; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - unsigned long cpuflags; unsigned short rt_flagmask; unsigned short objnamel; struct dn_scp *scp; - save_flags(cpuflags); - cli(); + read_lock(&dn_raw_hash_lock); for(sk = dn_raw_routing_sklist; sk != NULL; sk = sk->next) { if (skb->len > sock_rspace(sk)) continue; @@ -343,7 +350,7 @@ continue; scp = &sk->protinfo.dn; - rt_flagmask = *(unsigned short *)scp->addr.sdn_objname; + rt_flagmask = dn_ntohs(*(unsigned short *)scp->addr.sdn_objname); objnamel = dn_ntohs(scp->addr.sdn_objnamel); if ((objnamel == 2) && (!((1 << (cb->rt_flags & 0x0f)) & rt_flagmask))) @@ -351,33 +358,10 @@ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { skb_set_owner_r(skb2, sk); - __skb_queue_tail(&sk->receive_queue, skb2); + skb_queue_tail(&sk->receive_queue, skb2); sk->data_ready(sk, skb->len); } } - restore_flags(cpuflags); + read_unlock(&dn_raw_hash_lock); } -#ifdef CONFIG_DECNET_MOP -void dn_raw_rx_mop(struct sk_buff *skb) -{ - struct sock *sk; - struct sk_buff *skb2; - unsigned long cpuflags; - - save_flags(cpuflags); - cli(); - for(sk = dn_raw_mop_sklist; sk != NULL; sk = sk->next) { - if (skb->len > sock_rspace(sk)) - continue; - if (sk->dead) - continue; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { - skb_set_owner_r(skb2, sk); - __skb_queue_tail(&sk->receive_queue, skb2); - sk->data_ready(sk, skb->len); - } - } - restore_flags(cpuflags); -} -#endif /* CONFIG_DECNET_MOP */ diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c --- v2.3.14/linux/net/decnet/dn_route.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/dn_route.c Mon Aug 23 10:01:02 1999 @@ -16,6 +16,10 @@ * Steve Whitehouse : Timeouts for cached routes. * Steve Whitehouse : Use dst cache for input routes too. * Steve Whitehouse : Fixed error values in dn_send_skb. + * Steve Whitehouse : Rework routing functions to better fit + * DECnet routing design + * Alexey Kuznetsov : New SMP locking + * Steve Whitehouse : More SMP locking changes & dn_cache_dump() */ /****************************************************************************** @@ -49,9 +53,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -77,6 +81,8 @@ static int dn_route_input(struct sk_buff *); static struct dn_route *dn_route_cache[DN_HASHBUCKETS]; +static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED; + static struct timer_list dn_route_timer = { NULL, NULL, 0, 0L, NULL }; int decnet_dst_gc_interval = 2; @@ -90,6 +96,7 @@ NULL, dn_dst_negative_advice, dn_dst_link_failure, + sizeof(struct dn_route), ATOMIC_INIT(0) }; @@ -108,14 +115,17 @@ for(i = 0; i < DN_HASHBUCKETS; i++) { rtp = &dn_route_cache[i]; + + write_lock(&dn_hash_lock); for(;(rt=*rtp); rtp = &rt->u.rt_next) { - if (atomic_read(&rt->u.dst.use) || + if (atomic_read(&rt->u.dst.__refcnt) || (now - rt->u.dst.lastuse) < expire) continue; *rtp = rt->u.rt_next; rt->u.rt_next = NULL; dst_free(&rt->u.dst); } + write_unlock(&dn_hash_lock); if ((jiffies - now) > 0) break; @@ -132,11 +142,11 @@ unsigned long now = jiffies; unsigned long expire = 10 * HZ; - start_bh_atomic(); + write_lock_bh(&dn_hash_lock); for(i = 0; i < DN_HASHBUCKETS; i++) { rtp = &dn_route_cache[i]; for(; (rt=*rtp); rtp = &rt->u.rt_next) { - if (atomic_read(&rt->u.dst.use) || + if (atomic_read(&rt->u.dst.__refcnt) || (now - rt->u.dst.lastuse) < expire) continue; *rtp = rt->u.rt_next; @@ -145,7 +155,7 @@ break; } } - end_bh_atomic(); + write_unlock_bh(&dn_hash_lock); return 0; } @@ -182,27 +192,27 @@ unsigned hash = dn_hash(rt->rt_daddr); unsigned long now = jiffies; - start_bh_atomic(); - + write_lock_bh(&dn_hash_lock); rt->u.rt_next = dn_route_cache[hash]; dn_route_cache[hash] = rt; - atomic_inc(&rt->u.dst.refcnt); - atomic_inc(&rt->u.dst.use); + dst_hold(&rt->u.dst); + rt->u.dst.__use++; rt->u.dst.lastuse = now; - end_bh_atomic(); + write_unlock_bh(&dn_hash_lock); } -#if defined(CONFIG_DECNET_MODULE) -static void dn_run_flush(unsigned long dummy) +void dn_run_flush(unsigned long dummy) { int i; struct dn_route *rt, *next; for(i = 0; i < DN_HASHBUCKETS; i++) { + write_lock_bh(&dn_hash_lock); if ((rt = xchg(&dn_route_cache[i], NULL)) == NULL) continue; + write_unlock_bh(&dn_hash_lock); for(; rt; rt=next) { next = rt->u.rt_next; @@ -211,12 +221,13 @@ } } } -#endif /* CONFIG_DECNET_MODULE */ + static int dn_route_rx_long(struct sk_buff *skb) { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; unsigned char *ptr = skb->data; + int err; if (skb->len < 21) /* 20 for long header, 1 for shortest nsp */ goto drop_it; @@ -242,24 +253,8 @@ ptr++; cb->hops = *ptr++; /* Visit Count */ - if (dn_route_input(skb) == 0) { - -#ifdef CONFIG_DECNET_FW - struct neighbour *neigh = skb->dst->neighbour; - - switch(call_in_firewall(PF_DECnet, skb->dev, NULL, NULL, &skb)) { - case FW_REJECT: - neigh->ops->error_report(neigh, skb); - return 0; - case FW_BLOCK: - default: - goto drop_it; - case FW_ACCEPT: - } -#endif /* CONFIG_DECNET_FW */ - - return skb->dst->input(skb); - } + if ((err = dn_route_input(skb)) == 0) + return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, skb->dst->input); drop_it: kfree_skb(skb); @@ -272,6 +267,7 @@ { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; unsigned char *ptr = skb->data; + int err; if (skb->len < 6) /* 5 for short header + 1 for shortest nsp */ goto drop_it; @@ -285,25 +281,8 @@ ptr += 2; cb->hops = *ptr & 0x3f; - if (dn_route_input(skb) == 0) { - -#ifdef CONFIG_DECNET_FW - struct neighbour *neigh = skb->dst->neighbour; - - switch(call_in_firewall(PF_DECnet, skb->dev, NULL, NULL, &skb)) { - case FW_REJECT: - neigh->ops->error_report(neigh, skb); - return 0; - case FW_BLOCK: - default: - goto drop_it; - - case FW_ACCEPT: - } -#endif /* CONFIG_DECNET_FW */ - - return skb->dst->input(skb); - } + if ((err = dn_route_input(skb)) == 0) + return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, skb->dst->input); drop_it: kfree_skb(skb); @@ -352,11 +331,11 @@ cb->rt_flags = flags; - if (dn->parms.setsrc) - dn->parms.setsrc(skb); - - /* printk(KERN_DEBUG "dn_route_rcv: got 0x%02x from %s [%d %d %d]\n", (int)flags, - (dev) ? dev->name : "???", len, skb->len, padlen); */ + if (decnet_debug_level & 1) + printk(KERN_DEBUG + "dn_route_rcv: got 0x%02x from %s [%d %d %d]\n", + (int)flags, (dev) ? dev->name : "???", len, skb->len, + padlen); #ifdef CONFIG_DECNET_RAW dn_raw_rx_routing(skb); @@ -411,59 +390,21 @@ } dump_it: - if (net_ratelimit()) - printk(KERN_DEBUG "dn_route_rcv: Dumping packet\n"); kfree_skb(skb); return 0; } - -void dn_send_skb(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - struct dn_scp *scp = &sk->protinfo.dn; - - if (sk == NULL) { - dev_queue_xmit(skb); - return ; - } - - skb->h.raw = skb->data; - - scp->stamp = jiffies; /* Record time packet was sent */ - - /* printk(KERN_DEBUG "dn_send_skb\n"); */ - - if (sk->dst_cache && sk->dst_cache->obsolete) { - dst_release(sk->dst_cache); - sk->dst_cache = NULL; - } - - if (sk->dst_cache == NULL) { - if (dn_route_output(sk) != 0) { - kfree_skb(skb); - sk->err = EHOSTUNREACH; - if (!sk->dead) - sk->state_change(sk); - return; - } - } - - skb->dst = dst_clone(sk->dst_cache); - - sk->dst_cache->output(skb); -} - - static int dn_output(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct dn_route *rt = (struct dn_route *)dst; struct net_device *dev = dst->dev; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; + struct neighbour *neigh; + int err = -EINVAL; - if (!dst->neighbour) + if ((neigh = dst->neighbour) == NULL) goto error; skb->dev = dev; @@ -480,44 +421,26 @@ cb->rt_flags |= DN_RT_F_IE; cb->hops = 0; - /* - * Filter through the outgoing firewall - */ -#ifdef CONFIG_DECNET_FW - switch(call_out_firewall(PF_DECnet, dst->dev, NULL, NULL, &skb)) { - case FW_REJECT: - err = -EPERM; - goto drop; - case FW_BLOCK: - default: - err = 0; - goto drop; - case FW_ACCEPT: - } -#endif /* CONFIG_DECNET_FW */ - - return dst->neighbour->output(skb); + return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output); error: if (net_ratelimit()) printk(KERN_DEBUG "dn_output: This should not happen\n"); -#ifdef CONFIG_DECNET_FW -drop: -#endif kfree_skb(skb); return err; } #ifdef CONFIG_DECNET_ROUTER -static int dn_l2_forward(struct sk_buff *skb) +static int dn_forward(struct sk_buff *skb) { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; struct dst_entry *dst = skb->dst; + struct neighbour *neigh; int err = -EINVAL; - if (!dst->neighbour) + if ((neigh = dst->neighbour) == NULL) goto error; /* @@ -527,21 +450,6 @@ if (++cb->hops > 30) goto drop; - /* - * Forwarding firewall - */ -#ifdef CONFIG_DECNET_FW - switch(call_fw_firewall(PF_DECnet, dst->dev, NULL, NULL, &skb)) { - case FW_REJECT: - dst->neighbour->ops->error_report(dst->neighbour, skb); - return -EPERM; - case FW_BLOCK: - default: - goto drop; - case FW_ACCEPT: - } -#endif /* CONFIG_DECNET_FW */ - skb->dev = dst->dev; /* @@ -554,19 +462,7 @@ else cb->rt_flags &= ~DN_RT_F_IE; -#ifdef CONFIG_DECNET_FW - switch(call_out_firewall(PF_DECnet, dst->dev, NULL, NULL, &skb)) { - case FW_REJECT: - dst->neighbour->ops->error_report(dst->neighbour, skb); - return -EPERM; - case FW_BLOCK: - default: - goto drop; - case FW_ACCEPT: - } -#endif /* CONFIG_DECNET_FW */ - - return dst->neighbour->output(skb); + return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, skb->rx_dev, skb->dev, neigh->output); error: @@ -577,22 +473,6 @@ return err; } - -/* - * Simple frontend to the l2 routing function which filters - * traffic not in our area when we should only do l1 - * routing. - */ -static int dn_l1_forward(struct sk_buff *skb) -{ - struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - - if ((dn_ntohs(cb->dst ^ decnet_address) & 0xfc00) == 0) - return dn_l2_forward(skb); - - kfree_skb(skb); - return 0; -} #endif /* @@ -624,46 +504,61 @@ return -EINVAL; } -static int dn_route_output_slow(struct sock *sk) +static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_address src, int flags) { - struct dn_scp *scp = &sk->protinfo.dn; - dn_address dest = dn_saddr2dn(&scp->peer); struct dn_route *rt = NULL; - struct net_device *dev = decnet_default_device; + struct net_device *dev = decnet_default_device; struct neighbour *neigh = NULL; struct dn_dev *dn_db; - unsigned char addr[6]; + #ifdef CONFIG_DECNET_ROUTER - if ((decnet_node_type == DN_RT_INFO_L1RT) || (decnet_node_type == DN_RT_INFO_L2RT)) { -#if 0 - struct dn_fib_ent *fe = dn_fib_lookup(dest, decnet_address); - - if (fe != NULL) { - neigh = neigh_clone(fe->neigh); - dn_fib_release(fe); - goto got_route; + if (decnet_node_type != DN_RT_INFO_ENDN) { + struct dn_fib_res res; + int err = 0; + + res.res_addr = dst; + res.res_mask = 0; + res.res_ifindex = 0; + res.res_proto = RTN_UNSPEC; + res.res_cost = 0; + + if ((err = dn_fib_resolve(&res)) == 0) { + + if (!res.res_fa || (res.res_fa->fa_type != RTN_UNICAST)) + return -EPROTO; + + if ((neigh = neigh_clone(res.res_fa->fa_neigh)) != NULL) + goto got_route; + + return -ENOBUFS; } -#endif + + if (err != -ENOENT) + return err; } #endif - dn_dn2eth(addr, dest); - /* Look in On-Ethernet cache first */ - if ((neigh = dn_neigh_lookup(&dn_neigh_table, &addr)) != NULL) - goto got_route; + if (!(flags & MSG_TRYHARD)) { + if ((neigh = dn_neigh_lookup(&dn_neigh_table, &dst)) != NULL) + goto got_route; + } if (dev == NULL) return -EINVAL; - /* FIXME: We need to change this for routing nodes */ - /* Send to default router if that doesn't work */ - if ((neigh = neigh_lookup(&dn_neigh_table, &addr, dev)) != NULL) + dn_db = dev->dn_ptr; + + if (dn_db == NULL) + return -EINVAL; + + /* Try default router */ + if ((neigh = neigh_clone(dn_db->router)) != NULL) goto got_route; /* Send to default device (and hope for the best) if above fail */ - if ((neigh = __neigh_lookup(&dn_neigh_table, &addr, dev, 1)) != NULL) + if ((neigh = __neigh_lookup(&dn_neigh_table, &dst, dev, 1)) != NULL) goto got_route; @@ -671,15 +566,15 @@ got_route: - if ((rt = dst_alloc(sizeof(struct dn_route), &dn_dst_ops)) == NULL) { + if ((rt = dst_alloc(&dn_dst_ops)) == NULL) { neigh_release(neigh); return -EINVAL; } dn_db = (struct dn_dev *)neigh->dev->dn_ptr; - rt->rt_saddr = decnet_address; - rt->rt_daddr = dest; + rt->rt_saddr = src; + rt->rt_daddr = dst; rt->rt_oif = neigh->dev->ifindex; rt->rt_iif = 0; @@ -693,36 +588,35 @@ rt->u.dst.input = dn_nsp_rx; dn_insert_route(rt); - sk->dst_cache = &rt->u.dst; + *pprt = &rt->u.dst; return 0; } -int dn_route_output(struct sock *sk) +int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags) { - struct dn_scp *scp = &sk->protinfo.dn; - dn_address dest = dn_saddr2dn(&scp->peer); - unsigned hash = dn_hash(dest); + unsigned hash = dn_hash(dst); struct dn_route *rt = NULL; - unsigned short src = dn_saddr2dn(&scp->addr); - start_bh_atomic(); - for(rt = dn_route_cache[hash]; rt; rt = rt->u.rt_next) { - if ((dest == rt->rt_daddr) && - (src == rt->rt_saddr) && - (rt->rt_iif == 0) && - (rt->rt_oif != 0)) { - rt->u.dst.lastuse = jiffies; - atomic_inc(&rt->u.dst.use); - atomic_inc(&rt->u.dst.refcnt); - end_bh_atomic(); - sk->dst_cache = &rt->u.dst; - return 0; + if (!(flags & MSG_TRYHARD)) { + read_lock_bh(&dn_hash_lock); + for(rt = dn_route_cache[hash]; rt; rt = rt->u.rt_next) { + if ((dst == rt->rt_daddr) && + (src == rt->rt_saddr) && + (rt->rt_iif == 0) && + (rt->rt_oif != 0)) { + rt->u.dst.lastuse = jiffies; + dst_hold(&rt->u.dst); + rt->u.dst.__use++; + read_unlock_bh(&dn_hash_lock); + *pprt = &rt->u.dst; + return 0; + } } + read_unlock_bh(&dn_hash_lock); } - end_bh_atomic(); - return dn_route_output_slow(sk); + return dn_route_output_slow(pprt, dst, src, flags); } static int dn_route_input_slow(struct sk_buff *skb) @@ -730,8 +624,16 @@ struct dn_route *rt = NULL; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; struct net_device *dev = skb->dev; + struct dn_dev *dn_db; struct neighbour *neigh = NULL; - unsigned char addr[6]; + int (*dnrt_input)(struct sk_buff *skb); + int (*dnrt_output)(struct sk_buff *skb); + + if (dev == NULL) + return -EINVAL; + + if ((dn_db = dev->dn_ptr) == NULL) + return -EINVAL; /* * In this case we've just received a packet from a source @@ -741,44 +643,56 @@ * so this only affects packets which have originated elsewhere. */ if (dn_dev_islocal(dev, cb->src)) - return 1; + return -ENOTUNIQ; -#ifdef CONFIG_DECNET_ROUTER - if ((decnet_node_type == DN_RT_INFO_L1RT) || (decnet_node_type == DN_RT_INFO_L2RT)) { -#if 0 - struct dn_fib_ent *fe = NULL; - - fe = dn_fib_lookup(cb->src, cb->dst); - - /* Try routing table first */ - if (fe != NULL) { - neigh = neigh_clone(fe->neigh); - dn_fib_release(fe); - goto got_route; - } -#endif - } -#endif + /* + * Default is to create a drop everything entry + */ + dnrt_input = dn_blackhole; + dnrt_output = dn_rt_bug; - dn_dn2eth(addr, cb->src); + /* + * Is the destination us ? + */ + if (!dn_dev_islocal(dev, cb->dst)) + goto non_local_input; - /* Now see if we are directly connected */ - if ((neigh = dn_neigh_lookup(&dn_neigh_table, &addr)) != NULL) - goto got_route; + /* + * Local input... find source of skb + */ + dnrt_input = dn_nsp_rx; + dnrt_output = dn_output; - if (dev == NULL) - return -EINVAL; + if ((neigh = neigh_lookup(&dn_neigh_table, &cb->src, dev)) != NULL) + goto add_entry; - /* FIXME: Try the default router here .... */ + if (dn_db->router && ((neigh = neigh_clone(dn_db->router)) != NULL)) + goto add_entry; - if ((neigh = __neigh_lookup(&dn_neigh_table, &addr, dev, 1)) != NULL) - goto got_route; + if ((neigh = neigh_create(&dn_neigh_table, &cb->src, dev)) != NULL) { + if (dev->type == ARPHRD_ETHER) + memcpy(neigh->ha, skb->mac.ethernet->h_source, ETH_ALEN); + goto add_entry; + } - return -EINVAL; + return -ENOBUFS; -got_route: +non_local_input: + +#ifdef CONFIG_DECNET_ROUTER + /* + * Destination is another node... find next hop in + * routing table here. + */ + if (decnet_node_type == DN_RT_INFO_ENDN) + goto add_entry; + + +#endif /* CONFIG_DECNET_ROUTER */ - if ((rt = dst_alloc(sizeof(struct dn_route), &dn_dst_ops)) == NULL) { +add_entry: + + if ((rt = dst_alloc(&dn_dst_ops)) == NULL) { neigh_release(neigh); return -EINVAL; } @@ -786,33 +700,13 @@ rt->rt_saddr = cb->dst; rt->rt_daddr = cb->src; rt->rt_oif = 0; - rt->rt_iif = neigh->dev->ifindex; + rt->rt_iif = dev->ifindex; rt->u.dst.neighbour = neigh; - rt->u.dst.dev = neigh->dev; + rt->u.dst.dev = dev; rt->u.dst.lastuse = jiffies; - rt->u.dst.output = dn_output; - - switch(decnet_node_type) { - case DN_RT_INFO_ENDN: - rt->u.dst.input = dn_blackhole; - break; -#ifdef CONFIG_DECNET_ROUTER - case DN_RT_INFO_L1RT: - rt->u.dst.input = dn_l1_forward; - break; - case DN_RT_INFO_L2RT: - rt->u.dst.input = dn_l2_forward; - break; -#endif /* CONFIG_DECNET_ROUTER */ - default: - rt->u.dst.input = dn_blackhole; - if (net_ratelimit()) - printk(KERN_DEBUG "dn_route_input_slow: What kind of node are we?\n"); - } - - if (dn_dev_islocal(dev, cb->dst)) - rt->u.dst.input = dn_nsp_rx; + rt->u.dst.output = dnrt_output; + rt->u.dst.input = dnrt_input; dn_insert_route(rt); skb->dst = (struct dst_entry *)rt; @@ -829,23 +723,25 @@ if (skb->dst) return 0; + read_lock_bh(&dn_hash_lock); for(rt = dn_route_cache[hash]; rt != NULL; rt = rt->u.rt_next) { if ((rt->rt_saddr == cb->dst) && (rt->rt_daddr == cb->src) && (rt->rt_oif == 0) && (rt->rt_iif == cb->iif)) { rt->u.dst.lastuse = jiffies; - atomic_inc(&rt->u.dst.use); - atomic_inc(&rt->u.dst.refcnt); + dst_hold(&rt->u.dst); + rt->u.dst.__use++; + read_unlock_bh(&dn_hash_lock); skb->dst = (struct dst_entry *)rt; return 0; } } + read_unlock_bh(&dn_hash_lock); return dn_route_input_slow(skb); } -#ifdef CONFIG_DECNET_ROUTER #ifdef CONFIG_RTNETLINK static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait) { @@ -863,6 +759,7 @@ r->rtm_tos = 0; r->rtm_table = 0; r->rtm_type = 0; + r->rtm_flags = 0; r->rtm_scope = RT_SCOPE_UNIVERSE; r->rtm_protocol = RTPROT_UNSPEC; RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr); @@ -883,11 +780,14 @@ return -1; } -int dn_fib_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) +/* + * This is called by both endnodes and routers now. + */ +int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) { struct rtattr **rta = arg; - /* struct rtmsg *rtm = NLMSG_DATA(nlh); */ struct dn_route *rt = NULL; + struct dn_skb_cb *cb; dn_address dst = 0; dn_address src = 0; int iif = 0; @@ -898,6 +798,7 @@ if (skb == NULL) return -ENOBUFS; skb->mac.raw = skb->data; + cb = (struct dn_skb_cb *)skb->cb; if (rta[RTA_SRC-1]) memcpy(&src, RTA_DATA(rta[RTA_SRC-1]), 2); @@ -908,24 +809,33 @@ if (iif) { struct net_device *dev; - if ((dev = dev_get_by_index(iif)) == NULL) + if ((dev = dev_get_by_index(iif)) == NULL) { + kfree_skb(skb); return -ENODEV; - if (!dev->dn_ptr) + } + if (!dev->dn_ptr) { + dev_put(dev); + kfree_skb(skb); return -ENODEV; + } skb->protocol = __constant_htons(ETH_P_DNA_RT); skb->dev = dev; - start_bh_atomic(); + skb->rx_dev = dev; + cb->src = src; + cb->dst = dst; err = dn_route_input(skb); - end_bh_atomic(); + memset(cb, 0, sizeof(struct dn_skb_cb)); rt = (struct dn_route *)skb->dst; - if (!err && rt->u.dst.error) - err = rt->u.dst.error; } else { - int oif = 0; - if (rta[RTA_OIF-1]) - memcpy(&oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); - err = -EOPNOTSUPP; + err = dn_route_output((struct dst_entry **)&rt, dst, src, 0); } + + if (!err && rt->u.dst.error) + err = rt->u.dst.error; + if (skb->dev) + dev_put(skb->dev); + skb->dev = NULL; + skb->rx_dev = NULL; if (err) { kfree_skb(skb); return err; @@ -945,8 +855,51 @@ return err; } + +/* + * For routers, this is called from dn_fib_dump, but for endnodes its + * called directly from the rtnetlink dispatch table. + */ +int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct dn_route *rt; + int h, s_h; + int idx, s_idx; + + if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) + return -EINVAL; + if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)) + return 0; + + s_h = cb->args[0]; + s_idx = idx = cb->args[1]; + for(h = 0; h < DN_HASHBUCKETS; h++) { + if (h < s_h) + continue; + if (h > s_h) + s_idx = 0; + read_lock_bh(&dn_hash_lock); + for(rt = dn_route_cache[h], idx = 0; rt; rt = rt->u.rt_next, idx++) { + if (idx < s_idx) + continue; + skb->dst = dst_clone(&rt->u.dst); + if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) { + dst_release(xchg(&skb->dst, NULL)); + read_unlock_bh(&dn_hash_lock); + goto done; + } + dst_release(xchg(&skb->dst, NULL)); + } + read_unlock_bh(&dn_hash_lock); + } + +done: + cb->args[0] = h; + cb->args[1] = idx; + return skb->len; +} #endif /* CONFIG_RTNETLINK */ -#endif /* CONFIG_DECNET_ROUTER */ #ifdef CONFIG_PROC_FS @@ -959,7 +912,7 @@ int i; char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN]; - start_bh_atomic(); + read_lock_bh(&dn_hash_lock); for(i = 0; i < DN_HASHBUCKETS; i++) { rt = dn_route_cache[i]; for(; rt != NULL; rt = rt->u.rt_next) { @@ -967,8 +920,8 @@ rt->u.dst.dev ? rt->u.dst.dev->name : "*", dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), - atomic_read(&rt->u.dst.use), - atomic_read(&rt->u.dst.refcnt), + atomic_read(&rt->u.dst.__refcnt), + rt->u.dst.__use, (int)rt->u.dst.rtt ); @@ -984,7 +937,7 @@ if (pos > offset + length) break; } - end_bh_atomic(); + read_unlock_bh(&dn_hash_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -1006,6 +959,11 @@ void __init dn_route_init(void) { memset(dn_route_cache, 0, sizeof(struct dn_route *) * DN_HASHBUCKETS); + + dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache", + sizeof(struct dn_route), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); dn_route_timer.function = dn_dst_check_expire; dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; diff -u --recursive --new-file v2.3.14/linux/net/decnet/dn_timer.c linux/net/decnet/dn_timer.c --- v2.3.14/linux/net/decnet/dn_timer.c Wed Jun 30 11:24:55 1999 +++ linux/net/decnet/dn_timer.c Mon Aug 23 10:01:02 1999 @@ -12,6 +12,8 @@ * Steve Whitehouse : Made keepalive timer part of the same * timer idea. * Steve Whitehouse : Added checks for sk->sock_readers + * David S. Miller : New socket locking + * Steve Whitehouse : Timer grabs socket ref. */ #include #include @@ -44,12 +46,7 @@ void dn_stop_slow_timer(struct sock *sk) { - unsigned long cpuflags; - - save_flags(cpuflags); - cli(); del_timer(&sk->timer); - restore_flags(cpuflags); } static void dn_slow_timer(unsigned long arg) @@ -57,6 +54,7 @@ struct sock *sk = (struct sock *)arg; struct dn_scp *scp = &sk->protinfo.dn; + sock_hold(sk); bh_lock_sock(sk); if (sk->lock.users != 0) { @@ -72,7 +70,9 @@ * the function pointer in the socket. Setting the timer to a value * of zero turns it off. We allow the persist_fxn to turn the * timer off in a permant way by returning non-zero, so that - * timer based routines may remove sockets. + * timer based routines may remove sockets. This is why we have a + * sock_hold()/sock_put() around the timer to prevent the socket + * going away in the middle. */ if (scp->persist && scp->persist_fxn) { if (scp->persist <= SLOW_INTERVAL) { @@ -106,6 +106,7 @@ add_timer(&sk->timer); out: bh_unlock_sock(sk); + sock_put(sk); } static void dn_fast_timer(unsigned long arg) @@ -131,10 +132,7 @@ void dn_start_fast_timer(struct sock *sk) { struct dn_scp *scp = &sk->protinfo.dn; - unsigned long cpuflags; - save_flags(cpuflags); - cli(); if (!scp->delack_pending) { scp->delack_pending = 1; scp->delack_timer.next = @@ -144,20 +142,15 @@ scp->delack_timer.function = dn_fast_timer; add_timer(&scp->delack_timer); } - restore_flags(cpuflags); } void dn_stop_fast_timer(struct sock *sk) { struct dn_scp *scp = &sk->protinfo.dn; - unsigned long cpuflags; - save_flags(cpuflags); - cli(); if (scp->delack_pending) { scp->delack_pending = 0; del_timer(&scp->delack_timer); } - restore_flags(cpuflags); } diff -u --recursive --new-file v2.3.14/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c --- v2.3.14/linux/net/decnet/sysctl_net_decnet.c Wed Aug 18 11:38:49 1999 +++ linux/net/decnet/sysctl_net_decnet.c Mon Aug 23 10:01:02 1999 @@ -247,7 +247,7 @@ dn_dev_devices_off(); decnet_address = addr; - dn_dn2eth(decnet_ether_address, decnet_address); + dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); dn_dev_devices_on(); } @@ -281,7 +281,7 @@ dn_dev_devices_off(); decnet_address = dnaddr; - dn_dn2eth(decnet_ether_address, decnet_address); + dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); dn_dev_devices_on(); @@ -345,7 +345,7 @@ devname[newlen] = 0; - if ((dev = dev_get(devname)) == NULL) + if ((dev = __dev_get_by_name(devname)) == NULL) return -ENODEV; if (dev->dn_ptr == NULL) @@ -381,7 +381,7 @@ devname[*lenp] = 0; - if ((dev = dev_get(devname)) == NULL) + if ((dev = __dev_get_by_name(devname)) == NULL) return -ENODEV; if (dev->dn_ptr == NULL) diff -u --recursive --new-file v2.3.14/linux/net/econet/econet.c linux/net/econet/econet.c --- v2.3.14/linux/net/econet/econet.c Wed Aug 18 11:38:49 1999 +++ linux/net/econet/econet.c Mon Aug 23 10:01:02 1999 @@ -115,6 +115,8 @@ /* * Find an Econet device given its `dev' pointer. This is IRQ safe. + * + * Against what is it safe? --ANK */ static struct ec_device *edev_get(struct net_device *dev) @@ -329,7 +331,7 @@ { /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE - dev_lock_list(); + atomic_inc(&dev->refcnt); skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags & MSG_DONTWAIT, &err); @@ -372,14 +374,15 @@ * Now send it */ - dev_unlock_list(); dev_queue_xmit(skb); + dev_put(dev); return(len); out_free: kfree_skb(skb); out_unlock: - dev_unlock_list(); + if (dev) + dev_put(dev); #else err = -EPROTOTYPE; #endif @@ -402,9 +405,16 @@ y.x maps to IP a.b.c.x. This should be replaced with something more flexible and more aware of subnet masks. */ { - struct in_device *idev = (struct in_device *)dev->ip_ptr; - unsigned long network = ntohl(idev->ifa_list->ifa_address) & - 0xffffff00; /* !!! */ + struct in_device *idev = in_dev_get(dev); + unsigned long network = 0; + if (idev) { + read_lock(&idev->lock); + if (idev->ifa_list) + network = ntohl(idev->ifa_list->ifa_address) & + 0xffffff00; /* !!! */ + read_unlock(&idev->lock); + in_dev_put(idev); + } udpdest.sin_addr.s_addr = htonl(network | addr.station); } @@ -502,7 +512,7 @@ * Close an econet socket. */ -static int econet_release(struct socket *sock, struct socket *peersock) +static int econet_release(struct socket *sock) { struct sk_buff *skb; struct sock *sk = sock->sk; @@ -602,7 +612,7 @@ if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; - if ((dev = dev_get(ifr.ifr_name)) == NULL) + if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) return -ENODEV; sec = (struct sockaddr_ec *)&ifr.ifr_addr; @@ -615,10 +625,19 @@ if (edev == NULL) { /* Magic up a new one. */ + printk("Get fascist grenade!!!\n"); + *(int*)0 = 0; + /* Note to author: please, remove this spinlock. + You do not change edevlist from interrupts, + so that such aggressive protection is redundant. + + BTW not all scans of edev_list are protected. + */ edev = kmalloc(GFP_KERNEL, sizeof(struct ec_device)); if (edev == NULL) { printk("af_ec: memory squeeze.\n"); spin_unlock_irqrestore(&edevlist_lock, flags); + dev_put(dev); return -ENOMEM; } memset(edev, 0, sizeof(struct ec_device)); @@ -629,6 +648,7 @@ edev->station = sec->addr.station; edev->net = sec->addr.net; spin_unlock_irqrestore(&edevlist_lock, flags); + dev_put(dev); return 0; case SIOCGIFADDR: @@ -637,6 +657,7 @@ if (edev == NULL) { spin_unlock_irqrestore(&edevlist_lock, flags); + dev_put(dev); return -ENODEV; } memset(sec, 0, sizeof(struct sockaddr_ec)); @@ -644,11 +665,13 @@ sec->addr.net = edev->net; sec->sec_family = AF_ECONET; spin_unlock_irqrestore(&edevlist_lock, flags); + dev_put(dev); if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return 0; } + dev_put(dev); return -EINVAL; } @@ -722,10 +745,9 @@ econet_create }; -static struct proto_ops econet_ops = { +static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = { PF_ECONET, - sock_no_dup, econet_release, econet_bind, sock_no_connect, @@ -740,8 +762,12 @@ sock_no_getsockopt, sock_no_fcntl, econet_sendmsg, - econet_recvmsg + econet_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(econet, PF_ECONET); /* * Find the listening socket, if any, for the given data. diff -u --recursive --new-file v2.3.14/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.3.14/linux/net/ipv4/Config.in Sun Mar 21 07:22:00 1999 +++ linux/net/ipv4/Config.in Mon Aug 23 10:01:02 1999 @@ -15,6 +15,9 @@ bool 'IP: fast network address translation' CONFIG_IP_ROUTE_NAT fi fi +if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then + bool 'IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK +fi bool 'IP: kernel level autoconfiguration' CONFIG_IP_PNP if [ "$CONFIG_IP_PNP" = "y" ]; then bool ' BOOTP support' CONFIG_IP_PNP_BOOTP @@ -22,40 +25,6 @@ # not yet ready.. # bool ' ARP support' CONFIG_IP_PNP_ARP fi -if [ "$CONFIG_FIREWALL" = "y" ]; then - bool 'IP: firewalling' CONFIG_IP_FIREWALL - if [ "$CONFIG_IP_FIREWALL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK - if [ "$CONFIG_IP_FIREWALL_NETLINK" = "y" ]; then - define_bool CONFIG_NETLINK_DEV y - fi - fi - bool 'IP: always defragment (required for masquerading)' CONFIG_IP_ALWAYS_DEFRAG - if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then - bool 'IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK - fi - fi -fi -if [ "$CONFIG_IP_FIREWALL" = "y" ]; then - if [ "$CONFIG_IP_ALWAYS_DEFRAG" != "n" ]; then - bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY - bool 'IP: masquerading' CONFIG_IP_MASQUERADE - if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then - comment 'Protocol-specific masquerading support will be built as modules.' - bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP - comment 'Protocol-specific masquerading support will be built as modules.' - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'IP: masquerading special modules support' CONFIG_IP_MASQUERADE_MOD - if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then - tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW - tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW - tristate 'IP: ip fwmark masq-forwarding support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_MFW - fi - fi - fi - fi -fi bool 'IP: optimize as router not host' CONFIG_IP_ROUTER tristate 'IP: tunneling' CONFIG_NET_IPIP tristate 'IP: GRE tunnels over IP' CONFIG_NET_IPGRE @@ -78,7 +47,6 @@ bool 'IP: TCP syncookie support (not enabled per default)' CONFIG_SYN_COOKIES comment '(it is safe to leave these untouched)' #bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP -tristate 'IP: Reverse ARP' CONFIG_INET_RARP #bool 'IP: Path MTU Discovery (normally enabled)' CONFIG_PATH_MTU_DISCOVERY #bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE diff -u --recursive --new-file v2.3.14/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v2.3.14/linux/net/ipv4/Makefile Mon Jan 4 15:31:35 1999 +++ linux/net/ipv4/Makefile Mon Aug 23 10:01:02 1999 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := ipv4.o -IPV4_OBJS := utils.o route.o proc.o timer.o protocol.o \ +IPV4_OBJS := utils.o route.o proc.o protocol.o \ ip_input.o ip_fragment.o ip_forward.o ip_options.o \ ip_output.o ip_sockglue.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\ @@ -19,10 +19,6 @@ MOD_LIST_NAME := IPV4_MODULES M_OBJS := -ifeq ($(CONFIG_IP_FIREWALL),y) -IPV4_OBJS += ip_fw.o -endif - ifeq ($(CONFIG_IP_MULTIPLE_TABLES),y) IPV4_OBJS += fib_rules.o endif @@ -35,14 +31,6 @@ IPV4_OBJS += ipmr.o endif -ifeq ($(CONFIG_INET_RARP),y) -IPV4_OBJS += rarp.o -else - ifeq ($(CONFIG_INET_RARP),m) - M_OBJS += rarp.o - endif -endif - ifeq ($(CONFIG_NET_IPIP),y) IPV4X_OBJS += ipip.o else @@ -57,43 +45,6 @@ ifeq ($(CONFIG_NET_IPGRE),m) MX_OBJS += ip_gre.o endif -endif - -ifeq ($(CONFIG_IP_MASQUERADE),y) -IPV4X_OBJS += ip_masq.o ip_masq_app.o - -ifeq ($(CONFIG_IP_MASQUERADE_MOD),y) - IPV4X_OBJS += ip_masq_mod.o - - ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y) - IPV4_OBJS += ip_masq_autofw.o - else - ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m) - M_OBJS += ip_masq_autofw.o - endif - endif - - ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y) - IPV4_OBJS += ip_masq_portfw.o - else - ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m) - M_OBJS += ip_masq_portfw.o - endif - endif - - ifeq ($(CONFIG_IP_MASQUERADE_MFW),y) - IPV4_OBJS += ip_masq_mfw.o - else - ifeq ($(CONFIG_IP_MASQUERADE_MFW),m) - M_OBJS += ip_masq_mfw.o - endif - endif - -endif - -M_OBJS += ip_masq_user.o -M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o -M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o endif ifeq ($(CONFIG_SYN_COOKIES),y) diff -u --recursive --new-file v2.3.14/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.3.14/linux/net/ipv4/af_inet.c Sat Jul 3 17:57:22 1999 +++ linux/net/ipv4/af_inet.c Wed Aug 25 14:46:02 1999 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.93 1999/07/02 11:26:24 davem Exp $ + * Version: $Id: af_inet.c,v 1.94 1999/08/20 11:04:51 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -80,16 +80,17 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -99,13 +100,9 @@ #include #include #include -#include #ifdef CONFIG_IP_MROUTE #include #endif -#ifdef CONFIG_IP_MASQUERADE -#include -#endif #ifdef CONFIG_BRIDGE #include #endif @@ -120,6 +117,8 @@ struct linux_mib net_statistics; +atomic_t inet_sock_nr; + extern int raw_get_info(char *, char **, off_t, int, int); extern int snmp_get_info(char *, char **, off_t, int, int); extern int netstat_get_info(char *, char **, off_t, int, int); @@ -136,90 +135,78 @@ int (*dlci_ioctl_hook)(unsigned int, void *) = NULL; #endif -int (*rarp_ioctl_hook)(unsigned int,void*) = NULL; +/* New destruction routine */ -/* - * Destroy an AF_INET socket - */ - -static __inline__ void kill_sk_queues(struct sock *sk) +void inet_sock_destruct(struct sock *sk) { - struct sk_buff *skb; + __skb_queue_purge(&sk->receive_queue); + __skb_queue_purge(&sk->error_queue); - /* First the read buffer. */ - while((skb = skb_dequeue(&sk->receive_queue)) != NULL) - kfree_skb(skb); - - /* Next, the error queue. */ - while((skb = skb_dequeue(&sk->error_queue)) != NULL) - kfree_skb(skb); - - /* It is _impossible_ for the backlog to contain anything - * when we get here. All user references to this socket - * have gone away, only the net layer knows can touch it. - */ -} + if (sk->type == SOCK_STREAM && sk->state != TCP_CLOSE) { + printk("Attempt to release TCP socket in state %d %p\n", + sk->state, + sk); + return; + } + if (!sk->dead) { + printk("Attempt to release alive inet socket %p\n", sk); + return; + } -static __inline__ void kill_sk_now(struct sock *sk) -{ - /* Remove from protocol hash chains. */ - sk->prot->unhash(sk); + BUG_TRAP(atomic_read(&sk->rmem_alloc) == 0); + BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0); - if(sk->opt) - kfree(sk->opt); + if (sk->protinfo.af_inet.opt) + kfree(sk->protinfo.af_inet.opt); dst_release(sk->dst_cache); - sk_free(sk); -} - -static __inline__ void kill_sk_later(struct sock *sk) -{ - /* this should never happen. */ - /* actually it can if an ack has just been sent. */ - /* - * It's more normal than that... - * It can happen because a skb is still in the device queues - * [PR] - */ - - NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n", - atomic_read(&sk->rmem_alloc), - atomic_read(&sk->wmem_alloc))); - - sk->destroy = 1; - sk->ack_backlog = 0; - bh_unlock_sock(sk); - net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); + atomic_dec(&inet_sock_nr); +#ifdef INET_REFCNT_DEBUG + printk(KERN_DEBUG "INET socket %p released, %d are still alive\n", sk, atomic_read(&inet_sock_nr)); +#endif } -/* Callers must hold the BH spinlock. - * - * At this point, there should be no process reference to this - * socket, and thus no user references at all. Therefore we - * can assume the socket waitqueue is inactive and nobody will - * try to jump onto it. - */ -void destroy_sock(struct sock *sk) +void inet_sock_release(struct sock *sk) { - /* Now we can no longer get new packets or once the - * timers are killed, send them. - */ - net_delete_timer(sk); - if (sk->prot->destroy) sk->prot->destroy(sk); - kill_sk_queues(sk); + /* Observation: when inet_sock_release is called, processes have + no access to socket. But net still has. + Step one, detach it from networking: - /* Now if everything is gone we can free the socket - * structure, otherwise we need to keep it around until - * everything is gone. + A. Remove from hash tables. */ - if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0) - kill_sk_now(sk); - else - kill_sk_later(sk); + + sk->prot->unhash(sk); + + /* In this point socket cannot receive new packets, + but it is possible that some packets are in flight + because some CPU runs receiver and did hash table lookup + before we unhashed socket. They will achieve receive queue + and will be purged by socket destructor. + + Also we still have packets pending on receive + queue and probably, our own packets waiting in device queues. + sock_destroy will drain receive queue, but transmitted + packets will delay socket destruction until the last reference + will be released. + */ + + write_lock_irq(&sk->callback_lock); + sk->dead=1; + sk->socket = NULL; + sk->sleep = NULL; + write_unlock_irq(&sk->callback_lock); + +#ifdef INET_REFCNT_DEBUG + if (atomic_read(&sk->refcnt) != 1) { + printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n", sk, atomic_read(&sk->refcnt)); + } +#endif + sock_put(sk); } + /* * The routines beyond this point handle the behaviour of an AF_INET * socket object. Mostly it punts to the subprotocols of IP to do @@ -264,12 +251,16 @@ static int inet_autobind(struct sock *sk) { /* We may need to bind the socket. */ + lock_sock(sk); if (sk->num == 0) { - if (sk->prot->get_port(sk, 0) != 0) + if (sk->prot->get_port(sk, 0) != 0) { + release_sock(sk); return -EAGAIN; + } sk->sport = htons(sk->num); sk->prot->hash(sk); } + release_sock(sk); return 0; } @@ -289,6 +280,7 @@ { struct sock *sk = sock->sk; unsigned char old_state; + int err; if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) return -EINVAL; @@ -297,29 +289,43 @@ backlog = 1; if ((unsigned) backlog > SOMAXCONN) backlog = SOMAXCONN; - sk->max_ack_backlog = backlog; + + lock_sock(sk); + old_state = sk->state; + err = -EINVAL; + if (!((1<state; if (old_state != TCP_LISTEN) { sk->state = TCP_LISTEN; sk->ack_backlog = 0; if (sk->num == 0) { if (sk->prot->get_port(sk, 0) != 0) { sk->state = old_state; - return -EAGAIN; + err = -EAGAIN; + goto out; } sk->sport = htons(sk->num); + } else { + /* Not nice, but the simplest solution however */ + if (sk->prev) + ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0; } - dst_release(xchg(&sk->dst_cache, NULL)); + sk_dst_reset(sk); sk->prot->hash(sk); sk->socket->flags |= SO_ACCEPTCON; sk->write_space = inet_listen_write_space; } - return 0; + sk->max_ack_backlog = backlog; + err = 0; + +out: + release_sock(sk); + return err; } /* @@ -334,24 +340,6 @@ struct sock *sk; struct proto *prot; - /* Compatibility */ - if (sock->type == SOCK_PACKET) { - static int warned; - if (net_families[PF_PACKET]==NULL) - { -#if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE) - char module_name[30]; - sprintf(module_name,"net-pf-%d", PF_PACKET); - request_module(module_name); - if (net_families[PF_PACKET] == NULL) -#endif - return -ESOCKTNOSUPPORT; - } - if (!warned++) - printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); - return net_families[PF_PACKET]->create(sock, protocol); - } - sock->state = SS_UNCONNECTED; sk = sk_alloc(PF_INET, GFP_KERNEL, 1); if (sk == NULL) @@ -363,9 +351,9 @@ goto free_and_noproto; protocol = IPPROTO_TCP; if (ipv4_config.no_pmtu_disc) - sk->ip_pmtudisc = IP_PMTUDISC_DONT; + sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT; else - sk->ip_pmtudisc = IP_PMTUDISC_WANT; + sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT; prot = &tcp_prot; sock->ops = &inet_stream_ops; break; @@ -376,7 +364,7 @@ goto free_and_noproto; protocol = IPPROTO_UDP; sk->no_check = UDP_CSUM_DEFAULT; - sk->ip_pmtudisc = IP_PMTUDISC_DONT; + sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT; prot=&udp_prot; sock->ops = &inet_dgram_ops; break; @@ -387,19 +375,19 @@ goto free_and_noproto; prot = &raw_prot; sk->reuse = 1; - sk->ip_pmtudisc = IP_PMTUDISC_DONT; + sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT; sk->num = protocol; sock->ops = &inet_dgram_ops; if (protocol == IPPROTO_RAW) - sk->ip_hdrincl = 1; + sk->protinfo.af_inet.hdrincl = 1; break; default: goto free_and_badtype; } sock_init_data(sock,sk); - - sk->destruct = NULL; + + sk->destruct = inet_sock_destruct; sk->zapped=0; #ifdef CONFIG_TCP_NAGLE_OFF @@ -412,15 +400,17 @@ sk->backlog_rcv = prot->backlog_rcv; sk->timer.data = (unsigned long)sk; - sk->timer.function = &net_timer; + sk->timer.function = &tcp_keepalive_timer; - sk->ip_ttl=ip_statistics.IpDefaultTTL; + sk->protinfo.af_inet.ttl=ip_statistics.IpDefaultTTL; + + sk->protinfo.af_inet.mc_loop=1; + sk->protinfo.af_inet.mc_ttl=1; + sk->protinfo.af_inet.mc_index=0; + sk->protinfo.af_inet.mc_list=NULL; + + atomic_inc(&inet_sock_nr); - sk->ip_mc_loop=1; - sk->ip_mc_ttl=1; - sk->ip_mc_index=0; - sk->ip_mc_list=NULL; - if (sk->num) { /* It assumes that any protocol which allows * the user to assign a number at socket @@ -436,7 +426,8 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - destroy_sock(sk); + sk->dead = 1; + inet_sock_release(sk); return(err); } } @@ -465,18 +456,13 @@ * should refer to it. */ -int inet_release(struct socket *sock, struct socket *peersock) +int inet_release(struct socket *sock) { struct sock *sk = sock->sk; if (sk) { long timeout; - /* Begin closedown and wake up sleepers. */ - if (sock->state != SS_UNCONNECTED) - sock->state = SS_DISCONNECTING; - sk->state_change(sk); - /* Applications forget to leave groups before exiting */ ip_mc_drop_socket(sk); @@ -494,7 +480,6 @@ timeout = MAX_SCHEDULE_TIMEOUT; } sock->sk = NULL; - sk->socket = NULL; sk->prot->close(sk, timeout); } return(0); @@ -506,27 +491,25 @@ struct sock *sk=sock->sk; unsigned short snum; int chk_addr_ret; + int err; /* If the socket has its own bind function then use it. (RAW) */ if(sk->prot->bind) return sk->prot->bind(sk, uaddr, addr_len); - - /* Check these errors (active socket, bad address length, double bind). */ - if ((sk->state != TCP_CLOSE) || - (addr_len < sizeof(struct sockaddr_in)) || - (sk->num != 0)) + + if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); if (addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { -#ifdef CONFIG_IP_TRANSPARENT_PROXY - /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) -#endif - return -EADDRNOTAVAIL; /* Source address MUST be ours! */ + return -EADDRNOTAVAIL; /* Source address MUST be ours! */ } + snum = ntohs(addr->sin_port); + if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + /* We keep a pair of addresses. rcv_saddr is the one * used by hash lookups, and saddr is used for transmit. * @@ -534,46 +517,47 @@ * would be illegal to use them (multicast/broadcast) in * which case the sending device address is used. */ + lock_sock(sk); + + /* Check these errors (active socket, double bind). */ + err = -EINVAL; + if ((sk->state != TCP_CLOSE) || + (sk->num != 0)) + goto out; + sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr; - if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) + if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) sk->saddr = 0; /* Use device */ - snum = ntohs(addr->sin_port); -#ifdef CONFIG_IP_MASQUERADE - /* The kernel masquerader needs some ports. */ - if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END)) - return -EADDRINUSE; -#endif - if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) - return -EACCES; - /* Make sure we are allowed to bind here. */ - if (sk->prot->get_port(sk, snum) != 0) - return -EADDRINUSE; + if (sk->prot->get_port(sk, snum) != 0) { + sk->saddr = sk->rcv_saddr = 0; + err = -EADDRINUSE; + goto out; + } sk->sport = htons(sk->num); sk->daddr = 0; sk->dport = 0; sk->prot->hash(sk); - dst_release(sk->dst_cache); - sk->dst_cache=NULL; - return(0); + sk_dst_reset(sk); + err = 0; +out: + release_sock(sk); + return err; } int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags) { struct sock *sk=sock->sk; - int err; - if (inet_autobind(sk) != 0) + if (uaddr->sa_family == AF_UNSPEC) + return sk->prot->disconnect(sk, flags); + + if (sk->num==0 && inet_autobind(sk) != 0) return -EAGAIN; - if (sk->prot->connect == NULL) - return -EOPNOTSUPP; - err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len); - if (err < 0) - return err; - return(0); + return sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len); } static void inet_wait_for_connect(struct sock *sk) @@ -582,13 +566,21 @@ add_wait_queue(sk->sleep, &wait); current->state = TASK_INTERRUPTIBLE; - while (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) { + + /* RED-PEN. current->state is volatile. Is it enough to prevent + * reordering it and sk->state check? I put barrier to be sure. + */ + barrier(); + while ((1<state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { if (signal_pending(current)) break; if (sk->err) break; + release_sock(sk); schedule(); + lock_sock(sk); current->state = TASK_INTERRUPTIBLE; + barrier(); } current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); @@ -605,68 +597,71 @@ struct sock *sk=sock->sk; int err; - if(sock->state != SS_UNCONNECTED && sock->state != SS_CONNECTING) { - if(sock->state == SS_CONNECTED) - return -EISCONN; - return -EINVAL; + if (uaddr->sa_family == AF_UNSPEC) { + lock_sock(sk); + err = sk->prot->disconnect(sk, flags); + sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; + release_sock(sk); + return err; } - if(sock->state == SS_CONNECTING) { - /* Note: tcp_connected contains SYN_RECV, which may cause - bogus results here. -AK */ - if(tcp_connected(sk->state)) { + lock_sock(sk); + switch (sock->state) { + default: + err = -EINVAL; + goto out; + case SS_CONNECTED: + err = -EISCONN; + goto out; + case SS_CONNECTING: + if (tcp_established(sk->state)) { sock->state = SS_CONNECTED; - return 0; + err = 0; + goto out; } - if (sk->zapped || sk->err) + if (sk->err) goto sock_error; + err = -EALREADY; if (flags & O_NONBLOCK) - return -EALREADY; - } else { - if (sk->prot->connect == NULL) - return -EOPNOTSUPP; - - /* We may need to bind the socket. */ - if (inet_autobind(sk) != 0) - return -EAGAIN; - + goto out; + break; + case SS_UNCONNECTED: err = sk->prot->connect(sk, uaddr, addr_len); - /* Note: there is a theoretical race here when an wake up - occurred before inet_wait_for_connect is entered. In 2.3 - the wait queue setup should be moved before the low level - connect call. -AK*/ if (err < 0) - return err; + goto out; sock->state = SS_CONNECTING; } - - if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING) + + if (sk->state > TCP_FIN_WAIT2) goto sock_error; - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - return -EINPROGRESS; + err = -EINPROGRESS; + if (!tcp_established(sk->state) && (flags & O_NONBLOCK)) + goto out; - if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) { + if ((1<state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { inet_wait_for_connect(sk); + err = -ERESTARTSYS; if (signal_pending(current)) - return -ERESTARTSYS; + goto out; } - sock->state = SS_CONNECTED; - if ((sk->state != TCP_ESTABLISHED) && sk->err) + if (sk->err && !tcp_established(sk->state)) goto sock_error; - return 0; + sock->state = SS_CONNECTED; + err = 0; +out: + release_sock(sk); + return err; -sock_error: - /* This is ugly but needed to fix a race in the ICMP error handler */ - if (sk->zapped && sk->state != TCP_CLOSE) { - lock_sock(sk); - tcp_set_state(sk, TCP_CLOSE); - release_sock(sk); - sk->zapped = 0; - } +sock_error: + err = sock_error(sk) ? : -ECONNABORTED; sock->state = SS_UNCONNECTED; - return sock_error(sk); + if (sk->prot->disconnect(sk, O_NONBLOCK)) + sock->state = SS_DISCONNECTING; + release_sock(sk); + + return err; } /* @@ -675,62 +670,27 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags) { - struct sock *sk1 = sock->sk, *sk2; - struct sock *newsk = newsock->sk; + struct sock *sk1 = sock->sk; + struct sock *sk2; int err = -EINVAL; - if (sock->state != SS_UNCONNECTED || !(sock->flags & SO_ACCEPTCON)) + if((sk2 = sk1->prot->accept(sk1,flags,&err)) == NULL) goto do_err; - err = -EOPNOTSUPP; - if (sk1->prot->accept == NULL) - goto do_err; + lock_sock(sk2); - if((sk2 = sk1->prot->accept(sk1,flags)) == NULL) - goto do_sk1_err; - - /* - * We've been passed an extra socket. - * We need to free it up because the tcp module creates - * its own when it accepts one. - */ - sk2->sleep = newsk->sleep; + BUG_TRAP((1<state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE)); + write_lock_irq(&sk2->callback_lock); + sk2->sleep = &newsock->wait; newsock->sk = sk2; sk2->socket = newsock; - newsk->socket = NULL; - - if (flags & O_NONBLOCK) - goto do_half_success; + write_unlock_irq(&sk2->callback_lock); - if(sk2->state == TCP_ESTABLISHED) - goto do_full_success; - if(sk2->err > 0) - goto do_connect_err; - err = -ECONNABORTED; - if (sk2->state == TCP_CLOSE) - goto do_bad_connection; -do_full_success: - destroy_sock(newsk); newsock->state = SS_CONNECTED; + release_sock(sk2); return 0; -do_half_success: - destroy_sock(newsk); - return(0); - -do_connect_err: - err = sock_error(sk2); -do_bad_connection: - sk2->sleep = NULL; - sk2->socket = NULL; - destroy_sock(sk2); - newsock->sk = newsk; - newsk->socket = newsock; - return err; - -do_sk1_err: - err = sock_error(sk1); do_err: return err; } @@ -748,7 +708,7 @@ sin->sin_family = AF_INET; if (peer) { - if (!tcp_connected(sk->state)) + if (!sk->dport) return -ENOTCONN; sin->sin_port = sk->dport; sin->sin_addr.s_addr = sk->daddr; @@ -772,12 +732,9 @@ int addr_len = 0; int err; - if (sock->flags & SO_ACCEPTCON) - return -EINVAL; - if (sk->prot->recvmsg == NULL) - return -EOPNOTSUPP; /* We may need to bind the socket. */ - if (inet_autobind(sk) != 0) + /* It is pretty strange. I would return error in this case --ANK */ + if (sk->num==0 && inet_autobind(sk) != 0) return -EAGAIN; err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT, flags&~MSG_DONTWAIT, &addr_len); @@ -792,27 +749,17 @@ { struct sock *sk = sock->sk; - if (sk->shutdown & SEND_SHUTDOWN) { - if (!(msg->msg_flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 1); - return -EPIPE; - } - if (sk->prot->sendmsg == NULL) - return -EOPNOTSUPP; - if(sk->err) - return sock_error(sk); - /* We may need to bind the socket. */ - if (inet_autobind(sk) != 0) + if (sk->num==0 && inet_autobind(sk) != 0) return -EAGAIN; return sk->prot->sendmsg(sk, msg, size); } - int inet_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + int err; /* This should really check to make sure * the socket is a TCP socket. (WHY AC...) @@ -824,19 +771,24 @@ return -EINVAL; if (!sk) return -ENOTCONN; - if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + + lock_sock(sk); + if (sock->state == SS_CONNECTING && tcp_established(sk->state)) sock->state = SS_CONNECTED; - if (!tcp_connected(sk->state)) - return -ENOTCONN; + err = -ENOTCONN; + if (!tcp_connected(sk->state)) + goto out; sk->shutdown |= how; if (sk->prot->shutdown) sk->prot->shutdown(sk, how); /* Wake up anyone sleeping in poll. */ sk->state_change(sk); - return(0); + err = 0; +out: + release_sock(sk); + return err; } - unsigned int inet_poll(struct file * file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; @@ -892,15 +844,6 @@ case SIOCGARP: case SIOCSARP: return(arp_ioctl(cmd,(void *) arg)); - case SIOCDRARP: - case SIOCGRARP: - case SIOCSRARP: -#ifdef CONFIG_KMOD - if (rarp_ioctl_hook == NULL) - request_module("rarp"); -#endif - if (rarp_ioctl_hook != NULL) - return(rarp_ioctl_hook(cmd,(void *) arg)); case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: @@ -915,8 +858,11 @@ return(devinet_ioctl(cmd,(void *) arg)); case SIOCGIFBR: case SIOCSIFBR: -#ifdef CONFIG_BRIDGE - return(br_ioctl(cmd,(void *) arg)); +#ifdef CONFIG_BRIDGE + lock_kernel(); + err = br_ioctl(cmd,(void *) arg); + unlock_kernel(); + return err; #else return -ENOPKG; #endif @@ -924,7 +870,10 @@ case SIOCADDDLCI: case SIOCDELDLCI: #ifdef CONFIG_DLCI - return(dlci_ioctl(cmd, (void *) arg)); + lock_kernel(); + err = dlci_ioctl(cmd, (void *) arg); + unlock_kernel(); + return err; #endif #ifdef CONFIG_DLCI_MODULE @@ -934,8 +883,12 @@ request_module("dlci"); #endif - if (dlci_ioctl_hook) - return((*dlci_ioctl_hook)(cmd, (void *) arg)); + if (dlci_ioctl_hook) { + lock_kernel(); + err = (*dlci_ioctl_hook)(cmd, (void *) arg); + unlock_kernel(); + return err; + } #endif return -ENOPKG; @@ -960,7 +913,6 @@ struct proto_ops inet_stream_ops = { PF_INET, - sock_no_dup, inet_release, inet_bind, inet_stream_connect, @@ -975,13 +927,13 @@ inet_getsockopt, sock_no_fcntl, inet_sendmsg, - inet_recvmsg + inet_recvmsg, + sock_no_mmap }; struct proto_ops inet_dgram_ops = { PF_INET, - sock_no_dup, inet_release, inet_bind, inet_dgram_connect, @@ -996,7 +948,8 @@ inet_getsockopt, sock_no_fcntl, inet_sendmsg, - inet_recvmsg + inet_recvmsg, + sock_no_mmap }; struct net_proto_family inet_family_ops = { @@ -1006,14 +959,6 @@ #ifdef CONFIG_PROC_FS -#ifdef CONFIG_INET_RARP -static struct proc_dir_entry proc_net_rarp = { - PROC_NET_RARP, 4, "rarp", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - rarp_get_info -}; -#endif /* RARP */ static struct proc_dir_entry proc_net_raw = { PROC_NET_RAW, 3, "raw", S_IFREG | S_IRUGO, 1, 0, 0, @@ -1060,7 +1005,7 @@ * Called by socket.c on kernel startup. */ -__initfunc(void inet_proto_init(struct net_proto *pro)) +void __init inet_proto_init(struct net_proto *pro) { struct sk_buff *dummy_skb; struct inet_protocol *p; @@ -1127,34 +1072,17 @@ #endif /* - * Set the firewalling up - */ -#if defined(CONFIG_IP_FIREWALL) - ip_fw_init(); -#endif - -#ifdef CONFIG_IP_MASQUERADE - ip_masq_init(); -#endif - - /* * Initialise the multicast router */ #if defined(CONFIG_IP_MROUTE) ip_mr_init(); #endif -#ifdef CONFIG_INET_RARP - rarp_ioctl_hook = rarp_ioctl; -#endif /* * Create all the /proc entries. */ #ifdef CONFIG_PROC_FS -#ifdef CONFIG_INET_RARP - proc_net_register(&proc_net_rarp); -#endif /* RARP */ proc_net_register(&proc_net_raw); proc_net_register(&proc_net_snmp); proc_net_register(&proc_net_netstat); diff -u --recursive --new-file v2.3.14/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.3.14/linux/net/ipv4/arp.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/arp.c Wed Aug 25 14:46:02 1999 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.78 1999/06/09 10:10:36 davem Exp $ + * Version: $Id: arp.c,v 1.80 1999/08/20 11:04:54 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -115,6 +115,9 @@ #include #endif #endif +#ifdef CONFIG_ATM_CLIP +#include +#endif #include #include @@ -127,6 +130,7 @@ /* * Interface to generic neighbour cache. */ +static u32 arp_hash(const void *pkey, const struct net_device *dev); static int arp_constructor(struct neighbour *neigh); static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); @@ -186,10 +190,12 @@ AF_INET, sizeof(struct neighbour) + 4, 4, + arp_hash, arp_constructor, NULL, NULL, parp_redo, + "arp_cache", { NULL, NULL, &arp_tbl, 0, NULL, NULL, 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ }, 30*HZ, 128, 512, 1024, @@ -213,12 +219,24 @@ } +static u32 arp_hash(const void *pkey, const struct net_device *dev) +{ + u32 hash_val; + + hash_val = *(u32*)pkey; + hash_val ^= (hash_val>>16); + hash_val ^= hash_val>>8; + hash_val ^= hash_val>>3; + hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + + return hash_val; +} static int arp_constructor(struct neighbour *neigh) { u32 addr = *(u32*)neigh->primary_key; struct net_device *dev = neigh->dev; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = in_dev_get(dev); if (in_dev == NULL) return -EINVAL; @@ -227,6 +245,8 @@ if (in_dev->arp_parms) neigh->parms = in_dev->arp_parms; + in_dev_put(in_dev); + if (dev->hard_header == NULL) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; @@ -293,7 +313,6 @@ else neigh->output = neigh->ops->output; } - return 0; } @@ -409,7 +428,11 @@ u32 nexthop = ((struct rtable*)dst)->rt_gateway; if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)) nexthop = 0; - dst->neighbour = __neigh_lookup(&arp_tbl, &nexthop, dev, 1); + dst->neighbour = __neigh_lookup( +#ifdef CONFIG_ATM_CLIP + dev->type == ARPHRD_ATM ? &clip_tbl : +#endif + &arp_tbl, &nexthop, dev, 1); } return (dst->neighbour != NULL); } @@ -540,7 +563,7 @@ u32 sip, tip; u16 dev_type = dev->type; int addr_type; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = in_dev_get(dev); struct neighbour *n; /* @@ -558,6 +581,9 @@ arp->ar_pln != 4) goto out; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + goto out_of_mem; + switch (dev_type) { default: if (arp->ar_pro != __constant_htons(ETH_P_IP)) @@ -610,7 +636,7 @@ #endif } - /* Undertsand only these message types */ + /* Understand only these message types */ if (arp->ar_op != __constant_htons(ARPOP_REPLY) && arp->ar_op != __constant_htons(ARPOP_REQUEST)) @@ -685,6 +711,7 @@ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); } else { pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb); + in_dev_put(in_dev); return 0; } goto out; @@ -731,6 +758,9 @@ out: kfree_skb(skb); + if (in_dev) + in_dev_put(in_dev); +out_of_mem: return 0; } @@ -768,8 +798,8 @@ ipv4_devconf.proxy_arp = 1; return 0; } - if (dev->ip_ptr) { - ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 1; + if (__in_dev_get(dev)) { + __in_dev_get(dev)->cnf.proxy_arp = 1; return 0; } return -ENXIO; @@ -851,8 +881,8 @@ ipv4_devconf.proxy_arp = 0; return 0; } - if (dev->ip_ptr) { - ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 0; + if (__in_dev_get(dev)) { + __in_dev_get(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; @@ -915,7 +945,7 @@ rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; - if ((dev = dev_get(r.arp_dev)) == NULL) + if ((dev = __dev_get_by_name(r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ @@ -1082,7 +1112,7 @@ __constant_htons(ETH_P_ARP), NULL, /* All devices */ arp_rcv, - NULL, + (void*)1, NULL }; @@ -1095,7 +1125,7 @@ }; #endif -__initfunc(void arp_init (void)) +void __init arp_init (void) { neigh_table_init(&arp_tbl); diff -u --recursive --new-file v2.3.14/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.3.14/linux/net/ipv4/devinet.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/devinet.c Mon Aug 23 10:01:02 1999 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.32 1999/06/09 11:15:33 davem Exp $ + * Version: $Id: devinet.c,v 1.34 1999/08/20 11:04:57 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -77,6 +77,11 @@ int inet_ifa_count; int inet_dev_count; +/* Locks all the inet devices. */ + +rwlock_t inetdev_lock = RW_LOCK_UNLOCKED; + + static struct in_ifaddr * inet_alloc_ifa(void) { struct in_ifaddr *ifa; @@ -92,19 +97,41 @@ static __inline__ void inet_free_ifa(struct in_ifaddr *ifa) { + if (ifa->ifa_dev) + __in_dev_put(ifa->ifa_dev); kfree_s(ifa, sizeof(*ifa)); inet_ifa_count--; } +void in_dev_finish_destroy(struct in_device *idev) +{ + struct net_device *dev = idev->dev; + + BUG_TRAP(idev->ifa_list==NULL); + BUG_TRAP(idev->mc_list==NULL); +#ifdef NET_REFCNT_DEBUG + printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n", idev, dev ? dev->name : "NIL"); +#endif + dev_put(dev); + if (!idev->dead) { + printk("Freeing alive in_device %p\n", idev); + return; + } + inet_dev_count--; + kfree_s(idev, sizeof(*idev)); +} + struct in_device *inetdev_init(struct net_device *dev) { struct in_device *in_dev; + ASSERT_RTNL(); + in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL); if (!in_dev) return NULL; - inet_dev_count++; memset(in_dev, 0, sizeof(*in_dev)); + in_dev->lock = RW_LOCK_UNLOCKED; memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; @@ -112,10 +139,17 @@ kfree(in_dev); return NULL; } + inet_dev_count++; + /* Reference in_dev->dev */ + dev_hold(dev); #ifdef CONFIG_SYSCTL neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4"); #endif + write_lock_bh(&inetdev_lock); dev->ip_ptr = in_dev; + /* Account for reference dev->ip_ptr */ + in_dev_hold(in_dev); + write_unlock_bh(&inetdev_lock); #ifdef CONFIG_SYSCTL devinet_sysctl_register(in_dev, &in_dev->cnf); #endif @@ -128,6 +162,10 @@ { struct in_ifaddr *ifa; + ASSERT_RTNL(); + + in_dev->dead = 1; + ip_mc_destroy_dev(in_dev); while ((ifa = in_dev->ifa_list) != NULL) { @@ -138,28 +176,38 @@ #ifdef CONFIG_SYSCTL devinet_sysctl_unregister(&in_dev->cnf); #endif + write_lock_bh(&inetdev_lock); in_dev->dev->ip_ptr = NULL; - synchronize_bh(); + /* in_dev_put following below will kill the in_device */ + write_unlock_bh(&inetdev_lock); + + neigh_parms_release(&arp_tbl, in_dev->arp_parms); - kfree(in_dev); + in_dev_put(in_dev); } -struct in_ifaddr * inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) +int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) { + read_lock(&in_dev->lock); for_primary_ifa(in_dev) { if (inet_ifa_match(a, ifa)) { - if (!b || inet_ifa_match(b, ifa)) - return ifa; + if (!b || inet_ifa_match(b, ifa)) { + read_unlock(&in_dev->lock); + return 1; + } } } endfor_ifa(in_dev); - return NULL; -} + read_unlock(&in_dev->lock); + return 0; +} static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy) { struct in_ifaddr *ifa1 = *ifap; + ASSERT_RTNL(); + /* 1. Deleting primary ifaddr forces deletion all secondaries */ if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) { @@ -173,8 +221,9 @@ ifap1 = &ifa->ifa_next; continue; } + write_lock_bh(&in_dev->lock); *ifap1 = ifa->ifa_next; - synchronize_bh(); + write_unlock_bh(&in_dev->lock); rtmsg_ifa(RTM_DELADDR, ifa); notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); @@ -184,8 +233,9 @@ /* 2. Unlink it */ + write_lock_bh(&in_dev->lock); *ifap = ifa1->ifa_next; - synchronize_bh(); + write_unlock_bh(&in_dev->lock); /* 3. Announce address deletion */ @@ -201,16 +251,20 @@ notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); if (destroy) { inet_free_ifa(ifa1); + if (in_dev->ifa_list == NULL) inetdev_destroy(in_dev); } } static int -inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa) +inet_insert_ifa(struct in_ifaddr *ifa) { + struct in_device *in_dev = ifa->ifa_dev; struct in_ifaddr *ifa1, **ifap, **last_primary; + ASSERT_RTNL(); + if (ifa->ifa_local == 0) { inet_free_ifa(ifa); return 0; @@ -241,8 +295,9 @@ } ifa->ifa_next = *ifap; - wmb(); + write_lock_bh(&in_dev->lock); *ifap = ifa; + write_unlock_bh(&in_dev->lock); /* Send message first, then call notifier. Notifier will trigger FIB update, so that @@ -256,7 +311,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = __in_dev_get(dev); + + ASSERT_RTNL(); if (in_dev == NULL) { in_dev = inetdev_init(dev); @@ -265,23 +322,34 @@ return -ENOBUFS; } } - ifa->ifa_dev = in_dev; + if (ifa->ifa_dev != in_dev) { + BUG_TRAP(ifa->ifa_dev==NULL); + in_dev_hold(in_dev); + ifa->ifa_dev=in_dev; + } if (LOOPBACK(ifa->ifa_local)) ifa->ifa_scope = RT_SCOPE_HOST; - return inet_insert_ifa(in_dev, ifa); + return inet_insert_ifa(ifa); } struct in_device *inetdev_by_index(int ifindex) { struct net_device *dev; - dev = dev_get_by_index(ifindex); + struct in_device *in_dev = NULL; + read_lock(&dev_base_lock); + dev = __dev_get_by_index(ifindex); if (dev) - return dev->ip_ptr; - return NULL; + in_dev = in_dev_get(dev); + read_unlock(&dev_base_lock); + return in_dev; } +/* Called only from RTNL semaphored context. No locks. */ + struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask) { + ASSERT_RTNL(); + for_primary_ifa(in_dev) { if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa)) return ifa; @@ -291,10 +359,6 @@ #ifdef CONFIG_RTNETLINK -/* rtm_{add|del} functions are not reenterable, so that - this structure can be made static - */ - int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -303,8 +367,11 @@ struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in_ifaddr *ifa, **ifap; + ASSERT_RTNL(); + if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL) return -EADDRNOTAVAIL; + __in_dev_put(in_dev); for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) { if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) || @@ -329,13 +396,15 @@ struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in_ifaddr *ifa; + ASSERT_RTNL(); + if (ifm->ifa_prefixlen > 32 || rta[IFA_LOCAL-1] == NULL) return -EINVAL; - if ((dev = dev_get_by_index(ifm->ifa_index)) == NULL) + if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) return -ENODEV; - if ((in_dev = dev->ip_ptr) == NULL) { + if ((in_dev = __in_dev_get(dev)) == NULL) { in_dev = inetdev_init(dev); if (!in_dev) return -ENOBUFS; @@ -356,13 +425,14 @@ memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST-1]), 4); ifa->ifa_flags = ifm->ifa_flags; ifa->ifa_scope = ifm->ifa_scope; + in_dev_hold(in_dev); ifa->ifa_dev = in_dev; if (rta[IFA_LABEL-1]) memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ); else memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - return inet_insert_ifa(in_dev, ifa); + return inet_insert_ifa(ifa); } #endif @@ -403,7 +473,6 @@ #ifdef CONFIG_IP_ALIAS char *colon; #endif - int exclusive = 0; int ret = 0; /* @@ -440,8 +509,6 @@ case SIOCSIFFLAGS: if (!capable(CAP_NET_ADMIN)) return -EACCES; - rtnl_lock(); - exclusive = 1; break; case SIOCSIFADDR: /* Set interface address (and family) */ case SIOCSIFBRDADDR: /* Set the broadcast address */ @@ -451,15 +518,14 @@ return -EACCES; if (sin->sin_family != AF_INET) return -EINVAL; - rtnl_lock(); - exclusive = 1; break; default: return -EINVAL; } + rtnl_lock(); - if ((dev = dev_get(ifr.ifr_name)) == NULL) { + if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) { ret = -ENODEV; goto done; } @@ -469,7 +535,7 @@ *colon = ':'; #endif - if ((in_dev=dev->ip_ptr) != NULL) { + if ((in_dev=__in_dev_get(dev)) != NULL) { for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0) break; @@ -557,7 +623,7 @@ if (ifa->ifa_broadcast != sin->sin_addr.s_addr) { inet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = sin->sin_addr.s_addr; - inet_insert_ifa(in_dev, ifa); + inet_insert_ifa(ifa); } break; @@ -569,7 +635,7 @@ } inet_del_ifa(in_dev, ifap, 0); ifa->ifa_address = sin->sin_addr.s_addr; - inet_insert_ifa(in_dev, ifa); + inet_insert_ifa(ifa); } break; @@ -587,16 +653,16 @@ inet_del_ifa(in_dev, ifap, 0); ifa->ifa_mask = sin->sin_addr.s_addr; ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); - inet_set_ifa(dev, ifa); + inet_insert_ifa(ifa); } break; } done: - if (exclusive) - rtnl_unlock(); + rtnl_unlock(); return ret; rarok: + rtnl_unlock(); if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return 0; @@ -605,31 +671,33 @@ static int inet_gifconf(struct net_device *dev, char *buf, int len) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = __in_dev_get(dev); struct in_ifaddr *ifa; - struct ifreq *ifr = (struct ifreq *) buf; + struct ifreq ifr; int done=0; if (in_dev==NULL || (ifa=in_dev->ifa_list)==NULL) return 0; for ( ; ifa; ifa = ifa->ifa_next) { - if (!ifr) { + if (!buf) { done += sizeof(ifr); continue; } if (len < (int) sizeof(ifr)) return done; - memset(ifr, 0, sizeof(struct ifreq)); + memset(&ifr, 0, sizeof(struct ifreq)); if (ifa->ifa_label) - strcpy(ifr->ifr_name, ifa->ifa_label); + strcpy(ifr.ifr_name, ifa->ifa_label); else - strcpy(ifr->ifr_name, dev->name); + strcpy(ifr.ifr_name, dev->name); - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_family = AF_INET; - (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr = ifa->ifa_local; + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET; + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local; - ifr++; + if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) + return -EFAULT; + buf += sizeof(struct ifreq); len -= sizeof(struct ifreq); done += sizeof(struct ifreq); } @@ -639,19 +707,29 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) { u32 addr = 0; - const struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev; - if (in_dev == NULL) + read_lock(&inetdev_lock); + in_dev = __in_dev_get(dev); + if (in_dev == NULL) { + read_unlock(&inetdev_lock); return 0; + } + read_lock(&in_dev->lock); for_primary_ifa(in_dev) { if (ifa->ifa_scope > scope) continue; - addr = ifa->ifa_local; - if (!dst || inet_ifa_match(dst, ifa)) - return addr; + if (!dst || inet_ifa_match(dst, ifa)) { + addr = ifa->ifa_local; + break; + } + if (!addr) + addr = ifa->ifa_local; } endfor_ifa(in_dev); - + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); + if (addr || scope >= RT_SCOPE_LINK) return addr; @@ -660,17 +738,23 @@ in dev_base list. */ read_lock(&dev_base_lock); + read_lock(&inetdev_lock); for (dev=dev_base; dev; dev=dev->next) { - if ((in_dev=dev->ip_ptr) == NULL) + if ((in_dev=__in_dev_get(dev)) == NULL) continue; + read_lock(&in_dev->lock); for_primary_ifa(in_dev) { if (ifa->ifa_scope <= scope) { + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); read_unlock(&dev_base_lock); return ifa->ifa_local; } } endfor_ifa(in_dev); + read_unlock(&in_dev->lock); } + read_unlock(&inetdev_lock); read_unlock(&dev_base_lock); return 0; @@ -689,22 +773,27 @@ { return notifier_chain_unregister(&inetaddr_chain,nb); } - + +/* Called only under RTNL semaphore */ + static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = __in_dev_get(dev); + + ASSERT_RTNL(); if (in_dev == NULL) return NOTIFY_DONE; switch (event) { case NETDEV_REGISTER: - if (in_dev) - printk(KERN_DEBUG "inetdev_event: bug\n"); + printk(KERN_DEBUG "inetdev_event: bug\n"); dev->ip_ptr = NULL; break; case NETDEV_UP: + if (dev->mtu < 68) + break; if (dev == &loopback_dev) { struct in_ifaddr *ifa; if ((ifa = inet_alloc_ifa()) != NULL) { @@ -712,10 +801,11 @@ ifa->ifa_address = htonl(INADDR_LOOPBACK); ifa->ifa_prefixlen = 8; ifa->ifa_mask = inet_make_mask(8); + in_dev_hold(in_dev); ifa->ifa_dev = in_dev; ifa->ifa_scope = RT_SCOPE_HOST; memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - inet_insert_ifa(in_dev, ifa); + inet_insert_ifa(ifa); } } ip_mc_up(in_dev); @@ -723,6 +813,10 @@ case NETDEV_DOWN: ip_mc_down(in_dev); break; + case NETDEV_CHANGEMTU: + if (dev->mtu >= 68) + break; + /* MTU falled under 68, disable IP */ case NETDEV_UNREGISTER: inetdev_destroy(in_dev); break; @@ -798,17 +892,27 @@ continue; if (idx > s_idx) s_ip_idx = 0; - if ((in_dev = dev->ip_ptr) == NULL) + read_lock(&inetdev_lock); + if ((in_dev = __in_dev_get(dev)) == NULL) { + read_unlock(&inetdev_lock); continue; + } + read_lock(&in_dev->lock); for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; ifa = ifa->ifa_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) + cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) { + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); goto done; + } } + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); } + done: read_unlock(&dev_base_lock); cb->args[0] = idx; @@ -887,9 +991,12 @@ read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev; + read_lock(&inetdev_lock); + in_dev = __in_dev_get(dev); if (in_dev) in_dev->cnf.forwarding = on; + read_unlock(&inetdev_lock); } read_unlock(&dev_base_lock); @@ -921,7 +1028,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[12]; + ctl_table devinet_vars[13]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -961,6 +1068,9 @@ {NET_IPV4_CONF_LOG_MARTIANS, "log_martians", &ipv4_devconf.log_martians, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_CONF_TAG, "tag", + &ipv4_devconf.tag, sizeof(int), 0644, NULL, + &proc_dointvec}, {0}}, {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}}, diff -u --recursive --new-file v2.3.14/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.3.14/linux/net/ipv4/fib_frontend.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/fib_frontend.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.16 1999/06/09 10:10:42 davem Exp $ + * Version: $Id: fib_frontend.c,v 1.18 1999/08/20 11:04:59 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -146,21 +146,33 @@ { struct rt_key key; struct fib_result res; + struct net_device *dev = NULL; memset(&key, 0, sizeof(key)); key.dst = addr; +#ifdef CONFIG_IP_MULTIPLE_TABLES + res.r = NULL; +#endif - if (!local_table || local_table->tb_lookup(local_table, &key, &res) - || res.type != RTN_LOCAL) + if (!local_table || local_table->tb_lookup(local_table, &key, &res)) { return NULL; - - return FIB_RES_DEV(res); + } + if (res.type != RTN_LOCAL) + goto out; + dev = FIB_RES_DEV(res); + if (dev) + atomic_inc(&dev->refcnt); + +out: + fib_res_put(&res); + return dev; } unsigned inet_addr_type(u32 addr) { struct rt_key key; struct fib_result res; + unsigned ret = RTN_BROADCAST; if (ZERONET(addr) || BADCLASS(addr)) return RTN_BROADCAST; @@ -169,13 +181,18 @@ memset(&key, 0, sizeof(key)); key.dst = addr; - +#ifdef CONFIG_IP_MULTIPLE_TABLES + res.r = NULL; +#endif + if (local_table) { - if (local_table->tb_lookup(local_table, &key, &res) == 0) - return res.type; - return RTN_UNICAST; + ret = RTN_UNICAST; + if (local_table->tb_lookup(local_table, &key, &res) == 0) { + ret = res.type; + fib_res_put(&res); + } } - return RTN_BROADCAST; + return ret; } /* Given (packet source, input interface) and optional (dst, oif, tos): @@ -189,9 +206,11 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, struct net_device *dev, u32 *spec_dst, u32 *itag) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev; struct rt_key key; struct fib_result res; + int no_addr, rpf; + int ret; key.dst = src; key.src = dst; @@ -200,12 +219,22 @@ key.iif = oif; key.scope = RT_SCOPE_UNIVERSE; + no_addr = rpf = 0; + read_lock(&inetdev_lock); + in_dev = __in_dev_get(dev); + if (in_dev) { + no_addr = in_dev->ifa_list == NULL; + rpf = IN_DEV_RPFILTER(in_dev); + } + read_unlock(&inetdev_lock); + if (in_dev == NULL) - return -EINVAL; + goto e_inval; + if (fib_lookup(&key, &res)) goto last_resort; if (res.type != RTN_UNICAST) - return -EINVAL; + goto e_inval_res; *spec_dst = FIB_RES_PREFSRC(res); if (itag) fib_combine_itag(itag, &res); @@ -214,25 +243,39 @@ #else if (FIB_RES_DEV(res) == dev) #endif - return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; - - if (in_dev->ifa_list == NULL) + { + ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + fib_res_put(&res); + return ret; + } + fib_res_put(&res); + if (no_addr) goto last_resort; - if (IN_DEV_RPFILTER(in_dev)) - return -EINVAL; + if (rpf) + goto e_inval; key.oif = dev->ifindex; - if (fib_lookup(&key, &res) == 0 && res.type == RTN_UNICAST) { - *spec_dst = FIB_RES_PREFSRC(res); - return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + + ret = 0; + if (fib_lookup(&key, &res) == 0) { + if (res.type == RTN_UNICAST) { + *spec_dst = FIB_RES_PREFSRC(res); + ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + } + fib_res_put(&res); } - return 0; + return ret; last_resort: - if (IN_DEV_RPFILTER(in_dev)) - return -EINVAL; + if (rpf) + goto e_inval; *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); *itag = 0; return 0; + +e_inval_res: + fib_res_put(&res); +e_inval: + return -EINVAL; } #ifndef CONFIG_IP_NOSIOCRT @@ -561,7 +604,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = __in_dev_get(dev); if (!in_dev) return NOTIFY_DONE; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c --- v2.3.14/linux/net/ipv4/fib_hash.c Wed Jun 9 14:45:36 1999 +++ linux/net/ipv4/fib_hash.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * IPv4 FIB: lookup engine and maintenance routines. * - * Version: $Id: fib_hash.c,v 1.10 1999/06/09 10:10:45 davem Exp $ + * Version: $Id: fib_hash.c,v 1.11 1999/08/20 11:05:01 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -48,6 +48,8 @@ printk(KERN_DEBUG a) */ +static kmem_cache_t * fn_hash_kmem; + /* These bizarre types are just to force strict type checking. When I reversed order of bytes and changed to natural mask lengths, @@ -216,7 +218,7 @@ static void fn_free_node(struct fib_node * f) { fib_release_info(FIB_INFO(f)); - kfree_s(f, sizeof(struct fib_node)); + kmem_cache_free(fn_hash_kmem, f); } @@ -298,7 +300,6 @@ res->type = f->fn_type; res->scope = f->fn_scope; res->prefixlen = fz->fz_order; - res->prefix = &fz_prefix(f->fn_key, fz); goto out; } if (err < 0) @@ -372,7 +373,10 @@ if (next_fi != res->fi) break; } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) { + if (res->fi) + fib_info_put(res->fi); res->fi = fi; + atomic_inc(&fi->fib_clntref); fn_hash_last_dflt = order; goto out; } @@ -386,13 +390,21 @@ } if (!fib_detect_death(fi, order, &last_resort, &last_idx)) { + if (res->fi) + fib_info_put(res->fi); res->fi = fi; + atomic_inc(&fi->fib_clntref); fn_hash_last_dflt = order; goto out; } - if (last_idx >= 0) + if (last_idx >= 0) { + if (res->fi) + fib_info_put(res->fi); res->fi = last_resort; + if (last_resort) + atomic_inc(&last_resort->fib_clntref); + } fn_hash_last_dflt = last_idx; out: read_unlock(&fib_hash_lock); @@ -554,7 +566,7 @@ replace: err = -ENOBUFS; - new_f = (struct fib_node *) kmalloc(sizeof(struct fib_node), GFP_KERNEL); + new_f = kmem_cache_alloc(fn_hash_kmem, SLAB_KERNEL); if (new_f == NULL) goto out; @@ -891,9 +903,17 @@ #endif { struct fib_table *tb; + + if (fn_hash_kmem == NULL) + fn_hash_kmem = kmem_cache_create("ip_fib_hash", + sizeof(struct fib_node), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), GFP_KERNEL); if (tb == NULL) return NULL; + tb->tb_id = id; tb->tb_lookup = fn_hash_lookup; tb->tb_insert = fn_hash_insert; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c --- v2.3.14/linux/net/ipv4/fib_rules.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/fib_rules.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: policy rules. * - * Version: $Id: fib_rules.c,v 1.11 1999/06/09 10:10:47 davem Exp $ + * Version: $Id: fib_rules.c,v 1.13 1999/08/20 11:05:05 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -52,6 +52,7 @@ struct fib_rule { struct fib_rule *r_next; + atomic_t r_clntref; u32 r_preference; unsigned char r_table; unsigned char r_action; @@ -72,11 +73,12 @@ __u32 r_tclassid; #endif char r_ifname[IFNAMSIZ]; + int r_dead; }; -static struct fib_rule default_rule = { NULL, 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, }; -static struct fib_rule main_rule = { &default_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, }; -static struct fib_rule local_rule = { &main_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST, }; +static struct fib_rule default_rule = { NULL, ATOMIC_INIT(2), 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, }; +static struct fib_rule main_rule = { &default_rule, ATOMIC_INIT(2), 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, }; +static struct fib_rule local_rule = { &main_rule, ATOMIC_INIT(2), 0, RT_TABLE_LOCAL, RTN_UNICAST, }; static struct fib_rule *fib_rules = &local_rule; static rwlock_t fib_rules_lock = RW_LOCK_UNLOCKED; @@ -107,9 +109,9 @@ write_lock_bh(&fib_rules_lock); *rp = r->r_next; + r->r_dead = 1; write_unlock_bh(&fib_rules_lock); - if (r != &default_rule && r != &main_rule) - kfree(r); + fib_rule_put(r); err = 0; break; } @@ -129,6 +131,15 @@ return NULL; } +void fib_rule_put(struct fib_rule *r) +{ + if (atomic_dec_and_test(&r->r_clntref)) { + if (r->r_dead) + kfree(r); + else + printk("Freeing alive rule %p\n", r); + } +} int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { @@ -183,7 +194,7 @@ memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ); new_r->r_ifname[IFNAMSIZ-1] = 0; new_r->r_ifindex = -1; - dev = dev_get(new_r->r_ifname); + dev = __dev_get_by_name(new_r->r_ifname); if (dev) new_r->r_ifindex = dev->ifindex; } @@ -209,6 +220,7 @@ } new_r->r_next = r; + atomic_inc(&new_r->r_clntref); write_lock_bh(&fib_rules_lock); *rp = new_r; write_unlock_bh(&fib_rules_lock); @@ -322,8 +334,9 @@ continue; err = tb->tb_lookup(tb, key, res); if (err == 0) { -FRprintk("ok\n"); res->r = policy; + if (policy) + atomic_inc(&policy->r_clntref); read_unlock(&fib_rules_lock); return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c --- v2.3.14/linux/net/ipv4/fib_semantics.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/fib_semantics.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: semantics. * - * Version: $Id: fib_semantics.c,v 1.13 1999/03/21 05:22:34 davem Exp $ + * Version: $Id: fib_semantics.c,v 1.15 1999/08/20 11:05:07 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -46,6 +46,8 @@ #define FSprintk(a...) static struct fib_info *fib_info_list; +static rwlock_t fib_info_lock = RW_LOCK_UNLOCKED; +int fib_info_cnt; #define for_fib_info() { struct fib_info *fi; \ for (fi = fib_info_list; fi; fi = fi->fib_next) @@ -98,19 +100,38 @@ { -EINVAL, RT_SCOPE_NOWHERE} /* RTN_XRESOLVE */ }; + /* Release a nexthop info record */ +void free_fib_info(struct fib_info *fi) +{ + if (fi->fib_dead == 0) { + printk("Freeing alive fib_info %p\n", fi); + return; + } + change_nexthops(fi) { + if (nh->nh_dev) + dev_put(nh->nh_dev); + nh->nh_dev = NULL; + } endfor_nexthops(fi); + fib_info_cnt--; + kfree(fi); +} + void fib_release_info(struct fib_info *fi) { - if (fi && !--fi->fib_refcnt) { + write_lock(&fib_info_lock); + if (fi && --fi->fib_treeref == 0) { if (fi->fib_next) fi->fib_next->fib_prev = fi->fib_prev; if (fi->fib_prev) fi->fib_prev->fib_next = fi->fib_next; if (fi == fib_info_list) fib_info_list = fi->fib_next; - kfree(fi); + fi->fib_dead = 1; + fib_info_put(fi); } + write_unlock(&fib_info_lock); } extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) @@ -142,9 +163,7 @@ if (nfi->fib_protocol == fi->fib_protocol && nfi->fib_prefsrc == fi->fib_prefsrc && nfi->fib_priority == fi->fib_priority && - nfi->fib_mtu == fi->fib_mtu && - nfi->fib_rtt == fi->fib_rtt && - nfi->fib_window == fi->fib_window && + memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 && ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 && (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) return fi; @@ -158,15 +177,19 @@ int ip_fib_check_default(u32 gw, struct net_device *dev) { + read_lock(&fib_info_lock); for_fib_info() { if (fi->fib_flags & RTNH_F_DEAD) continue; for_nexthops(fi) { if (nh->nh_dev == dev && nh->nh_gw == gw && - !(nh->nh_flags&RTNH_F_DEAD)) + !(nh->nh_flags&RTNH_F_DEAD)) { + read_unlock(&fib_info_lock); return 0; + } } endfor_nexthops(fi); } endfor_fib_info(); + read_unlock(&fib_info_lock); return -1; } @@ -337,11 +360,12 @@ return -EINVAL; if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; + atomic_inc(&dev->refcnt); nh->nh_scope = RT_SCOPE_LINK; return 0; } @@ -359,6 +383,9 @@ nh->nh_scope = res.scope; nh->nh_oif = FIB_RES_OIF(res); nh->nh_dev = FIB_RES_DEV(res); + if (nh->nh_dev) + atomic_inc(&nh->nh_dev->refcnt); + fib_res_put(&res); } else { struct in_device *in_dev; @@ -368,10 +395,14 @@ in_dev = inetdev_by_index(nh->nh_oif); if (in_dev == NULL) return -ENODEV; - if (!(in_dev->dev->flags&IFF_UP)) + if (!(in_dev->dev->flags&IFF_UP)) { + in_dev_put(in_dev); return -ENETDOWN; + } nh->nh_dev = in_dev->dev; + atomic_inc(&nh->nh_dev->refcnt); nh->nh_scope = RT_SCOPE_HOST; + in_dev_put(in_dev); } return 0; } @@ -405,6 +436,7 @@ err = -ENOBUFS; if (fi == NULL) goto failure; + fib_info_cnt++; memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct fib_nh)); fi->fib_protocol = r->rtm_protocol; @@ -419,7 +451,7 @@ while (RTA_OK(attr, attrlen)) { unsigned flavor = attr->rta_type; if (flavor) { - if (flavor > FIB_MAX_METRICS) + if (flavor > RTAX_MAX) goto err_inval; fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr); } @@ -505,17 +537,21 @@ link_it: if ((ofi = fib_find_info(fi)) != NULL) { - kfree(fi); - ofi->fib_refcnt++; + fi->fib_dead = 1; + free_fib_info(fi); + ofi->fib_treeref++; return ofi; } - fi->fib_refcnt++; + fi->fib_treeref++; + atomic_inc(&fi->fib_clntref); + write_lock(&fib_info_lock); fi->fib_next = fib_info_list; fi->fib_prev = NULL; if (fib_info_list) fib_info_list->fib_prev = fi; fib_info_list = fi; + write_unlock(&fib_info_lock); return fi; err_inval: @@ -523,8 +559,10 @@ failure: *errp = err; - if (fi) - kfree(fi); + if (fi) { + fi->fib_dead = 1; + free_fib_info(fi); + } return NULL; } @@ -543,6 +581,7 @@ #ifdef CONFIG_IP_ROUTE_NAT case RTN_NAT: FIB_RES_RESET(*res); + atomic_inc(&fi->fib_clntref); return 0; #endif case RTN_UNICAST: @@ -559,15 +598,20 @@ #ifdef CONFIG_IP_ROUTE_MULTIPATH if (nhsel < fi->fib_nhs) { res->nh_sel = nhsel; + atomic_inc(&fi->fib_clntref); return 0; } #else - if (nhsel < 1) + if (nhsel < 1) { + atomic_inc(&fi->fib_clntref); return 0; + } #endif endfor_nexthops(fi); + res->fi = NULL; return 1; default: + res->fi = NULL; printk(KERN_DEBUG "impossible 102\n"); return -EINVAL; } @@ -612,16 +656,8 @@ if (fi->fib_nh[0].nh_tclassid) RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid); #endif - if (fi->fib_mtu || fi->fib_window || fi->fib_rtt) { - int i; - struct rtattr *mx = (struct rtattr *)skb->tail; - RTA_PUT(skb, RTA_METRICS, 0, NULL); - for (i=0; ifib_metrics[i]) - RTA_PUT(skb, i+1, sizeof(unsigned), fi->fib_metrics + i); - } - mx->rta_len = skb->tail - (u8*)mx; - } + if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) + goto rtattr_failure; if (fi->fib_prefsrc) RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc); if (fi->fib_nhs == 1) { @@ -742,14 +778,14 @@ if (colon) *colon = 0; #endif - dev = dev_get(devname); + dev = __dev_get_by_name(devname); if (!dev) return -ENODEV; rta->rta_oif = &dev->ifindex; #ifdef CONFIG_IP_ALIAS if (colon) { struct in_ifaddr *ifa; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = __in_dev_get(dev); if (!in_dev) return -ENODEV; *colon = ':'; @@ -789,10 +825,10 @@ mx->rta_len = RTA_LENGTH(0); if (r->rt_flags&RTF_MTU) { rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); - rec->rta_type = RTAX_MTU; + rec->rta_type = RTAX_ADVMSS; rec->rta_len = RTA_LENGTH(4); mx->rta_len += RTA_LENGTH(4); - *(u32*)RTA_DATA(rec) = r->rt_mtu; + *(u32*)RTA_DATA(rec) = r->rt_mtu - 40; } if (r->rt_flags&RTF_WINDOW) { rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); @@ -806,7 +842,7 @@ rec->rta_type = RTAX_RTT; rec->rta_len = RTA_LENGTH(4); mx->rta_len += RTA_LENGTH(4); - *(u32*)RTA_DATA(rec) = r->rt_irtt; + *(u32*)RTA_DATA(rec) = r->rt_irtt<<3; } } return 0; @@ -882,7 +918,7 @@ } if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) continue; - if (nh->nh_dev != dev || dev->ip_ptr == NULL) + if (nh->nh_dev != dev || __in_dev_get(dev) == NULL) continue; alive++; nh->nh_power = 0; @@ -977,7 +1013,7 @@ len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", fi->fib_dev ? fi->fib_dev->name : "*", prefix, fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, - mask, fi->fib_mtu, fi->fib_window, fi->fib_rtt); + mask, fi->fib_advmss+40, fi->fib_window, fi->fib_rtt>>3); } else { len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", prefix, 0, diff -u --recursive --new-file v2.3.14/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.3.14/linux/net/ipv4/icmp.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/icmp.c Mon Aug 23 10:01:02 1999 @@ -3,7 +3,7 @@ * * Alan Cox, * - * Version: $Id: icmp.c,v 1.57 1999/06/09 10:10:50 davem Exp $ + * Version: $Id: icmp.c,v 1.60 1999/08/20 11:05:10 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -261,6 +261,7 @@ #include #include #include +#include #include #include #include @@ -278,10 +279,6 @@ #include #include -#ifdef CONFIG_IP_MASQUERADE -#include -#endif - #define min(a,b) ((a)<(b)?(a):(b)) /* @@ -357,6 +354,47 @@ struct inode icmp_inode; struct socket *icmp_socket=&icmp_inode.u.socket_i; +/* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6, + which is strongly non-reenterable). A bit later it will be made + reenterable and the lock may be removed then. + */ + +static int icmp_xmit_holder = -1; + +static int icmp_xmit_lock_bh(void) +{ + if (!spin_trylock(&icmp_socket->sk->lock.slock)) { + if (icmp_xmit_holder == smp_processor_id()) + return -EAGAIN; + spin_lock(&icmp_socket->sk->lock.slock); + } + icmp_xmit_holder = smp_processor_id(); + return 0; +} + +static __inline__ int icmp_xmit_lock(void) +{ + int ret; + local_bh_disable(); + ret = icmp_xmit_lock_bh(); + if (ret) + local_bh_enable(); + return ret; +} + +static void icmp_xmit_unlock_bh(void) +{ + icmp_xmit_holder = -1; + spin_unlock(&icmp_socket->sk->lock.slock); +} + +static __inline__ void icmp_xmit_unlock(void) +{ + icmp_xmit_unlock_bh(); + local_bh_enable(); +} + + /* * Send an ICMP frame. */ @@ -480,21 +518,26 @@ if (ip_options_echo(&icmp_param->replyopts, skb)) return; + if (icmp_xmit_lock_bh()) + return; + icmp_param->icmph.checksum=0; icmp_param->csum=0; icmp_out_count(icmp_param->icmph.type); - sk->ip_tos = skb->nh.iph->tos; + sk->protinfo.af_inet.tos = skb->nh.iph->tos; daddr = ipc.addr = rt->rt_src; ipc.opt = &icmp_param->replyopts; if (ipc.opt->srr) daddr = icmp_param->replyopts.faddr; if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) - return; + goto out; ip_build_xmit(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+sizeof(struct icmphdr), &ipc, rt, MSG_DONTWAIT); ip_rt_put(rt); +out: + icmp_xmit_unlock_bh(); } @@ -536,10 +579,8 @@ * Now check at the protocol level */ if (!rt) { -#ifndef CONFIG_IP_ALWAYS_DEFRAG if (net_ratelimit()) printk(KERN_DEBUG "icmp_send: destinationless packet\n"); -#endif return; } if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) @@ -575,6 +616,9 @@ } + if (icmp_xmit_lock()) + return; + /* * Construct source address and options. */ @@ -588,11 +632,6 @@ iph->saddr = rt->key.src; } #endif -#ifdef CONFIG_IP_MASQUERADE - if (type==ICMP_DEST_UNREACH && IPCB(skb_in)->flags&IPSKB_MASQUERADED) { - ip_fw_unmasq_icmp(skb_in); - } -#endif saddr = iph->daddr; if (!(rt->rt_flags & RTCF_LOCAL)) @@ -609,7 +648,7 @@ * grow the routing table. */ if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) - return; + goto out; if (ip_options_echo(&icmp_param.replyopts, skb_in)) goto ende; @@ -626,13 +665,13 @@ icmp_param.csum=0; icmp_param.data_ptr=iph; icmp_out_count(icmp_param.icmph.type); - icmp_socket->sk->ip_tos = tos; + icmp_socket->sk->protinfo.af_inet.tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; if (icmp_param.replyopts.srr) { ip_rt_put(rt); if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0)) - return; + goto out; } if (!icmpv4_xrlim_allow(rt, type, code)) @@ -656,6 +695,8 @@ ende: ip_rt_put(rt); +out: + icmp_xmit_unlock(); } @@ -752,19 +793,22 @@ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ hash = iph->protocol & (MAX_INET_PROTOS - 1); + read_lock(&raw_v4_lock); if ((raw_sk = raw_v4_htable[hash]) != NULL) { - while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, - iph->daddr, skb->dev->ifindex)) != NULL) { + while ((raw_sk = __raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, + iph->daddr, skb->dev->ifindex)) != NULL) { raw_err(raw_sk, skb); raw_sk = raw_sk->next; } } + read_unlock(&raw_v4_lock); /* * This can't change while we are doing it. */ + read_lock(&inet_protocol_lock); ipprot = (struct inet_protocol *) inet_protos[hash]; while(ipprot != NULL) { struct inet_protocol *nextip; @@ -783,6 +827,7 @@ ipprot = nextip; } + read_unlock(&inet_protocol_lock); } @@ -936,89 +981,40 @@ { struct rtable *rt = (struct rtable*)skb->dst; struct net_device *dev = skb->dev; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev; struct in_ifaddr *ifa; u32 mask; - if (!in_dev || !in_dev->ifa_list || - !IN_DEV_LOG_MARTIANS(in_dev) || - !IN_DEV_FORWARD(in_dev) || - len < 4 || - !(rt->rt_flags&RTCF_DIRECTSRC)) + if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) return; - mask = *(u32*)&icmph[1]; - for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa)) - return; + in_dev = in_dev_get(dev); + if (!in_dev) + return; + read_lock(&in_dev->lock); + if (in_dev->ifa_list && + IN_DEV_LOG_MARTIANS(in_dev) && + IN_DEV_FORWARD(in_dev)) { + + mask = *(u32*)&icmph[1]; + for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa)) + break; + } + if (!ifa && net_ratelimit()) { + char b1[16], b2[16]; + printk(KERN_INFO "Wrong address mask %s from %s/%s\n", + in_ntoa2(mask, b1), in_ntoa2(rt->rt_src, b2), dev->name); + } } - if (net_ratelimit()) - printk(KERN_INFO "Wrong address mask %08lX from %08lX/%s\n", - ntohl(mask), ntohl(rt->rt_src), dev->name); + read_unlock(&in_dev->lock); + in_dev_put(in_dev); } static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len) { } -#ifdef CONFIG_IP_TRANSPARENT_PROXY -/* - * Check incoming icmp packets not addressed locally, to check whether - * they relate to a (proxying) socket on our system. - * Needed for transparent proxying. - * - * This code is presently ugly and needs cleanup. - * Probably should add a chkaddr entry to ipprot to call a chk routine - * in udp.c or tcp.c... - */ - -/* This should work with the new hashes now. -DaveM */ -extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); -extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); - -int icmp_chkaddr(struct sk_buff *skb) -{ - struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4); - struct iphdr *iph = (struct iphdr *) (icmph + 1); - void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler; - - if (handler == icmp_unreach || handler == icmp_redirect) { - struct sock *sk; - - switch (iph->protocol) { - case IPPROTO_TCP: - { - struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); - - sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex); - if (!sk || (sk->state == TCP_LISTEN)) - return 0; - /* - * This packet came from us. - */ - return 1; - } - case IPPROTO_UDP: - { - struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); - - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); - if (!sk) return 0; - if (sk->saddr != iph->saddr && inet_addr_type(iph->saddr) != RTN_LOCAL) - return 0; - /* - * This packet may have come from us. - * Assume it did. - */ - return 1; - } - } - } - return 0; -} - -#endif - /* * Deal with incoming ICMP packets. */ @@ -1151,7 +1147,7 @@ if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0) panic("Failed to create the ICMP control socket.\n"); icmp_socket->sk->allocation=GFP_ATOMIC; - icmp_socket->sk->ip_ttl = MAXTTL; + icmp_socket->sk->protinfo.af_inet.ttl = MAXTTL; /* Unhash it so that IP input processing does not even * see it, we do not wish this socket to see incoming diff -u --recursive --new-file v2.3.14/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.3.14/linux/net/ipv4/igmp.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/igmp.c Mon Aug 23 10:01:02 1999 @@ -8,7 +8,7 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.32 1999/06/09 10:10:53 davem Exp $ + * Version: $Id: igmp.c,v 1.34 1999/08/20 11:05:12 davem Exp $ * * Authors: * Alan Cox @@ -97,19 +97,12 @@ #include #endif -/* Big mc list lock for all the devices */ -static rwlock_t ip_mc_lock = RW_LOCK_UNLOCKED; -/* Big mc list semaphore for all the sockets. - We do not refer to this list in IP data paths or from BH, - so that semaphore is OK. - */ -DECLARE_MUTEX(ip_sk_mc_sem); - #define IP_MAX_MEMBERSHIPS 20 #ifdef CONFIG_IP_MULTICAST + /* Parameter names and values are taken from igmp-v2-06 draft */ #define IGMP_V1_Router_Present_Timeout (400*HZ) @@ -129,29 +122,65 @@ #define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0) +#endif + +static void ip_ma_put(struct ip_mc_list *im) +{ + if (atomic_dec_and_test(&im->refcnt)) { + in_dev_put(im->interface); + kfree_s(im, sizeof(*im)); + } +} + +#ifdef CONFIG_IP_MULTICAST + /* * Timer management */ static __inline__ void igmp_stop_timer(struct ip_mc_list *im) { - if (im->tm_running) { - del_timer(&im->timer); - im->tm_running=0; - } + spin_lock_bh(&im->lock); + if (del_timer(&im->timer)) + atomic_dec(&im->refcnt); + im->tm_running=0; + im->reporter = 0; + im->unsolicit_count = 0; + spin_unlock_bh(&im->lock); } static __inline__ void igmp_start_timer(struct ip_mc_list *im, int max_delay) { - int tv; - if (im->tm_running) - return; - tv=net_random() % max_delay; + int tv=net_random() % max_delay; + + spin_lock_bh(&im->lock); + if (!del_timer(&im->timer)) + atomic_inc(&im->refcnt); im->timer.expires=jiffies+tv+2; im->tm_running=1; add_timer(&im->timer); + spin_unlock_bh(&im->lock); +} + +static void igmp_mod_timer(struct ip_mc_list *im, int max_delay) +{ + spin_lock_bh(&im->lock); + im->unsolicit_count = 0; + if (del_timer(&im->timer)) { + if ((long)(im->timer.expires-jiffies) < max_delay) { + add_timer(&im->timer); + im->tm_running=1; + spin_unlock_bh(&im->lock); + return; + } + atomic_dec(&im->refcnt); + } + spin_unlock_bh(&im->lock); + + igmp_start_timer(im, max_delay); } + /* * Send an IGMP report. */ @@ -225,8 +254,6 @@ struct in_device *in_dev = im->interface; int err; - read_lock(&ip_mc_lock); - im->tm_running=0; if (IGMP_V1_SEEN(in_dev)) @@ -236,7 +263,9 @@ /* Failed. Retry later. */ if (err) { - igmp_start_timer(im, IGMP_Unsolicited_Report_Interval); + if (!in_dev->dead) + igmp_start_timer(im, IGMP_Unsolicited_Report_Interval); + ip_ma_put(im); return; } @@ -245,7 +274,7 @@ igmp_start_timer(im, IGMP_Unsolicited_Report_Interval); } im->reporter = 1; - read_unlock(&ip_mc_lock); + ip_ma_put(im); } static void igmp_heard_report(struct in_device *in_dev, u32 group) @@ -254,19 +283,17 @@ /* Timers are only set for non-local groups */ - if (LOCAL_MCAST(group)) + if (group == IGMP_ALL_HOSTS) return; - read_lock(&ip_mc_lock); + read_lock(&in_dev->lock); for (im=in_dev->mc_list; im!=NULL; im=im->next) { if (im->multiaddr == group) { igmp_stop_timer(im); - im->reporter = 0; - im->unsolicit_count = 0; break; } } - read_unlock(&ip_mc_lock); + read_unlock(&in_dev->lock); } static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time, @@ -284,7 +311,7 @@ in_dev->mr_v1_seen = jiffies + IGMP_V1_Router_Present_Timeout; group = 0; } - + /* * - Start the timers in all of our membership records * that the query applies to for the interface on @@ -295,28 +322,30 @@ * - Use the igmp->igmp_code field as the maximum * delay possible */ - read_lock(&ip_mc_lock); + read_lock(&in_dev->lock); for (im=in_dev->mc_list; im!=NULL; im=im->next) { if (group && group != im->multiaddr) continue; - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) continue; - im->unsolicit_count = 0; - if (im->tm_running && (long)(im->timer.expires-jiffies) > max_delay) - igmp_stop_timer(im); - igmp_start_timer(im, max_delay); + igmp_mod_timer(im, max_delay); } - read_unlock(&ip_mc_lock); + read_unlock(&in_dev->lock); } int igmp_rcv(struct sk_buff *skb, unsigned short len) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih = skb->h.igmph; - struct in_device *in_dev = skb->dev->ip_ptr; + struct in_device *in_dev = in_dev_get(skb->dev); + + if (in_dev==NULL) { + kfree_skb(skb); + return 0; + } - if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len) - || in_dev==NULL) { + if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) { + in_dev_put(in_dev); kfree_skb(skb); return 0; } @@ -334,6 +363,7 @@ break; case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 + in_dev_put(in_dev); return pim_rcv_v1(skb, len); #endif case IGMP_DVMRP: @@ -345,6 +375,7 @@ default: NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type)); } + in_dev_put(in_dev); kfree_skb(skb); return 0; } @@ -367,7 +398,7 @@ routine. Something sort of: if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; } --ANK - */ + */ if (arp_mc_map(addr, buf, dev, 0) == 0) dev_mc_add(dev,buf,dev->addr_len,0); } @@ -387,18 +418,23 @@ static void igmp_group_dropped(struct ip_mc_list *im) { +#ifdef CONFIG_IP_MULTICAST + int reporter; +#endif + if (im->loaded) { im->loaded = 0; ip_mc_filter_del(im->interface, im->multiaddr); } #ifdef CONFIG_IP_MULTICAST - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) return; + reporter = im->reporter; igmp_stop_timer(im); - if (im->reporter && !IGMP_V1_SEEN(im->interface)) + if (reporter && !IGMP_V1_SEEN(im->interface)) igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE); #endif } @@ -411,7 +447,7 @@ } #ifdef CONFIG_IP_MULTICAST - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) return; igmp_start_timer(im, IGMP_Initial_Report_Delay); @@ -430,24 +466,27 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr) { - struct ip_mc_list *i, *im; + struct ip_mc_list *im; - im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL); + ASSERT_RTNL(); - write_lock_bh(&ip_mc_lock); - for (i=in_dev->mc_list; i; i=i->next) { - if (i->multiaddr == addr) { - i->users++; - if (im) - kfree(im); + for (im=in_dev->mc_list; im; im=im->next) { + if (im->multiaddr == addr) { + im->users++; goto out; } } + + im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL); if (!im) goto out; + im->users=1; im->interface=in_dev; + in_dev_hold(in_dev); im->multiaddr=addr; + atomic_set(&im->refcnt, 1); + spin_lock_init(&im->lock); #ifdef CONFIG_IP_MULTICAST im->tm_running=0; init_timer(&im->timer); @@ -457,15 +496,14 @@ im->reporter = 0; im->loaded = 0; #endif + write_lock_bh(&in_dev->lock); im->next=in_dev->mc_list; in_dev->mc_list=im; + write_unlock_bh(&in_dev->lock); igmp_group_added(im); - write_unlock_bh(&ip_mc_lock); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev); - return; out: - write_unlock_bh(&ip_mc_lock); return; } @@ -477,25 +515,27 @@ { int err = -ESRCH; struct ip_mc_list *i, **ip; - - write_lock_bh(&ip_mc_lock); + + ASSERT_RTNL(); + for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { if (i->multiaddr==addr) { if (--i->users == 0) { + write_lock_bh(&in_dev->lock); *ip = i->next; + write_unlock_bh(&in_dev->lock); igmp_group_dropped(i); - write_unlock_bh(&ip_mc_lock); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev); - kfree_s(i, sizeof(*i)); + + ip_ma_put(i); return 0; } err = 0; break; } } - write_unlock_bh(&ip_mc_lock); return -ESRCH; } @@ -505,10 +545,10 @@ { struct ip_mc_list *i; - read_lock_bh(&ip_mc_lock); + ASSERT_RTNL(); + for (i=in_dev->mc_list; i; i=i->next) igmp_group_dropped(i); - read_unlock_bh(&ip_mc_lock); ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS); } @@ -519,12 +559,12 @@ { struct ip_mc_list *i; + ASSERT_RTNL(); + ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); - read_lock_bh(&ip_mc_lock); for (i=in_dev->mc_list; i; i=i->next) igmp_group_added(i); - read_unlock_bh(&ip_mc_lock); } /* @@ -535,24 +575,32 @@ { struct ip_mc_list *i; - write_lock_bh(&ip_mc_lock); + ASSERT_RTNL(); + + write_lock_bh(&in_dev->lock); while ((i = in_dev->mc_list) != NULL) { in_dev->mc_list = i->next; + write_unlock_bh(&in_dev->lock); + igmp_group_dropped(i); - kfree_s(i, sizeof(*i)); + ip_ma_put(i); + + write_lock_bh(&in_dev->lock); } - write_unlock_bh(&ip_mc_lock); + write_unlock_bh(&in_dev->lock); } static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) { struct rtable *rt; struct net_device *dev = NULL; + struct in_device *idev = NULL; if (imr->imr_address.s_addr) { dev = ip_dev_find(imr->imr_address.s_addr); if (!dev) return NULL; + __dev_put(dev); } if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) { @@ -561,9 +609,9 @@ } if (dev) { imr->imr_ifindex = dev->ifindex; - return dev->ip_ptr; + idev = __in_dev_get(dev); } - return NULL; + return idev; } /* @@ -586,8 +634,11 @@ if (!imr->imr_ifindex) in_dev = ip_mc_find_dev(imr); - else + else { in_dev = inetdev_by_index(imr->imr_ifindex); + if (in_dev) + __in_dev_put(in_dev); + } if (!in_dev) { iml = NULL; @@ -598,31 +649,28 @@ iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); err = -EADDRINUSE; - down(&ip_sk_mc_sem); - for (i=sk->ip_mc_list; i; i=i->next) { + for (i=sk->protinfo.af_inet.mc_list; i; i=i->next) { if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) { /* New style additions are reference counted */ if (imr->imr_address.s_addr == 0) { i->count++; err = 0; } - goto done_unlock; + goto done; } count++; } err = -ENOBUFS; if (iml == NULL || count >= sysctl_igmp_max_memberships) - goto done_unlock; + goto done; memcpy(&iml->multi, imr, sizeof(*imr)); - iml->next = sk->ip_mc_list; + iml->next = sk->protinfo.af_inet.mc_list; iml->count = 1; - sk->ip_mc_list = iml; + sk->protinfo.af_inet.mc_list = iml; ip_mc_inc_group(in_dev, addr); iml = NULL; err = 0; -done_unlock: - up(&ip_sk_mc_sem); done: rtnl_shunlock(); if (iml) @@ -638,26 +686,30 @@ { struct ip_mc_socklist *iml, **imlp; - down(&ip_sk_mc_sem); - for (imlp=&sk->ip_mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) { + rtnl_lock(); + for (imlp=&sk->protinfo.af_inet.mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) { if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr && iml->multi.imr_address.s_addr==imr->imr_address.s_addr && (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) { struct in_device *in_dev; - if (--iml->count) + if (--iml->count) { + rtnl_unlock(); return 0; + } *imlp = iml->next; - up(&ip_sk_mc_sem); in_dev = inetdev_by_index(iml->multi.imr_ifindex); - if (in_dev) + if (in_dev) { ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr); + in_dev_put(in_dev); + } + rtnl_unlock(); sock_kfree_s(sk, iml, sizeof(*iml)); return 0; } } - up(&ip_sk_mc_sem); + rtnl_unlock(); return -EADDRNOTAVAIL; } @@ -669,36 +721,36 @@ { struct ip_mc_socklist *iml; - down(&ip_sk_mc_sem); - while ((iml=sk->ip_mc_list) != NULL) { + if (sk->protinfo.af_inet.mc_list == NULL) + return; + + rtnl_lock(); + while ((iml=sk->protinfo.af_inet.mc_list) != NULL) { struct in_device *in_dev; - sk->ip_mc_list = iml->next; - up(&ip_sk_mc_sem); + sk->protinfo.af_inet.mc_list = iml->next; - if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) + if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) { ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); + in_dev_put(in_dev); + } sock_kfree_s(sk, iml, sizeof(*iml)); - down(&ip_sk_mc_sem); } - up(&ip_sk_mc_sem); + rtnl_unlock(); } -int ip_check_mc(struct net_device *dev, u32 mc_addr) +int ip_check_mc(struct in_device *in_dev, u32 mc_addr) { - struct in_device *in_dev = dev->ip_ptr; struct ip_mc_list *im; - if (in_dev) { - read_lock(&ip_mc_lock); - for (im=in_dev->mc_list; im; im=im->next) { - if (im->multiaddr == mc_addr) { - read_unlock(&ip_mc_lock); - return 1; - } + read_lock(&in_dev->lock); + for (im=in_dev->mc_list; im; im=im->next) { + if (im->multiaddr == mc_addr) { + read_unlock(&in_dev->lock); + return 1; } - read_unlock(&ip_mc_lock); } + read_unlock(&in_dev->lock); return 0; } @@ -716,9 +768,9 @@ read_lock(&dev_base_lock); for(dev = dev_base; dev; dev = dev->next) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = in_dev_get(dev); char *querier = "NONE"; - + if (in_dev == NULL) continue; @@ -727,7 +779,7 @@ len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n", dev->ifindex, dev->name, dev->mc_count, querier); - read_lock(&ip_mc_lock); + read_lock(&in_dev->lock); for (im = in_dev->mc_list; im; im = im->next) { len+=sprintf(buffer+len, "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n", @@ -741,11 +793,13 @@ begin=pos; } if(pos>offset+length) { - read_unlock(&ip_mc_lock); + read_unlock(&in_dev->lock); + in_dev_put(in_dev); goto done; } } - read_unlock(&ip_mc_lock); + read_unlock(&in_dev->lock); + in_dev_put(in_dev); } done: read_unlock(&dev_base_lock); diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.3.14/linux/net/ipv4/ip_forward.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_forward.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.43 1999/03/21 05:22:37 davem Exp $ + * Version: $Id: ip_forward.c,v 1.45 1999/08/20 11:05:16 davem Exp $ * * Authors: see ip.c * @@ -36,37 +36,41 @@ #include #include #include -#include -#include -#ifdef CONFIG_IP_MASQUERADE -#include -#endif +#include #include #include #include -#ifdef CONFIG_IP_TRANSPARENT_PROXY -/* - * Check the packet against our socket administration to see - * if it is related to a connection on our system. - * Needed for transparent proxying. - */ - -int ip_chksock(struct sk_buff *skb) +static inline int ip_forward_finish(struct sk_buff *skb) { - switch (skb->nh.iph->protocol) { - case IPPROTO_ICMP: - return icmp_chkaddr(skb); - case IPPROTO_TCP: - return tcp_chkaddr(skb); - case IPPROTO_UDP: - return udp_chkaddr(skb); - default: + struct ip_options * opt = &(IPCB(skb)->opt); + + ip_statistics.IpForwDatagrams++; + + if (opt->optlen == 0) { +#ifdef CONFIG_NET_FASTROUTE + struct rtable *rt = (struct rtable*)skb->dst; + + if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) { + struct dst_entry *old_dst; + unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK; + + write_lock_irq(&skb->dev->fastpath_lock); + old_dst = skb->dev->fastpath[h]; + skb->dev->fastpath[h] = dst_clone(&rt->u.dst); + write_unlock_irq(&skb->dev->fastpath_lock); + + dst_release(old_dst); + } +#endif + ip_send(skb); return 0; } -} -#endif + ip_forward_options(skb); + ip_send(skb); + return 0; +} int ip_forward(struct sk_buff *skb) { @@ -75,9 +79,6 @@ struct rtable *rt; /* Route we use */ struct ip_options * opt = &(IPCB(skb)->opt); unsigned short mtu; -#if defined(CONFIG_FIREWALL) || defined(CONFIG_IP_MASQUERADE) - int fw_res = 0; -#endif if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) return 0; @@ -94,20 +95,6 @@ iph = skb->nh.iph; rt = (struct rtable*)skb->dst; -#ifdef CONFIG_CPU_IS_SLOW - if (net_cpu_congestion > 1 && !(iph->tos&IPTOS_RELIABILITY) && - IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) { - if (((xtime.tv_usec&0xF)< 0x1C) - goto drop; - } -#endif - - -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (ip_chksock(skb)) - goto local_pkt; -#endif - if (iph->ttl <= 1) goto too_many_hops; @@ -123,10 +110,6 @@ dev2 = rt->u.dst.dev; mtu = rt->u.dst.pmtu; -#ifdef CONFIG_NET_SECURITY - call_fw_firewall(PF_SECURITY, dev2, NULL, &mtu, NULL); -#endif - /* * We now generate an ICMP HOST REDIRECT giving the route * we calculated. @@ -160,121 +143,8 @@ } #endif -#ifdef CONFIG_IP_MASQUERADE - if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) { - /* - * Check that any ICMP packets are not for a - * masqueraded connection. If so rewrite them - * and skip the firewall checks - */ - if (iph->protocol == IPPROTO_ICMP) { - __u32 maddr; -#ifdef CONFIG_IP_MASQUERADE_ICMP - struct icmphdr *icmph = (struct icmphdr *)((char*)iph + (iph->ihl << 2)); - if ((icmph->type==ICMP_DEST_UNREACH)|| - (icmph->type==ICMP_SOURCE_QUENCH)|| - (icmph->type==ICMP_TIME_EXCEEDED)) - { -#endif - maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE); - fw_res = ip_fw_masq_icmp(&skb, maddr); - if (fw_res < 0) { - kfree_skb(skb); - return -1; - } - - if (fw_res) - /* ICMP matched - skip firewall */ - goto skip_call_fw_firewall; -#ifdef CONFIG_IP_MASQUERADE_ICMP - } -#endif - } - if (rt->rt_flags&RTCF_MASQ) - goto skip_call_fw_firewall; -#endif /* CONFIG_IP_MASQUERADE */ - -#ifdef CONFIG_FIREWALL - fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb); - switch (fw_res) { - case FW_ACCEPT: - case FW_MASQUERADE: - break; - case FW_REJECT: - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - /* fall thru */ - default: - kfree_skb(skb); - return -1; - } -#endif - -#ifdef CONFIG_IP_MASQUERADE - } - -skip_call_fw_firewall: - /* - * If this fragment needs masquerading, make it so... - * (Don't masquerade de-masqueraded fragments) - */ - if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) && - (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) { - u32 maddr; - -#ifdef CONFIG_IP_ROUTE_NAT - maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0; - - if (maddr == 0) -#endif - maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE); - - if (ip_fw_masquerade(&skb, maddr) < 0) { - kfree_skb(skb); - return -1; - } else { - /* - * Masquerader may have changed skb - */ - iph = skb->nh.iph; - opt = &(IPCB(skb)->opt); - } - } -#endif - - -#ifdef CONFIG_FIREWALL - if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) { - /* FW_ACCEPT and FW_MASQUERADE are treated equal: - masquerading is only supported via forward rules */ - if (fw_res == FW_REJECT) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - kfree_skb(skb); - return -1; - } -#endif - - ip_statistics.IpForwDatagrams++; - - if (opt->optlen == 0) { -#ifdef CONFIG_NET_FASTROUTE - if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) { - unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK; - /* Time to switch to functional programming :-) */ - dst_release_irqwait(xchg(&skb->dev->fastpath[h], dst_clone(&rt->u.dst))); - } -#endif - ip_send(skb); - return 0; - } - - ip_forward_options(skb); - ip_send(skb); - return 0; - -#ifdef CONFIG_IP_TRANSPARENT_PROXY -local_pkt: - return ip_local_deliver(skb); -#endif + return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2, + ip_forward_finish); frag_needed: ip_statistics.IpFragFails++; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.3.14/linux/net/ipv4/ip_fragment.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_fragment.c Mon Aug 23 13:44:03 1999 @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.42 1999/06/12 13:11:34 davem Exp $ + * Version: $Id: ip_fragment.c,v 1.44 1999/08/20 11:05:19 davem Exp $ * * Authors: Fred N. van Kempen * Alan Cox @@ -20,6 +20,7 @@ * John McDonald : 0 length frag bug. */ +#include #include #include #include @@ -33,8 +34,7 @@ #include #include #include -#include -#include +#include /* Fragment cache limits. We will commit 256K at one time. Should we * cross that limit we will prune down to 192K. This should cope with @@ -386,6 +386,10 @@ * --rct */ skb->security = qp->fragments->skb->security; + +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = qp->fragments->skb->nf_debug; +#endif /* Done with all fragments. Fixup the new IP header. */ iph = skb->nh.iph; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.3.14/linux/net/ipv4/ip_fw.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_fw.c Wed Dec 31 16:00:00 1969 @@ -1,1731 +0,0 @@ -/* - * This code is heavily based on the code on the old ip_fw.c code; see below for - * copyrights and attributions of the old code. This code is basically GPL. - * - * 15-Aug-1997: Major changes to allow graphs for firewall rules. - * Paul Russell and - * Michael Neuling - * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP). - * Added explicit RETURN from chains. - * Removed TOS mangling (done in ipchains 1.0.1). - * Fixed read & reset bug by reworking proc handling. - * Paul Russell - * 28-Sep-1997: Added packet marking for net sched code. - * Removed fw_via comparisons: all done on device name now, - * similar to changes in ip_fw.c in DaveM's CVS970924 tree. - * Paul Russell - * 2-Nov-1997: Moved types across to __u16, etc. - * Added inverse flags. - * Fixed fragment bug (in args to port_match). - * Changed mark to only one flag (MARKABS). - * 21-Nov-1997: Added ability to test ICMP code. - * 19-Jan-1998: Added wildcard interfaces. - * 6-Feb-1998: Merged 2.0 and 2.1 versions. - * Initialised ip_masq for 2.0.x version. - * Added explicit NETLINK option for 2.1.x version. - * Added packet and byte counters for policy matches. - * 26-Feb-1998: Fixed race conditions, added SMP support. - * 18-Mar-1998: Fix SMP, fix race condition fix. - * 1-May-1998: Remove caching of device pointer. - * 12-May-1998: Allow tiny fragment case for TCP/UDP. - * 15-May-1998: Treat short packets as fragments, don't just block. - * 3-Jan-1999: Fixed serious procfs security hole -- users should never - * be allowed to view the chains! - * Marc Santoro - * 29-Jan-1999: Locally generated bogus IPs dealt with, rather than crash - * during dump_packet. --RR. - */ - -/* - * - * The origina Linux port was done Alan Cox, with changes/fixes from - * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan - * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others. - * - * Copyright from the original FreeBSD version follows: - * - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. */ - - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_IP_MASQUERADE -#include -#endif - -#include -#include -#include - -/* Understanding locking in this code: (thanks to Alan Cox for using - * little words to explain this to me). -- PR - * - * In UP, there can be two packets traversing the chains: - * 1) A packet from the current userspace context - * 2) A packet off the bh handlers (timer or net). - * - * For SMP (kernel v2.1+), multiply this by # CPUs. - * - * [Note that this in not correct for 2.2 - because the socket code always - * uses lock_kernel() to serialize, and bottom halves (timers and net_bhs) - * only run on one CPU at a time. This will probably change for 2.3. - * It is still good to use spinlocks because that avoids the global cli() - * for updating the tables, which is rather costly in SMP kernels -AK] - * - * This means counters and backchains can get corrupted if no precautions - * are taken. - * - * To actually alter a chain on UP, we need only do a cli(), as this will - * stop a bh handler firing, as we are in the current userspace context - * (coming from a setsockopt()). - * - * On SMP, we need a write_lock_irqsave(), which is a simple cli() in - * UP. - * - * For backchains and counters, we use an array, indexed by - * [cpu_number_map[smp_processor_id()]*2 + !in_interrupt()]; the array is of - * size [smp_num_cpus*2]. For v2.0, smp_num_cpus is effectively 1. So, - * confident of uniqueness, we modify counters even though we only - * have a read lock (to read the counters, you need a write lock, - * though). */ - -/* Why I didn't use straight locking... -- PR - * - * The backchains can be separated out of the ip_chains structure, and - * allocated as needed inside ip_fw_check(). - * - * The counters, however, can't. Trying to lock these means blocking - * interrupts every time we want to access them. This would suck HARD - * performance-wise. Not locking them leads to possible corruption, - * made worse on 32-bit machines (counters are 64-bit). */ - -/*#define DEBUG_IP_FIREWALL*/ -/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */ -/*#define DEBUG_IP_FIREWALL_USER*/ -/*#define DEBUG_IP_FIREWALL_LOCKING*/ - -#ifdef CONFIG_IP_FIREWALL_NETLINK -static struct sock *ipfwsk; -#endif - -#ifdef __SMP__ -#define SLOT_NUMBER() (cpu_number_map[smp_processor_id()]*2 + !in_interrupt()) -#else -#define SLOT_NUMBER() (!in_interrupt()) -#endif -#define NUM_SLOTS (smp_num_cpus*2) - -#define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \ - + NUM_SLOTS*sizeof(struct ip_reent)) -#define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \ - + NUM_SLOTS*sizeof(struct ip_counters)) - -#ifdef DEBUG_IP_FIREWALL_LOCKING -static unsigned int fwc_rlocks, fwc_wlocks; -#define FWC_DEBUG_LOCK(d) \ -do { \ - FWC_DONT_HAVE_LOCK(d); \ - d |= (1 << SLOT_NUMBER()); \ -} while (0) - -#define FWC_DEBUG_UNLOCK(d) \ -do { \ - FWC_HAVE_LOCK(d); \ - d &= ~(1 << SLOT_NUMBER()); \ -} while (0) - -#define FWC_DONT_HAVE_LOCK(d) \ -do { \ - if ((d) & (1 << SLOT_NUMBER())) \ - printk("%s:%i: Got lock on %i already!\n", \ - __FILE__, __LINE__, SLOT_NUMBER()); \ -} while(0) - -#define FWC_HAVE_LOCK(d) \ -do { \ - if (!((d) & (1 << SLOT_NUMBER()))) \ - printk("%s:%i:No lock on %i!\n", \ - __FILE__, __LINE__, SLOT_NUMBER()); \ -} while (0) - -#else -#define FWC_DEBUG_LOCK(d) do { } while(0) -#define FWC_DEBUG_UNLOCK(d) do { } while(0) -#define FWC_DONT_HAVE_LOCK(d) do { } while(0) -#define FWC_HAVE_LOCK(d) do { } while(0) -#endif /*DEBUG_IP_FIRWALL_LOCKING*/ - -#define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0) -#define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0) -#define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0) -#define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0) -#define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0) -#define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0) -#define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0) -#define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0) - -struct ip_chain; - -struct ip_counters -{ - __u64 pcnt, bcnt; /* Packet and byte counters */ -}; - -struct ip_fwkernel -{ - struct ip_fw ipfw; - struct ip_fwkernel *next; /* where to go next if current - * rule doesn't match */ - struct ip_chain *branch; /* which branch to jump to if - * current rule matches */ - int simplebranch; /* Use this if branch == NULL */ - struct ip_counters counters[0]; /* Actually several of these */ -}; - -struct ip_reent -{ - struct ip_chain *prevchain; /* Pointer to referencing chain */ - struct ip_fwkernel *prevrule; /* Pointer to referencing rule */ - struct ip_counters counters; -}; - -struct ip_chain -{ - ip_chainlabel label; /* Defines the label for each block */ - struct ip_chain *next; /* Pointer to next block */ - struct ip_fwkernel *chain; /* Pointer to first rule in block */ - __u32 refcount; /* Number of refernces to block */ - int policy; /* Default rule for chain. Only * - * used in built in chains */ - struct ip_reent reent[0]; /* Actually several of these */ -}; - -/* - * Implement IP packet firewall - */ - -#ifdef DEBUG_IP_FIREWALL -#define dprintf(format, args...) printk(format , ## args) -#else -#define dprintf(format, args...) -#endif - -#ifdef DEBUG_IP_FIREWALL_USER -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - -/* Lock around ip_fw_chains linked list structure */ -rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED; - -/* Head of linked list of fw rules */ -static struct ip_chain *ip_fw_chains; - -#define IP_FW_INPUT_CHAIN ip_fw_chains -#define IP_FW_FORWARD_CHAIN (ip_fw_chains->next) -#define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next) - -/* Returns 1 if the port is matched by the range, 0 otherwise */ -extern inline int port_match(__u16 min, __u16 max, __u16 port, - int frag, int invert) -{ - if (frag) /* Fragments fail ANY port test. */ - return (min == 0 && max == 0xFFFF); - else return (port >= min && port <= max) ^ invert; -} - -/* Returns whether matches rule or not. */ -static int ip_rule_match(struct ip_fwkernel *f, - const char *ifname, - struct iphdr *ip, - char tcpsyn, - __u16 src_port, __u16 dst_port, - char isfrag) -{ -#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg)) - /* - * This is a bit simpler as we don't have to walk - * an interface chain as you do in BSD - same logic - * however. - */ - - if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr, - IP_FW_INV_SRCIP) - || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr, - IP_FW_INV_DSTIP)) { - dprintf("Source or dest mismatch.\n"); - - dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, - f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr, - f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : ""); - dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, - f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr, - f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : ""); - return 0; - } - - /* - * Look for a VIA device match - */ - if (f->ipfw.fw_flg & IP_FW_F_WILDIF) { - if (FWINV(strncmp(ifname, f->ipfw.fw_vianame, - strlen(f->ipfw.fw_vianame)) != 0, - IP_FW_INV_VIA)) { - dprintf("Wildcard interface mismatch.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : ""); - return 0; /* Mismatch */ - } - } - else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0, - IP_FW_INV_VIA)) { - dprintf("Interface name does not match.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_VIA - ? " (INV)" : ""); - return 0; /* Mismatch */ - } - - /* - * Ok the chain addresses match. - */ - - /* If we have a fragment rule but the packet is not a fragment - * the we return zero */ - if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) { - dprintf("Fragment rule but not fragment.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : ""); - return 0; - } - - /* Fragment NEVER passes a SYN test, even an inverted one. */ - if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN) - || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) { - dprintf("Rule requires SYN and packet has no SYN.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : ""); - return 0; - } - - if (f->ipfw.fw_proto) { - /* - * Specific firewall - packet's protocol - * must match firewall's. - */ - - if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) { - dprintf("Packet protocol %hi does not match %hi.%s\n", - ip->protocol, f->ipfw.fw_proto, - f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":""); - return 0; - } - - /* For non TCP/UDP/ICMP, port range is max anyway. */ - if (!port_match(f->ipfw.fw_spts[0], - f->ipfw.fw_spts[1], - src_port, isfrag, - !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT)) - || !port_match(f->ipfw.fw_dpts[0], - f->ipfw.fw_dpts[1], - dst_port, isfrag, - !!(f->ipfw.fw_invflg - &IP_FW_INV_DSTPT))) { - dprintf("Port match failed.\n"); - return 0; - } - } - - dprintf("Match succeeded.\n"); - return 1; -} - -static const char *branchname(struct ip_chain *branch,int simplebranch) -{ - if (branch) - return branch->label; - switch (simplebranch) - { - case FW_BLOCK: return IP_FW_LABEL_BLOCK; - case FW_ACCEPT: return IP_FW_LABEL_ACCEPT; - case FW_REJECT: return IP_FW_LABEL_REJECT; - case FW_REDIRECT: return IP_FW_LABEL_REDIRECT; - case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE; - case FW_SKIP: return "-"; - case FW_SKIP+1: return IP_FW_LABEL_RETURN; - default: - return "UNKNOWN"; - } -} - -/* - * VERY ugly piece of code which actually - * makes kernel printf for matching packets... - */ -static void dump_packet(const struct iphdr *ip, - const char *ifname, - struct ip_fwkernel *f, - const ip_chainlabel chainlabel, - __u16 src_port, - __u16 dst_port) -{ - __u32 *opt = (__u32 *) (ip + 1); - int opti; - - if (f) - { - printk(KERN_INFO "Packet log: %s ",chainlabel); - - printk("%s ",branchname(f->branch,f->simplebranch)); - if (f->simplebranch==FW_REDIRECT) - printk("%d ",f->ipfw.fw_redirpt); - } - - printk("%s PROTO=%d %ld.%ld.%ld.%ld:%hu %ld.%ld.%ld.%ld:%hu" - " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", - ifname, ip->protocol, - (ntohl(ip->saddr)>>24)&0xFF, - (ntohl(ip->saddr)>>16)&0xFF, - (ntohl(ip->saddr)>>8)&0xFF, - (ntohl(ip->saddr))&0xFF, - src_port, - (ntohl(ip->daddr)>>24)&0xFF, - (ntohl(ip->daddr)>>16)&0xFF, - (ntohl(ip->daddr)>>8)&0xFF, - (ntohl(ip->daddr))&0xFF, - dst_port, - ntohs(ip->tot_len), ip->tos, ntohs(ip->id), - ntohs(ip->frag_off), ip->ttl); - - for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk("\n"); -} - -/* function for checking chain labels for user space. */ -static int check_label(ip_chainlabel label) -{ - unsigned int i; - /* strlen must be < IP_FW_MAX_LABEL_LENGTH. */ - for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1; i++) - if (label[i] == '\0') return 1; - - return 0; -} - -/* This function returns a pointer to the first chain with a label - * that matches the one given. */ -static struct ip_chain *find_label(ip_chainlabel label) -{ - struct ip_chain *tmp; - FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks); - for (tmp = ip_fw_chains; tmp; tmp = tmp->next) - if (strcmp(tmp->label,label) == 0) - break; - return tmp; -} - -/* This function returns a boolean which when true sets answer to one - of the FW_*. */ -static int find_special(ip_chainlabel label, int *answer) -{ - if (label[0] == '\0') { - *answer = FW_SKIP; /* => pass-through rule */ - return 1; - } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) { - *answer = FW_ACCEPT; - return 1; - } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) { - *answer = FW_BLOCK; - return 1; - } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) { - *answer = FW_REJECT; - return 1; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) { - *answer = FW_REDIRECT; - return 1; -#endif -#ifdef CONFIG_IP_MASQUERADE - } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) { - *answer = FW_MASQUERADE; - return 1; -#endif - } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) { - *answer = FW_SKIP+1; - return 1; - } else { - return 0; - } -} - -/* This function cleans up the prevchain and prevrule. If the verbose - * flag is set then he names of the chains will be printed as it - * cleans up. */ -static void cleanup(struct ip_chain *chain, - const int verbose, - unsigned int slot) -{ - struct ip_chain *tmpchain = chain->reent[slot].prevchain; - if (verbose) - printk(KERN_ERR "Chain backtrace: "); - while (tmpchain) { - if (verbose) - printk("%s<-",chain->label); - chain->reent[slot].prevchain = NULL; - chain = tmpchain; - tmpchain = chain->reent[slot].prevchain; - } - if (verbose) - printk("%s\n",chain->label); -} - -static inline int -ip_fw_domatch(struct ip_fwkernel *f, - struct iphdr *ip, - const char *rif, - const ip_chainlabel label, - struct sk_buff *skb, - unsigned int slot, - __u16 src_port, __u16 dst_port) -{ - f->counters[slot].bcnt+=ntohs(ip->tot_len); - f->counters[slot].pcnt++; - if (f->ipfw.fw_flg & IP_FW_F_PRN) { - dump_packet(ip,rif,f,label,src_port,dst_port); - } - ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor; - -/* This functionality is useless in stock 2.0.x series, but we don't - * discard the mark thing altogether, to avoid breaking ipchains (and, - * more importantly, the ipfwadm wrapper) --PR */ - if (f->ipfw.fw_flg & IP_FW_F_MARKABS) - skb->fwmark = f->ipfw.fw_mark; - else - skb->fwmark+=f->ipfw.fw_mark; -#ifdef CONFIG_IP_FIREWALL_NETLINK - if (f->ipfw.fw_flg & IP_FW_F_NETLINK) { - size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len)) - + sizeof(__u32) + sizeof(skb->fwmark) + IFNAMSIZ; - struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC); - - duprintf("Sending packet out NETLINK (length = %u).\n", - (unsigned int)len); - if (outskb) { - /* Prepend length, mark & interface */ - skb_put(outskb, len); - *((__u32 *)outskb->data) = (__u32)len; - *((__u32 *)(outskb->data+sizeof(__u32))) = skb->fwmark; - strcpy(outskb->data+sizeof(__u32)*2, rif); - memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip, - len-(sizeof(__u32)*2+IFNAMSIZ)); - netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL); - } - else { - if (net_ratelimit()) - printk(KERN_WARNING "ip_fw: packet drop due to " - "netlink failure\n"); - return 0; - } - } -#endif - return 1; -} - -/* - * Returns one of the generic firewall policies, like FW_ACCEPT. - * - * The testing is either false for normal firewall mode or true for - * user checking mode (counters are not updated, TOS & mark not done). - */ -static int -ip_fw_check(struct iphdr *ip, - const char *rif, - __u16 *redirport, - struct ip_chain *chain, - struct sk_buff *skb, - unsigned int slot, - int testing) -{ - struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); - struct udphdr *udp=(struct udphdr *)((__u32 *)ip+ip->ihl); - struct icmphdr *icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl); - __u32 src, dst; - __u16 src_port = 0xFFFF, dst_port = 0xFFFF; - char tcpsyn=0; - __u16 offset; - unsigned char oldtos; - struct ip_fwkernel *f; - int ret = FW_SKIP+2; - - /* We handle fragments by dealing with the first fragment as - * if it was a normal packet. All other fragments are treated - * normally, except that they will NEVER match rules that ask - * things we don't know, ie. tcp syn flag or ports). If the - * rule is also a fragment-specific rule, non-fragments won't - * match it. */ - - offset = ntohs(ip->frag_off) & IP_OFFSET; - - /* - * Don't allow a fragment of TCP 8 bytes in. Nobody - * normal causes this. Its a cracker trying to break - * in by doing a flag overwrite to pass the direction - * checks. - */ - - if (offset == 1 && ip->protocol == IPPROTO_TCP) { - if (!testing && net_ratelimit()) { - printk("Suspect TCP fragment.\n"); - dump_packet(ip,rif,NULL,NULL,0,0); - } - return FW_BLOCK; - } - - /* If we can't investigate ports, treat as fragment. It's - * either a trucated whole packet, or a truncated first - * fragment, or a TCP first fragment of length 8-15, in which - * case the above rule stops reassembly. - */ - if (offset == 0) { - unsigned int size_req; - switch (ip->protocol) { - case IPPROTO_TCP: - /* Don't care about things past flags word */ - size_req = 16; - break; - - case IPPROTO_UDP: - case IPPROTO_ICMP: - size_req = 8; - break; - - default: - size_req = 0; - } - offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req); - } - - src = ip->saddr; - dst = ip->daddr; - oldtos = ip->tos; - - /* - * If we got interface from which packet came - * we can use the address directly. Linux 2.1 now uses address - * chains per device too, but unlike BSD we first check if the - * incoming packet matches a device address and the routing - * table before calling the firewall. - */ - - dprintf("Packet "); - switch(ip->protocol) - { - case IPPROTO_TCP: - dprintf("TCP "); - if (!offset) { - src_port=ntohs(tcp->source); - dst_port=ntohs(tcp->dest); - - /* Connection initilisation can only - * be made when the syn bit is set and - * neither of the ack or reset is - * set. */ - if(tcp->syn && !(tcp->ack || tcp->rst)) - tcpsyn=1; - } - break; - case IPPROTO_UDP: - dprintf("UDP "); - if (!offset) { - src_port=ntohs(udp->source); - dst_port=ntohs(udp->dest); - } - break; - case IPPROTO_ICMP: - if (!offset) { - src_port=(__u16)icmp->type; - dst_port=(__u16)icmp->code; - } - dprintf("ICMP "); - break; - default: - dprintf("p=%d ",ip->protocol); - break; - } -#ifdef DEBUG_IP_FIREWALL - print_ip(ip->saddr); - - if (offset) - dprintf(":fragment (%i) ", ((int)offset)<<2); - else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP - || ip->protocol==IPPROTO_ICMP) - dprintf(":%hu:%hu", src_port, dst_port); - dprintf("\n"); -#endif - - if (!testing) FWC_READ_LOCK(&ip_fw_lock); - else FWC_HAVE_LOCK(fwc_rlocks); - - f = chain->chain; - do { - for (; f; f = f->next) { - if (ip_rule_match(f,rif,ip, - tcpsyn,src_port,dst_port,offset)) { - if (!testing - && !ip_fw_domatch(f, ip, rif, chain->label, - skb, slot, - src_port, dst_port)) { - ret = FW_BLOCK; - goto out; - } - break; - } - } - if (f) { - if (f->branch) { - /* Do sanity check to see if we have - * already set prevchain and if so we - * must be in a loop */ - if (f->branch->reent[slot].prevchain) { - if (!testing) { - printk(KERN_ERR - "IP firewall: " - "Loop detected " - "at `%s'.\n", - f->branch->label); - cleanup(chain, 1, slot); - ret = FW_BLOCK; - } else { - cleanup(chain, 0, slot); - ret = FW_SKIP+1; - } - } - else { - f->branch->reent[slot].prevchain - = chain; - f->branch->reent[slot].prevrule - = f->next; - chain = f->branch; - f = chain->chain; - } - } - else if (f->simplebranch == FW_SKIP) - f = f->next; - else if (f->simplebranch == FW_SKIP+1) { - /* Just like falling off the chain */ - goto fall_off_chain; - } - else { - cleanup(chain, 0, slot); - ret = f->simplebranch; - } - } /* f == NULL */ - else { - fall_off_chain: - if (chain->reent[slot].prevchain) { - struct ip_chain *tmp = chain; - f = chain->reent[slot].prevrule; - chain = chain->reent[slot].prevchain; - tmp->reent[slot].prevchain = NULL; - } - else { - ret = chain->policy; - if (!testing) { - chain->reent[slot].counters.pcnt++; - chain->reent[slot].counters.bcnt - += ntohs(ip->tot_len); - } - } - } - } while (ret == FW_SKIP+2); - - out: - if (!testing) FWC_READ_UNLOCK(&ip_fw_lock); - - /* Recalculate checksum if not going to reject, and TOS changed. */ - if (ip->tos != oldtos - && ret != FW_REJECT && ret != FW_BLOCK - && !testing) - ip_send_check(ip); - -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (ret == FW_REDIRECT && redirport) { - if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) { - /* Wildcard redirection. - * Note that redirport will become - * 0xFFFF for non-TCP/UDP packets. - */ - *redirport = htons(dst_port); - } - } -#endif - -#ifdef DEBUG_ALLOW_ALL - return (testing ? ret : FW_ACCEPT); -#else - return ret; -#endif -} - -/* Must have write lock & interrupts off for any of these */ - -/* This function sets all the byte counters in a chain to zero. The - * input is a pointer to the chain required for zeroing */ -static int zero_fw_chain(struct ip_chain *chainptr) -{ - struct ip_fwkernel *i; - - FWC_HAVE_LOCK(fwc_wlocks); - for (i = chainptr->chain; i; i = i->next) - memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); - return 0; -} - -static int clear_fw_chain(struct ip_chain *chainptr) -{ - struct ip_fwkernel *i= chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - chainptr->chain=NULL; - - while (i) { - struct ip_fwkernel *tmp = i->next; - if (i->branch) - i->branch->refcount--; - kfree(i); - i = tmp; - } - return 0; -} - -static int replace_in_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl, - __u32 position) -{ - struct ip_fwkernel *f = chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - - while (--position && f != NULL) f = f->next; - if (f == NULL) - return EINVAL; - - if (f->branch) f->branch->refcount--; - if (frwl->branch) frwl->branch->refcount++; - - frwl->next = f->next; - memcpy(f,frwl,sizeof(struct ip_fwkernel)); - kfree(frwl); - return 0; -} - -static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule) -{ - struct ip_fwkernel *i; - - FWC_HAVE_LOCK(fwc_wlocks); - /* Special case if no rules already present */ - if (chainptr->chain == NULL) { - - /* If pointer writes are atomic then turning off - * interupts is not necessary. */ - chainptr->chain = rule; - if (rule->branch) rule->branch->refcount++; - return 0; - } - - /* Find the rule before the end of the chain */ - for (i = chainptr->chain; i->next; i = i->next); - i->next = rule; - if (rule->branch) rule->branch->refcount++; - return 0; -} - -/* This function inserts a rule at the position of position in the - * chain refenced by chainptr. If position is 1 then this rule will - * become the new rule one. */ -static int insert_in_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl, - __u32 position) -{ - struct ip_fwkernel *f = chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - /* special case if the position is number 1 */ - if (position == 1) { - frwl->next = chainptr->chain; - if (frwl->branch) frwl->branch->refcount++; - chainptr->chain = frwl; - return 0; - } - position--; - while (--position && f != NULL) f = f->next; - if (f == NULL) - return EINVAL; - if (frwl->branch) frwl->branch->refcount++; - frwl->next = f->next; - - f->next = frwl; - return 0; -} - -/* This function deletes the a rule from a given rulenum and chain. - * With rulenum = 1 is the first rule is deleted. */ - -static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum) -{ - struct ip_fwkernel *i=chainptr->chain,*tmp; - - FWC_HAVE_LOCK(fwc_wlocks); - - if (!chainptr->chain) - return ENOENT; - - /* Need a special case for the first rule */ - if (rulenum == 1) { - /* store temp to allow for freeing up of memory */ - tmp = chainptr->chain; - if (chainptr->chain->branch) chainptr->chain->branch->refcount--; - chainptr->chain = chainptr->chain->next; - kfree(tmp); /* free memory that is now unused */ - } else { - rulenum--; - while (--rulenum && i->next ) i = i->next; - if (!i->next) - return ENOENT; - tmp = i->next; - if (i->next->branch) - i->next->branch->refcount--; - i->next = i->next->next; - kfree(tmp); - } - return 0; -} - - -/* This function deletes the a rule from a given rule and chain. - * The rule that is deleted is the first occursance of that rule. */ -static int del_rule_from_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl) -{ - struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ; - int was_found; - - FWC_HAVE_LOCK(fwc_wlocks); - - /* Sure, we should compare marks, but since the `ipfwadm' - * script uses it for an unholy hack... well, life is easier - * this way. We also mask it out of the flags word. --PR */ - for (ltmp=NULL, was_found=0; - !was_found && ftmp != NULL; - ltmp = ftmp,ftmp = ftmp->next) { - if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr - || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr - || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr - || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr -#if 0 - || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg -#else - || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS) - != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS)) -#endif - || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg - || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto -#if 0 - || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark -#endif - || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt - || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0] - || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1] - || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0] - || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1] - || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) { - duprintf("del_rule_from_chain: mismatch:" - "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u " - "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u " - "mark:%u/%u " - "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu " - "outputsize:%hu-%hu\n", - ftmp->ipfw.fw_src.s_addr, - frwl->ipfw.fw_src.s_addr, - ftmp->ipfw.fw_dst.s_addr, - frwl->ipfw.fw_dst.s_addr, - ftmp->ipfw.fw_smsk.s_addr, - frwl->ipfw.fw_smsk.s_addr, - ftmp->ipfw.fw_dmsk.s_addr, - frwl->ipfw.fw_dmsk.s_addr, - ftmp->ipfw.fw_flg, - frwl->ipfw.fw_flg, - ftmp->ipfw.fw_invflg, - frwl->ipfw.fw_invflg, - ftmp->ipfw.fw_proto, - frwl->ipfw.fw_proto, - ftmp->ipfw.fw_mark, - frwl->ipfw.fw_mark, - ftmp->ipfw.fw_spts[0], - frwl->ipfw.fw_spts[0], - ftmp->ipfw.fw_spts[1], - frwl->ipfw.fw_spts[1], - ftmp->ipfw.fw_dpts[0], - frwl->ipfw.fw_dpts[0], - ftmp->ipfw.fw_dpts[1], - frwl->ipfw.fw_dpts[1], - ftmp->ipfw.fw_outputsize, - frwl->ipfw.fw_outputsize); - continue; - } - - if (strncmp(ftmp->ipfw.fw_vianame, - frwl->ipfw.fw_vianame, - IFNAMSIZ)) { - duprintf("del_rule_from_chain: if mismatch: %s/%s\n", - ftmp->ipfw.fw_vianame, - frwl->ipfw.fw_vianame); - continue; - } - if (ftmp->branch != frwl->branch) { - duprintf("del_rule_from_chain: branch mismatch: " - "%s/%s\n", - ftmp->branch?ftmp->branch->label:"(null)", - frwl->branch?frwl->branch->label:"(null)"); - continue; - } - if (ftmp->branch == NULL - && ftmp->simplebranch != frwl->simplebranch) { - duprintf("del_rule_from_chain: simplebranch mismatch: " - "%i/%i\n", - ftmp->simplebranch, frwl->simplebranch); - continue; - } - was_found = 1; - if (ftmp->branch) - ftmp->branch->refcount--; - if (ltmp) - ltmp->next = ftmp->next; - else - chainptr->chain = ftmp->next; - kfree(ftmp); - break; - } - - if (was_found) - return 0; - else { - duprintf("del_rule_from_chain: no matching rule found\n"); - return EINVAL; - } -} - -/* This function takes the label of a chain and deletes the first - * chain with that name. No special cases required for the built in - * chains as they have their refcount initilised to 1 so that they are - * never deleted. */ -static int del_chain(ip_chainlabel label) -{ - struct ip_chain *tmp,*tmp2; - - FWC_HAVE_LOCK(fwc_wlocks); - /* Corner case: return EBUSY not ENOENT for first elem ("input") */ - if (strcmp(label, ip_fw_chains->label) == 0) - return EBUSY; - - for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) - if(strcmp(tmp->next->label,label) == 0) - break; - - tmp2 = tmp->next; - if (!tmp2) - return ENOENT; - - if (tmp2->refcount) - return EBUSY; - - if (tmp2->chain) - return ENOTEMPTY; - - tmp->next = tmp2->next; - kfree(tmp2); - return 0; -} - -/* This is a function to initilise a chain. Built in rules start with - * refcount = 1 so that they cannot be deleted. User defined rules - * start with refcount = 0 so they can be deleted. */ -static struct ip_chain *ip_init_chain(ip_chainlabel name, - __u32 ref, - int policy) -{ - unsigned int i; - struct ip_chain *label - = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL); - if (label == NULL) - panic("Can't kmalloc for firewall chains.\n"); - strcpy(label->label,name); - label->next = NULL; - label->chain = NULL; - label->refcount = ref; - label->policy = policy; - for (i = 0; i < smp_num_cpus*2; i++) { - label->reent[i].counters.pcnt = label->reent[i].counters.bcnt - = 0; - label->reent[i].prevchain = NULL; - label->reent[i].prevrule = NULL; - } - - return label; -} - -/* This is a function for reating a new chain. The chains is not - * created if a chain of the same name already exists */ -static int create_chain(ip_chainlabel label) -{ - struct ip_chain *tmp; - - if (!check_label(label)) - return EINVAL; - - FWC_HAVE_LOCK(fwc_wlocks); - for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) - if (strcmp(tmp->label,label) == 0) - return EEXIST; - - if (strcmp(tmp->label,label) == 0) - return EEXIST; - - tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is - * zero since this is a - * user defined chain * - * and therefore can be - * deleted */ - return 0; -} - -/* This function simply changes the policy on one of the built in - * chains. checking must be done before this is call to ensure that - * chainptr is pointing to one of the three possible chains */ -static int change_policy(struct ip_chain *chainptr, int policy) -{ - FWC_HAVE_LOCK(fwc_wlocks); - chainptr->policy = policy; - return 0; -} - -/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also - * performs some checks in the structure. */ -static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno) -{ - struct ip_fwkernel *fwkern; - - if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) { - duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n", - fwuser->ipfw.fw_flg); - *errno = EINVAL; - return NULL; - } - -#ifdef DEBUG_IP_FIREWALL_USER - /* These are sanity checks that don't really matter. - * We can get rid of these once testing is complete. - */ - if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) - && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) - || fwuser->ipfw.fw_proto != IPPROTO_TCP)) { - duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n"); - *errno = EINVAL; - return NULL; - } - - if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0 - && fwuser->ipfw.fw_redirpt != 0) { - duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n"); - *errno = EINVAL; - return NULL; - } - - if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG) - && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)) - || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) - && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) { - duprintf("convert_ipfw: Can't have INV flag if flag unset!\n"); - *errno = EINVAL; - return NULL; - } - - if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT) - && fwuser->ipfw.fw_spts[0] == 0 - && fwuser->ipfw.fw_spts[1] == 0xFFFF) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT) - && fwuser->ipfw.fw_dpts[0] == 0 - && fwuser->ipfw.fw_dpts[1] == 0xFFFF) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA) - && (fwuser->ipfw.fw_vianame)[0] == '\0') - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP) - && fwuser->ipfw.fw_smsk.s_addr == 0) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP) - && fwuser->ipfw.fw_dmsk.s_addr == 0)) { - duprintf("convert_ipfw: INV flag makes rule unmatchable!\n"); - *errno = EINVAL; - return NULL; - } - - if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG) - && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG) - && (fwuser->ipfw.fw_spts[0] != 0 - || fwuser->ipfw.fw_spts[1] != 0xFFFF - || fwuser->ipfw.fw_dpts[0] != 0 - || fwuser->ipfw.fw_dpts[1] != 0xFFFF - || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) { - duprintf("convert_ipfw: Can't test ports or SYN with frag!\n"); - *errno = EINVAL; - return NULL; - } -#endif - - if ((fwuser->ipfw.fw_spts[0] != 0 - || fwuser->ipfw.fw_spts[1] != 0xFFFF - || fwuser->ipfw.fw_dpts[0] != 0 - || fwuser->ipfw.fw_dpts[1] != 0xFFFF) - && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) - || (fwuser->ipfw.fw_proto != IPPROTO_TCP - && fwuser->ipfw.fw_proto != IPPROTO_UDP - && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) { - duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n"); - *errno = EINVAL; - return NULL; - } - - fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL); - if (!fwkern) { - duprintf("convert_ipfw: kmalloc failed!\n"); - *errno = ENOMEM; - return NULL; - } - memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw)); - - if (!find_special(fwuser->label, &fwkern->simplebranch)) { - fwkern->branch = find_label(fwuser->label); - if (!fwkern->branch) { - duprintf("convert_ipfw: chain doesn't exist `%s'.\n", - fwuser->label); - kfree(fwkern); - *errno = ENOENT; - return NULL; - } else if (fwkern->branch == IP_FW_INPUT_CHAIN - || fwkern->branch == IP_FW_FORWARD_CHAIN - || fwkern->branch == IP_FW_OUTPUT_CHAIN) { - duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n", - fwuser->label); - kfree(fwkern); - *errno = ENOENT; - return NULL; - } - } else - fwkern->branch = NULL; - memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); - - /* Handle empty vianame by making it a wildcard */ - if ((fwkern->ipfw.fw_vianame)[0] == '\0') - fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF; - - fwkern->next = NULL; - return fwkern; -} - -int ip_fw_ctl(int cmd, void *m, int len) -{ - int ret; - struct ip_chain *chain; - unsigned long flags; - - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - switch (cmd) { - case IP_FW_FLUSH: - if (len != sizeof(ip_chainlabel) || !check_label(m)) - ret = EINVAL; - else if ((chain = find_label(m)) == NULL) - ret = ENOENT; - else ret = clear_fw_chain(chain); - break; - - case IP_FW_ZERO: - if (len != sizeof(ip_chainlabel) || !check_label(m)) - ret = EINVAL; - else if ((chain = find_label(m)) == NULL) - ret = ENOENT; - else ret = zero_fw_chain(chain); - break; - - case IP_FW_CHECK: { - struct ip_fwtest *new = m; - struct iphdr *ip; - - /* Don't need write lock. */ - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - - if (len != sizeof(struct ip_fwtest) || !check_label(m)) - return EINVAL; - - /* Need readlock to do find_label */ - FWC_READ_LOCK(&ip_fw_lock); - - if ((chain = find_label(new->fwt_label)) == NULL) - ret = ENOENT; - else { - ip = &(new->fwt_packet.fwp_iph); - - if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) { - duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n", - ip->ihl, - sizeof(struct iphdr) / sizeof(int)); - ret = EINVAL; - } - else { - ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame, - NULL, chain, - NULL, SLOT_NUMBER(), 1); - switch (ret) { - case FW_ACCEPT: - ret = 0; break; - case FW_REDIRECT: - ret = ECONNABORTED; break; - case FW_MASQUERADE: - ret = ECONNRESET; break; - case FW_REJECT: - ret = ECONNREFUSED; break; - /* Hack to help diag; these only get - returned when testing. */ - case FW_SKIP+1: - ret = ELOOP; break; - case FW_SKIP: - ret = ENFILE; break; - default: /* FW_BLOCK */ - ret = ETIMEDOUT; break; - } - } - } - FWC_READ_UNLOCK(&ip_fw_lock); - return ret; - } - - case IP_FW_MASQ_TIMEOUTS: { -#ifdef CONFIG_IP_MASQUERADE - ret = ip_fw_masq_timeouts(m, len); -#else - ret = EINVAL; -#endif - } - break; - - case IP_FW_REPLACE: { - struct ip_fwkernel *ip_fwkern; - struct ip_fwnew *new = m; - - if (len != sizeof(struct ip_fwnew) - || !check_label(new->fwn_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwn_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) - != NULL) - ret = replace_in_chain(chain, ip_fwkern, - new->fwn_rulenum); - } - break; - - case IP_FW_APPEND: { - struct ip_fwchange *new = m; - struct ip_fwkernel *ip_fwkern; - - if (len != sizeof(struct ip_fwchange) - || !check_label(new->fwc_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwc_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) - != NULL) - ret = append_to_chain(chain, ip_fwkern); - } - break; - - case IP_FW_INSERT: { - struct ip_fwkernel *ip_fwkern; - struct ip_fwnew *new = m; - - if (len != sizeof(struct ip_fwnew) - || !check_label(new->fwn_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwn_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) - != NULL) - ret = insert_in_chain(chain, ip_fwkern, - new->fwn_rulenum); - } - break; - - case IP_FW_DELETE: { - struct ip_fwchange *new = m; - struct ip_fwkernel *ip_fwkern; - - if (len != sizeof(struct ip_fwchange) - || !check_label(new->fwc_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwc_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) - != NULL) - ret = del_rule_from_chain(chain, ip_fwkern); - } - break; - - case IP_FW_DELETE_NUM: { - struct ip_fwdelnum *new = m; - - if (len != sizeof(struct ip_fwdelnum) - || !check_label(new->fwd_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwd_label)) == NULL) - ret = ENOENT; - else ret = del_num_from_chain(chain, new->fwd_rulenum); - } - break; - - case IP_FW_CREATECHAIN: { - if (len != sizeof(ip_chainlabel)) { - duprintf("create_chain: bad size %i\n", len); - ret = EINVAL; - } - else ret = create_chain(m); - } - break; - - case IP_FW_DELETECHAIN: { - if (len != sizeof(ip_chainlabel)) { - duprintf("delete_chain: bad size %i\n", len); - ret = EINVAL; - } - else ret = del_chain(m); - } - break; - - case IP_FW_POLICY: { - struct ip_fwpolicy *new = m; - - if (len != sizeof(struct ip_fwpolicy) - || !check_label(new->fwp_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwp_label)) == NULL) - ret = ENOENT; - else if (chain != IP_FW_INPUT_CHAIN - && chain != IP_FW_FORWARD_CHAIN - && chain != IP_FW_OUTPUT_CHAIN) { - duprintf("change_policy: can't change policy on user" - " defined chain.\n"); - ret = EINVAL; - } - else { - int pol = FW_SKIP; - find_special(new->fwp_policy, &pol); - - switch(pol) { - case FW_MASQUERADE: - if (chain != IP_FW_FORWARD_CHAIN) { - ret = EINVAL; - break; - } - /* Fall thru... */ - case FW_BLOCK: - case FW_ACCEPT: - case FW_REJECT: - ret = change_policy(chain, pol); - break; - default: - duprintf("change_policy: bad policy `%s'\n", - new->fwp_policy); - ret = EINVAL; - } - } - break; - - } - default: - duprintf("ip_fw_ctl: unknown request %d\n",cmd); - ret = EINVAL; - } - - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - return ret; -} - -/* Returns bytes used - doesn't NUL terminate */ -static int dump_rule(char *buffer, - const char *chainlabel, - const struct ip_fwkernel *rule) -{ - int len; - unsigned int i; - __u64 packets = 0, bytes = 0; - - FWC_HAVE_LOCK(fwc_wlocks); - for (i = 0; i < NUM_SLOTS; i++) { - packets += rule->counters[i].pcnt; - bytes += rule->counters[i].bcnt; - } - - len=sprintf(buffer, - "%9s " /* Chain name */ - "%08lX/%08lX->%08lX/%08lX " /* Source & Destination IPs */ - "%.16s " /* Interface */ - "%X %X " /* fw_flg and fw_invflg fields */ - "%u " /* Protocol */ - "%-9u %-9u %-9u %-9u " /* Packet & byte counters */ - "%u-%u %u-%u " /* Source & Dest port ranges */ - "A%02X X%02X " /* TOS and and xor masks */ - "%08X " /* Redirection port */ - "%u " /* fw_mark field */ - "%u " /* output size */ - "%9s\n", /* Target */ - chainlabel, - ntohl(rule->ipfw.fw_src.s_addr), - ntohl(rule->ipfw.fw_smsk.s_addr), - ntohl(rule->ipfw.fw_dst.s_addr), - ntohl(rule->ipfw.fw_dmsk.s_addr), - (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-", - rule->ipfw.fw_flg, - rule->ipfw.fw_invflg, - rule->ipfw.fw_proto, - (__u32)(packets >> 32), (__u32)packets, - (__u32)(bytes >> 32), (__u32)bytes, - rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1], - rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1], - rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor, - rule->ipfw.fw_redirpt, - rule->ipfw.fw_mark, - rule->ipfw.fw_outputsize, - branchname(rule->branch,rule->simplebranch)); - - duprintf("dump_rule: %i bytes done.\n", len); - return len; -} - -/* File offset is actually in records, not bytes. */ -static int ip_chain_procinfo(char *buffer, char **start, - off_t offset, int length, int reset) -{ - struct ip_chain *i; - struct ip_fwkernel *j = ip_fw_chains->chain; - unsigned long flags; - int len = 0; - int last_len = 0; - off_t upto = 0; - - duprintf("Offset starts at %lu\n", offset); - duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains); - - /* Need a write lock to lock out ``readers'' which update counters. */ - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - for (i = ip_fw_chains; i; i = i->next) { - for (j = i->chain; j; j = j->next) { - if (upto == offset) break; - duprintf("Skipping rule in chain `%s'\n", - i->label); - upto++; - } - if (upto == offset) break; - } - - /* Don't init j first time, or once i = NULL */ - for (; i; (void)((i = i->next) && (j = i->chain))) { - duprintf("Dumping chain `%s'\n", i->label); - for (; j; j = j->next, upto++, last_len = len) - { - len += dump_rule(buffer+len, i->label, j); - if (len > length) { - duprintf("Dumped to %i (past %i). " - "Moving back to %i.\n", - len, length, last_len); - len = last_len; - goto outside; - } - else if (reset) - memset(j->counters, 0, - sizeof(struct ip_counters)*NUM_SLOTS); - } - } -outside: - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - buffer[len] = '\0'; - - duprintf("ip_chain_procinfo: Length = %i (of %i). Offset = %li.\n", - len, length, upto); - /* `start' hack - see fs/proc/generic.c line ~165 */ - *start=(char *)((unsigned int)upto-offset); - return len; -} - -static int ip_chain_name_procinfo(char *buffer, char **start, - off_t offset, int length, int reset) -{ - struct ip_chain *i; - int len = 0,last_len = 0; - off_t pos = 0,begin = 0; - unsigned long flags; - - /* Need a write lock to lock out ``readers'' which update counters. */ - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - for (i = ip_fw_chains; i; i = i->next) - { - unsigned int j; - __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0; - - for (j = 0; j < NUM_SLOTS; j++) { - packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF; - packetsHi += ((i->reent[j].counters.pcnt >> 32) - & 0xFFFFFFFF); - bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF; - bytesHi += ((i->reent[j].counters.bcnt >> 32) - & 0xFFFFFFFF); - } - - /* print the label and the policy */ - len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n", - i->label,branchname(NULL, i->policy),i->refcount, - packetsHi, packetsLo, bytesHi, bytesLo); - pos=begin+len; - if(posoffset+length) { - len = last_len; - break; - } - - last_len = len; - } - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - - *start = buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -/* - * Interface to the generic firewall chains. - */ -int ipfw_input_check(struct firewall_ops *this, int pf, struct net_device *dev, - void *phdr, void *arg, struct sk_buff **pskb) -{ - return ip_fw_check(phdr, dev->name, - arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0); -} - -int ipfw_output_check(struct firewall_ops *this, int pf, struct net_device *dev, - void *phdr, void *arg, struct sk_buff **pskb) -{ - /* Locally generated bogus packets by root. . */ - if (((struct iphdr *)phdr)->ihl * 4 < sizeof(struct iphdr) - || (*pskb)->len < sizeof(struct iphdr)) - return FW_ACCEPT; - return ip_fw_check(phdr, dev->name, - arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0); -} - -int ipfw_forward_check(struct firewall_ops *this, int pf, struct net_device *dev, - void *phdr, void *arg, struct sk_buff **pskb) -{ - return ip_fw_check(phdr, dev->name, - arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0); -} - -struct firewall_ops ipfw_ops= -{ - NULL, - ipfw_forward_check, - ipfw_input_check, - ipfw_output_check, - PF_INET, - 0 /* We don't even allow a fall through so we are last */ -}; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_net_ipfwchains_chain = { - PROC_NET_IPFW_CHAINS, sizeof(IP_FW_PROC_CHAINS)-1, - IP_FW_PROC_CHAINS, S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, ip_chain_procinfo -}; - -static struct proc_dir_entry proc_net_ipfwchains_chainnames = { - PROC_NET_IPFW_CHAIN_NAMES, sizeof(IP_FW_PROC_CHAIN_NAMES)-1, - IP_FW_PROC_CHAIN_NAMES, S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, ip_chain_name_procinfo -}; - -#endif - -__initfunc(void ip_fw_init(void)) -{ -#ifdef DEBUG_IP_FIRWALL_LOCKING - fwc_wlocks = fwc_rlocks = 0; -#endif - - IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT); - IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT); - IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT); - - if(register_firewall(PF_INET,&ipfw_ops)<0) - panic("Unable to register IP firewall.\n"); - -#ifdef CONFIG_PROC_FS - proc_net_register(&proc_net_ipfwchains_chain); - proc_net_register(&proc_net_ipfwchains_chainnames); -#endif - -#ifdef CONFIG_IP_FIREWALL_NETLINK - ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL); - if (ipfwsk == NULL) - panic("ip_fw_init: cannot initialize netlink\n"); -#endif -#if defined(DEBUG_IP_FIREWALL) || defined(DEBUG_IP_FIREWALL_USER) - printk("Firewall graphs enabled! Untested kernel coming thru. \n"); -#endif -} diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c --- v2.3.14/linux/net/ipv4/ip_gre.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/ip_gre.c Mon Aug 23 10:01:02 1999 @@ -153,6 +153,8 @@ #define tunnels_l (tunnels[1]) #define tunnels_wc (tunnels[0]) +static rwlock_t ipgre_lock = RW_LOCK_UNLOCKED; + /* Given src, dst and key, find approriate for input tunnel. */ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) @@ -212,8 +214,9 @@ struct ip_tunnel **tp = ipgre_bucket(t); t->next = *tp; - wmb(); + write_lock_bh(&ipgre_lock); *tp = t; + write_unlock_bh(&ipgre_lock); } static void ipgre_tunnel_unlink(struct ip_tunnel *t) @@ -222,8 +225,9 @@ for (tp = ipgre_bucket(t); *tp; tp = &(*tp)->next) { if (t == *tp) { + write_lock_bh(&ipgre_lock); *tp = t->next; - synchronize_bh(); + write_unlock_bh(&ipgre_lock); break; } } @@ -266,12 +270,13 @@ nt->dev = dev; dev->name = nt->parms.name; dev->init = ipgre_tunnel_init; + dev->new_style = 1; memcpy(&nt->parms, parms, sizeof(*parms)); if (dev->name[0] == 0) { int i; for (i=1; i<100; i++) { sprintf(dev->name, "gre%d", i); - if (dev_get(dev->name) == NULL) + if (__dev_get_by_name(dev->name) == NULL) break; } if (i==100) @@ -281,6 +286,7 @@ if (register_netdevice(dev) < 0) goto failed; + dev_hold(dev); ipgre_tunnel_link(nt); /* Do not decrement MOD_USE_COUNT here. */ return nt; @@ -291,16 +297,19 @@ return NULL; } -static void ipgre_tunnel_destroy(struct net_device *dev) +static void ipgre_tunnel_destructor(struct net_device *dev) { - ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv); - if (dev != &ipgre_fb_tunnel_dev) { - kfree(dev); MOD_DEC_USE_COUNT; } } +static void ipgre_tunnel_uninit(struct net_device *dev) +{ + ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv); + dev_put(dev); +} + void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len) { @@ -370,18 +379,21 @@ break; } + read_lock(&ipgre_lock); t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) - return; + goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) - return; + goto out; if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO) t->err_count++; else t->err_count = 1; t->err_time = jiffies; +out: + read_unlock(&ipgre_lock); return; #else struct iphdr *iph = (struct iphdr*)dp; @@ -533,7 +545,7 @@ - We do not support routing headers. */ if (flags&(GRE_VERSION|GRE_ROUTING)) - goto drop; + goto drop_nolock; if (flags&GRE_CSUM) { csum = ip_compute_csum(h, len); @@ -549,6 +561,7 @@ } } + read_lock(&ipgre_lock); if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { skb->mac.raw = skb->nh.raw; skb->nh.raw = skb_pull(skb, h + offset - skb->data); @@ -587,11 +600,14 @@ dst_release(skb->dst); skb->dst = NULL; netif_rx(skb); + read_unlock(&ipgre_lock); return(0); } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); drop: + read_unlock(&ipgre_lock); +drop_nolock: kfree_skb(skb); return(0); } @@ -890,7 +906,6 @@ err = -EINVAL; break; } - start_bh_atomic(); ipgre_tunnel_unlink(t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; @@ -899,7 +914,6 @@ memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); ipgre_tunnel_link(t); - end_bh_atomic(); netdev_state_change(dev); } } @@ -1032,12 +1046,12 @@ } dev = rt->u.dst.dev; ip_rt_put(rt); - if (dev->ip_ptr == NULL) { + if (__in_dev_get(dev) == NULL) { MOD_DEC_USE_COUNT; return -EADDRNOTAVAIL; } t->mlink = dev->ifindex; - ip_mc_inc_group(dev->ip_ptr, t->parms.iph.daddr); + ip_mc_inc_group(__in_dev_get(dev), t->parms.iph.daddr); } return 0; } @@ -1046,9 +1060,11 @@ { struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; if (MULTICAST(t->parms.iph.daddr) && t->mlink) { - dev = dev_get_by_index(t->mlink); - if (dev && dev->ip_ptr) - ip_mc_dec_group(dev->ip_ptr, t->parms.iph.daddr); + struct in_device *in_dev = inetdev_by_index(t->mlink); + if (in_dev) { + ip_mc_dec_group(in_dev, t->parms.iph.daddr); + in_dev_put(in_dev); + } } MOD_DEC_USE_COUNT; return 0; @@ -1060,7 +1076,8 @@ { struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; - dev->destructor = ipgre_tunnel_destroy; + dev->uninit = ipgre_tunnel_uninit; + dev->destructor = ipgre_tunnel_destructor; dev->hard_start_xmit = ipgre_tunnel_xmit; dev->get_stats = ipgre_tunnel_get_stats; dev->do_ioctl = ipgre_tunnel_ioctl; @@ -1116,7 +1133,7 @@ } if (!tdev && tunnel->parms.link) - tdev = dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(tunnel->parms.link); if (tdev) { hlen = tdev->hard_header_len; @@ -1170,6 +1187,7 @@ iph->ihl = 5; tunnel->hlen = sizeof(struct iphdr) + 4; + dev_hold(dev); tunnels_wc[0] = &ipgre_fb_tunnel; return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.3.14/linux/net/ipv4/ip_input.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_input.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.40 1999/06/09 10:10:55 davem Exp $ + * Version: $Id: ip_input.c,v 1.42 1999/08/20 11:05:27 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -140,11 +140,7 @@ #include #include #include -#include -#ifdef CONFIG_IP_MASQUERADE -#include -#endif -#include +#include #include #include @@ -154,10 +150,6 @@ struct ip_mib ip_statistics={2,IPDEFTTL,}; /* Forwarding=No, Default TTL=64 */ -#if defined(CONFIG_IP_TRANSPARENT_PROXY) && !defined(CONFIG_IP_ALWAYS_DEFRAG) -#define CONFIG_IP_ALWAYS_DEFRAG 1 -#endif - /* * Process Router Attention IP option */ @@ -167,13 +159,16 @@ u8 protocol = skb->nh.iph->protocol; struct sock *last = NULL; + read_lock(&ip_ra_lock); for (ra = ip_ra_chain; ra; ra = ra->next) { struct sock *sk = ra->sk; if (sk && sk->num == protocol) { if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); - if (skb == NULL) + if (skb == NULL) { + read_unlock(&ip_ra_lock); return 1; + } } if (last) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); @@ -186,8 +181,10 @@ if (last) { raw_rcv(last, skb); + read_unlock(&ip_ra_lock); return 1; } + read_unlock(&ip_ra_lock); return 0; } @@ -214,59 +211,19 @@ return ret; } -extern struct sock *raw_v4_input(struct sk_buff *, struct iphdr *, int); - -/* - * Deliver IP Packets to the higher protocol layers. - */ -int ip_local_deliver(struct sk_buff *skb) +static inline int ip_local_deliver_finish(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; -#ifndef CONFIG_IP_ALWAYS_DEFRAG - /* - * Reassemble IP fragments. - */ - - if (iph->frag_off & htons(IP_MF|IP_OFFSET)) { - skb = ip_defrag(skb); - if (!skb) - return 0; - iph = skb->nh.iph; +#ifdef CONFIG_NETFILTER_DEBUG + nf_debug_ip_local_deliver(skb); +#endif /*CONFIG_NETFILTER_DEBUG*/ + + /* Free rx_dev before enqueueing to sockets */ + if (skb->rx_dev) { + dev_put(skb->rx_dev); + skb->rx_dev = NULL; } -#endif - -#ifdef CONFIG_IP_MASQUERADE - /* Do we need to de-masquerade this packet? */ - if((IPCB(skb)->flags&IPSKB_MASQUERADED)) { - /* Some masq modules can re-inject packets if - * bad configured. - */ - printk(KERN_DEBUG "ip_input(): demasq recursion detected. " - "Check masq modules configuration\n"); - kfree_skb(skb); - return 0; - } else { - int ret = ip_fw_demasquerade(&skb); - - if (ret < 0) { - kfree_skb(skb); - return 0; - } - if (ret) { - iph = skb->nh.iph; - IPCB(skb)->flags |= IPSKB_MASQUERADED; - dst_release(skb->dst); - skb->dst = NULL; - if (ip_route_input(skb, iph->daddr, iph->saddr, - iph->tos, skb->dev)) { - kfree_skb(skb); - return 0; - } - return skb->dst->input(skb); - } - } -#endif /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->nh.raw + iph->ihl*4; @@ -284,19 +241,26 @@ if(raw_sk != NULL) raw_sk = raw_v4_input(skb, iph, hash); + read_lock(&inet_protocol_lock); ipprot = (struct inet_protocol *) inet_protos[hash]; flag = 0; if(ipprot != NULL) { if(raw_sk == NULL && ipprot->next == NULL && ipprot->protocol == iph->protocol) { + int ret; + /* Fast path... */ - return ipprot->handler(skb, (ntohs(iph->tot_len) - - (iph->ihl * 4))); + ret = ipprot->handler(skb, (ntohs(iph->tot_len) - + (iph->ihl * 4))); + + read_unlock(&inet_protocol_lock); + return ret; } else { flag = ip_run_ipprot(skb, iph, ipprot, (raw_sk != NULL)); } - } + } + read_unlock(&inet_protocol_lock); /* All protocols checked. * If this packet was a broadcast, we may *not* reply to it, since that @@ -305,6 +269,7 @@ */ if(raw_sk != NULL) { /* Shift to last raw user */ raw_rcv(raw_sk, skb); + sock_put(raw_sk); } else if (!flag) { /* Free and report errors */ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); kfree_skb(skb); @@ -315,75 +280,31 @@ } /* - * Main IP Receive routine. + * Deliver IP Packets to the higher protocol layers. */ -int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +int ip_local_deliver(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; -#ifdef CONFIG_FIREWALL - int fwres; - u16 rport; -#endif /* CONFIG_FIREWALL */ - - /* When the interface is in promisc. mode, drop all the crap - * that it receives, do not try to analyse it. - */ - if (skb->pkt_type == PACKET_OTHERHOST) - goto drop; - - ip_statistics.IpInReceives++; /* - * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. - * - * Is the datagram acceptable? - * - * 1. Length at least the size of an ip header - * 2. Version of 4 - * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] - * 4. Doesn't have a bogus length + * Reassemble IP fragments. */ - if (skb->len < sizeof(struct iphdr)) - goto inhdr_error; - if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0) - goto inhdr_error; - - { - __u32 len = ntohs(iph->tot_len); - if (skb->len < len) - goto inhdr_error; - - /* Our transport medium may have padded the buffer out. Now we know it - * is IP we can trim to the true length of the frame. - * Note this now means skb->len holds ntohs(iph->tot_len). - */ - __skb_trim(skb, len); - } - -#ifdef CONFIG_IP_ALWAYS_DEFRAG - /* Won't send ICMP reply, since skb->dst == NULL. --RR */ if (iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); if (!skb) return 0; iph = skb->nh.iph; - ip_send_check(iph); } -#endif -#ifdef CONFIG_FIREWALL - /* - * See if the firewall wants to dispose of the packet. - * - * We can't do ICMP reply or local delivery before routing, - * so we delay those decisions until after route. --RR - */ - fwres = call_in_firewall(PF_INET, dev, iph, &rport, &skb); - if (fwres < FW_ACCEPT && fwres != FW_REJECT) - goto drop; - iph = skb->nh.iph; -#endif /* CONFIG_FIREWALL */ + return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, + ip_local_deliver_finish); +} + +static inline int ip_rcv_finish(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct iphdr *iph = skb->nh.iph; /* * Initialise the virtual path cache for the packet. It describes @@ -428,36 +349,85 @@ opt = &(IPCB(skb)->opt); if (opt->srr) { - struct in_device *in_dev = dev->ip_ptr; - if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev)) { - if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "source route option %d.%d.%d.%d -> %d.%d.%d.%d\n", - NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); - goto drop; + struct in_device *in_dev = in_dev_get(dev); + if (in_dev) { + if (!IN_DEV_SOURCE_ROUTE(in_dev)) { + if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) + printk(KERN_INFO "source route option %d.%d.%d.%d -> %d.%d.%d.%d\n", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + in_dev_put(in_dev); + goto drop; + } + in_dev_put(in_dev); } if (ip_options_rcv_srr(skb)) goto drop; } } -#ifdef CONFIG_FIREWALL -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (fwres == FW_REDIRECT && (IPCB(skb)->redirport = rport) != 0) - return ip_local_deliver(skb); -#endif /* CONFIG_IP_TRANSPARENT_PROXY */ + return skb->dst->input(skb); - if (fwres == FW_REJECT) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); +inhdr_error: + ip_statistics.IpInHdrErrors++; +drop: + kfree_skb(skb); + return(0); +} + +/* + * Main IP Receive routine. + */ +int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +{ + struct iphdr *iph = skb->nh.iph; + + /* When the interface is in promisc. mode, drop all the crap + * that it receives, do not try to analyse it. + */ + if (skb->pkt_type == PACKET_OTHERHOST) goto drop; + + ip_statistics.IpInReceives++; + + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + goto out; + + /* + * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. + * + * Is the datagram acceptable? + * + * 1. Length at least the size of an ip header + * 2. Version of 4 + * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] + * 4. Doesn't have a bogus length + */ + + if (skb->len < sizeof(struct iphdr)) + goto inhdr_error; + if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0) + goto inhdr_error; + + { + __u32 len = ntohs(iph->tot_len); + if (skb->len < len) + goto inhdr_error; + + /* Our transport medium may have padded the buffer out. Now we know it + * is IP we can trim to the true length of the frame. + * Note this now means skb->len holds ntohs(iph->tot_len). + */ + __skb_trim(skb, len); } -#endif /* CONFIG_FIREWALL */ - return skb->dst->input(skb); + return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, + ip_rcv_finish); inhdr_error: ip_statistics.IpInHdrErrors++; drop: kfree_skb(skb); +out: return(0); } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v2.3.14/linux/net/ipv4/ip_masq.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/ip_masq.c Wed Dec 31 16:00:00 1969 @@ -1,2453 +0,0 @@ -/* - * - * Masquerading functionality - * - * Copyright (c) 1994 Pauline Middelink - * - * $Id: ip_masq.c,v 1.35 1999/06/29 12:35:46 davem Exp $ - * - * - * See ip_fw.c for original log - * - * Fixes: - * Juan Jose Ciarlante : Modularized application masquerading (see ip_masq_app.c) - * Juan Jose Ciarlante : New struct ip_masq_seq that holds output/input delta seq. - * Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport - * Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted - * Juan Jose Ciarlante : Added NO_ADDR status flag. - * Richard Lynch : Added IP Autoforward - * Nigel Metheringham : Added ICMP handling for demasquerade - * Nigel Metheringham : Checksum checking of masqueraded data - * Nigel Metheringham : Better handling of timeouts of TCP conns - * Delian Delchev : Added support for ICMP requests and replys - * Nigel Metheringham : ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional - * Juan Jose Ciarlante : re-assign maddr if no packet received from outside - * Juan Jose Ciarlante : ported to 2.1 tree - * Juan Jose Ciarlante : reworked control connections - * Steven Clarke : Added Port Forwarding - * Juan Jose Ciarlante : Just ONE ip_masq_new (!) - * Juan Jose Ciarlante : IP masq modules support - * Juan Jose Ciarlante : don't go into search loop if mport specified - * Juan Jose Ciarlante : locking - * Steven Clarke : IP_MASQ_S_xx state design - * Juan Jose Ciarlante : IP_MASQ_S state implementation - * Juan Jose Ciarlante : xx_get() clears timer, _put() inserts it - * Juan Jose Ciarlante : create /proc/net/ip_masq/ - * Juan Jose Ciarlante : reworked checksums (save payload csum if possible) - * Juan Jose Ciarlante : added missing ip_fw_masquerade checksum - * Juan Jose Ciarlante : csum savings - * Juan Jose Ciarlante : added user-space tunnel creation/del, etc - * Juan Jose Ciarlante : (last) moved to ip_masq_user runtime module - * Juan Jose Ciarlante : user timeout handling again - * Juan Jose Ciarlante : make new modules support optional - * Juan Jose Ciarlante : u-space context => locks reworked - * Juan Jose Ciarlante : fixed stupid SMP locking bug - * Juan Jose Ciarlante : fixed "tap"ing in demasq path by copy-on-w - * Juan Jose Ciarlante : make masq_proto_doff() robust against fake sized/corrupted packets - * Kai Bankett : do not toss other IP protos in proto_doff() - * Dan Kegel : pointed correct NAT behavior for UDP streams - * - */ - -#include -#include -#ifdef CONFIG_KMOD -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_IP_MASQUERADE_MOD -#include -#endif - -#include -#include -#include - -int sysctl_ip_masq_debug = 0; - -/* - * Exported wrapper - */ -int ip_masq_get_debug_level(void) -{ - return sysctl_ip_masq_debug; -} - -struct ip_masq_hook *ip_masq_user_hook = NULL; - -/* - * Timeout table[state] - */ -/* static int masq_timeout_table[IP_MASQ_S_LAST+1] = { */ -static struct ip_masq_timeout_table masq_timeout_table = { - ATOMIC_INIT(0), /* refcnt */ - 0, /* scale */ - { - 30*60*HZ, /* IP_MASQ_S_NONE, */ - 15*60*HZ, /* IP_MASQ_S_ESTABLISHED, */ - 2*60*HZ, /* IP_MASQ_S_SYN_SENT, */ - 1*60*HZ, /* IP_MASQ_S_SYN_RECV, */ - 2*60*HZ, /* IP_MASQ_S_FIN_WAIT, */ - 2*60*HZ, /* IP_MASQ_S_TIME_WAIT, */ - 10*HZ, /* IP_MASQ_S_CLOSE, */ - 60*HZ, /* IP_MASQ_S_CLOSE_WAIT, */ - 30*HZ, /* IP_MASQ_S_LAST_ACK, */ - 2*60*HZ, /* IP_MASQ_S_LISTEN, */ - 5*60*HZ, /* IP_MASQ_S_UDP, */ - 1*60*HZ, /* IP_MASQ_S_ICMP, */ - 2*HZ,/* IP_MASQ_S_LAST */ - }, /* timeout */ -}; - -#define MASQUERADE_EXPIRE_RETRY masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT] - -static const char * state_name_table[IP_MASQ_S_LAST+1] = { - "NONE", /* IP_MASQ_S_NONE, */ - "ESTABLISHED", /* IP_MASQ_S_ESTABLISHED, */ - "SYN_SENT", /* IP_MASQ_S_SYN_SENT, */ - "SYN_RECV", /* IP_MASQ_S_SYN_RECV, */ - "FIN_WAIT", /* IP_MASQ_S_FIN_WAIT, */ - "TIME_WAIT", /* IP_MASQ_S_TIME_WAIT, */ - "CLOSE", /* IP_MASQ_S_CLOSE, */ - "CLOSE_WAIT", /* IP_MASQ_S_CLOSE_WAIT, */ - "LAST_ACK", /* IP_MASQ_S_LAST_ACK, */ - "LISTEN", /* IP_MASQ_S_LISTEN, */ - "UDP", /* IP_MASQ_S_UDP, */ - "ICMP", /* IP_MASQ_S_ICMP, */ - "BUG!", /* IP_MASQ_S_LAST */ -}; - -#define mNO IP_MASQ_S_NONE -#define mES IP_MASQ_S_ESTABLISHED -#define mSS IP_MASQ_S_SYN_SENT -#define mSR IP_MASQ_S_SYN_RECV -#define mFW IP_MASQ_S_FIN_WAIT -#define mTW IP_MASQ_S_TIME_WAIT -#define mCL IP_MASQ_S_CLOSE -#define mCW IP_MASQ_S_CLOSE_WAIT -#define mLA IP_MASQ_S_LAST_ACK -#define mLI IP_MASQ_S_LISTEN - -struct masq_tcp_states_t { - int next_state[IP_MASQ_S_LAST]; /* should be _LAST_TCP */ -}; - -const char * ip_masq_state_name(int state) -{ - if (state >= IP_MASQ_S_LAST) - return "ERR!"; - return state_name_table[state]; -} - -struct masq_tcp_states_t masq_tcp_states [] = { -/* INPUT */ -/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */ -/*syn*/ {{mSR, mES, mES, mSR, mSR, mSR, mSR, mSR, mSR, mSR }}, -/*fin*/ {{mCL, mCW, mSS, mTW, mTW, mTW, mCL, mCW, mLA, mLI }}, -/*ack*/ {{mCL, mES, mSS, mSR, mFW, mTW, mCL, mCW, mCL, mLI }}, -/*rst*/ {{mCL, mCL, mCL, mSR, mCL, mCL, mCL, mCL, mLA, mLI }}, - -/* OUTPUT */ -/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */ -/*syn*/ {{mSS, mES, mSS, mES, mSS, mSS, mSS, mSS, mSS, mLI }}, -/*fin*/ {{mTW, mFW, mSS, mTW, mFW, mTW, mCL, mTW, mLA, mLI }}, -/*ack*/ {{mES, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mES }}, -/*rst*/ {{mCL, mCL, mSS, mCL, mCL, mTW, mCL, mCL, mCL, mCL }}, -}; - -static __inline__ int masq_tcp_state_idx(struct tcphdr *th, int output) -{ - /* - * [0-3]: input states, [4-7]: output. - */ - if (output) - output=4; - - if (th->rst) - return output+3; - if (th->syn) - return output+0; - if (th->fin) - return output+1; - if (th->ack) - return output+2; - return -1; -} - - - -static int masq_set_state_timeout(struct ip_masq *ms, int state) -{ - struct ip_masq_timeout_table *mstim = ms->timeout_table; - int scale; - - /* - * Use default timeout table if no specific for this entry - */ - if (!mstim) - mstim = &masq_timeout_table; - - ms->timeout = mstim->timeout[ms->state=state]; - scale = mstim->scale; - - if (scale<0) - ms->timeout >>= -scale; - else if (scale > 0) - ms->timeout <<= scale; - - return state; -} - -static int masq_tcp_state(struct ip_masq *ms, int output, struct tcphdr *th) -{ - int state_idx; - int new_state = IP_MASQ_S_CLOSE; - - if ((state_idx = masq_tcp_state_idx(th, output)) < 0) { - IP_MASQ_DEBUG(1, "masq_state_idx(%d)=%d!!!\n", - output, state_idx); - goto tcp_state_out; - } - - new_state = masq_tcp_states[state_idx].next_state[ms->state]; - -tcp_state_out: - if (new_state!=ms->state) - IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n", - masq_proto_name(ms->protocol), - output? "output" : "input ", - th->syn? 'S' : '.', - th->fin? 'F' : '.', - th->ack? 'A' : '.', - th->rst? 'R' : '.', - ntohl(ms->saddr), ntohs(ms->sport), - ntohl(ms->daddr), ntohs(ms->dport), - ip_masq_state_name(ms->state), - ip_masq_state_name(new_state)); - return masq_set_state_timeout(ms, new_state); -} - - -/* - * Handle state transitions - */ -static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp) -{ - switch (iph->protocol) { - case IPPROTO_ICMP: - return masq_set_state_timeout(ms, IP_MASQ_S_ICMP); - case IPPROTO_UDP: - return masq_set_state_timeout(ms, IP_MASQ_S_UDP); - case IPPROTO_TCP: - return masq_tcp_state(ms, output, tp); - } - return -1; -} - -/* - * Set LISTEN timeout. (ip_masq_put will setup timer) - */ -int ip_masq_listen(struct ip_masq *ms) -{ - masq_set_state_timeout(ms, IP_MASQ_S_LISTEN); - return ms->timeout; -} - -/* - * Dynamic address rewriting - */ -extern int sysctl_ip_dynaddr; - -/* - * Lookup lock - */ -rwlock_t __ip_masq_lock = RW_LOCK_UNLOCKED; - -/* - * Implement IP packet masquerading - */ - -/* - * Converts an ICMP reply code into the equivalent request code - */ -static __inline__ const __u8 icmp_type_request(__u8 type) -{ - switch (type) - { - case ICMP_ECHOREPLY: return ICMP_ECHO; break; - case ICMP_TIMESTAMPREPLY: return ICMP_TIMESTAMP; break; - case ICMP_INFO_REPLY: return ICMP_INFO_REQUEST; break; - case ICMP_ADDRESSREPLY: return ICMP_ADDRESS; break; - default: return (255); break; - } -} - -/* - * Helper macros - attempt to make code clearer! - */ - -/* ID used in ICMP lookups */ -#define icmp_id(icmph) ((icmph->un).echo.id) -/* (port) hash value using in ICMP lookups for requests */ -#define icmp_hv_req(icmph) ((__u16)(icmph->code+(__u16)(icmph->type<<8))) -/* (port) hash value using in ICMP lookups for replies */ -#define icmp_hv_rep(icmph) ((__u16)(icmph->code+(__u16)(icmp_type_request(icmph->type)<<8))) - -/* - * Last masq_port number in use. - * Will cycle in MASQ_PORT boundaries. - */ -static __u16 masq_port = PORT_MASQ_BEGIN; -static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED; - -/* - * free ports counters (UDP & TCP) - * - * Their value is _less_ or _equal_ to actual free ports: - * same masq port, diff masq addr (firewall iface address) allocated - * entries are accounted but their actually don't eat a more than 1 port. - * - * Greater values could lower MASQ_EXPIRATION setting as a way to - * manage 'masq_entries resource'. - * - * By default we will reuse masq.port iff (output) connection - * (5-upla) if not duplicated. - * This may break midentd and others ... - */ - -#ifdef CONFIG_IP_MASQ_NREUSE -#define PORT_MASQ_MUL 1 -#else -#define PORT_MASQ_MUL 10 -#endif - -/* - * At the moment, hardcore in sync with masq_proto_num - */ -atomic_t ip_masq_free_ports[3] = { - ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */ - ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */ - ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */ -}; - -/* - * Counts entries that have been requested with specific mport. - * Used for incoming packets to "relax" input rule (port in MASQ range). - */ -atomic_t mport_count = ATOMIC_INIT(0); - -EXPORT_SYMBOL(ip_masq_get_debug_level); -EXPORT_SYMBOL(ip_masq_new); -EXPORT_SYMBOL(ip_masq_listen); -EXPORT_SYMBOL(ip_masq_free_ports); -EXPORT_SYMBOL(ip_masq_out_get); -EXPORT_SYMBOL(ip_masq_in_get); -EXPORT_SYMBOL(ip_masq_put); -EXPORT_SYMBOL(ip_masq_control_add); -EXPORT_SYMBOL(ip_masq_control_del); -EXPORT_SYMBOL(ip_masq_control_get); -EXPORT_SYMBOL(ip_masq_user_hook); -EXPORT_SYMBOL(ip_masq_m_tab); -EXPORT_SYMBOL(ip_masq_state_name); -EXPORT_SYMBOL(ip_masq_select_addr); -EXPORT_SYMBOL(__ip_masq_lock); - -/* - * 2 ip_masq hash tables: for input and output pkts lookups. - */ - -struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE]; -struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE]; - -/* - * timeouts - */ - -#if 000 /* FIXED timeout handling */ -static struct ip_fw_masq ip_masq_dummy = { - MASQUERADE_EXPIRE_TCP, - MASQUERADE_EXPIRE_TCP_FIN, - MASQUERADE_EXPIRE_UDP -}; - -EXPORT_SYMBOL(ip_masq_expire); -struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy; -#endif - -/* - * These flags enable non-strict d{addr,port} checks - * Given that both (in/out) lookup tables are hashed - * by m{addr,port} and s{addr,port} this is quite easy - */ - -#define MASQ_DADDR_PASS (IP_MASQ_F_NO_DADDR|IP_MASQ_F_DLOOSE) -#define MASQ_DPORT_PASS (IP_MASQ_F_NO_DPORT|IP_MASQ_F_DLOOSE) - -/* - * By default enable dest loose semantics - */ -#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1 - - -/* - * Set masq expiration (deletion) and adds timer, - * if timeout==0 cancel expiration. - * Warning: it does not check/delete previous timer! - */ - -static void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout) -{ - if (tout) { - ms->timer.expires = jiffies+tout; - add_timer(&ms->timer); - } else { - del_timer(&ms->timer); - } -} - - -/* - * Returns hash value - */ - -static __inline__ unsigned -ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port) -{ - return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1); -} - -/* - * Hashes ip_masq by its proto,addrs,ports. - * should be called with locked tables. - * returns bool success. - */ - -static int ip_masq_hash(struct ip_masq *ms) -{ - unsigned hash; - - if (ms->flags & IP_MASQ_F_HASHED) { - IP_MASQ_ERR( "ip_masq_hash(): request for already hashed, called from %p\n", - __builtin_return_address(0)); - return 0; - } - /* - * Hash by proto,m{addr,port} - */ - hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport); - ms->m_link = ip_masq_m_tab[hash]; - atomic_inc(&ms->refcnt); - ip_masq_m_tab[hash] = ms; - - /* - * Hash by proto,s{addr,port} - */ - hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport); - ms->s_link = ip_masq_s_tab[hash]; - atomic_inc(&ms->refcnt); - ip_masq_s_tab[hash] = ms; - - - ms->flags |= IP_MASQ_F_HASHED; - return 1; -} - -/* - * UNhashes ip_masq from ip_masq_[ms]_tables. - * should be called with locked tables. - * returns bool success. - */ - -static int ip_masq_unhash(struct ip_masq *ms) -{ - unsigned hash; - struct ip_masq ** ms_p; - if (!(ms->flags & IP_MASQ_F_HASHED)) { - IP_MASQ_ERR( "ip_masq_unhash(): request for unhash flagged, called from %p\n", - __builtin_return_address(0)); - return 0; - } - /* - * UNhash by m{addr,port} - */ - hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport); - for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link) - if (ms == (*ms_p)) { - atomic_dec(&ms->refcnt); - *ms_p = ms->m_link; - break; - } - - /* - * UNhash by s{addr,port} - */ - hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport); - for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link) - if (ms == (*ms_p)) { - atomic_dec(&ms->refcnt); - *ms_p = ms->s_link; - break; - } - - ms->flags &= ~IP_MASQ_F_HASHED; - return 1; -} - -/* - * Returns ip_masq associated with supplied parameters, either - * broken out of the ip/tcp headers or directly supplied for those - * pathological protocols with address/port in the data stream - * (ftp, irc). addresses and ports are in network order. - * called for pkts coming from OUTside-to-INside the firewall. - * - * s_addr, s_port: pkt source address (foreign host) - * d_addr, d_port: pkt dest address (firewall) - * - * NB. Cannot check destination address, just for the incoming port. - * reason: archie.doc.ac.uk has 6 interfaces, you send to - * phoenix and get a reply from any other interface(==dst)! - * - * [Only for UDP] - AC - * - * Caller must lock tables - */ - -static struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) -{ - unsigned hash; - struct ip_masq *ms = NULL; - - hash = ip_masq_hash_key(protocol, d_addr, d_port); - - for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { - if (protocol==ms->protocol && - (d_addr==ms->maddr && d_port==ms->mport) && - (s_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) && - (s_port==ms->dport || ms->flags & MASQ_DPORT_PASS) - ) { - IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n", - protocol, - s_addr, - s_port, - d_addr, - d_port); - atomic_inc(&ms->refcnt); - goto out; - } - } - IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX fail\n", - protocol, - s_addr, - s_port, - d_addr, - d_port); - -out: - return ms; -} - -/* - * Returns ip_masq associated with supplied parameters, either - * broken out of the ip/tcp headers or directly supplied for those - * pathological protocols with address/port in the data stream - * (ftp, irc). addresses and ports are in network order. - * called for pkts coming from inside-to-OUTside the firewall. - * - * Normally we know the source address and port but for some protocols - * (e.g. ftp PASV) we do not know the source port initially. Alas the - * hash is keyed on source port so if the first lookup fails then try again - * with a zero port, this time only looking at entries marked "no source - * port". - * - * Caller must lock tables - */ - -static struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) -{ - unsigned hash; - struct ip_masq *ms = NULL; - - /* - * Check for "full" addressed entries - */ - hash = ip_masq_hash_key(protocol, s_addr, s_port); - - for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) { - if (protocol == ms->protocol && - s_addr == ms->saddr && s_port == ms->sport && - (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) && - (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS) - ) { - IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX OK\n", - protocol, - s_addr, - s_port, - d_addr, - d_port); - - atomic_inc(&ms->refcnt); - goto out; - } - - } - - /* - * Check for NO_SPORT entries - */ - hash = ip_masq_hash_key(protocol, s_addr, 0); - for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) { - if (ms->flags & IP_MASQ_F_NO_SPORT && - protocol == ms->protocol && - s_addr == ms->saddr && - (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) && - (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS) - ) { - IP_MASQ_DEBUG(2, "lk/out2 %d %08X:%04hX->%08X:%04hX OK\n", - protocol, - s_addr, - s_port, - d_addr, - d_port); - - atomic_inc(&ms->refcnt); - goto out; - } - } - IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX fail\n", - protocol, - s_addr, - s_port, - d_addr, - d_port); - -out: - return ms; -} - -#ifdef CONFIG_IP_MASQ_NREUSE -/* - * Returns ip_masq for given proto,m_addr,m_port. - * called by allocation routine to find an unused m_port. - * - * Caller must lock tables - */ - -static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port) -{ - unsigned hash; - struct ip_masq *ms = NULL; - - hash = ip_masq_hash_key(protocol, m_addr, m_port); - - for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { - if ( protocol==ms->protocol && - (m_addr==ms->maddr && m_port==ms->mport)) { - atomic_inc(&ms->refcnt); - goto out; - } - } - -out: - return ms; -} -#endif - -struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) -{ - struct ip_masq *ms; - - read_lock(&__ip_masq_lock); - ms = __ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port); - read_unlock(&__ip_masq_lock); - - if (ms) - __ip_masq_set_expire(ms, 0); - return ms; -} - -struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) -{ - struct ip_masq *ms; - - read_lock(&__ip_masq_lock); - ms = __ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port); - read_unlock(&__ip_masq_lock); - - if (ms) - __ip_masq_set_expire(ms, 0); - return ms; -} - -static __inline__ void __ip_masq_put(struct ip_masq *ms) -{ - atomic_dec(&ms->refcnt); -} - -void ip_masq_put(struct ip_masq *ms) -{ - /* - * Decrement refcnt - */ - __ip_masq_put(ms); - - /* - * if refcnt==2 (2 hashes) - */ - if (atomic_read(&ms->refcnt)==2) { - __ip_masq_set_expire(ms, ms->timeout); - } else { - IP_MASQ_DEBUG(0, "did not set timer with refcnt=%d, called from %p\n", - atomic_read(&ms->refcnt), - __builtin_return_address(0)); - } -} - -static void masq_expire(unsigned long data) -{ - struct ip_masq *ms = (struct ip_masq *)data; - ms->timeout = MASQUERADE_EXPIRE_RETRY; - - /* - * hey, I'm using it - */ - atomic_inc(&ms->refcnt); - - IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n", - masq_proto_name(ms->protocol), - ntohl(ms->saddr),ntohs(ms->sport)); - - write_lock(&__ip_masq_lock); - -#if 0000 - /* - * Already locked, do bounce ... - */ - if (ip_masq_nlocks(&__ip_masq_lock) != 1) { - goto masq_expire_later; - } - -#endif - /* - * do I control anybody? - */ - if (atomic_read(&ms->n_control)) - goto masq_expire_later; - - /* - * does anybody controls me? - */ - - if (ms->control) - ip_masq_control_del(ms); - - if (ip_masq_unhash(ms)) { - if (ms->flags&IP_MASQ_F_MPORT) { - atomic_dec(&mport_count); - } else { - atomic_inc(ip_masq_free_ports + masq_proto_num(ms->protocol)); - } - ip_masq_unbind_app(ms); - } - - /* - * refcnt==1 implies I'm the only one referrer - */ - if (atomic_read(&ms->refcnt) == 1) { - kfree_s(ms,sizeof(*ms)); - MOD_DEC_USE_COUNT; - goto masq_expire_out; - } - -masq_expire_later: - IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X masq.refcnt-1=%d masq.n_control=%d\n", - masq_proto_name(ms->protocol), - ntohl(ms->saddr), ntohs(ms->sport), - ntohl(ms->daddr), ntohs(ms->dport), - atomic_read(&ms->refcnt)-1, - atomic_read(&ms->n_control)); - - ip_masq_put(ms); - -masq_expire_out: - write_unlock(&__ip_masq_lock); -} - -static __u16 get_next_mport(void) -{ - __u16 mport; - - spin_lock_irq(&masq_port_lock); - /* - * Try the next available port number - */ - mport = htons(masq_port++); - if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN; - - spin_unlock_irq(&masq_port_lock); - return mport; -} - -/* - * Create a new masquerade list entry, also allocate an - * unused mport, keeping the portnumber between the - * given boundaries MASQ_BEGIN and MASQ_END. - * - * Be careful, it can be called from u-space - */ - -struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags) -{ - struct ip_masq *ms, *mst; - int ports_tried; - atomic_t *free_ports_p = NULL; - static int n_fails = 0; - int prio; - - - if (masq_proto_num(proto)!=-1 && mport == 0) { - free_ports_p = ip_masq_free_ports + masq_proto_num(proto); - - if (atomic_read(free_ports_p) == 0) { - if (++n_fails < 5) - IP_MASQ_ERR( "ip_masq_new(proto=%s): no free ports.\n", - masq_proto_name(proto)); - return NULL; - } - } - - prio = (mflags&IP_MASQ_F_USER) ? GFP_KERNEL : GFP_ATOMIC; - - ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), prio); - if (ms == NULL) { - if (++n_fails < 5) - IP_MASQ_ERR("ip_masq_new(proto=%s): no memory available.\n", - masq_proto_name(proto)); - return NULL; - } - MOD_INC_USE_COUNT; - memset(ms, 0, sizeof(*ms)); - init_timer(&ms->timer); - ms->timer.data = (unsigned long)ms; - ms->timer.function = masq_expire; - ms->protocol = proto; - ms->saddr = saddr; - ms->sport = sport; - ms->daddr = daddr; - ms->dport = dport; - ms->flags = mflags; - ms->app_data = NULL; - ms->control = NULL; - - atomic_set(&ms->n_control,0); - atomic_set(&ms->refcnt,0); - - if (proto == IPPROTO_UDP && !mport) -#ifdef CONFIG_IP_MASQ_LOOSE_DEFAULT - /* - * Flag this tunnel as "dest loose" - * - */ - ms->flags |= IP_MASQ_F_DLOOSE; -#else - ms->flags |= IP_MASQ_F_NO_DADDR; -#endif - - - /* get masq address from rif */ - ms->maddr = maddr; - - /* - * This flag will allow masq. addr (ms->maddr) - * to follow forwarding interface address. - */ - ms->flags |= IP_MASQ_F_NO_REPLY; - - /* - * We want a specific mport. Be careful. - */ - if (masq_proto_num(proto) == -1 || mport) { - ms->mport = mport; - - /* - * Check 5-upla uniqueness - */ - if (mflags & IP_MASQ_F_USER) - write_lock_bh(&__ip_masq_lock); - else - write_lock(&__ip_masq_lock); - - mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport); - if (mst==NULL) { - ms->flags |= IP_MASQ_F_MPORT; - - atomic_inc(&mport_count); - ip_masq_hash(ms); - - if (mflags & IP_MASQ_F_USER) - write_unlock_bh(&__ip_masq_lock); - else - write_unlock(&__ip_masq_lock); - - ip_masq_bind_app(ms); - atomic_inc(&ms->refcnt); - masq_set_state_timeout(ms, IP_MASQ_S_NONE); - return ms; - } - if (mflags & IP_MASQ_F_USER) - write_unlock_bh(&__ip_masq_lock); - else - write_unlock(&__ip_masq_lock); - - __ip_masq_put(mst); - - IP_MASQ_ERR( "Already used connection: %s, %d.%d.%d.%d:%d => %d.%d.%d.%d:%d, called from %p\n", - masq_proto_name(proto), - NIPQUAD(maddr), ntohs(mport), - NIPQUAD(daddr), ntohs(dport), - __builtin_return_address(0)); - - - goto mport_nono; - } - - - for (ports_tried = 0; - (atomic_read(free_ports_p) && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN))); - ports_tried++){ - - mport = ms->mport = get_next_mport(); - /* - * lookup to find out if this connection is used. - */ - - if (mflags & IP_MASQ_F_USER) - write_lock_bh(&__ip_masq_lock); - else - write_lock(&__ip_masq_lock); - -#ifdef CONFIG_IP_MASQ_NREUSE - mst = __ip_masq_getbym(proto, maddr, mport); -#else - mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport); -#endif - if (mst == NULL) { - - if (atomic_read(free_ports_p) == 0) { - if (mflags & IP_MASQ_F_USER) - write_unlock_bh(&__ip_masq_lock); - else - write_unlock(&__ip_masq_lock); - - break; - } - atomic_dec(free_ports_p); - ip_masq_hash(ms); - - if (mflags & IP_MASQ_F_USER) - write_unlock_bh(&__ip_masq_lock); - else - write_unlock(&__ip_masq_lock); - - ip_masq_bind_app(ms); - n_fails = 0; - atomic_inc(&ms->refcnt); - masq_set_state_timeout(ms, IP_MASQ_S_NONE); - return ms; - } - if (mflags & IP_MASQ_F_USER) - write_unlock_bh(&__ip_masq_lock); - else - write_unlock(&__ip_masq_lock); - - __ip_masq_put(mst); - } - - if (++n_fails < 5) - IP_MASQ_ERR( "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n", - masq_proto_name(ms->protocol), - atomic_read(free_ports_p)); -mport_nono: - kfree_s(ms, sizeof(*ms)); - - MOD_DEC_USE_COUNT; - return NULL; -} - -/* - * Get transport protocol data offset, check against size - * return: - * 0 if other IP proto - * -1 if error - */ -static __inline__ int proto_doff(unsigned proto, char *th, unsigned size) -{ - int ret = -1; - switch (proto) { - case IPPROTO_ICMP: - if (size >= sizeof(struct icmphdr)) - ret = sizeof(struct icmphdr); - break; - case IPPROTO_UDP: - if (size >= sizeof(struct udphdr)) - ret = sizeof(struct udphdr); - break; - case IPPROTO_TCP: - /* - * Is this case, this check _also_ avoids - * touching an invalid pointer if - * size is invalid - */ - if (size >= sizeof(struct tcphdr)) { - ret = ((struct tcphdr*)th)->doff << 2; - if (ret > size) { - ret = -1 ; - } - } - - break; - default: - /* Other proto: nothing to say, by now :) */ - ret = 0; - } - if (ret < 0) - IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n", - proto, size); - return ret; -} - -int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - union ip_masq_tphdr h; - struct ip_masq *ms; - int size; - - /* - * doff holds transport protocol data offset - * csum holds its checksum - * csum_ok says if csum is valid - */ - int doff = 0; - int csum = 0; - int csum_ok = 0; - - /* - * We can only masquerade protocols with ports... and hack some ICMPs - */ - - h.raw = (char*) iph + iph->ihl * 4; - size = ntohs(iph->tot_len) - (iph->ihl * 4); - - - doff = proto_doff(iph->protocol, h.raw, size); - if (doff <= 0) { - /* - * Output path: do not pass other IP protos nor - * invalid packets. - */ - return -1; - } - - switch (iph->protocol) { - case IPPROTO_ICMP: - return(ip_fw_masq_icmp(skb_p, maddr)); - case IPPROTO_UDP: - if (h.uh->check == 0) - /* No UDP checksum */ - break; - case IPPROTO_TCP: - /* Make sure packet is in the masq range */ - IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n", - masq_proto_name(iph->protocol), - size); - -#ifdef CONFIG_IP_MASQ_DEBUG - if (ip_masq_get_debug_level() > 3) { - skb->ip_summed = CHECKSUM_NONE; - } -#endif - /* Check that the checksum is OK */ - switch (skb->ip_summed) - { - case CHECKSUM_NONE: - { - csum = csum_partial(h.raw + doff, size - doff, 0); - IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n", - masq_proto_name(iph->protocol), - csum); - - skb->csum = csum_partial(h.raw , doff, csum); - } - case CHECKSUM_HW: - if (csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, skb->csum)) - { - IP_MASQ_DEBUG(0, "Outgoing failed %s checksum from %d.%d.%d.%d (size=%d)!\n", - masq_proto_name(iph->protocol), - NIPQUAD(iph->saddr), - size); - return -1; - } - default: - /* CHECKSUM_UNNECESSARY */ - } - break; - default: - return -1; - } - /* - * Now hunt the list to see if we have an old entry - */ - - /* h.raw = (char*) iph + iph->ihl * 4; */ - - IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n", - masq_proto_name(iph->protocol), - ntohl(iph->saddr), ntohs(h.portp[0]), - ntohl(iph->daddr), ntohs(h.portp[1])); - - ms = ip_masq_out_get_iph(iph); - if (ms!=NULL) { - - /* - * If sysctl !=0 and no pkt has been received yet - * in this tunnel and routing iface address has changed... - * "You are welcome, diald". - */ - if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) { - - if (sysctl_ip_dynaddr > 1) { - IP_MASQ_INFO( "ip_fw_masquerade(): change masq.addr from %d.%d.%d.%d to %d.%d.%d.%d\n", - NIPQUAD(ms->maddr),NIPQUAD(maddr)); - } - - write_lock(&__ip_masq_lock); - - ip_masq_unhash(ms); - ms->maddr = maddr; - ip_masq_hash(ms); - - write_unlock(&__ip_masq_lock); - } - - /* - * Set sport if not defined yet (e.g. ftp PASV). Because - * masq entries are hashed on sport, unhash with old value - * and hash with new. - */ - - if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) { - ms->flags &= ~IP_MASQ_F_NO_SPORT; - - write_lock(&__ip_masq_lock); - - ip_masq_unhash(ms); - ms->sport = h.portp[0]; - ip_masq_hash(ms); /* hash on new sport */ - - write_unlock(&__ip_masq_lock); - - IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n", - ntohs(ms->sport)); - } - if (ms->flags & IP_MASQ_F_DLOOSE) { - /* - * update dest loose values - */ - ms->dport = h.portp[1]; - ms->daddr = iph->daddr; - } - } else { - /* - * Nope, not found, create a new entry for it - */ - -#ifdef CONFIG_IP_MASQUERADE_MOD - if (!(ms = ip_masq_mod_out_create(skb, iph, maddr))) -#endif - ms = ip_masq_new(iph->protocol, - maddr, 0, - iph->saddr, h.portp[0], - iph->daddr, h.portp[1], - 0); - if (ms == NULL) - return -1; - } - - /* - * Call module's output update hook - */ - -#ifdef CONFIG_IP_MASQUERADE_MOD - ip_masq_mod_out_update(skb, iph, ms); -#endif - - /* - * Change the fragments origin - */ - - size = skb->len - (h.raw - skb->nh.raw); - - /* - * Set iph addr and port from ip_masq obj. - */ - iph->saddr = ms->maddr; - h.portp[0] = ms->mport; - - /* - * Invalidate csum saving if tunnel has masq helper - */ - - if (ms->app) - csum_ok = 0; - - /* - * Attempt ip_masq_app call. - * will fix ip_masq and iph seq stuff - */ - if (ip_masq_app_pkt_out(ms, skb_p, maddr) != 0) - { - /* - * skb has possibly changed, update pointers. - */ - skb = *skb_p; - iph = skb->nh.iph; - h.raw = (char*) iph + iph->ihl *4; - size = skb->len - (h.raw - skb->nh.raw); - /* doff should have not changed */ - } - - /* - * Adjust packet accordingly to protocol - */ - - /* - * Transport's payload partial csum - */ - - if (!csum_ok) { - csum = csum_partial(h.raw + doff, size - doff, 0); - } - skb->csum = csum; - - IP_MASQ_DEBUG(3, "O-pkt: %s size=%d O-datacsum=%d\n", - masq_proto_name(iph->protocol), - size, - csum); - - /* - * Protocol csum - */ - switch (iph->protocol) { - case IPPROTO_TCP: - h.th->check = 0; - h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, - csum_partial(h.raw , doff, csum)); - IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n", - masq_proto_name(iph->protocol), - h.th->check, - (char*) & (h.th->check) - (char*) h.raw); - - break; - case IPPROTO_UDP: - h.uh->check = 0; - h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, - csum_partial(h.raw , doff, csum)); - if (h.uh->check == 0) - h.uh->check = 0xFFFF; - IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n", - masq_proto_name(iph->protocol), - h.uh->check, - (char*) &(h.uh->check)- (char*) h.raw); - break; - } - ip_send_check(iph); - - IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n", - ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr)); - - masq_set_state(ms, 1, iph, h.portp); - ip_masq_put(ms); - - return 0; - } - -/* - * Restore original addresses and ports in the original IP - * datagram if the failing packet has been [de]masqueraded. - * This is ugly in the extreme. We no longer have the original - * packet so we have to reconstruct it from the failing packet - * plus data in the masq tables. The resulting "original data" - * should be good enough to tell the sender which session to - * throttle. Relies on far too much knowledge of masq internals, - * there ought to be a better way - KAO 990303. - * - * Moved here from icmp.c - JJC. - * Already known: type == ICMP_DEST_UNREACH, IPSKB_MASQUERADED - * skb->nh.iph points to original header. - * - * Must try both OUT and IN tables; we could add a flag - * ala IPSKB_MASQUERADED to avoid 2nd tables lookup, but this is VERY - * unlike because routing makes mtu decision before reaching - * ip_fw_masquerade(). - * - */ -int ip_fw_unmasq_icmp(struct sk_buff *skb) { - struct ip_masq *ms; - struct iphdr *iph = skb->nh.iph; - __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - - /* - * Always called from _bh context: use read_[un]lock() - */ - - /* - * Peek "out" table, this packet has bounced: - * out->in(frag_needed!)->OUT[icmp] - * - * iph->daddr is IN host - * iph->saddr is OUT host - */ - read_lock(&__ip_masq_lock); - ms = __ip_masq_out_get(iph->protocol, - iph->daddr, portp[1], - iph->saddr, portp[0]); - read_unlock(&__ip_masq_lock); - if (ms) { - IP_MASQ_DEBUG(1, "Incoming frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n", - NIPQUAD(iph->daddr), NIPQUAD(ms->maddr)); - iph->daddr = ms->maddr; - portp[1] = ms->mport; - __ip_masq_put(ms); - return 1; - } - /* - * Peek "in" table - * in->out(frag_needed!)->IN[icmp] - * - * iph->daddr is OUT host - * iph->saddr is MASQ host - * - */ - read_lock(&__ip_masq_lock); - ms = __ip_masq_in_get(iph->protocol, - iph->daddr, portp[1], - iph->saddr, portp[0]); - read_unlock(&__ip_masq_lock); - if (ms) { - IP_MASQ_DEBUG(1, "Outgoing frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n", - NIPQUAD(iph->saddr), NIPQUAD(ms->saddr)); - iph->saddr = ms->saddr; - portp[0] = ms->sport; - __ip_masq_put(ms); - return 1; - } - return 0; - -} -/* - * Handle ICMP messages in forward direction. - * Find any that might be relevant, check against existing connections, - * forward to masqueraded host if relevant. - * Currently handles error types - unreachable, quench, ttl exceeded - */ - -int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); - struct iphdr *ciph; /* The ip header contained within the ICMP */ - __u16 *pptr; /* port numbers from TCP/UDP contained header */ - struct ip_masq *ms; - unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); - - IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n", - icmph->type, ntohs(icmp_id(icmph)), - ntohl(iph->saddr), ntohl(iph->daddr)); - -#ifdef CONFIG_IP_MASQUERADE_ICMP - if ((icmph->type == ICMP_ECHO ) || - (icmph->type == ICMP_TIMESTAMP ) || - (icmph->type == ICMP_INFO_REQUEST ) || - (icmph->type == ICMP_ADDRESS )) { - - IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX id %d type %d\n", - ntohl(iph->saddr), - ntohl(iph->daddr), - ntohs(icmp_id(icmph)), - icmph->type); - - ms = ip_masq_out_get(iph->protocol, - iph->saddr, - icmp_id(icmph), - iph->daddr, - icmp_hv_req(icmph)); - if (ms == NULL) { - ms = ip_masq_new(iph->protocol, - maddr, 0, - iph->saddr, icmp_id(icmph), - iph->daddr, icmp_hv_req(icmph), - 0); - if (ms == NULL) - return (-1); - IP_MASQ_DEBUG(1, "Created new icmp entry\n"); - } - /* Rewrite source address */ - - /* - * If sysctl !=0 and no pkt has been received yet - * in this tunnel and routing iface address has changed... - * "You are welcome, diald". - */ - if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) { - - if (sysctl_ip_dynaddr > 1) { - IP_MASQ_INFO( "ip_fw_masq_icmp(): change masq.addr %d.%d.%d.%d to %d.%d.%d.%d", - NIPQUAD(ms->maddr), NIPQUAD(maddr)); - } - - write_lock(&__ip_masq_lock); - - ip_masq_unhash(ms); - ms->maddr = maddr; - ip_masq_hash(ms); - - write_unlock(&__ip_masq_lock); - } - - iph->saddr = ms->maddr; - ip_send_check(iph); - /* Rewrite port (id) */ - (icmph->un).echo.id = ms->mport; - icmph->checksum = 0; - icmph->checksum = ip_compute_csum((unsigned char *)icmph, len); - - IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n", - ntohl(iph->saddr), - ntohl(iph->daddr), - ntohs(icmp_id(icmph)), - icmph->type); - - masq_set_state(ms, 1, iph, icmph); - ip_masq_put(ms); - - return 1; - } -#endif - - /* - * Work through seeing if this is for us. - * These checks are supposed to be in an order that - * means easy things are checked first to speed up - * processing.... however this means that some - * packets will manage to get a long way down this - * stack and then be rejected, but thats life - */ - if ((icmph->type != ICMP_DEST_UNREACH) && - (icmph->type != ICMP_SOURCE_QUENCH) && - (icmph->type != ICMP_TIME_EXCEEDED)) - return 0; - - /* Now find the contained IP header */ - ciph = (struct iphdr *) (icmph + 1); - -#ifdef CONFIG_IP_MASQUERADE_ICMP - if (ciph->protocol == IPPROTO_ICMP) { - /* - * This section handles ICMP errors for ICMP packets - */ - struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + - (ciph->ihl<<2)); - - - IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n", - ntohl(ciph->saddr), - ntohl(ciph->daddr), - ntohs(icmp_id(cicmph)), - cicmph->type); - - read_lock(&__ip_masq_lock); - ms = __ip_masq_out_get(ciph->protocol, - ciph->daddr, - icmp_id(cicmph), - ciph->saddr, - icmp_hv_rep(cicmph)); - read_unlock(&__ip_masq_lock); - - if (ms == NULL) - return 0; - - /* Now we do real damage to this packet...! */ - /* First change the source IP address, and recalc checksum */ - iph->saddr = ms->maddr; - ip_send_check(iph); - - /* Now change the *dest* address in the contained IP */ - ciph->daddr = ms->maddr; - __ip_masq_put(ms); - - ip_send_check(ciph); - - /* Change the ID to the masqed one! */ - (cicmph->un).echo.id = ms->mport; - - /* And finally the ICMP checksum */ - icmph->checksum = 0; - icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - - - IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n", - ntohl(ciph->saddr), - ntohl(ciph->daddr), - ntohs(icmp_id(cicmph)), - cicmph->type); - - return 1; - } -#endif /* CONFIG_IP_MASQUERADE_ICMP */ - - /* We are only interested ICMPs generated from TCP or UDP packets */ - if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) - return 0; - - /* - * Find the ports involved - this packet was - * incoming so the ports are right way round - * (but reversed relative to outer IP header!) - */ - pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); -#if 0 - if (ntohs(pptr[1]) < PORT_MASQ_BEGIN || - ntohs(pptr[1]) > PORT_MASQ_END) - return 0; -#endif - - /* Ensure the checksum is correct */ - if (ip_compute_csum((unsigned char *) icmph, len)) - { - /* Failed checksum! */ - IP_MASQ_DEBUG(0, "forward ICMP: failed checksum from %d.%d.%d.%d!\n", - NIPQUAD(iph->saddr)); - return(-1); - } - - - IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n", - ntohl(ciph->saddr), ntohs(pptr[0]), - ntohl(ciph->daddr), ntohs(pptr[1])); - - -#if 0 - /* This is pretty much what __ip_masq_in_get_iph() does */ - ms = __ip_masq_in_get(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]); -#endif - read_lock(&__ip_masq_lock); - ms = __ip_masq_out_get(ciph->protocol, - ciph->daddr, - pptr[1], - ciph->saddr, - pptr[0]); - read_unlock(&__ip_masq_lock); - - if (ms == NULL) - return 0; - - /* Now we do real damage to this packet...! */ - /* First change the source IP address, and recalc checksum */ - iph->saddr = ms->maddr; - ip_send_check(iph); - - /* Now change the *dest* address in the contained IP */ - ciph->daddr = ms->maddr; - ip_send_check(ciph); - - /* the TCP/UDP dest port - cannot redo check */ - pptr[1] = ms->mport; - __ip_masq_put(ms); - - /* And finally the ICMP checksum */ - icmph->checksum = 0; - icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - - - IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n", - ntohl(ciph->saddr), ntohs(pptr[0]), - ntohl(ciph->daddr), ntohs(pptr[1])); - - - return 1; -} - - -/* - * Own skb_cow() beast, tweaked for rewriting commonly - * used pointers in masq code - */ -static struct sk_buff * masq_skb_cow(struct sk_buff **skb_p, - struct iphdr **iph_p, unsigned char **t_p) { - struct sk_buff *skb=(*skb_p); - if (skb_cloned(skb)) { - skb = skb_copy(skb, GFP_ATOMIC); - if (skb) { - /* - * skb changed, update other pointers - */ - struct iphdr *iph = skb->nh.iph; - kfree_skb(*skb_p); - *skb_p = skb; - *iph_p = iph; - *t_p = (char*) iph + iph->ihl * 4; - } - } - return skb; -} - -/* - * Handle ICMP messages in reverse (demasquerade) direction. - * Find any that might be relevant, check against existing connections, - * forward to masqueraded host if relevant. - * Currently handles error types - unreachable, quench, ttl exceeded - */ - -int ip_fw_demasq_icmp(struct sk_buff **skb_p) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); - struct iphdr *ciph; /* The ip header contained within the ICMP */ - __u16 *pptr; /* port numbers from TCP/UDP contained header */ - struct ip_masq *ms; - unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); - - - IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n", - icmph->type, ntohs(icmp_id(icmph)), - ntohl(iph->saddr), ntohl(iph->daddr)); - - -#ifdef CONFIG_IP_MASQUERADE_ICMP - if ((icmph->type == ICMP_ECHOREPLY) || - (icmph->type == ICMP_TIMESTAMPREPLY) || - (icmph->type == ICMP_INFO_REPLY) || - (icmph->type == ICMP_ADDRESSREPLY)) { - - IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n", - ntohl(iph->saddr), - ntohl(iph->daddr), - ntohs(icmp_id(icmph)), - icmph->type, - icmp_type_request(icmph->type)); - - ms = ip_masq_in_get(iph->protocol, - iph->saddr, - icmp_hv_rep(icmph), - iph->daddr, - icmp_id(icmph)); - if (ms == NULL) - return 0; - - /* - * got reply, so clear flag - */ - ms->flags &= ~IP_MASQ_F_NO_REPLY; - - if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) { - ip_masq_put(ms); - return -1; - } - - /* Reset source address */ - iph->daddr = ms->saddr; - /* Redo IP header checksum */ - ip_send_check(iph); - /* Set ID to fake port number */ - (icmph->un).echo.id = ms->sport; - /* Reset ICMP checksum and set expiry */ - icmph->checksum=0; - icmph->checksum=ip_compute_csum((unsigned char *)icmph,len); - - - - IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n", - ntohl(iph->saddr), - ntohl(iph->daddr), - ntohs(icmp_id(icmph)), - icmph->type); - - masq_set_state(ms, 0, iph, icmph); - ip_masq_put(ms); - - return 1; - } else { -#endif - if ((icmph->type != ICMP_DEST_UNREACH) && - (icmph->type != ICMP_SOURCE_QUENCH) && - (icmph->type != ICMP_TIME_EXCEEDED)) - return 0; -#ifdef CONFIG_IP_MASQUERADE_ICMP - } -#endif - /* - * If we get here we have an ICMP error of one of the above 3 types - * Now find the contained IP header - */ - - ciph = (struct iphdr *) (icmph + 1); - -#ifdef CONFIG_IP_MASQUERADE_ICMP - if (ciph->protocol == IPPROTO_ICMP) { - /* - * This section handles ICMP errors for ICMP packets - * - * First get a new ICMP header structure out of the IP packet - */ - struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + - (ciph->ihl<<2)); - - - IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n", - ntohl(ciph->saddr), - ntohl(ciph->daddr), - ntohs(icmp_id(cicmph)), - cicmph->type); - - read_lock(&__ip_masq_lock); - ms = __ip_masq_in_get(ciph->protocol, - ciph->daddr, - icmp_hv_req(cicmph), - ciph->saddr, - icmp_id(cicmph)); - read_unlock(&__ip_masq_lock); - - if (ms == NULL) - return 0; - - if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) { - __ip_masq_put(ms); - return -1; - } - ciph = (struct iphdr *) (icmph + 1); - cicmph = (struct icmphdr *)((char *)ciph + - (ciph->ihl<<2)); - /* Now we do real damage to this packet...! */ - /* First change the dest IP address, and recalc checksum */ - iph->daddr = ms->saddr; - ip_send_check(iph); - - /* Now change the *source* address in the contained IP */ - ciph->saddr = ms->saddr; - ip_send_check(ciph); - - /* Change the ID to the original one! */ - (cicmph->un).echo.id = ms->sport; - __ip_masq_put(ms); - - /* And finally the ICMP checksum */ - icmph->checksum = 0; - icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - - - IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n", - ntohl(ciph->saddr), - ntohl(ciph->daddr), - ntohs(icmp_id(cicmph)), - cicmph->type); - - return 1; - } -#endif /* CONFIG_IP_MASQUERADE_ICMP */ - - /* We are only interested ICMPs generated from TCP or UDP packets */ - if ((ciph->protocol != IPPROTO_UDP) && - (ciph->protocol != IPPROTO_TCP)) - return 0; - - /* - * Find the ports involved - remember this packet was - * *outgoing* so the ports are reversed (and addresses) - */ - pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); - if (ntohs(pptr[0]) < PORT_MASQ_BEGIN || - ntohs(pptr[0]) > PORT_MASQ_END) - return 0; - - /* Ensure the checksum is correct */ - if (ip_compute_csum((unsigned char *) icmph, len)) - { - /* Failed checksum! */ - IP_MASQ_ERR( "reverse ICMP: failed checksum from %d.%d.%d.%d!\n", - NIPQUAD(iph->saddr)); - return(-1); - } - - - IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n", - ntohl(ciph->saddr), ntohs(pptr[0]), - ntohl(ciph->daddr), ntohs(pptr[1])); - - - /* This is pretty much what __ip_masq_in_get_iph() does, except params are wrong way round */ - read_lock(&__ip_masq_lock); - ms = __ip_masq_in_get(ciph->protocol, - ciph->daddr, - pptr[1], - ciph->saddr, - pptr[0]); - read_unlock(&__ip_masq_lock); - - if (ms == NULL) - return 0; - - if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) { - __ip_masq_put(ms); - return -1; - } - ciph = (struct iphdr *) (icmph + 1); - pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); - - /* Now we do real damage to this packet...! */ - /* First change the dest IP address, and recalc checksum */ - iph->daddr = ms->saddr; - ip_send_check(iph); - - /* Now change the *source* address in the contained IP */ - ciph->saddr = ms->saddr; - ip_send_check(ciph); - - /* the TCP/UDP source port - cannot redo check */ - pptr[0] = ms->sport; - __ip_masq_put(ms); - - /* And finally the ICMP checksum */ - icmph->checksum = 0; - icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - - - IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n", - ntohl(ciph->saddr), ntohs(pptr[0]), - ntohl(ciph->daddr), ntohs(pptr[1])); - - - return 1; -} - - /* - * Check if it's an masqueraded port, look it up, - * and send it on its way... - * - * Better not have many hosts using the designated portrange - * as 'normal' ports, or you'll be spending many time in - * this function. - */ - -int ip_fw_demasquerade(struct sk_buff **skb_p) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - union ip_masq_tphdr h; - struct ip_masq *ms; - unsigned short size; - int doff = 0; - int csum = 0; - int csum_ok = 0; - __u32 maddr; - - /* - * Big tappo: only PACKET_HOST (nor loopback neither mcasts) - * ... don't know why 1st test DOES NOT include 2nd (?) - */ - - if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) { - IP_MASQ_DEBUG(2, "ip_fw_demasquerade(): packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", - skb->pkt_type, - iph->protocol, - NIPQUAD(iph->daddr)); - return 0; - } - - h.raw = (char*) iph + iph->ihl * 4; - - /* - * IP payload size - */ - size = ntohs(iph->tot_len) - (iph->ihl * 4); - - doff = proto_doff(iph->protocol, h.raw, size); - - switch (doff) { - case 0: - /* - * Input path: other IP protos Ok, will - * reach local sockets path. - */ - return 0; - case -1: - IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n"); - return -1; - } - - maddr = iph->daddr; - switch (iph->protocol) { - case IPPROTO_ICMP: - return(ip_fw_demasq_icmp(skb_p)); - case IPPROTO_TCP: - case IPPROTO_UDP: - /* - * Make sure packet is in the masq range - * ... or some mod-ule relaxes input range - * ... or there is still some `special' mport opened - */ - if ((ntohs(h.portp[1]) < PORT_MASQ_BEGIN - || ntohs(h.portp[1]) > PORT_MASQ_END) -#ifdef CONFIG_IP_MASQUERADE_MOD - && (ip_masq_mod_in_rule(skb, iph) != 1) -#endif - && atomic_read(&mport_count) == 0 ) - return 0; - - /* Check that the checksum is OK */ - if ((iph->protocol == IPPROTO_UDP) && (h.uh->check == 0)) - /* No UDP checksum */ - break; -#ifdef CONFIG_IP_MASQ_DEBUG - if (ip_masq_get_debug_level() > 3) { - skb->ip_summed = CHECKSUM_NONE; - } -#endif - - switch (skb->ip_summed) - { - case CHECKSUM_NONE: - csum = csum_partial(h.raw + doff, size - doff, 0); - csum_ok++; - skb->csum = csum_partial(h.raw , doff, csum); - - case CHECKSUM_HW: - if (csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, skb->csum)) - { - IP_MASQ_DEBUG(0, "Incoming failed %s checksum from %d.%d.%d.%d (size=%d)!\n", - masq_proto_name(iph->protocol), - NIPQUAD(iph->saddr), - size); - return -1; - } - default: - /* CHECKSUM_UNNECESSARY */ - } - break; - default: - return 0; - } - - - - IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n", - masq_proto_name(iph->protocol), - ntohl(iph->saddr), ntohs(h.portp[0]), - ntohl(iph->daddr), ntohs(h.portp[1])); - - /* - * reroute to original host:port if found... - */ - - ms = ip_masq_in_get_iph(iph); - - /* - * Give additional modules a chance to create an entry - */ -#ifdef CONFIG_IP_MASQUERADE_MOD - if (!ms) - ms = ip_masq_mod_in_create(skb, iph, maddr); - - /* - * Call module's input update hook - */ - ip_masq_mod_in_update(skb, iph, ms); -#endif - - - if (ms != NULL) - { - - /* - * got reply, so clear flag - */ - ms->flags &= ~IP_MASQ_F_NO_REPLY; - - /* - * Set daddr,dport if not defined yet - * and tunnel is not setup as "dest loose" - */ - - if (ms->flags & IP_MASQ_F_DLOOSE) { - /* - * update dest loose values - */ - ms->dport = h.portp[0]; - ms->daddr = iph->saddr; - } else { - if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /* && ms->protocol == IPPROTO_TCP ) { */ - ms->flags &= ~IP_MASQ_F_NO_DPORT; - ms->dport = h.portp[0]; - - IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n", - ntohs(ms->dport)); - - } - if (ms->flags & IP_MASQ_F_NO_DADDR ) { /* && ms->protocol == IPPROTO_TCP) { */ - ms->flags &= ~IP_MASQ_F_NO_DADDR; - ms->daddr = iph->saddr; - - IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n", - ntohl(ms->daddr)); - - } - } - if ((skb=masq_skb_cow(skb_p, &iph, &h.raw)) == NULL) { - ip_masq_put(ms); - return -1; - } - iph->daddr = ms->saddr; - h.portp[1] = ms->sport; - - /* - * Invalidate csum saving if tunnel has masq helper - */ - - if (ms->app) - csum_ok = 0; - - /* - * Attempt ip_masq_app call. - * will fix ip_masq and iph ack_seq stuff - */ - - if (ip_masq_app_pkt_in(ms, skb_p, maddr) != 0) - { - /* - * skb has changed, update pointers. - */ - - skb = *skb_p; - iph = skb->nh.iph; - h.raw = (char*) iph + iph->ihl*4; - size = ntohs(iph->tot_len) - (iph->ihl * 4); - } - - /* - * Yug! adjust UDP/TCP checksums - */ - - /* - * Transport's payload partial csum - */ - - if (!csum_ok) { - csum = csum_partial(h.raw + doff, size - doff, 0); - } - skb->csum = csum; - - /* - * Protocol csum - */ - switch (iph->protocol) { - case IPPROTO_TCP: - h.th->check = 0; - h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, - csum_partial(h.raw , doff, csum)); - break; - case IPPROTO_UDP: - h.uh->check = 0; - h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr, - size, iph->protocol, - csum_partial(h.raw , doff, csum)); - if (h.uh->check == 0) - h.uh->check = 0xFFFF; - break; - } - ip_send_check(iph); - - IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1])); - - masq_set_state (ms, 0, iph, h.portp); - ip_masq_put(ms); - - return 1; - } - - /* sorry, all this trouble for a no-hit :) */ - return 0; -} - - -void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms) -{ - if (ms->control) { - IP_MASQ_ERR( "request control ADD for already controlled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", - NIPQUAD(ms->saddr),ntohs(ms->sport), - NIPQUAD(ms->daddr),ntohs(ms->dport)); - ip_masq_control_del(ms); - } - IP_MASQ_DEBUG(1, "ADDing control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n", - NIPQUAD(ms->daddr),ntohs(ms->dport), - NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport)); - ms->control = ctl_ms; - atomic_inc(&ctl_ms->n_control); -} - -void ip_masq_control_del(struct ip_masq *ms) -{ - struct ip_masq *ctl_ms = ms->control; - if (!ctl_ms) { - IP_MASQ_ERR( "request control DEL for uncontrolled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", - NIPQUAD(ms->saddr),ntohs(ms->sport), - NIPQUAD(ms->daddr),ntohs(ms->dport)); - return; - } - IP_MASQ_DEBUG(1, "DELeting control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n", - NIPQUAD(ms->daddr),ntohs(ms->dport), - NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport)); - ms->control = NULL; - if (atomic_read(&ctl_ms->n_control) == 0) { - IP_MASQ_ERR( "BUG control DEL with n=0 : %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", - NIPQUAD(ms->saddr),ntohs(ms->sport), - NIPQUAD(ms->daddr),ntohs(ms->dport)); - return; - - } - atomic_dec(&ctl_ms->n_control); -} - -struct ip_masq * ip_masq_control_get(struct ip_masq *ms) -{ - return ms->control; -} - - -#ifdef CONFIG_PROC_FS -/* - * /proc/net entries - * From userspace - */ -static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, - int length, int unused) -{ - off_t pos=0, begin; - struct ip_masq *ms; - char temp[129]; - int idx = 0; - int len=0; - - - if (offset < 128) - { - sprintf(temp, - "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d,%d)", - atomic_read(ip_masq_free_ports), - atomic_read(ip_masq_free_ports+1), - atomic_read(ip_masq_free_ports+2)); - len = sprintf(buffer, "%-127s\n", temp); - } - pos = 128; - - for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) - { - /* - * Lock is actually only need in next loop - * we are called from uspace: must stop bh. - */ - read_lock_bh(&__ip_masq_lock); - - for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) - { - pos += 128; - if (pos <= offset) { - len = 0; - continue; - } - - /* - * We have locked the tables, no need to del/add timers - * nor cli() 8) - */ - - sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu", - masq_proto_name(ms->protocol), - ntohl(ms->saddr), ntohs(ms->sport), - ntohl(ms->daddr), ntohs(ms->dport), - ntohs(ms->mport), - ms->out_seq.init_seq, - ms->out_seq.delta, - ms->out_seq.previous_delta, - ms->timer.expires-jiffies); - len += sprintf(buffer+len, "%-127s\n", temp); - - if(len >= length) { - - read_unlock_bh(&__ip_masq_lock); - goto done; - } - } - read_unlock_bh(&__ip_masq_lock); - - } -done: - - - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - if(len>length) - len = length; - return len; -} - -#endif - -/* - * Timeouts handling by ipfwadm/ipchains - * From ip_fw.c - */ - -int ip_fw_masq_timeouts(void *m, int len) -{ - struct ip_fw_masq *masq; - int ret = EINVAL; - - if (len != sizeof(struct ip_fw_masq)) { - IP_MASQ_DEBUG(1, "ip_fw_masq_timeouts: length %d, expected %d\n", - len, sizeof(struct ip_fw_masq)); - } else { - masq = (struct ip_fw_masq *)m; - if (masq->tcp_timeout) - masq_timeout_table.timeout[IP_MASQ_S_ESTABLISHED] - = masq->tcp_timeout; - - if (masq->tcp_fin_timeout) - masq_timeout_table.timeout[IP_MASQ_S_FIN_WAIT] - = masq->tcp_fin_timeout; - - if (masq->udp_timeout) - masq_timeout_table.timeout[IP_MASQ_S_UDP] - = masq->udp_timeout; - ret = 0; - } - return ret; -} -/* - * Module autoloading stuff - */ - -static int ip_masq_user_check_hook(void) { -#ifdef CONFIG_KMOD - if (ip_masq_user_hook == NULL) { - IP_MASQ_DEBUG(1, "About to request \"ip_masq_user\" module\n"); - request_module("ip_masq_user"); - } -#endif /* CONFIG_KMOD */ - return (ip_masq_user_hook != NULL); -} - -/* - * user module hook- info - */ -static int ip_masq_user_info(char *buffer, char **start, off_t offset, - int len, int *eof, void *data) -{ - int ret = -ENOPKG; - if (ip_masq_user_check_hook()) { - ret = ip_masq_user_hook->info(buffer, start, offset, len, (int) data); - } - return ret; -} - -/* - * user module hook- entry mgmt - */ -static int ip_masq_user_ctl(int optname, void *arg, int arglen) -{ - int ret = -ENOPKG; - if (ip_masq_user_check_hook()) { - ret = ip_masq_user_hook->ctl(optname, arg, arglen); - } - return ret; -} - -/* - * Control from ip_sockglue - * MAIN ENTRY point from userspace (apart from /proc *info entries) - * Returns errno - */ -int ip_masq_uctl(int optname, char * optval , int optlen) -{ - struct ip_masq_ctl masq_ctl; - int ret = -EINVAL; - - if(optlen>sizeof(masq_ctl)) - return -EINVAL; - - if(copy_from_user(&masq_ctl,optval,optlen)) - return -EFAULT; - - IP_MASQ_DEBUG(1,"ip_masq_ctl(optname=%d, optlen=%d, target=%d, cmd=%d)\n", - optname, optlen, masq_ctl.m_target, masq_ctl.m_cmd); - - switch (masq_ctl.m_target) { - case IP_MASQ_TARGET_USER: - ret = ip_masq_user_ctl(optname, &masq_ctl, optlen); - break; -#ifdef CONFIG_IP_MASQUERADE_MOD - case IP_MASQ_TARGET_MOD: - ret = ip_masq_mod_ctl(optname, &masq_ctl, optlen); - break; -#endif - } - - /* - * If ret>0, copy to user space - */ - - if (ret > 0 && ret <= sizeof (masq_ctl)) { - if (copy_to_user(optval, &masq_ctl, ret) ) - return -EFAULT; - ret = 0; - } - - return ret; -} - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *proc_net_ip_masq = NULL; - -#ifdef MODULE -static void ip_masq_proc_count(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} -#endif - -int ip_masq_proc_register(struct proc_dir_entry *ent) -{ - if (!proc_net_ip_masq) return -1; - IP_MASQ_DEBUG(1, "registering \"/proc/net/ip_masq/%s\" entry\n", - ent->name); - return proc_register(proc_net_ip_masq, ent); -} -void ip_masq_proc_unregister(struct proc_dir_entry *ent) -{ - if (!proc_net_ip_masq) return; - IP_MASQ_DEBUG(1, "unregistering \"/proc/net/ip_masq/%s\" entry\n", - ent->name); - proc_unregister(proc_net_ip_masq, ent->low_ino); -} - - -__initfunc(static void masq_proc_init(void)) -{ - IP_MASQ_DEBUG(1,"registering /proc/net/ip_masq\n"); - if (!proc_net_ip_masq) { - struct proc_dir_entry *ent; - ent = create_proc_entry("net/ip_masq", S_IFDIR, 0); - if (ent) { -#ifdef MODULE - ent->fill_inode = ip_masq_proc_count; -#endif - proc_net_ip_masq = ent; - } else { - IP_MASQ_ERR("Could not create \"/proc/net/ip_masq\" entry\n"); - } - } -} -#endif /* CONFIG_PROC_FS */ -/* - * Wrapper over inet_select_addr() - */ -u32 ip_masq_select_addr(struct net_device *dev, u32 dst, int scope) -{ - return inet_select_addr(dev, dst, scope); -} - -/* - * Initialize ip masquerading - */ -__initfunc(int ip_masq_init(void)) -{ -#ifdef CONFIG_PROC_FS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_IPMSQHST, 13, "ip_masquerade", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_msqhst_procinfo - }); - masq_proc_init(); - - ip_masq_proc_register(&(struct proc_dir_entry) { - 0, 3, "tcp", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - NULL, /* get_info */ - NULL, /* fill_inode */ - NULL, NULL, NULL, - (char *) IPPROTO_TCP, - ip_masq_user_info - }); - ip_masq_proc_register(&(struct proc_dir_entry) { - 0, 3, "udp", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - NULL, /* get_info */ - NULL, /* fill_inode */ - NULL, NULL, NULL, - (char *) IPPROTO_UDP, - ip_masq_user_info - }); - ip_masq_proc_register(&(struct proc_dir_entry) { - 0, 4, "icmp", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - NULL, /* get_info */ - NULL, /* fill_inode */ - NULL, NULL, NULL, - (char *) IPPROTO_ICMP, - ip_masq_user_info - }); -#endif -#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW - ip_autofw_init(); -#endif -#ifdef CONFIG_IP_MASQUERADE_IPPORTFW - ip_portfw_init(); -#endif -#ifdef CONFIG_IP_MASQUERADE_MFW - ip_mfw_init(); -#endif - ip_masq_app_init(); - - return 0; -} diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c --- v2.3.14/linux/net/ipv4/ip_masq_app.c Sun Oct 4 10:21:45 1998 +++ linux/net/ipv4/ip_masq_app.c Wed Dec 31 16:00:00 1969 @@ -1,603 +0,0 @@ -/* - * IP_MASQ_APP application masquerading module - * - * - * $Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $ - * - * Author: Juan Jose Ciarlante, - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * JJC : Implemented also input pkt hook - * Miquel van Smoorenburg : Copy more stuff when resizing skb - * - * - * FIXME: - * - ip_masq_skb_replace(): use same skb if space available. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */ - -#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1)) -#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port ) -#define IP_MASQ_APP_PORT(type) ( type & 0xffff ) -#define IP_MASQ_APP_PROTO(type) ( (type>>16) & 0x00ff ) - - -EXPORT_SYMBOL(register_ip_masq_app); -EXPORT_SYMBOL(unregister_ip_masq_app); -EXPORT_SYMBOL(ip_masq_skb_replace); - -/* - * will hold masq app. hashed list heads - */ - -struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE]; - -/* - * ip_masq_app registration routine - * port: host byte order. - */ - -int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port) -{ - unsigned long flags; - unsigned hash; - if (!mapp) { - IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n"); - return -EINVAL; - } - mapp->type = IP_MASQ_APP_TYPE(proto, port); - mapp->n_attach = 0; - hash = IP_MASQ_APP_HASH(proto, port); - - save_flags(flags); - cli(); - mapp->next = ip_masq_app_base[hash]; - ip_masq_app_base[hash] = mapp; - restore_flags(flags); - - return 0; -} - -/* - * ip_masq_app unreg. routine. - */ - -int unregister_ip_masq_app(struct ip_masq_app *mapp) -{ - struct ip_masq_app **mapp_p; - unsigned hash; - unsigned long flags; - if (!mapp) { - IP_MASQ_ERR("unregister_ip_masq_app(): NULL arg\n"); - return -EINVAL; - } - /* - * only allow unregistration if it has no attachments - */ - if (mapp->n_attach) { - IP_MASQ_ERR("unregister_ip_masq_app(): has %d attachments. failed\n", - mapp->n_attach); - return -EINVAL; - } - hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type)); - - save_flags(flags); - cli(); - for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next) - if (mapp == (*mapp_p)) { - *mapp_p = mapp->next; - restore_flags(flags); - return 0; - } - - restore_flags(flags); - IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type)); - return -EINVAL; -} - -/* - * get ip_masq_app object by its proto and port (net byte order). - */ - -struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port) -{ - struct ip_masq_app *mapp; - unsigned hash; - unsigned type; - - port = ntohs(port); - type = IP_MASQ_APP_TYPE(proto,port); - hash = IP_MASQ_APP_HASH(proto,port); - for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) { - if (type == mapp->type) return mapp; - } - return NULL; -} - -/* - * ip_masq_app object binding related funcs. - */ - -/* - * change ip_masq_app object's number of bindings - */ - -static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta) -{ - unsigned long flags; - int n_at; - if (!mapp) return -1; - save_flags(flags); - cli(); - n_at = mapp->n_attach + delta; - if (n_at < 0) { - restore_flags(flags); - IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), - IP_MASQ_APP_PORT(mapp->type)); - return -1; - } - mapp->n_attach = n_at; - restore_flags(flags); - return 0; -} - -/* - * Bind ip_masq to its ip_masq_app based on proto and dport ALREADY - * set in ip_masq struct. Also calls constructor. - */ - -struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms) -{ - struct ip_masq_app * mapp; - - if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP) - return NULL; - - mapp = ip_masq_app_get(ms->protocol, ms->dport); - -#if 0000 -/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */ - if (mapp == NULL) - mapp = ip_masq_app_get(ms->protocol, ms->sport); -/* #endif */ -#endif - - if (mapp != NULL) { - /* - * don't allow binding if already bound - */ - - if (ms->app != NULL) { - IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n"); - return ms->app; - } - - ms->app = mapp; - if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms); - ip_masq_app_bind_chg(mapp, +1); - } - return mapp; -} - -/* - * Unbind ms from type object and call ms destructor (does not kfree()). - */ - -int ip_masq_unbind_app(struct ip_masq *ms) -{ - struct ip_masq_app * mapp; - mapp = ms->app; - - if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP) - return 0; - - if (mapp != NULL) { - if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms); - ms->app = NULL; - ip_masq_app_bind_chg(mapp, -1); - } - return (mapp != NULL); -} - -/* - * Fixes th->seq based on ip_masq_seq info. - */ - -static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th) -{ - __u32 seq; - - seq = ntohl(th->seq); - - /* - * Adjust seq with delta-offset for all packets after - * the most recent resized pkt seq and with previous_delta offset - * for all packets before most recent resized pkt seq. - */ - - if (ms_seq->delta || ms_seq->previous_delta) { - if(after(seq,ms_seq->init_seq) ) { - th->seq = htonl(seq + ms_seq->delta); - IP_MASQ_DEBUG(1, "masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta); - } else { - th->seq = htonl(seq + ms_seq->previous_delta); - IP_MASQ_DEBUG(1, "masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta); - } - } - - -} - -/* - * Fixes th->ack_seq based on ip_masq_seq info. - */ - -static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th) -{ - __u32 ack_seq; - - ack_seq=ntohl(th->ack_seq); - - /* - * Adjust ack_seq with delta-offset for - * the packets AFTER most recent resized pkt has caused a shift - * for packets before most recent resized pkt, use previous_delta - */ - - if (ms_seq->delta || ms_seq->previous_delta) { - if(after(ack_seq,ms_seq->init_seq)) { - th->ack_seq = htonl(ack_seq-ms_seq->delta); - IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta); - - } else { - th->ack_seq = htonl(ack_seq-ms_seq->previous_delta); - IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta); - } - } - -} - -/* - * Updates ip_masq_seq if pkt has been resized - * Assumes already checked proto==IPPROTO_TCP and diff!=0. - */ - -static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff) -{ - /* if (diff == 0) return; */ - - if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq)) - { - ms_seq->previous_delta=ms_seq->delta; - ms_seq->delta+=diff; - ms_seq->init_seq=seq; - ms->flags |= mflag; - } -} - -/* - * Output pkt hook. Will call bound ip_masq_app specific function - * called by ip_fw_masquerade(), assumes previously checked ms!=NULL - * returns (new - old) skb->len diff. - */ - -int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct ip_masq_app * mapp; - struct iphdr *iph; - struct tcphdr *th; - int diff; - __u32 seq; - - /* - * check if application masquerading is bound to - * this ip_masq. - * assumes that once an ip_masq is bound, - * it will not be unbound during its life. - */ - - if ( (mapp = ms->app) == NULL) - return 0; - - iph = (*skb_p)->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - - /* - * Remember seq number in case this pkt gets resized - */ - - seq = ntohl(th->seq); - - /* - * Fix seq stuff if flagged as so. - */ - - if (ms->protocol == IPPROTO_TCP) { - if (ms->flags & IP_MASQ_F_OUT_SEQ) - masq_fix_seq(&ms->out_seq, th); - if (ms->flags & IP_MASQ_F_IN_SEQ) - masq_fix_ack_seq(&ms->in_seq, th); - } - - /* - * Call private output hook function - */ - - if ( mapp->pkt_out == NULL ) - return 0; - - diff = mapp->pkt_out(mapp, ms, skb_p, maddr); - - /* - * Update ip_masq seq stuff if len has changed. - */ - - if (diff != 0 && ms->protocol == IPPROTO_TCP) - masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff); - - return diff; -} - -/* - * Input pkt hook. Will call bound ip_masq_app specific function - * called by ip_fw_demasquerade(), assumes previously checked ms!=NULL. - * returns (new - old) skb->len diff. - */ - -int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct ip_masq_app * mapp; - struct iphdr *iph; - struct tcphdr *th; - int diff; - __u32 seq; - - /* - * check if application masquerading is bound to - * this ip_masq. - * assumes that once an ip_masq is bound, - * it will not be unbound during its life. - */ - - if ( (mapp = ms->app) == NULL) - return 0; - - iph = (*skb_p)->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - - /* - * Remember seq number in case this pkt gets resized - */ - - seq = ntohl(th->seq); - - /* - * Fix seq stuff if flagged as so. - */ - - if (ms->protocol == IPPROTO_TCP) { - if (ms->flags & IP_MASQ_F_IN_SEQ) - masq_fix_seq(&ms->in_seq, th); - if (ms->flags & IP_MASQ_F_OUT_SEQ) - masq_fix_ack_seq(&ms->out_seq, th); - } - - /* - * Call private input hook function - */ - - if ( mapp->pkt_in == NULL ) - return 0; - - diff = mapp->pkt_in(mapp, ms, skb_p, maddr); - - /* - * Update ip_masq seq stuff if len has changed. - */ - - if (diff != 0 && ms->protocol == IPPROTO_TCP) - masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff); - - return diff; -} - -/* - * /proc/ip_masq_app entry function - */ - -int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy) -{ - off_t pos=0, begin=0; - int len=0; - struct ip_masq_app * mapp; - unsigned idx; - - if (offset < 40) - len=sprintf(buffer,"%-39s\n", "prot port n_attach name"); - pos = 40; - - for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++) - for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) { - /* - * If you change the length of this sprintf, then all - * the length calculations need fixing too! - * Line length = 40 (3 + 2 + 7 + 1 + 7 + 1 + 2 + 17) - */ - pos += 40; - if (pos < offset) - continue; - - len += sprintf(buffer+len, "%-3s %-7u %-7d %-17s\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), - IP_MASQ_APP_PORT(mapp->type), mapp->n_attach, - mapp->name); - - if(len >= length) - goto done; - } -done: - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - if (len > length) - len = length; - return len; -} - - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_net_ip_masq_app = { - PROC_NET_IP_MASQ_APP, 3, "app", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_masq_app_getinfo -}; -#endif - -/* - * Initialization routine - */ - -__initfunc(int ip_masq_app_init(void)) -{ -#ifdef CONFIG_PROC_FS - ip_masq_proc_register(&proc_net_ip_masq_app); -#endif - return 0; -} - -/* - * Replace a segment (of skb->data) with a new one. - * FIXME: Should re-use same skb if space available, this could - * be done if n_len < o_len, unless some extra space - * were already allocated at driver level :P . - */ - -static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len) -{ - int maxsize, diff, o_offset; - struct sk_buff *n_skb; - int offset; - - maxsize = skb->truesize; - - diff = n_len - o_len; - o_offset = o_buf - (char*) skb->data; - - if (maxsize <= n_len) { - if (diff != 0) { - memcpy(skb->data + o_offset + n_len,o_buf + o_len, - skb->len - (o_offset + o_len)); - } - - memcpy(skb->data + o_offset, n_buf, n_len); - - n_skb = skb; - skb->len = n_len; - skb->end = skb->head+n_len; - } else { - /* - * Sizes differ, make a copy. - * - * FIXME: move this to core/sbuff.c:skb_grow() - */ - - n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri); - if (n_skb == NULL) { - IP_MASQ_ERR("skb_replace(): no room left (from %p)\n", - __builtin_return_address(0)); - return skb; - - } - skb_reserve(n_skb, MAX_HEADER); - skb_put(n_skb, skb->len + diff); - - /* - * Copy as much data from the old skb as possible. Even - * though we're only forwarding packets, we need stuff - * like skb->protocol (PPP driver wants it). - */ - offset = n_skb->data - skb->data; - n_skb->nh.raw = skb->nh.raw + offset; - n_skb->h.raw = skb->h.raw + offset; - n_skb->dev = skb->dev; - n_skb->mac.raw = skb->mac.raw + offset; - n_skb->pkt_type = skb->pkt_type; - n_skb->protocol = skb->protocol; - n_skb->ip_summed = skb->ip_summed; - n_skb->dst = dst_clone(skb->dst); - - /* - * Copy pkt in new buffer - */ - - memcpy(n_skb->data, skb->data, o_offset); - memcpy(n_skb->data + o_offset, n_buf, n_len); - memcpy(n_skb->data + o_offset + n_len, o_buf + o_len, - skb->len - (o_offset + o_len) ); - - /* - * Problem, how to replace the new skb with old one, - * preferably inplace - */ - - kfree_skb(skb); - } - return n_skb; -} - -/* - * calls skb_replace() and update ip header if new skb was allocated - */ - -struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len) -{ - int diff; - struct sk_buff *n_skb; - unsigned skb_len; - - diff = n_len - o_len; - n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len); - skb_len = skb->len; - - if (diff) - { - struct iphdr *iph; - IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len); - /* - * update ip header - */ - iph = n_skb->nh.iph; - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - iph->tot_len = htons(skb_len + diff); - } - return n_skb; -} diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_autofw.c linux/net/ipv4/ip_masq_autofw.c --- v2.3.14/linux/net/ipv4/ip_masq_autofw.c Sun Oct 4 10:21:45 1998 +++ linux/net/ipv4/ip_masq_autofw.c Wed Dec 31 16:00:00 1969 @@ -1,448 +0,0 @@ -/* - * IP_MASQ_AUTOFW auto forwarding module - * - * - * $Id: ip_masq_autofw.c,v 1.3 1998/08/29 23:51:10 davem Exp $ - * - * Author: Richard Lynch - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * Fixes: - * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c - * Juan Jose Ciarlante : modularized - * Juan Jose Ciarlante : use GFP_KERNEL when creating entries - * Juan Jose Ciarlante : call del_timer() when freeing entries (!) - * FIXME: - * - implement refcnt - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IP_AUTOFW_EXPIRE 15*HZ - -/* WARNING: bitwise equal to ip_autofw_user in linux/ip_masq.h */ -struct ip_autofw { - struct ip_autofw * next; - __u16 type; - __u16 low; - __u16 hidden; - __u16 high; - __u16 visible; - __u16 protocol; - __u32 lastcontact; - __u32 where; - __u16 ctlproto; - __u16 ctlport; - __u16 flags; - struct timer_list timer; -}; - -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -/* - * Auto-forwarding table - */ - -static struct ip_autofw * ip_autofw_hosts = NULL; -static struct ip_masq_mod * mmod_self = NULL; - -/* - * Check if a masq entry should be created for a packet - */ - -static __inline__ struct ip_autofw * ip_autofw_check_range (__u32 where, __u16 port, __u16 protocol, int reqact) -{ - struct ip_autofw *af; - af=ip_autofw_hosts; - port=ntohs(port); - while (af) { - if (af->type==IP_FWD_RANGE && - port>=af->low && - port<=af->high && - protocol==af->protocol && - - /* - * It's ok to create masq entries after - * the timeout if we're in insecure mode - */ - (af->flags & IP_AUTOFW_ACTIVE || !reqact || !(af->flags & IP_AUTOFW_SECURE)) && - (!(af->flags & IP_AUTOFW_SECURE) || af->lastcontact==where || !reqact)) - return(af); - af=af->next; - } - return(NULL); -} - -static __inline__ struct ip_autofw * ip_autofw_check_port (__u16 port, __u16 protocol) -{ - struct ip_autofw *af; - af=ip_autofw_hosts; - port=ntohs(port); - while (af) - { - if (af->type==IP_FWD_PORT && port==af->visible && protocol==af->protocol) - return(af); - af=af->next; - } - return(NULL); -} - -static __inline__ struct ip_autofw * ip_autofw_check_direct (__u16 port, __u16 protocol) -{ - struct ip_autofw *af; - af=ip_autofw_hosts; - port=ntohs(port); - while (af) - { - if (af->type==IP_FWD_DIRECT && af->low<=port && af->high>=port) - return(af); - af=af->next; - } - return(NULL); -} - -static __inline__ void ip_autofw_update_out (__u32 who, __u32 where, __u16 port, __u16 protocol) -{ - struct ip_autofw *af; - af=ip_autofw_hosts; - port=ntohs(port); - while (af) - { - if (af->type==IP_FWD_RANGE && af->ctlport==port && af->ctlproto==protocol) - { - if (af->flags & IP_AUTOFW_USETIME) - { - mod_timer(&af->timer, - jiffies+IP_AUTOFW_EXPIRE); - } - af->flags|=IP_AUTOFW_ACTIVE; - af->lastcontact=where; - af->where=who; - } - af=af->next; - } -} - -#if 0 -static __inline__ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol) -{ - struct ip_autofw *af; - af=ip_autofw_check_range(where, port,protocol); - if (af) - { - mod_timer(&af->timer, jiffies+IP_AUTOFW_EXPIRE); - } -} -#endif - - -static __inline__ void ip_autofw_expire(unsigned long data) -{ - struct ip_autofw * af; - af=(struct ip_autofw *) data; - af->flags &= ~IP_AUTOFW_ACTIVE; - af->timer.expires=0; - af->lastcontact=0; - if (af->flags & IP_AUTOFW_SECURE) - af->where=0; -} - - - -static __inline__ int ip_autofw_add(struct ip_autofw_user * af) -{ - struct ip_autofw * newaf; - newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL ); - init_timer(&newaf->timer); - if ( newaf == NULL ) - { - printk("ip_autofw_add: malloc said no\n"); - return( ENOMEM ); - } - - MOD_INC_USE_COUNT; - - memcpy(newaf, af, sizeof(struct ip_autofw_user)); - newaf->timer.data = (unsigned long) newaf; - newaf->timer.function = ip_autofw_expire; - newaf->timer.expires = 0; - newaf->lastcontact=0; - newaf->next=ip_autofw_hosts; - ip_autofw_hosts=newaf; - ip_masq_mod_inc_nent(mmod_self); - return(0); -} - -static __inline__ int ip_autofw_del(struct ip_autofw_user * af) -{ - struct ip_autofw ** af_p, *curr; - - for (af_p=&ip_autofw_hosts, curr=*af_p; (curr=*af_p); af_p = &(*af_p)->next) { - if (af->type == curr->type && - af->low == curr->low && - af->high == curr->high && - af->hidden == curr->hidden && - af->visible == curr->visible && - af->protocol == curr->protocol && - af->where == curr->where && - af->ctlproto == curr->ctlproto && - af->ctlport == curr->ctlport) - { - ip_masq_mod_dec_nent(mmod_self); - *af_p = curr->next; - if (af->flags&IP_AUTOFW_ACTIVE) - del_timer(&curr->timer); - kfree_s(curr,sizeof(struct ip_autofw)); - MOD_DEC_USE_COUNT; - return 0; - } - curr=curr->next; - } - return EINVAL; -} - -static __inline__ int ip_autofw_flush(void) -{ - struct ip_autofw * af; - - while (ip_autofw_hosts) - { - af=ip_autofw_hosts; - ip_masq_mod_dec_nent(mmod_self); - ip_autofw_hosts=ip_autofw_hosts->next; - if (af->flags&IP_AUTOFW_ACTIVE) - del_timer(&af->timer); - kfree_s(af,sizeof(struct ip_autofw)); - MOD_DEC_USE_COUNT; - } - return(0); -} - -/* - * Methods for registered object - */ - -static int autofw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen) -{ - struct ip_autofw_user *af = &mctl->u.autofw_user; - - switch (mctl->m_cmd) { - case IP_MASQ_CMD_ADD: - case IP_MASQ_CMD_INSERT: - if (optlenihl*4]); - /* - * Update any ipautofw entries ... - */ - - ip_autofw_update_out(iph->saddr, iph->daddr, portp[1], iph->protocol); - return IP_MASQ_MOD_NOP; -} - -static struct ip_masq * autofw_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - /* - * If the source port is supposed to match the masq port, then - * make it so - */ - - if (ip_autofw_check_direct(portp[1],iph->protocol)) { - return ip_masq_new(iph->protocol, - maddr, portp[0], - iph->saddr, portp[0], - iph->daddr, portp[1], - 0); - } - return NULL; -} - -#if 0 -static int autofw_in_update(const struct sk_buff *skb, const struct iphdr *iph, __u16 *portp, struct ip_masq *ms) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - ip_autofw_update_in(iph->saddr, portp[1], iph->protocol); - return IP_MASQ_MOD_NOP; -} -#endif - -static int autofw_in_rule(const struct sk_buff *skb, const struct iphdr *iph) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0) - || ip_autofw_check_direct(portp[1], iph->protocol) - || ip_autofw_check_port(portp[1], iph->protocol)); -} - -static struct ip_masq * autofw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - struct ip_autofw *af; - - if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) { - IP_MASQ_DEBUG(1-debug, "autofw_check_range HIT\n"); - return ip_masq_new(iph->protocol, - maddr, portp[1], - af->where, portp[1], - iph->saddr, portp[0], - 0); - } - if ((af=ip_autofw_check_port(portp[1], iph->protocol)) ) { - IP_MASQ_DEBUG(1-debug, "autofw_check_port HIT\n"); - return ip_masq_new(iph->protocol, - maddr, htons(af->visible), - af->where, htons(af->hidden), - iph->saddr, portp[0], - 0); - } - return NULL; -} - -#ifdef CONFIG_PROC_FS -static int autofw_procinfo(char *buffer, char **start, off_t offset, - int length, int unused) -{ - off_t pos=0, begin=0; - struct ip_autofw * af; - int len=0; - - len=sprintf(buffer,"Type Prot Low High Vis Hid Where Last CPto CPrt Timer Flags\n"); - - for(af = ip_autofw_hosts; af ; af = af->next) - { - len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n", - af->type, - af->protocol, - af->low, - af->high, - af->visible, - af->hidden, - ntohl(af->where), - ntohl(af->lastcontact), - af->ctlproto, - af->ctlport, - (af->timer.expirestimer.expires-jiffies), - af->flags); - - pos=begin+len; - if(posoffset+length) - break; - } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -static struct proc_dir_entry autofw_proc_entry = { - 0, 0, NULL, - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - autofw_procinfo -}; - -#define proc_ent &autofw_proc_entry -#else /* !CONFIG_PROC_FS */ - -#define proc_ent NULL -#endif - - -#define autofw_in_update NULL -#define autofw_out_rule NULL -#define autofw_mod_init NULL -#define autofw_mod_done NULL - -static struct ip_masq_mod autofw_mod = { - NULL, /* next */ - NULL, /* next_reg */ - "autofw", /* name */ - ATOMIC_INIT(0), /* nent */ - ATOMIC_INIT(0), /* refcnt */ - proc_ent, - autofw_ctl, - autofw_mod_init, - autofw_mod_done, - autofw_in_rule, - autofw_in_update, - autofw_in_create, - autofw_out_rule, - autofw_out_update, - autofw_out_create, -}; - -__initfunc(int ip_autofw_init(void)) -{ - return register_ip_masq_mod ((mmod_self=&autofw_mod)); -} - -int ip_autofw_done(void) -{ - return unregister_ip_masq_mod(&autofw_mod); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - if (ip_autofw_init() != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - if (ip_autofw_done() != 0) - printk(KERN_INFO "ip_autofw_done(): can't remove module"); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_cuseeme.c linux/net/ipv4/ip_masq_cuseeme.c --- v2.3.14/linux/net/ipv4/ip_masq_cuseeme.c Tue Oct 27 09:57:19 1998 +++ linux/net/ipv4/ip_masq_cuseeme.c Wed Dec 31 16:00:00 1969 @@ -1,264 +0,0 @@ -/* - * IP_MASQ_FTP CUSeeMe masquerading module - * - * - * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $ - * - * Author: Richard Lynch - * - * - * Fixes: - * Richard Lynch : Updated patch to conform to new module - * specifications - * Nigel Metheringham : Multiple port support - * Michael Owings : Fixed broken init code - * Added code to update inbound - * packets with correct local addresses. - * Fixes audio and "chat" problems - * Thanx to the CU-SeeMe Consortium for - * technical docs - * Steven Clarke : Small changes for 2.1 - * - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Multiple Port Support - * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12) - * with the port numbers being defined at module load time. The module - * uses the symbol "ports" to define a list of monitored ports, which can - * be specified on the insmod command line as - * ports=x1,x2,x3... - * where x[n] are integer port numbers. This option can be put into - * /etc/conf.modules (or /etc/modules.conf depending on your config) - * where modload will pick it up should you use modload to load your - * modules. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IP_MASQ_NDEBUG */ -#include - -#pragma pack(1) -/* CU-SeeMe Data Header */ -typedef struct { - u_short dest_family; - u_short dest_port; - u_long dest_addr; - short family; - u_short port; - u_long addr; - u_long seq; - u_short msg; - u_short data_type; - u_short packet_len; -} cu_header; - -/* Open Continue Header */ -typedef struct { - cu_header cu_head; - u_short client_count; /* Number of client info structs */ - u_long seq_no; - char user_name[20]; - char stuff[4]; /* flags, version stuff, etc */ -}oc_header; - -/* client info structures */ -typedef struct { - u_long address; /* Client address */ - char stuff[8]; /* Flags, pruning bitfield, packet counts etc */ -} client_info; -#pragma pack() - -/* - * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper - * First port is set to the default port. - */ -static int ports[MAX_MASQ_APP_PORTS] = {7648}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; - -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); - -static int -masq_cuseeme_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int -masq_cuseeme_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -int -masq_cuseeme_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]); - cu_header *cu_head; - char *data=(char *)&uh[1]; - - if (skb->len - ((unsigned char *) data - skb->h.raw) >= sizeof(cu_header)) - { - cu_head = (cu_header *) data; - /* cu_head->port = ms->mport; */ - if( cu_head->addr ) - cu_head->addr = (u_long) maddr; - if(ntohs(cu_head->data_type) == 257) - IP_MASQ_DEBUG(1-debug, "Sending talk packet!\n"); - } - return 0; -} - -int -masq_cuseeme_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb = *skb_p; - struct iphdr *iph = skb->nh.iph; - struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]); - cu_header *cu_head; - oc_header *oc; - client_info *ci; - char *data=(char *)&uh[1]; - u_short len = skb->len - ((unsigned char *) data - skb->h.raw); - int i, off; - - if (len >= sizeof(cu_header)) - { - cu_head = (cu_header *) data; - if(cu_head->dest_addr) /* Correct destination address */ - cu_head->dest_addr = (u_long) ms->saddr; - if(ntohs(cu_head->data_type)==101 && len > sizeof(oc_header)) - { - oc = (oc_header * ) data; - /* Spin (grovel) thru client_info structs till we find our own */ - off=sizeof(oc_header); - for(i=0; - (i < oc->client_count && off+sizeof(client_info) <= len); - i++) - { - ci=(client_info *)(data+off); - if(ci->address==(u_long) maddr) - { - /* Update w/ our real ip address and exit */ - ci->address = (u_long) ms->saddr; - break; - } - else - off+=sizeof(client_info); - } - } - } - return 0; -} - -struct ip_masq_app ip_masq_cuseeme = { - NULL, /* next */ - "cuseeme", - 0, /* type */ - 0, /* n_attach */ - masq_cuseeme_init_1, /* ip_masq_init_1 */ - masq_cuseeme_done_1, /* ip_masq_done_1 */ - masq_cuseeme_out, /* pkt_out */ - masq_cuseeme_in /* pkt_in */ -}; - - -/* - * ip_masq_cuseeme initialization - */ - -__initfunc(int ip_masq_cuseeme_init(void)) -{ - int i, j; - - for (i=0; (i -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IP_MASQ_NDEBUG */ -#include - - -/* - * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper - * First port is set to the default port. - */ -static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; - -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); - -/* Dummy variable */ -static int masq_ftp_pasv; - -static int -masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int -masq_ftp_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -int -masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *p, *data, *data_limit; - unsigned char p1,p2,p3,p4,p5,p6; - __u32 from; - __u16 port; - struct ip_masq *n_ms; - char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ - unsigned buf_len; - int diff; - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - - data_limit = skb->h.raw + skb->len - 18; - if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0)) - ms->app_data = &masq_ftp_pasv; - - while (data < data_limit) - { - if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) - { - data ++; - continue; - } - p = data+5; - p1 = simple_strtoul(data+5,&data,10); - if (*data!=',') - continue; - p2 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p3 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p4 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p5 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p6 = simple_strtoul(data+1,&data,10); - if (*data!='\r' && *data!='\n') - continue; - - from = (p1<<24) | (p2<<16) | (p3<<8) | p4; - port = (p5<<8) | p6; - - IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port); - - /* - * Now update or create an masquerade entry for it - */ - - IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0); - - n_ms = ip_masq_out_get(iph->protocol, - htonl(from), htons(port), - iph->daddr, 0); - if (!n_ms) { - n_ms = ip_masq_new(IPPROTO_TCP, - maddr, 0, - htonl(from), htons(port), - iph->daddr, 0, - IP_MASQ_F_NO_DPORT); - - if (n_ms==NULL) - return 0; - ip_masq_control_add(n_ms, ms); - } - - /* - * Replace the old PORT with the new one - */ - from = ntohl(n_ms->maddr); - port = ntohs(n_ms->mport); - sprintf(buf,"%d,%d,%d,%d,%d,%d", - from>>24&255,from>>16&255,from>>8&255,from&255, - port>>8&255,port&255); - buf_len = strlen(buf); - - IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port); - - /* - * Calculate required delta-offset to keep TCP happy - */ - - diff = buf_len - (data-p); - - /* - * No shift. - */ - - if (diff==0) { - /* - * simple case, just replace the old PORT cmd - */ - memcpy(p,buf,buf_len); - } else { - - *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); - } - /* - * Move tunnel to listen state - */ - ip_masq_listen(n_ms); - ip_masq_put(n_ms); - - return diff; - - } - return 0; - -} - -/* - * Look at incoming ftp packets to catch the response to a PASV command. When - * we see one we build a masquerading entry for the client address, client port - * 0 (unknown at the moment), the server address and the server port. Mark the - * current masquerade entry as a control channel and point the new entry at the - * control entry. All this work just for ftp keepalive across masquerading. - * - * The incoming packet should be something like - * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)". - * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number. - * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into - * the data so we do the same. If it's good enough for ncftp then it's good - * enough for me. - * - * In this case, the client is the source machine being masqueraded, the server - * is the destination for ftp requests. It all depends on your point of view ... - */ - -int -masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *data, *data_limit; - unsigned char p1,p2,p3,p4,p5,p6; - __u32 to; - __u16 port; - struct ip_masq *n_ms; - - if (ms->app_data != &masq_ftp_pasv) - return 0; /* quick exit if no outstanding PASV */ - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - data_limit = skb->h.raw + skb->len; - - while (data < data_limit && *data != ' ') - ++data; - while (data < data_limit && *data == ' ') - ++data; - data += 22; - if (data >= data_limit || *data != '(') - return 0; - p1 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p2 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p3 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p4 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p5 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p6 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ')') - return 0; - - to = (p1<<24) | (p2<<16) | (p3<<8) | p4; - port = (p5<<8) | p6; - - /* - * Now update or create an masquerade entry for it - */ - IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port); - - n_ms = ip_masq_out_get(iph->protocol, - ms->saddr, 0, - htonl(to), htons(port)); - if (!n_ms) { - n_ms = ip_masq_new(IPPROTO_TCP, - maddr, 0, - ms->saddr, 0, - htonl(to), htons(port), - IP_MASQ_F_NO_SPORT); - - if (n_ms==NULL) - return 0; - ip_masq_control_add(n_ms, ms); - } - -#if 0 /* v0.12 state processing */ - - /* - * keep for a bit longer than tcp_fin, client may not issue open - * to server port before tcp_fin_timeout. - */ - n_ms->timeout = ip_masq_expire->tcp_fin_timeout*3; -#endif - ms->app_data = NULL; - ip_masq_put(n_ms); - - return 0; /* no diff required for incoming packets, thank goodness */ -} - -struct ip_masq_app ip_masq_ftp = { - NULL, /* next */ - "ftp", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_ftp_init_1, /* ip_masq_init_1 */ - masq_ftp_done_1, /* ip_masq_done_1 */ - masq_ftp_out, /* pkt_out */ - masq_ftp_in, /* pkt_in */ -}; - -/* - * ip_masq_ftp initialization - */ - -__initfunc(int ip_masq_ftp_init(void)) -{ - int i, j; - - for (i=0; (i - * Juan Jose Ciarlante : put new ms entry to listen() - * - * FIXME: - * - detect also previous "PRIVMSG" string ?. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Multiple Port Support - * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12) - * with the port numbers being defined at module load time. The module - * uses the symbol "ports" to define a list of monitored ports, which can - * be specified on the insmod command line as - * ports=x1,x2,x3... - * where x[n] are integer port numbers. This option can be put into - * /etc/conf.modules (or /etc/modules.conf depending on your config) - * where modload will pick it up should you use modload to load your - * modules. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper - * First port is set to the default port. - */ -int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); - - -/* - * List of supported DCC protocols - */ - -#define NUM_DCCPROTO 5 - -struct dccproto -{ - char *match; - int matchlen; - int xtra_args; -}; - -struct dccproto dccprotos[NUM_DCCPROTO] = { - { "SEND ", 5, 1 }, - { "CHAT ", 5, 0, }, - { "MOVE ", 5, 1 }, - { "TSEND ", 6, 1, }, - { "SCHAT ", 6, 0, } -}; -#define MAXMATCHLEN 6 - -static int -masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int -masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -int -masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *data, *data_limit; - __u32 s_addr; - __u16 s_port; - struct ip_masq *n_ms; - char buf[20]; /* "m_addr m_port" (dec base)*/ - unsigned buf_len; - int diff; - int xtra_args = 0; /* extra int args wanted after addr */ - char *dcc_p, *addr_beg_p, *addr_end_p; - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - - /* - * Hunt irc DCC string, the _shortest_: - * - * strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26 - * strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27 - * strlen("DCC SEND F AAAAAAAA P S\x01\n")=25 - * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25 - * strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26 - * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25 - * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits) - * P: bound port (min 1 d ) - * F: filename (min 1 d ) - * S: size (min 1 d ) - * 0x01, \n: terminators - */ - - data_limit = skb->h.raw + skb->len; - - while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) ) - { - int i; - if (memcmp(data,"DCC ",4)) { - data ++; - continue; - } - - dcc_p = data; - data += 4; /* point to DCC cmd */ - - for(i=0; i (data_limit-12)) return 0; - - - addr_beg_p = data; - - /* - * client bound address in dec base - */ - - s_addr = simple_strtoul(data,&data,10); - if (*data++ !=' ') - continue; - - /* - * client bound port in dec base - */ - - s_port = simple_strtoul(data,&data,10); - addr_end_p = data; - - /* - * should check args consistency? - */ - - while(xtra_args) { - if (*data != ' ') - break; - data++; - simple_strtoul(data,&data,10); - xtra_args--; - } - - if (xtra_args != 0) continue; - - /* - * terminators. - */ - - if (data[0] != 0x01) - continue; - if (data[1]!='\r' && data[1]!='\n') - continue; - - /* - * Now create an masquerade entry for it - * must set NO_DPORT and NO_DADDR because - * connection is requested by another client. - */ - - n_ms = ip_masq_new(IPPROTO_TCP, - maddr, 0, - htonl(s_addr),htons(s_port), - 0, 0, - IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR); - if (n_ms==NULL) - return 0; - - /* - * Replace the old "address port" with the new one - */ - - buf_len = sprintf(buf,"%lu %u", - ntohl(n_ms->maddr),ntohs(n_ms->mport)); - - /* - * Calculate required delta-offset to keep TCP happy - */ - - diff = buf_len - (addr_end_p-addr_beg_p); - - *addr_beg_p = '\0'; - IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff); - - /* - * No shift. - */ - - if (diff==0) { - /* - * simple case, just copy. - */ - memcpy(addr_beg_p,buf,buf_len); - } else { - - *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, - addr_beg_p, addr_end_p-addr_beg_p, - buf, buf_len); - } - ip_masq_listen(n_ms); - ip_masq_put(n_ms); - return diff; - } - } - } - return 0; - -} - -/* - * Main irc object - * You need 1 object per port in case you need - * to offer also other used irc ports (6665,6666,etc), - * they will share methods but they need own space for - * data. - */ - -struct ip_masq_app ip_masq_irc = { - NULL, /* next */ - "irc", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_irc_init_1, /* init_1 */ - masq_irc_done_1, /* done_1 */ - masq_irc_out, /* pkt_out */ - NULL /* pkt_in */ -}; - -/* - * ip_masq_irc initialization - */ - -__initfunc(int ip_masq_irc_init(void)) -{ - int i, j; - - for (i=0; (ifwmark value - * - * $Id: ip_masq_mfw.c,v 1.5 1999/06/29 12:35:49 davem Exp $ - * - * Author: Juan Jose Ciarlante - * based on Steven Clarke's portfw - * - * Fixes: - * JuanJo Ciarlante: added u-space sched support - * JuanJo Ciarlante: if rport==0, use packet dest port *grin* - * JuanJo Ciarlante: fixed tcp syn&&!ack creation - * - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct ip_masq_mod *mmod_self = NULL; -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -/* - * Lists structure: - * There is a "main" linked list with entries hashed - * by fwmark value (struct ip_masq_mfw, the "m-entries"). - * - * Each of this m-entry holds a double linked list - * of "forward-to" hosts (struct ip_masq_mfw_host, the "m.host"), - * the round-robin scheduling takes place by rotating m.host entries - * "inside" its m-entry. - */ - -/* - * Each forwarded host (addr:port) is stored here - */ -struct ip_masq_mfw_host { - struct list_head list; - __u32 addr; - __u16 port; - __u16 pad0; - __u32 fwmark; - int pref; - atomic_t pref_cnt; -}; - -#define IP_MASQ_MFW_HSIZE 16 -/* - * This entries are indexed by fwmark, - * they hold a list of forwarded addr:port - */ - -struct ip_masq_mfw { - struct ip_masq_mfw *next; /* linked list */ - __u32 fwmark; /* key: firewall mark */ - struct list_head hosts; /* list of forward-to hosts */ - atomic_t nhosts; /* number of "" */ - rwlock_t lock; -}; - - -static DECLARE_MUTEX(mfw_sema); -static rwlock_t mfw_lock = RW_LOCK_UNLOCKED; - -static struct ip_masq_mfw *ip_masq_mfw_table[IP_MASQ_MFW_HSIZE]; - -static __inline__ int mfw_hash_val(int fwmark) -{ - return fwmark & 0x0f; -} - -/* - * Get m-entry by "fwmark" - * Caller must lock tables. - */ - -static struct ip_masq_mfw *__mfw_get(int fwmark) -{ - struct ip_masq_mfw* mfw; - int hash = mfw_hash_val(fwmark); - - for (mfw=ip_masq_mfw_table[hash];mfw;mfw=mfw->next) { - if (mfw->fwmark==fwmark) { - goto out; - } - } -out: - return mfw; -} - -/* - * Links m-entry. - * Caller should have checked if already present for same fwmark - * - * Caller must lock tables. - */ -static int __mfw_add(struct ip_masq_mfw *mfw) -{ - int fwmark = mfw->fwmark; - int hash = mfw_hash_val(fwmark); - - mfw->next = ip_masq_mfw_table[hash]; - ip_masq_mfw_table[hash] = mfw; - ip_masq_mod_inc_nent(mmod_self); - - return 0; -} - -/* - * Creates a m-entry (doesn't link it) - */ - -static struct ip_masq_mfw * mfw_new(int fwmark) -{ - struct ip_masq_mfw *mfw; - - mfw = kmalloc(sizeof(*mfw), GFP_KERNEL); - if (mfw == NULL) - goto out; - - MOD_INC_USE_COUNT; - memset(mfw, 0, sizeof(*mfw)); - mfw->fwmark = fwmark; - mfw->lock = (rwlock_t) RW_LOCK_UNLOCKED; - - INIT_LIST_HEAD(&mfw->hosts); -out: - return mfw; -} - -static void mfw_host_to_user(struct ip_masq_mfw_host *h, struct ip_mfw_user *mu) -{ - mu->raddr = h->addr; - mu->rport = h->port; - mu->fwmark = h->fwmark; - mu->pref = h->pref; -} - -/* - * Creates a m.host (doesn't link it in a m-entry) - */ -static struct ip_masq_mfw_host * mfw_host_new(struct ip_mfw_user *mu) -{ - struct ip_masq_mfw_host * mfw_host; - mfw_host = kmalloc(sizeof (*mfw_host), GFP_KERNEL); - if (!mfw_host) - return NULL; - - MOD_INC_USE_COUNT; - memset(mfw_host, 0, sizeof(*mfw_host)); - mfw_host->addr = mu->raddr; - mfw_host->port = mu->rport; - mfw_host->fwmark = mu->fwmark; - mfw_host->pref = mu->pref; - atomic_set(&mfw_host->pref_cnt, mu->pref); - - return mfw_host; -} - -/* - * Create AND link m.host to m-entry. - * It locks m.lock. - */ -static int mfw_addhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu, int attail) -{ - struct ip_masq_mfw_host *mfw_host; - - mfw_host = mfw_host_new(mu); - if (!mfw_host) - return -ENOMEM; - - write_lock_bh(&mfw->lock); - list_add(&mfw_host->list, attail? mfw->hosts.prev : &mfw->hosts); - atomic_inc(&mfw->nhosts); - write_unlock_bh(&mfw->lock); - - return 0; -} - -/* - * Unlink AND destroy m.host(s) from m-entry. - * Wildcard (nul host or addr) ok. - * It uses m.lock. - */ -static int mfw_delhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu) -{ - - struct list_head *l,*e; - struct ip_masq_mfw_host *h; - int n_del = 0; - l = &mfw->hosts; - - write_lock_bh(&mfw->lock); - for (e=l->next; e!=l; e=e->next) - { - h = list_entry(e, struct ip_masq_mfw_host, list); - if ((!mu->raddr || h->addr == mu->raddr) && - (!mu->rport || h->port == mu->rport)) { - /* HIT */ - atomic_dec(&mfw->nhosts); - list_del(&h->list); - kfree_s(h, sizeof(*h)); - MOD_DEC_USE_COUNT; - n_del++; - } - - } - write_unlock_bh(&mfw->lock); - return n_del? 0 : -ESRCH; -} - -/* - * Changes m.host parameters - * Wildcards ok - * - * Caller must lock tables. - */ -static int __mfw_edithost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu) -{ - - struct list_head *l,*e; - struct ip_masq_mfw_host *h; - int n_edit = 0; - l = &mfw->hosts; - - for (e=l->next; e!=l; e=e->next) - { - h = list_entry(e, struct ip_masq_mfw_host, list); - if ((!mu->raddr || h->addr == mu->raddr) && - (!mu->rport || h->port == mu->rport)) { - /* HIT */ - h->pref = mu->pref; - atomic_set(&h->pref_cnt, mu->pref); - n_edit++; - } - - } - return n_edit? 0 : -ESRCH; -} - -/* - * Destroys m-entry. - * Caller must have checked that it doesn't hold any m.host(s) - */ -static void mfw_destroy(struct ip_masq_mfw *mfw) -{ - kfree_s(mfw, sizeof(*mfw)); - MOD_DEC_USE_COUNT; -} - -/* - * Unlink m-entry. - * - * Caller must lock tables. - */ -static int __mfw_del(struct ip_masq_mfw *mfw) -{ - struct ip_masq_mfw **mfw_p; - int ret = -EINVAL; - - - for(mfw_p=&ip_masq_mfw_table[mfw_hash_val(mfw->fwmark)]; - *mfw_p; - mfw_p = &((*mfw_p)->next)) - { - if (mfw==(*mfw_p)) { - *mfw_p = mfw->next; - ip_masq_mod_dec_nent(mmod_self); - ret = 0; - goto out; - } - } -out: - return ret; -} - -/* - * Crude m.host scheduler - * This interface could be exported to allow playing with - * other sched policies. - * - * Caller must lock m-entry. - */ -static struct ip_masq_mfw_host * __mfw_sched(struct ip_masq_mfw *mfw, int force) -{ - struct ip_masq_mfw_host *h = NULL; - - if (atomic_read(&mfw->nhosts) == 0) - goto out; - - /* - * Here resides actual sched policy: - * When pref_cnt touches 0, entry gets shifted to tail and - * its pref_cnt reloaded from h->pref (actual value - * passed from u-space). - * - * Exception is pref==0: avoid scheduling. - */ - - h = list_entry(mfw->hosts.next, struct ip_masq_mfw_host, list); - - if (atomic_read(&mfw->nhosts) <= 1) - goto out; - - if ((h->pref && atomic_dec_and_test(&h->pref_cnt)) || force) { - atomic_set(&h->pref_cnt, h->pref); - list_del(&h->list); - list_add(&h->list, mfw->hosts.prev); - } -out: - return h; -} - -/* - * Main lookup routine. - * HITs fwmark and schedules m.host entries if required - */ -static struct ip_masq_mfw_host * mfw_lookup(int fwmark) -{ - struct ip_masq_mfw *mfw; - struct ip_masq_mfw_host *h = NULL; - - read_lock(&mfw_lock); - mfw = __mfw_get(fwmark); - - if (mfw) { - write_lock(&mfw->lock); - h = __mfw_sched(mfw, 0); - write_unlock(&mfw->lock); - } - - read_unlock(&mfw_lock); - return h; -} - -#ifdef CONFIG_PROC_FS -static int mfw_procinfo(char *buffer, char **start, off_t offset, - int length, int dummy) -{ - struct ip_masq_mfw *mfw; - struct ip_masq_mfw_host *h; - struct list_head *l,*e; - off_t pos=0, begin; - char temp[129]; - int idx = 0; - int len=0; - - MOD_INC_USE_COUNT; - - IP_MASQ_DEBUG(1-debug, "Entered mfw_info\n"); - - if (offset < 64) - { - sprintf(temp, "FwMark > RAddr RPort PrCnt Pref"); - len = sprintf(buffer, "%-63s\n", temp); - } - pos = 64; - - for(idx = 0; idx < IP_MASQ_MFW_HSIZE; idx++) - { - read_lock(&mfw_lock); - for(mfw = ip_masq_mfw_table[idx]; mfw ; mfw = mfw->next) - { - read_lock_bh(&mfw->lock); - l=&mfw->hosts; - - for(e=l->next;l!=e;e=e->next) { - h = list_entry(e, struct ip_masq_mfw_host, list); - pos += 64; - if (pos <= offset) { - len = 0; - continue; - } - - sprintf(temp,"0x%x > %08lX %5u %5d %5d", - h->fwmark, - ntohl(h->addr), ntohs(h->port), - atomic_read(&h->pref_cnt), h->pref); - len += sprintf(buffer+len, "%-63s\n", temp); - - if(len >= length) { - read_unlock_bh(&mfw->lock); - read_unlock(&mfw_lock); - goto done; - } - } - read_unlock_bh(&mfw->lock); - } - read_unlock(&mfw_lock); - } - -done: - - if (len) { - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - } - if(len>length) - len = length; - MOD_DEC_USE_COUNT; - return len; -} -static struct proc_dir_entry mfw_proc_entry = { -/* 0, 0, NULL", */ - 0, 3, "mfw", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - mfw_procinfo -}; - -#define proc_ent &mfw_proc_entry -#else /* !CONFIG_PROC_FS */ - -#define proc_ent NULL -#endif - - -static void mfw_flush(void) -{ - struct ip_masq_mfw *mfw, *local_table[IP_MASQ_MFW_HSIZE]; - struct ip_masq_mfw_host *h; - struct ip_masq_mfw *mfw_next; - int idx; - struct list_head *l,*e; - - write_lock_bh(&mfw_lock); - memcpy(local_table, ip_masq_mfw_table, sizeof ip_masq_mfw_table); - memset(ip_masq_mfw_table, 0, sizeof ip_masq_mfw_table); - write_unlock_bh(&mfw_lock); - - /* - * For every hash table row ... - */ - for(idx=0;idxhosts; - while((e=l->next) != l) { - h = list_entry(e, struct ip_masq_mfw_host, list); - atomic_dec(&mfw->nhosts); - list_del(&h->list); - kfree_s(h, sizeof(*h)); - MOD_DEC_USE_COUNT; - } - - if (atomic_read(&mfw->nhosts)) { - IP_MASQ_ERR("mfw_flush(): after flushing row nhosts=%d\n", - atomic_read(&mfw->nhosts)); - } - mfw_next = mfw->next; - kfree_s(mfw, sizeof(*mfw)); - MOD_DEC_USE_COUNT; - ip_masq_mod_dec_nent(mmod_self); - } - } -} - -/* - * User space control entry point - */ -static int mfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen) -{ - struct ip_mfw_user *mu = &mctl->u.mfw_user; - struct ip_masq_mfw *mfw; - int ret = EINVAL; - int arglen = optlen - IP_MASQ_CTL_BSIZE; - int cmd; - - - IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n", - arglen, - sizeof (*mu), - optlen, - sizeof (*mctl)); - - /* - * checks ... - */ - if (arglen != sizeof(*mu) && optlen != sizeof(*mctl)) - return -EINVAL; - - /* - * Don't trust the lusers - plenty of error checking! - */ - cmd = mctl->m_cmd; - IP_MASQ_DEBUG(1-debug, "ip_masq_mfw_ctl(cmd=%d, fwmark=%d)\n", - cmd, mu->fwmark); - - - switch(cmd) { - case IP_MASQ_CMD_NONE: - return 0; - case IP_MASQ_CMD_FLUSH: - break; - case IP_MASQ_CMD_ADD: - case IP_MASQ_CMD_INSERT: - case IP_MASQ_CMD_SET: - if (mu->fwmark == 0) { - IP_MASQ_DEBUG(1-debug, "invalid fwmark==0\n"); - return -EINVAL; - } - if (mu->pref < 0) { - IP_MASQ_DEBUG(1-debug, "invalid pref==%d\n", - mu->pref); - return -EINVAL; - } - break; - } - - - ret = -EINVAL; - - switch(cmd) { - case IP_MASQ_CMD_ADD: - case IP_MASQ_CMD_INSERT: - if (!mu->raddr) { - IP_MASQ_DEBUG(0-debug, "ip_masq_mfw_ctl(ADD): invalid redirect 0x%x:%d\n", - mu->raddr, mu->rport); - goto out; - } - - /* - * Cannot just use mfw_lock because below - * are allocations that can sleep; so - * to assure "new entry" atomic creation - * I use a semaphore. - * - */ - down(&mfw_sema); - - read_lock(&mfw_lock); - mfw = __mfw_get(mu->fwmark); - read_unlock(&mfw_lock); - - /* - * If first host, create m-entry - */ - if (mfw == NULL) { - mfw = mfw_new(mu->fwmark); - if (mfw == NULL) - ret = -ENOMEM; - } - - if (mfw) { - /* - * Put m.host in m-entry. - */ - ret = mfw_addhost(mfw, mu, cmd == IP_MASQ_CMD_ADD); - - /* - * If first host, link m-entry to hash table. - * Already protected by global lock. - */ - if (ret == 0 && atomic_read(&mfw->nhosts) == 1) { - write_lock_bh(&mfw_lock); - __mfw_add(mfw); - write_unlock_bh(&mfw_lock); - } - if (atomic_read(&mfw->nhosts) == 0) { - mfw_destroy(mfw); - } - } - - up(&mfw_sema); - - break; - - case IP_MASQ_CMD_DEL: - down(&mfw_sema); - - read_lock(&mfw_lock); - mfw = __mfw_get(mu->fwmark); - read_unlock(&mfw_lock); - - if (mfw) { - ret = mfw_delhost(mfw, mu); - - /* - * Last lease will free - * XXX check logic XXX - */ - if (atomic_read(&mfw->nhosts) == 0) { - write_lock_bh(&mfw_lock); - __mfw_del(mfw); - write_unlock_bh(&mfw_lock); - mfw_destroy(mfw); - } - } else - ret = -ESRCH; - - up(&mfw_sema); - break; - case IP_MASQ_CMD_FLUSH: - - down(&mfw_sema); - mfw_flush(); - up(&mfw_sema); - ret = 0; - break; - case IP_MASQ_CMD_SET: - /* - * No need to semaphorize here, main list is not - * modified. - */ - read_lock(&mfw_lock); - - mfw = __mfw_get(mu->fwmark); - if (mfw) { - write_lock_bh(&mfw->lock); - - if (mu->flags & IP_MASQ_MFW_SCHED) { - struct ip_masq_mfw_host *h; - if ((h=__mfw_sched(mfw, 1))) { - mfw_host_to_user(h, mu); - ret = 0; - } - } else { - ret = __mfw_edithost(mfw, mu); - } - - write_unlock_bh(&mfw->lock); - } - - read_unlock(&mfw_lock); - break; - } -out: - - return ret; -} - -/* - * Module stubs called from ip_masq core module - */ - -/* - * Input rule stub, called very early for each incoming packet, - * to see if this module has "interest" in packet. - */ -static int mfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph) -{ - int val; - read_lock(&mfw_lock); - val = ( __mfw_get(skb->fwmark) != 0); - read_unlock(&mfw_lock); - return val; -} - -/* - * Input-create stub, called to allow "custom" masq creation - */ -static struct ip_masq * mfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - union ip_masq_tphdr tph; - struct ip_masq *ms = NULL; - struct ip_masq_mfw_host *h = NULL; - - tph.raw = (char*) iph + iph->ihl * 4; - - switch (iph->protocol) { - case IPPROTO_TCP: - /* - * Only open TCP tunnel if SYN+!ACK packet - */ - if (!tph.th->syn && tph.th->ack) - return NULL; - case IPPROTO_UDP: - break; - default: - return NULL; - } - - /* - * If no entry exists in the masquerading table - * and the port is involved - * in port forwarding, create a new masq entry - */ - - if ((h=mfw_lookup(skb->fwmark))) { - ms = ip_masq_new(iph->protocol, - iph->daddr, tph.portp[1], - /* if no redir-port, use packet dest port */ - h->addr, h->port? h->port : tph.portp[1], - iph->saddr, tph.portp[0], - 0); - - if (ms != NULL) - ip_masq_listen(ms); - } - return ms; -} - - -#define mfw_in_update NULL -#define mfw_out_rule NULL -#define mfw_out_create NULL -#define mfw_out_update NULL - -static struct ip_masq_mod mfw_mod = { - NULL, /* next */ - NULL, /* next_reg */ - "mfw", /* name */ - ATOMIC_INIT(0), /* nent */ - ATOMIC_INIT(0), /* refcnt */ - proc_ent, - mfw_ctl, - NULL, /* masq_mod_init */ - NULL, /* masq_mod_done */ - mfw_in_rule, - mfw_in_update, - mfw_in_create, - mfw_out_rule, - mfw_out_update, - mfw_out_create, -}; - - -__initfunc(int ip_mfw_init(void)) -{ - return register_ip_masq_mod ((mmod_self=&mfw_mod)); -} - -int ip_mfw_done(void) -{ - return unregister_ip_masq_mod(&mfw_mod); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - if (ip_mfw_init() != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - if (ip_mfw_done() != 0) - printk(KERN_INFO "can't remove module"); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c --- v2.3.14/linux/net/ipv4/ip_masq_mod.c Tue Jun 29 09:22:08 1999 +++ linux/net/ipv4/ip_masq_mod.c Wed Dec 31 16:00:00 1969 @@ -1,322 +0,0 @@ -/* - * IP_MASQ_MOD masq modules support - * - * - * Author: Juan Jose Ciarlante, - * - * $Id: ip_masq_mod.c,v 1.6 1999/06/29 12:35:51 davem Exp $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * Cyrus Durgin: fixed kerneld stuff for kmod. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef CONFIG_KMOD -#include -#endif - -EXPORT_SYMBOL(register_ip_masq_mod); -EXPORT_SYMBOL(unregister_ip_masq_mod); -EXPORT_SYMBOL(ip_masq_mod_lkp_link); -EXPORT_SYMBOL(ip_masq_mod_lkp_unlink); - -static spinlock_t masq_mod_lock = SPIN_LOCK_UNLOCKED; - -/* - * Base pointer for registered modules - */ -struct ip_masq_mod * ip_masq_mod_reg_base = NULL; - -/* - * Base pointer for lookup (subset of above, a module could be - * registered, but it could have no active rule); will avoid - * unnecessary lookups. - */ -struct ip_masq_mod * ip_masq_mod_lkp_base = NULL; - -int ip_masq_mod_register_proc(struct ip_masq_mod *mmod) -{ -#ifdef CONFIG_PROC_FS - int ret; - - struct proc_dir_entry *ent = mmod->mmod_proc_ent; - - if (!ent) - return 0; - if (!ent->name) { - ent->name = mmod->mmod_name; - ent->namelen = strlen (mmod->mmod_name); - } - ret = ip_masq_proc_register(ent); - if (ret) mmod->mmod_proc_ent = NULL; - - return ret; -#else - return 0; -#endif -} - -void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent = mmod->mmod_proc_ent; - if (!ent) - return; - ip_masq_proc_unregister(ent); -#endif -} - -/* - * Link/unlink object for lookups - */ - -int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod) -{ - struct ip_masq_mod **mmod_p; - - write_lock_bh(&masq_mod_lock); - - for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next) - if (mmod == (*mmod_p)) { - *mmod_p = mmod->next; - mmod->next = NULL; - write_unlock_bh(&masq_mod_lock); - return 0; - } - - write_unlock_bh(&masq_mod_lock); - return -EINVAL; -} - -int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod) -{ - write_lock_bh(&masq_mod_lock); - - mmod->next = ip_masq_mod_lkp_base; - ip_masq_mod_lkp_base=mmod; - - write_unlock_bh(&masq_mod_lock); - return 0; -} - -int register_ip_masq_mod(struct ip_masq_mod *mmod) -{ - if (!mmod) { - IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n"); - return -EINVAL; - } - if (!mmod->mmod_name) { - IP_MASQ_ERR("register_ip_masq_mod(): NULL mmod_name\n"); - return -EINVAL; - } - ip_masq_mod_register_proc(mmod); - - mmod->next_reg = ip_masq_mod_reg_base; - ip_masq_mod_reg_base=mmod; - - return 0; -} - -int unregister_ip_masq_mod(struct ip_masq_mod *mmod) -{ - struct ip_masq_mod **mmod_p; - - if (!mmod) { - IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n"); - return -EINVAL; - } - - /* - * Only allow unregistration if it is not referenced - */ - if (atomic_read(&mmod->refcnt)) { - IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n", - atomic_read(&mmod->refcnt)); - return -EINVAL; - } - - /* - * Must be already unlinked from lookup list - */ - if (mmod->next) { - IP_MASQ_WARNING("MASQ: unregistering \"%s\" while in lookup list.fixed.", - mmod->mmod_name); - ip_masq_mod_lkp_unlink(mmod); - } - - for (mmod_p = &ip_masq_mod_reg_base; *mmod_p ; mmod_p = &(*mmod_p)->next_reg) - if (mmod == (*mmod_p)) { - ip_masq_mod_unregister_proc(mmod); - *mmod_p = mmod->next_reg; - return 0; - } - - IP_MASQ_ERR("unregister_ip_masq_mod(%s): not linked \n", mmod->mmod_name); - return -EINVAL; -} - -int ip_masq_mod_in_rule(const struct sk_buff *skb, const struct iphdr *iph) -{ - struct ip_masq_mod *mmod; - int ret = IP_MASQ_MOD_NOP; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_in_rule) continue; - switch (ret=mmod->mmod_in_rule(skb, iph)) { - case IP_MASQ_MOD_NOP: - continue; - case IP_MASQ_MOD_ACCEPT: - case IP_MASQ_MOD_REJECT: - goto out; - } - } -out: - return ret; -} - -int ip_masq_mod_out_rule(const struct sk_buff *skb, const struct iphdr *iph) -{ - struct ip_masq_mod *mmod; - int ret = IP_MASQ_MOD_NOP; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_out_rule) continue; - switch (ret=mmod->mmod_out_rule(skb, iph)) { - case IP_MASQ_MOD_NOP: - continue; - case IP_MASQ_MOD_ACCEPT: - case IP_MASQ_MOD_REJECT: - goto out; - } - } -out: - return ret; -} - -struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - struct ip_masq_mod *mmod; - struct ip_masq *ms = NULL; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_in_create) continue; - if ((ms=mmod->mmod_in_create(skb, iph, maddr))) { - goto out; - } - } -out: - return ms; -} - -struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - struct ip_masq_mod *mmod; - struct ip_masq *ms = NULL; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_out_create) continue; - if ((ms=mmod->mmod_out_create(skb, iph, maddr))) { - goto out; - } - } -out: - return ms; -} - -int ip_masq_mod_in_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms) -{ - struct ip_masq_mod *mmod; - int ret = IP_MASQ_MOD_NOP; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_in_update) continue; - switch (ret=mmod->mmod_in_update(skb, iph, ms)) { - case IP_MASQ_MOD_NOP: - continue; - case IP_MASQ_MOD_ACCEPT: - case IP_MASQ_MOD_REJECT: - goto out; - } - } -out: - return ret; -} - -int ip_masq_mod_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms) -{ - struct ip_masq_mod *mmod; - int ret = IP_MASQ_MOD_NOP; - - for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) { - if (!mmod->mmod_out_update) continue; - switch (ret=mmod->mmod_out_update(skb, iph, ms)) { - case IP_MASQ_MOD_NOP: - continue; - case IP_MASQ_MOD_ACCEPT: - case IP_MASQ_MOD_REJECT: - goto out; - } - } -out: - return ret; -} - -struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name) -{ - struct ip_masq_mod * mmod; - - IP_MASQ_DEBUG(1, "searching mmod_name \"%s\"\n", mmod_name); - - for (mmod=ip_masq_mod_reg_base; mmod ; mmod=mmod->next_reg) { - if (mmod->mmod_ctl && *(mmod_name) - && (strcmp(mmod_name, mmod->mmod_name)==0)) { - /* HIT */ - return mmod; - } - } - return NULL; -} - -/* - * Module control entry - */ -int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *mctl, int optlen) -{ - struct ip_masq_mod * mmod; -#ifdef CONFIG_KMOD - char kmod_name[IP_MASQ_TNAME_MAX+8]; -#endif - /* tappo */ - mctl->m_tname[IP_MASQ_TNAME_MAX-1] = 0; - - mmod = ip_masq_mod_getbyname(mctl->m_tname); - if (mmod) - return mmod->mmod_ctl(optname, mctl, optlen); -#ifdef CONFIG_KMOD - sprintf(kmod_name,"ip_masq_%s", mctl->m_tname); - - IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name); - - /* - * Let sleep for a while ... - */ - request_module(kmod_name); - mmod = ip_masq_mod_getbyname(mctl->m_tname); - if (mmod) - return mmod->mmod_ctl(optname, mctl, optlen); -#endif - return ESRCH; -} diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_portfw.c linux/net/ipv4/ip_masq_portfw.c --- v2.3.14/linux/net/ipv4/ip_masq_portfw.c Tue Jun 29 09:22:08 1999 +++ linux/net/ipv4/ip_masq_portfw.c Wed Dec 31 16:00:00 1969 @@ -1,508 +0,0 @@ -/* - * IP_MASQ_PORTFW masquerading module - * - * - * $Id: ip_masq_portfw.c,v 1.4 1999/06/29 12:35:53 davem Exp $ - * - * Author: Steven Clarke - * - * Fixes: - * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c - * Juan Jose Ciarlante : modularized - * Juan Jose Ciarlante : use GFP_KERNEL - * Juan Jose Ciarlante : locking - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IP_PORTFW_PORT_MIN 1 -#define IP_PORTFW_PORT_MAX 60999 - -struct ip_portfw { - struct list_head list; - __u32 laddr, raddr; - __u16 lport, rport; - atomic_t pref_cnt; /* pref "counter" down to 0 */ - int pref; /* user set pref */ -}; - -static struct ip_masq_mod *mmod_self = NULL; -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -/* - * Lock - */ -static spinlock_t portfw_lock = SPIN_LOCK_UNLOCKED; - -static struct list_head portfw_list[2]; -static __inline__ int portfw_idx(int protocol) -{ - return (protocol==IPPROTO_TCP); -} - -/* - * - * Delete forwarding entry(s): - * called from _DEL, u-space. - * . "relaxed" match, except for lport - * - */ - -static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr) -{ - int prot = portfw_idx(protocol); - struct ip_portfw *n; - struct list_head *entry; - struct list_head *list = &portfw_list[prot]; - int nent; - - nent = atomic_read(&mmod_self->mmod_nent); - - write_lock_bh(&portfw_lock); - - for (entry=list->next;entry != list;entry = entry->next) { - n = list_entry(entry, struct ip_portfw, list); - if (n->lport == lport && - (!laddr || n->laddr == laddr) && - (!raddr || n->raddr == raddr) && - (!rport || n->rport == rport)) { - list_del(entry); - ip_masq_mod_dec_nent(mmod_self); - kfree_s(n, sizeof(struct ip_portfw)); - MOD_DEC_USE_COUNT; - } - } - write_unlock_bh(&portfw_lock); - - return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0; -} - -/* - * Flush tables - * called from _FLUSH, u-space. - */ -static __inline__ void ip_portfw_flush(void) -{ - int prot; - struct list_head *l; - struct list_head *e; - struct ip_portfw *n; - - write_lock_bh(&portfw_lock); - - for (prot = 0; prot < 2;prot++) { - l = &portfw_list[prot]; - while((e=l->next) != l) { - ip_masq_mod_dec_nent(mmod_self); - n = list_entry (e, struct ip_portfw, list); - list_del(e); - kfree_s(n, sizeof (*n)); - MOD_DEC_USE_COUNT; - } - } - - write_unlock_bh(&portfw_lock); -} - -/* - * Lookup routine for lport,laddr match - * must be called with locked tables - */ -static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p) -{ - int prot = portfw_idx(protocol); - - struct ip_portfw *n = NULL; - struct list_head *l, *e; - - l = &portfw_list[prot]; - - for (e=l->next;e!=l;e=e->next) { - n = list_entry(e, struct ip_portfw, list); - if (lport == n->lport && laddr == n->laddr) { - /* Please be nice, don't pass only a NULL dport */ - if (daddr_p) { - *daddr_p = n->raddr; - *dport_p = n->rport; - } - - goto out; - } - } - n = NULL; -out: - return n; -} - -/* - * Edit routine for lport,[laddr], [raddr], [rport] match - * By now, only called from u-space - */ -static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref) -{ - int prot = portfw_idx(protocol); - - struct ip_portfw *n = NULL; - struct list_head *l, *e; - int count = 0; - - - read_lock_bh(&portfw_lock); - - l = &portfw_list[prot]; - - for (e=l->next;e!=l;e=e->next) { - n = list_entry(e, struct ip_portfw, list); - if (lport == n->lport && - (!laddr || laddr == n->laddr) && - (!rport || rport == n->rport) && - (!raddr || raddr == n->raddr)) { - n->pref = pref; - atomic_set(&n->pref_cnt, pref); - count++; - } - } - - read_unlock_bh(&portfw_lock); - - return count; -} - -/* - * Add/edit en entry - * called from _ADD, u-space. - * must return 0 or +errno - */ -static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref) -{ - struct ip_portfw *npf; - int prot = portfw_idx(protocol); - - if (pref <= 0) - return EINVAL; - - if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) { - /* - * Edit ok ... - */ - return 0; - } - - /* may block ... */ - npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL); - - if (!npf) - return ENOMEM; - - MOD_INC_USE_COUNT; - memset(npf, 0, sizeof(*npf)); - - npf->laddr = laddr; - npf->lport = lport; - npf->rport = rport; - npf->raddr = raddr; - npf->pref = pref; - - atomic_set(&npf->pref_cnt, npf->pref); - INIT_LIST_HEAD(&npf->list); - - write_lock_bh(&portfw_lock); - - /* - * Add at head - */ - list_add(&npf->list, &portfw_list[prot]); - - write_unlock_bh(&portfw_lock); - - ip_masq_mod_inc_nent(mmod_self); - return 0; -} - - - -static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen) -{ - struct ip_portfw_user *mm = &mctl->u.portfw_user; - int ret = EINVAL; - int arglen = optlen - IP_MASQ_CTL_BSIZE; - int cmd; - - - IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n", - arglen, - sizeof (*mm), - optlen, - sizeof (*mctl)); - - /* - * Yes, I'm a bad guy ... - */ - if (arglen != sizeof(*mm) && optlen != sizeof(*mctl)) - return EINVAL; - - /* - * Don't trust the lusers - plenty of error checking! - */ - cmd = mctl->m_cmd; - IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd); - - - switch (cmd) { - case IP_MASQ_CMD_NONE: - return 0; - case IP_MASQ_CMD_FLUSH: - break; - default: - if (htons(mm->lport) < IP_PORTFW_PORT_MIN || htons(mm->lport) > IP_PORTFW_PORT_MAX) - return EINVAL; - - if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP) - return EINVAL; - } - - switch(cmd) { - case IP_MASQ_CMD_ADD: - ret = ip_portfw_add(mm->protocol, - mm->lport, mm->laddr, - mm->rport, mm->raddr, - mm->pref); - break; - - case IP_MASQ_CMD_DEL: - ret = ip_portfw_del(mm->protocol, - mm->lport, mm->laddr, - mm->rport, mm->raddr); - break; - case IP_MASQ_CMD_FLUSH: - ip_portfw_flush(); - ret = 0; - break; - } - - - return ret; -} - - - - -#ifdef CONFIG_PROC_FS - -static int portfw_procinfo(char *buffer, char **start, off_t offset, - int length, int unused) -{ - off_t pos=0, begin; - struct ip_portfw *pf; - struct list_head *l, *e; - char temp[65]; - int ind; - int len=0; - - - if (offset < 64) - { - sprintf(temp, "Prot LAddr LPort > RAddr RPort PrCnt Pref"); - len = sprintf(buffer, "%-63s\n", temp); - } - pos = 64; - - read_lock_bh(&portfw_lock); - - for(ind = 0; ind < 2; ind++) - { - l = &portfw_list[ind]; - for (e=l->next; e!=l; e=e->next) - { - pf = list_entry(e, struct ip_portfw, list); - pos += 64; - if (pos <= offset) { - len = 0; - continue; - } - - sprintf(temp,"%s %08lX %5u > %08lX %5u %5d %5d", - ind ? "TCP" : "UDP", - ntohl(pf->laddr), ntohs(pf->lport), - ntohl(pf->raddr), ntohs(pf->rport), - atomic_read(&pf->pref_cnt), pf->pref); - len += sprintf(buffer+len, "%-63s\n", temp); - - if (len >= length) - goto done; - } - } -done: - read_unlock_bh(&portfw_lock); - - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - if(len>length) - len = length; - return len; -} - -static struct proc_dir_entry portfw_proc_entry = { -/* 0, 0, NULL", */ - 0, 6, "portfw", /* Just for compatibility, for now ... */ - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - portfw_procinfo -}; - -#define proc_ent &portfw_proc_entry -#else /* !CONFIG_PROC_FS */ - -#define proc_ent NULL -#endif - -static int portfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph) -{ - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); -#ifdef CONFIG_IP_MASQ_DEBUG - struct rtable *rt = (struct rtable *)skb->dst; -#endif - struct ip_portfw *pfw; - - IP_MASQ_DEBUG(2, "portfw_in_rule(): skb:= dev=%s (index=%d), rt_iif=%d, rt_flags=0x%x rt_dev___=%s daddr=%d.%d.%d.%d dport=%d\n", - skb->dev->name, skb->dev->ifindex, rt->rt_iif, rt->rt_flags, - rt->u.dst.dev->name, - NIPQUAD(iph->daddr), ntohs(portp[1])); - - read_lock(&portfw_lock); - pfw = ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL); - read_unlock(&portfw_lock); - return (pfw!=0); -} - -static struct ip_masq * portfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr) -{ - /* - * If no entry exists in the masquerading table - * and the port is involved - * in port forwarding, create a new masq entry - */ - - __u32 raddr; - __u16 rport; - const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); - struct ip_masq *ms = NULL; - struct ip_portfw *pf; - - /* - * Lock for writing. - */ - write_lock(&portfw_lock); - - if ((pf=ip_portfw_lookup(iph->protocol, - portp[1], iph->daddr, - &raddr, &rport))) { - ms = ip_masq_new(iph->protocol, - iph->daddr, portp[1], - raddr, rport, - iph->saddr, portp[0], - 0); - ip_masq_listen(ms); - - if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1 - /* || ip_masq_nlocks(&portfw_lock) != 1 */ ) - /* - * Maybe later... - */ - goto out; - - /* - * Entry created, lock==1. - * if pref_cnt == 0, move - * entry at _tail_. - * This is a simple load balance scheduling - */ - - if (atomic_dec_and_test(&pf->pref_cnt)) { - - atomic_set(&pf->pref_cnt, pf->pref); - list_del(&pf->list); - list_add(&pf->list, - portfw_list[portfw_idx(iph->protocol)].prev); - - } - } -out: - write_unlock(&portfw_lock); - return ms; -} - -#define portfw_in_update NULL -#define portfw_out_rule NULL -#define portfw_out_create NULL -#define portfw_out_update NULL - -static struct ip_masq_mod portfw_mod = { - NULL, /* next */ - NULL, /* next_reg */ - "portfw", /* name */ - ATOMIC_INIT(0), /* nent */ - ATOMIC_INIT(0), /* refcnt */ - proc_ent, - portfw_ctl, - NULL, /* masq_mod_init */ - NULL, /* masq_mod_done */ - portfw_in_rule, - portfw_in_update, - portfw_in_create, - portfw_out_rule, - portfw_out_update, - portfw_out_create, -}; - - - -__initfunc(int ip_portfw_init(void)) -{ - INIT_LIST_HEAD(&portfw_list[0]); - INIT_LIST_HEAD(&portfw_list[1]); - return register_ip_masq_mod ((mmod_self=&portfw_mod)); -} - -int ip_portfw_done(void) -{ - return unregister_ip_masq_mod(&portfw_mod); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - if (ip_portfw_init() != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - if (ip_portfw_done() != 0) - printk(KERN_INFO "ip_portfw_done(): can't remove module"); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_quake.c linux/net/ipv4/ip_masq_quake.c --- v2.3.14/linux/net/ipv4/ip_masq_quake.c Tue Jun 1 23:25:48 1999 +++ linux/net/ipv4/ip_masq_quake.c Wed Dec 31 16:00:00 1969 @@ -1,324 +0,0 @@ -/* - * IP_MASQ_QUAKE quake masquerading module - * - * - * Version: @(#)ip_masq_quake.c 0.02 22/02/97 - * - * Author: Harald Hoyer mailto:HarryH@Royal.Net - * - * - * Fixes: - * Harald Hoyer : Unofficial Quake Specs found at - * http://www.gamers.org/dEngine/quake/spec/ - * Harald Hoyer : Check for QUAKE-STRING - * Juan Jose Ciarlante : litl bits for 2.1 - * Horst von Brand : Add #include - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_CONFIG_IP_MASQ_QUAKE 0 - -typedef struct -{ - __u16 type; // (Little Endian) Type of message. - __u16 length; // (Little Endian) Length of message, header included. - char message[0]; // The contents of the message. -} QUAKEHEADER; - -struct quake_priv_data { - /* Have we seen a client connect message */ - signed char cl_connect; -}; - -static int -masq_quake_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - if ((ms->app_data = kmalloc(sizeof(struct quake_priv_data), - GFP_ATOMIC)) == NULL) - printk(KERN_INFO "Quake: No memory for application data\n"); - else - { - struct quake_priv_data *priv = - (struct quake_priv_data *)ms->app_data; - priv->cl_connect = 0; - } - return 0; -} - -static int -masq_quake_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - if (ms->app_data) - kfree_s(ms->app_data, sizeof(struct quake_priv_data)); - return 0; -} - -int -masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct udphdr *uh; - QUAKEHEADER *qh; - __u16 udp_port; - char *data; - unsigned char code; - struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data; - - if(priv->cl_connect == -1) - return 0; - - skb = *skb_p; - - iph = skb->nh.iph; - uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]); - - /* Check for lenght */ - if(ntohs(uh->len) < 5) - return 0; - - qh = (QUAKEHEADER *)&uh[1]; - - if(qh->type != 0x0080) - return 0; - - - code = qh->message[0]; - -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_in: code = %d \n", (int)code); -#endif - - switch(code) { - case 0x01: - /* Connection Request */ - - if(ntohs(qh->length) < 0x0c) { -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_in: length < 0xc \n"); -#endif - return 0; - } - - data = &qh->message[1]; - - /* Check for stomping string */ - if(memcmp(data,"QUAKE\0\3",7)) { -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: memcmp failed \n"); -#endif - return 0; - } - else { - priv->cl_connect = 1; -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: memcmp ok \n"); -#endif - } - break; - - case 0x81: - /* Accept Connection */ - if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0)) - return 0; - data = &qh->message[1]; - - memcpy(&udp_port, data, 2); - - ms->dport = htons(udp_port); - -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_in: in_rewrote UDP port %d \n", udp_port); -#endif - priv->cl_connect = -1; - - break; - } - - return 0; -} - -int -masq_quake_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct udphdr *uh; - QUAKEHEADER *qh; - __u16 udp_port; - char *data; - unsigned char code; - struct ip_masq *n_ms; - struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data; - - if(priv->cl_connect == -1) - return 0; - - skb = *skb_p; - - iph = skb->nh.iph; - uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]); - - /* Check for lenght */ - if(ntohs(uh->len) < 5) - return 0; - - qh = (QUAKEHEADER *)&uh[1]; - -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: qh->type = %d \n", (int)qh->type); -#endif - - if(qh->type != 0x0080) - return 0; - - code = qh->message[0]; - -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: code = %d \n", (int)code); -#endif - - switch(code) { - case 0x01: - /* Connection Request */ - - if(ntohs(qh->length) < 0x0c) { -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: length < 0xc \n"); -#endif - return 0; - } - - data = &qh->message[1]; - - /* Check for stomping string */ - if(memcmp(data,"QUAKE\0\3",7)) { -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: memcmp failed \n"); -#endif - return 0; - } - else { - priv->cl_connect = 1; -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: memcmp ok \n"); -#endif - } - break; - - case 0x81: - /* Accept Connection */ - if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0)) - return 0; - - data = &qh->message[1]; - - memcpy(&udp_port, data, 2); - - n_ms = ip_masq_new(IPPROTO_UDP, - maddr, 0, - ms->saddr, htons(udp_port), - ms->daddr, ms->dport, - 0); - - if (n_ms==NULL) - return 0; - -#if DEBUG_CONFIG_IP_MASQ_QUAKE - printk("Quake_out: out_rewrote UDP port %d -> %d\n", - udp_port, ntohs(n_ms->mport)); -#endif - udp_port = ntohs(n_ms->mport); - memcpy(data, &udp_port, 2); - - ip_masq_listen(n_ms); - ip_masq_control_add(n_ms, ms); - ip_masq_put(n_ms); - - break; - } - - return 0; -} - -struct ip_masq_app ip_masq_quake = { - NULL, /* next */ - "Quake_26", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_quake_init_1, /* ip_masq_init_1 */ - masq_quake_done_1, /* ip_masq_done_1 */ - masq_quake_out, /* pkt_out */ - masq_quake_in /* pkt_in */ -}; -struct ip_masq_app ip_masq_quakenew = { - NULL, /* next */ - "Quake_27", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_quake_init_1, /* ip_masq_init_1 */ - masq_quake_done_1, /* ip_masq_done_1 */ - masq_quake_out, /* pkt_out */ - masq_quake_in /* pkt_in */ -}; - -/* - * ip_masq_quake initialization - */ - -__initfunc(int ip_masq_quake_init(void)) -{ - return (register_ip_masq_app(&ip_masq_quake, IPPROTO_UDP, 26000) + - register_ip_masq_app(&ip_masq_quakenew, IPPROTO_UDP, 27000)); -} - -/* - * ip_masq_quake fin. - */ - -int ip_masq_quake_done(void) -{ - return (unregister_ip_masq_app(&ip_masq_quake) + - unregister_ip_masq_app(&ip_masq_quakenew)); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - if (ip_masq_quake_init() != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - if (ip_masq_quake_done() != 0) - printk("ip_masq_quake: can't remove module"); -} - -#endif /* MODULE */ - - diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c --- v2.3.14/linux/net/ipv4/ip_masq_raudio.c Tue Oct 27 09:57:19 1998 +++ linux/net/ipv4/ip_masq_raudio.c Wed Dec 31 16:00:00 1969 @@ -1,578 +0,0 @@ -/* - * IP_MASQ_RAUDIO - Real Audio masquerading module - * - * - * Version: @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $ - * - * Author: Nigel Metheringham - * Real Time Streaming code by Progressive Networks - * [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne] - * [Real Audio information taken from Progressive Networks firewall docs] - * [Kudos to Progressive Networks for making the protocol specs available] - * - * - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * Limitations - * The IP Masquerading proxies at present do not have access to a processed - * data stream. Hence for a protocol like the Real Audio control protocol, - * which depends on knowing where you are in the data stream, you either - * to keep a *lot* of state in your proxy, or you cheat and simplify the - * problem [needless to say I did the latter]. - * - * This proxy only handles data in the first packet. Everything else is - * passed transparently. This means it should work under all normal - * circumstances, but it could be fooled by new data formats or a - * malicious application! - * - * At present the "first packet" is defined as a packet starting with - * the protocol ID string - "PNA". - * When the link is up there appears to be enough control data - * crossing the control link to keep it open even if a long audio - * piece is playing. - * - * The Robust UDP support added in RealAudio 3.0 is supported, but due - * to servers/clients not making great use of this has not been greatly - * tested. RealVideo (as used in the Real client version 4.0beta1) is - * supported but again is not greatly tested (bandwidth requirements - * appear to exceed that available at the sites supporting the protocol). - * - * Multiple Port Support - * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12) - * with the port numbers being defined at module load time. The module - * uses the symbol "ports" to define a list of monitored ports, which can - * be specified on the insmod command line as - * ports=x1,x2,x3... - * where x[n] are integer port numbers. This option can be put into - * /etc/conf.modules (or /etc/modules.conf depending on your config) - * where modload will pick it up should you use modload to load your - * modules. - * - * Fixes: - * Juan Jose Ciarlante : Use control_add() for control chan - * 10/15/97 - Modifications to allow masquerading of RTSP connections as - * well as PNA, which can potentially exist on the same port. - * Joe Rumsey - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO -#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0 -#endif -*/ - -#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c)) -#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9')) - -struct raudio_priv_data { - /* Associated data connection - setup but not used at present */ - struct ip_masq *data_conn; - /* UDP Error correction connection - setup but not used at present */ - struct ip_masq *error_conn; - /* Have we seen and performed setup */ - short seen_start; - short is_rtsp; -}; - -int -masq_rtsp_out (struct ip_masq_app *mapp, - struct ip_masq *ms, - struct sk_buff **skb_p, - __u32 maddr); - -/* - * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper - * First port is set to the default port. - */ -int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; - -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); - - -static int -masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data), - GFP_ATOMIC)) == NULL) - printk(KERN_INFO "RealAudio: No memory for application data\n"); - else - { - struct raudio_priv_data *priv = - (struct raudio_priv_data *)ms->app_data; - priv->seen_start = 0; - priv->data_conn = NULL; - priv->error_conn = NULL; - priv->is_rtsp = 0; - } - return 0; -} - -static int -masq_raudio_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - if (ms->app_data) - kfree_s(ms->app_data, sizeof(struct raudio_priv_data)); - return 0; -} - -int -masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *p, *data, *data_limit; - struct ip_masq *n_ms; - unsigned short version, msg_id, msg_len, udp_port; - struct raudio_priv_data *priv = - (struct raudio_priv_data *)ms->app_data; - - /* Everything running correctly already */ - if (priv && priv->seen_start) - return 0; - - if(priv && priv->is_rtsp) - return masq_rtsp_out(mapp, ms, skb_p, maddr); - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - - data_limit = skb->h.raw + skb->len; - - if(memcmp(data, "OPTIONS", 7) == 0 || - memcmp(data, "DESCRIBE", 8) == 0) - { - IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n"); - /* This is an RTSP client */ - if(priv) - priv->is_rtsp = 1; - return masq_rtsp_out(mapp, ms, skb_p, maddr); - } - - /* Check to see if this is the first packet with protocol ID */ - if (memcmp(data, "PNA", 3)) { - IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - ignored\n"); - return(0); - } - data += 3; - memcpy(&version, data, 2); - - IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n", - ntohs(version)); - if (priv) - priv->seen_start = 1; - - if (ntohs(version) >= 256) - { - printk(KERN_INFO "RealAudio: version (%d) not supported\n", - ntohs(version)); - return 0; - } - - data += 2; - while (data+4 < data_limit) { - memcpy(&msg_id, data, 2); - data += 2; - memcpy(&msg_len, data, 2); - data += 2; - if (ntohs(msg_id) == 0) { - /* The zero tag indicates the end of options */ - IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n"); - return 0; - } - IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n", - ntohs(msg_id), ntohs(msg_len)); - if (ntohs(msg_id) == 0) { - /* The zero tag indicates the end of options */ - return 0; - } - p = data; - data += ntohs(msg_len); - if (data > data_limit) - { - printk(KERN_INFO "RealAudio: Packet too short for data\n"); - return 0; - } - if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) { - /* - * MsgId == 1 - * Audio UDP data port on client - * - * MsgId == 7 - * Robust UDP error correction port number on client - * - * Since these messages are treated just the same, they - * are bundled together here.... - */ - memcpy(&udp_port, p, 2); - - /* - * Sometimes a server sends a message 7 with a zero UDP port - * Rather than do anything with this, just ignore it! - */ - if (udp_port == 0) - continue; - - - n_ms = ip_masq_new(IPPROTO_UDP, - maddr, 0, - ms->saddr, udp_port, - ms->daddr, 0, - IP_MASQ_F_NO_DPORT); - - if (n_ms==NULL) - return 0; - - ip_masq_listen(n_ms); - ip_masq_control_add(n_ms, ms); - - memcpy(p, &(n_ms->mport), 2); - IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d in msg %d\n", - ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id)); - - /* Make ref in application data to data connection */ - if (priv) { - if (ntohs(msg_id) == 1) - priv->data_conn = n_ms; - else - priv->error_conn = n_ms; - } - - ip_masq_put(n_ms); - } - } - return 0; -} - -/* - * masq_rtsp_out - * - * - */ -int -masq_rtsp_out (struct ip_masq_app *mapp, - struct ip_masq *ms, - struct sk_buff **skb_p, - __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *data, *data_limit; - struct ip_masq *n_ms, *n_ms2; - unsigned short udp_port; - struct raudio_priv_data *priv = - (struct raudio_priv_data *)ms->app_data; - const char* srch = "transport:"; - const char* srchpos = srch; - const char* srchend = srch + strlen(srch); - int state = 0; - char firstport[6]; - int firstportpos = 0; - char secondport[6]; - int secondportpos = 0; - char *portstart = NULL, *portend = NULL; - int diff; - - /* Everything running correctly already */ - if (priv && priv->seen_start) - return 0; - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - - data_limit = skb->h.raw + skb->len; - - firstport[0] = 0; - secondport[0] = 0; - - while(data < data_limit && state >= 0) - { - switch(state) - { - case 0: - case 1: - if(TOLOWER(*data) == *srchpos) - { - srchpos++; - if(srchpos == srchend) - { - IP_MASQ_DEBUG(1-debug, "Found string %s in message\n", - srch); - state++; - if(state == 1) - { - srch = "client_port"; - srchpos = srch; - srchend = srch + strlen(srch); - } - } - } - else - { - srchpos = srch; - } - break; - case 2: - if(*data == '=') - state = 3; - break; - case 3: - if(ISDIGIT(*data)) - { - portstart = data; - firstportpos = 0; - firstport[firstportpos++] = *data; - state = 4; - } - break; - case 4: - if(*data == '-') - { - state = 5; - } - else if(*data == ';') - { - portend = data - 1; - firstport[firstportpos] = 0; - state = -1; - } - else if(ISDIGIT(*data)) - { - firstport[firstportpos++] = *data; - } - else if(*data != ' ' && *data != '\t') - { - /* This is a badly formed RTSP message, let's bail out */ - IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n"); - return 0; - } - break; - case 5: - if(ISDIGIT(*data)) - { - secondportpos = 0; - secondport[secondportpos++] = *data; - state = 6; - } - else if(*data == ';') - { - portend = data - 1; - secondport[secondportpos] = 0; - state = -1; - } - break; - case 6: - if(*data == ';') - { - portend = data - 1; - secondport[secondportpos] = 0; - state = -1; - } - else if(ISDIGIT(*data)) - { - secondport[secondportpos++] = *data; - } - else if(*data != ' ' && *data != '\t') - { - /* This is a badly formed RTSP message, let's bail out */ - IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n"); - return 0; - } - break; - } - data++; - } - - if(state >= 0) - return 0; - - if(firstportpos > 0) - { - char newbuf[12]; /* xxxxx-xxxxx\0 */ - char* tmpptr; - - udp_port = htons(simple_strtoul(firstport, &tmpptr, 10)); - n_ms = ip_masq_new(IPPROTO_UDP, - maddr, 0, - ms->saddr, udp_port, - ms->daddr, 0, - IP_MASQ_F_NO_DPORT); - if (n_ms==NULL) - return 0; - - ip_masq_listen(n_ms); - ip_masq_control_add(n_ms, ms); - - if(secondportpos > 0) - { - udp_port = htons(simple_strtoul(secondport, &tmpptr, 10)); - n_ms2 = ip_masq_new(IPPROTO_UDP, - maddr, 0, - ms->saddr, udp_port, - ms->daddr, 0, - IP_MASQ_F_NO_DPORT); - if (n_ms2==NULL) { - ip_masq_put(n_ms); - return 0; - } - - ip_masq_listen(n_ms2); - ip_masq_control_add(n_ms2, ms); - sprintf(newbuf, "%d-%d", ntohs(n_ms->mport), - ntohs(n_ms2->mport)); - } - else - { - sprintf(newbuf, "%d", ntohs(n_ms->mport)); - n_ms2 = NULL; - } - *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, - portstart, portend - portstart + 1, - newbuf, strlen(newbuf)); - IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf); - diff = strlen(newbuf) - (portend - portstart); - } - else - { - return 0; - } - - if(priv) - { - priv->seen_start = 1; - if(n_ms) - priv->data_conn = n_ms; - if(n_ms2) - priv->error_conn = n_ms2; - } - /* - * Release tunnels - */ - - if (n_ms) - ip_masq_put(n_ms); - - if (n_ms2) - ip_masq_put(n_ms2); - - return diff; -} - -struct ip_masq_app ip_masq_raudio = { - NULL, /* next */ - "RealAudio", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_raudio_init_1, /* ip_masq_init_1 */ - masq_raudio_done_1, /* ip_masq_done_1 */ - masq_raudio_out, /* pkt_out */ - NULL /* pkt_in */ -}; - -/* - * ip_masq_raudio initialization - */ - -__initfunc(int ip_masq_raudio_init(void)) -{ - int i, j; - - for (i=0; (i -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Debug level - */ -static int debug=0; - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); -MODULE_PARM(debug, "i"); - -/* -static int check_5uple (struct ip_masq_user *ums) { - return 0; -} -*/ -static void masq_user_k2u(const struct ip_masq *ms, struct ip_masq_user *ums) -{ - ums->protocol = ms->protocol; - ums->daddr = ms->daddr; - ums->dport = ms->dport; - ums->maddr = ms->maddr; - ums->mport = ms->mport; - ums->saddr = ms->saddr; - ums->sport = ms->sport; - ums->timeout = ms->timeout; -} - - -static int ip_masq_user_maddr(struct ip_masq_user *ums) -{ - struct net_device *dev; - struct rtable *rt; - int ret = -EINVAL; - u32 rt_daddr, rt_saddr; - u32 tos; - - /* - * Did specify masq address. - */ - if (ums->maddr) - return 0; - - /* - * Select address to use for routing query - */ - - rt_daddr = ums->rt_daddr? ums->rt_daddr : ums->daddr; - rt_saddr = ums->rt_saddr? ums->rt_saddr : ums->saddr; - - - /* - * No address for routing, cannot continue - */ - if (rt_daddr == 0) { - IP_MASQ_DEBUG(1-debug, "cannot setup maddr with daddr=%lX, rt_addr=%lX\n", - ntohl(ums->daddr), ntohl(ums->rt_daddr)); - return -EINVAL; - } - - /* - * Find out rt device - */ - - rt_saddr = 0; - tos = RT_TOS(ums->ip_tos) | RTO_CONN; - - if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) { - IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n", - ntohl(rt_daddr), ntohl(rt_saddr)); - return ret; - } - dev = rt->u.dst.dev; - ums->maddr = ip_masq_select_addr(dev, rt->rt_gateway, RT_SCOPE_UNIVERSE); - - IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr)); - ip_rt_put(rt); - return 0; -} - -/* - * Create new entry (from uspace) - */ -static int ip_masq_user_new(struct ip_masq_user *ums) -{ - struct ip_masq *ms = NULL; - unsigned mflags = 0; - int ret; - - if (masq_proto_num (ums->protocol) == -1) { - return EPROTONOSUPPORT; - } - - if (ums->dport == 0) { - ums->flags |= IP_MASQ_USER_F_LISTEN; - } - - if (ums->flags | IP_MASQ_USER_F_LISTEN) { - if ((ums->saddr == 0) || (ums->sport == 0)) { - return EINVAL; - } - mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR); - - } - - if ((ret = ip_masq_user_maddr(ums)) < 0) { - return -ret; - } - - mflags |= IP_MASQ_F_USER; - ms = ip_masq_new(ums->protocol, - ums->maddr, ums->mport, - ums->saddr, ums->sport, - ums->daddr, ums->dport, - mflags); - - if (ms == NULL) { - /* - * FIXME: ip_masq_new() should return errno - */ - return EBUSY; - } - - /* - * Setup timeouts for this new entry - */ - - if (ums->timeout) { - ms->timeout = ums->timeout; - } else if (ums->flags | IP_MASQ_USER_F_LISTEN) { - ip_masq_listen(ms); - } - - masq_user_k2u(ms, ums); - ip_masq_put(ms); - return 0; -} - -/* - * Delete existing entry - */ -static int ip_masq_user_del(struct ip_masq_user *ums) -{ - struct ip_masq *ms=NULL; - - if (masq_proto_num (ums->protocol) == -1) { - return EPROTONOSUPPORT; - } - start_bh_atomic(); - if (ums->mport && ums->maddr) { - ms = ip_masq_in_get(ums->protocol, - ums->daddr, ums->dport, - ums->maddr, ums->mport); - end_bh_atomic(); - } else if (ums->sport && ums->saddr) { - ms = ip_masq_out_get(ums->protocol, - ums->saddr, ums->sport, - ums->daddr, ums->dport); - end_bh_atomic(); - } else - return EINVAL; - - if (ms == NULL) { - return ESRCH; - } - - /* - * got (locked) entry, setup almost tiny timeout :) and - * give away - * - * FIXME: should use something better than S_CLOSE - */ - ms->timeout = IP_MASQ_S_CLOSE; - - masq_user_k2u(ms, ums); - ip_masq_put(ms); - return 0; -} - -static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err) -{ - struct ip_masq *ms=NULL; - if (masq_proto_num (ums->protocol) == -1) { - *err = EPROTONOSUPPORT; - } - - start_bh_atomic(); - if (ums->mport && ums->maddr) { - ms = ip_masq_in_get(ums->protocol, - ums->daddr, ums->dport, - ums->maddr, ums->mport); - end_bh_atomic(); - } else if (ums->sport && ums->saddr) { - ms = ip_masq_out_get(ums->protocol, - ums->saddr, ums->sport, - ums->daddr, ums->dport); - end_bh_atomic(); - } else - *err = EINVAL; - - if (ms == NULL) *err = ESRCH; - return ms; -} - -/* - * Get existing entry (complete full tunnel info) - */ -static int ip_masq_user_get(struct ip_masq_user *ums) -{ - struct ip_masq *ms=NULL; - int err; - - ms = ip_masq_user_locked_get(ums, &err); - if (ms == NULL) - return err; - - masq_user_k2u(ms, ums); - - ip_masq_put(ms); - return 0; -} - -/* - * Set (some, valid) entry parameters - */ -static int ip_masq_user_set(struct ip_masq_user *ums) -{ - struct ip_masq *ms = NULL; - int err; - - ms = ip_masq_user_locked_get(ums, &err); - if (ms == NULL) - return err; - - /* - * FIXME: must allow selecting what you want to set - */ - ms->timeout = ums->timeout; - - masq_user_k2u(ms, ums); - - ip_masq_put(ms); - return 0; -} - - -/* - * Entry point - * ret value: - * <0 err - * ==0 ok - * >0 ok, copy to user - */ -static int ip_masq_user_ctl(int optname, struct ip_masq_ctl *mctl, int optlen) -{ - struct ip_masq_user *ums = &mctl->u.user; - int ret = EINVAL; - int arglen = optlen - IP_MASQ_CTL_BSIZE; - int cmd; - - IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n", - arglen, - sizeof (*ums), - optlen, - sizeof (*mctl)); - - /* - * Yes, I'm a bad guy ... - */ - if (arglen != sizeof(*ums) && optlen != sizeof(*mctl)) - return EINVAL; - - MOD_INC_USE_COUNT; - - /* - * Don't trust the lusers - plenty of error checking! - */ - cmd = mctl->m_cmd; - IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(cmd=%d)\n", cmd); - - switch (mctl->m_cmd) { - case IP_MASQ_CMD_ADD: - case IP_MASQ_CMD_INSERT: - ret = ip_masq_user_new(ums); - break; - case IP_MASQ_CMD_DEL: - ret = ip_masq_user_del(ums); - break; - case IP_MASQ_CMD_SET: - ret = ip_masq_user_set(ums); - break; - case IP_MASQ_CMD_GET: - ret = ip_masq_user_get(ums); - break; - } - - /* - * For all of the above, return masq tunnel info - */ - - ret = -ret; - - if (ret == 0) { - ret = sizeof (*ums) + IP_MASQ_CTL_BSIZE; - IP_MASQ_DEBUG(1-debug, "will return %d bytes to user\n", ret); - } - - MOD_DEC_USE_COUNT; - return ret; -} - - -#ifdef CONFIG_PROC_FS -static int ip_masq_user_info(char *buffer, char **start, off_t offset, - int length, int proto) -{ - off_t pos=0, begin; - struct ip_masq *ms; - char temp[129]; - int idx = 0; - int len=0; - int magic_control; - - MOD_INC_USE_COUNT; - - IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto); - - if (offset < 128) - { - sprintf(temp, - "Prot SrcIP SPrt DstIP DPrt MAddr MPrt State Flgs Ref Ctl Expires (free=%d,%d,%d)", - atomic_read(ip_masq_free_ports), - atomic_read(ip_masq_free_ports+1), - atomic_read(ip_masq_free_ports+2)); - len = sprintf(buffer, "%-127s\n", temp); - } - pos = 128; - - for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) - { - /* - * Lock is actually only need in next loop - * we are called from uspace: must stop bh. - */ - read_lock_bh(&__ip_masq_lock); - for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) - { - if (ms->protocol != proto) { - continue; - } - - pos += 128; - if (pos <= offset) { - len = 0; - continue; - } - - /* - * We have locked the tables, no need to del/add timers - * nor cli() 8) - */ - - - magic_control = atomic_read(&ms->n_control); - if (!magic_control && ms->control) magic_control = -1; - sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu", - masq_proto_name(ms->protocol), - ntohl(ms->saddr), ntohs(ms->sport), - ntohl(ms->daddr), ntohs(ms->dport), - ntohl(ms->maddr), ntohs(ms->mport), - ip_masq_state_name(ms->state), - ms->flags, - atomic_read(&ms->refcnt), - magic_control, - (ms->timer.expires-jiffies)/HZ); - len += sprintf(buffer+len, "%-127s\n", temp); - - if(len >= length) { - read_unlock_bh(&__ip_masq_lock); - goto done; - } - } - read_unlock_bh(&__ip_masq_lock); - } - -done: - - if (len) { - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - } - if(len>length) - len = length; - MOD_DEC_USE_COUNT; - return len; -} -#else -#define ip_masq_user_info NULL -#endif - -static struct ip_masq_hook ip_masq_user = { - ip_masq_user_ctl, - ip_masq_user_info -}; - -int ip_masq_user_init(void) -{ - if (ip_masq_user_hook != NULL) - return -EEXIST; - ip_masq_user_hook = &ip_masq_user; - return 0; -} - -int ip_masq_user_done(void) -{ - if (ip_masq_user_hook == NULL) - return ENOENT; - ip_masq_user_hook = NULL; - return 0; -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if (ip_masq_user_init() != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - if (ip_masq_user_done() != 0) - printk(KERN_INFO "ip_masq_user_done(): can't remove module"); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_masq_vdolive.c linux/net/ipv4/ip_masq_vdolive.c --- v2.3.14/linux/net/ipv4/ip_masq_vdolive.c Wed Jun 9 14:45:37 1999 +++ linux/net/ipv4/ip_masq_vdolive.c Wed Dec 31 16:00:00 1969 @@ -1,298 +0,0 @@ -/* - * IP_MASQ_VDOLIVE - VDO Live masquerading module - * - * - * Version: @(#)$Id: ip_masq_vdolive.c,v 1.6 1999/06/09 08:29:03 davem Exp $ - * - * Author: Nigel Metheringham - * PLAnet Online Ltd - * - * Fixes: Minor changes for 2.1 by - * Steven Clarke , Planet Online Ltd - * - * Add missing #include - * Horst von Brand - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Thanks: - * Thank you to VDOnet Corporation for allowing me access to - * a protocol description without an NDA. This means that - * this module can be distributed as source - a great help! - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct vdolive_priv_data { - /* Ports used */ - unsigned short origport; - unsigned short masqport; - /* State of decode */ - unsigned short state; -}; - -/* - * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper - * First port is set to the default port. - */ -static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; - -/* - * Debug level - */ -#ifdef CONFIG_IP_MASQ_DEBUG -static int debug=0; -MODULE_PARM(debug, "i"); -#endif - -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); - -static int -masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_INC_USE_COUNT; - if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data), - GFP_ATOMIC)) == NULL) - IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n"); - else - { - struct vdolive_priv_data *priv = - (struct vdolive_priv_data *)ms->app_data; - priv->origport = 0; - priv->masqport = 0; - priv->state = 0; - } - return 0; -} - -static int -masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) -{ - MOD_DEC_USE_COUNT; - if (ms->app_data) - kfree_s(ms->app_data, sizeof(struct vdolive_priv_data)); - return 0; -} - -int -masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct tcphdr *th; - char *data, *data_limit; - unsigned int tagval; /* This should be a 32 bit quantity */ - struct ip_masq *n_ms; - struct vdolive_priv_data *priv = - (struct vdolive_priv_data *)ms->app_data; - - /* This doesn't work at all if no priv data was allocated on startup */ - if (!priv) - return 0; - - /* Everything running correctly already */ - if (priv->state == 3) - return 0; - - skb = *skb_p; - iph = skb->nh.iph; - th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; - - data_limit = skb->h.raw + skb->len; - - if (data+8 > data_limit) { - IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit); - return 0; - } - memcpy(&tagval, data+4, 4); - IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state); - - /* Check for leading packet ID */ - if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) { - IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state); - return 0; - } - - - /* Check packet is long enough for data - ignore if not */ - if ((ntohl(tagval) == 6) && (data+36 > data_limit)) { - IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit); - return 0; - } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) { - IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit); - return 0; - } - - /* Adjust data pointers */ - /* - * I could check the complete protocol version tag - * in here however I am just going to look for the - * "VDO Live" tag in the hope that this part will - * remain constant even if the version changes - */ - if (ntohl(tagval) == 6) { - data += 24; - IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n"); - } else { - data += 8; - IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n"); - } - - if (memcmp(data, "VDO Live", 8) != 0) { - IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n"); - return 0; - } - /* - * The port number is the next word after the tag. - * VDOlive encodes all of these values - * in 32 bit words, so in this case I am - * skipping the first 2 bytes of the next - * word to get to the relevant 16 bits - */ - data += 10; - - /* - * If we have not seen the port already, - * set the masquerading tunnel up - */ - if (!priv->origport) { - memcpy(&priv->origport, data, 2); - IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport)); - - /* Open up a tunnel */ - n_ms = ip_masq_new(IPPROTO_UDP, - maddr, 0, - ms->saddr, priv->origport, - ms->daddr, 0, - IP_MASQ_F_NO_DPORT); - - if (n_ms==NULL) { - ip_masq_put(n_ms); - IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport); - /* Leave state as unset */ - priv->origport = 0; - return 0; - } - ip_masq_listen(n_ms); - - ip_masq_put(ms); - priv->masqport = n_ms->mport; - } else if (memcmp(data, &(priv->origport), 2)) { - IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n"); - /* Write the port in anyhow!!! */ - } - - /* - * Write masq port into packet - */ - memcpy(data, &(priv->masqport), 2); - IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr); - - /* - * Set state bit to make which bit has been done - */ - - priv->state |= (ntohl(tagval) == 6) ? 1 : 2; - - return 0; -} - - -struct ip_masq_app ip_masq_vdolive = { - NULL, /* next */ - "VDOlive", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_vdolive_init_1, /* ip_masq_init_1 */ - masq_vdolive_done_1, /* ip_masq_done_1 */ - masq_vdolive_out, /* pkt_out */ - NULL /* pkt_in */ -}; - -/* - * ip_masq_vdolive initialization - */ - -__initfunc(int ip_masq_vdolive_init(void)) -{ - int i, j; - - for (i=0; (i * @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include #include #include @@ -129,10 +127,13 @@ /* Use fib_lookup() until we get our own * hash table of NATed hosts -- Rani */ - if (fib_lookup(&key, &res) == 0 && res.r) { - ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags); - if (ciph->daddr != idaddr) - updated = 1; + if (fib_lookup(&key, &res) == 0) { + if (res.r) { + ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags); + if (ciph->daddr != idaddr) + updated = 1; + } + fib_res_put(&res); } } else { ciph->daddr = iph->saddr; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.3.14/linux/net/ipv4/ip_output.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_output.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.67 1999/03/25 00:43:00 davem Exp $ + * Version: $Id: ip_output.c,v 1.69 1999/08/20 11:05:48 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -72,8 +72,7 @@ #include #include #include -#include -#include +#include #include #include @@ -83,7 +82,6 @@ int sysctl_ip_dynaddr = 0; - int ip_id_count = 0; /* Generate a checksum for an outgoing IP datagram. */ @@ -93,6 +91,61 @@ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } +/* dev_loopback_xmit for use with netfilter. */ +static int ip_dev_loopback_xmit(struct sk_buff *newskb) +{ + newskb->mac.raw = newskb->data; + skb_pull(newskb, newskb->nh.raw - newskb->data); + newskb->pkt_type = PACKET_LOOPBACK; + newskb->ip_summed = CHECKSUM_UNNECESSARY; + BUG_TRAP(newskb->dst); + +#ifdef CONFIG_NETFILTER_DEBUG + nf_debug_ip_loopback_xmit(newskb); +#endif + netif_rx(newskb); + return 0; +} + +#ifdef CONFIG_NETFILTER +/* To preserve the cute illusion that a locally-generated packet can + be mangled before routing, we actually reroute if a hook altered + the packet. -RR */ +static int route_me_harder(struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + struct rtable *rt; + + if (ip_route_output(&rt, iph->daddr, iph->saddr, + RT_TOS(iph->tos) | RTO_CONN, + skb->sk ? skb->sk->bound_dev_if : 0)) { + printk("route_me_harder: No more route.\n"); + return -EINVAL; + } + + /* Drop old route. */ + dst_release(skb->dst); + + skb->dst = &rt->u.dst; + return 0; +} +#endif + +/* Do route recalc if netfilter changes skb. */ +static inline int +output_maybe_reroute(struct sk_buff *skb) +{ +#ifdef CONFIG_NETFILTER + if (skb->nfcache & NFC_ALTERED) { + if (route_me_harder(skb) != 0) { + kfree_skb(skb); + return -EINVAL; + } + } +#endif + return skb->dst->output(skb); +} + /* * Add an ip header to a skbuff and send it out. */ @@ -101,7 +154,6 @@ { struct rtable *rt = (struct rtable *)skb->dst; struct iphdr *iph; - struct net_device *dev; /* Build the IP header. */ if (opt) @@ -111,11 +163,11 @@ iph->version = 4; iph->ihl = 5; - iph->tos = sk->ip_tos; + iph->tos = sk->protinfo.af_inet.tos; iph->frag_off = 0; if (ip_dont_fragment(sk, &rt->u.dst)) iph->frag_off |= htons(IP_DF); - iph->ttl = sk->ip_ttl; + iph->ttl = sk->protinfo.af_inet.ttl; iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; iph->protocol = sk->protocol; @@ -127,32 +179,45 @@ iph->ihl += opt->optlen>>2; ip_options_build(skb, opt, daddr, rt, 0); } + ip_send_check(iph); - dev = rt->u.dst.dev; + /* Send it out. */ + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, NULL, + output_maybe_reroute); +} -#ifdef CONFIG_FIREWALL - /* Now we have no better mechanism to notify about error. */ - switch (call_out_firewall(PF_INET, dev, iph, NULL, &skb)) { - case FW_REJECT: - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - /* Fall thru... */ - case FW_BLOCK: - case FW_QUEUE: - kfree_skb(skb); - return; - } -#endif +static inline int ip_finish_output2(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; - ip_send_check(iph); +#ifdef CONFIG_NETFILTER_DEBUG + nf_debug_ip_finish_output2(skb); +#endif /*CONFIG_NETFILTER_DEBUG*/ - /* Send it out. */ - skb->dst->output(skb); - return; + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + return hh->hh_output(skb); + } else if (dst->neighbour) + return dst->neighbour->output(skb); + + printk(KERN_DEBUG "khm\n"); + kfree_skb(skb); + return -EINVAL; } -int __ip_finish_output(struct sk_buff *skb) +__inline__ int ip_finish_output(struct sk_buff *skb) { - return ip_finish_output(skb); + struct net_device *dev = skb->dst->dev; + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_IP); + + return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev, + ip_finish_output2); } int ip_mc_output(struct sk_buff *skb) @@ -164,7 +229,6 @@ /* * If the indicated interface is up and running, send the packet. */ - ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_ROUTE_NAT if (rt->rt_flags & RTCF_NAT) @@ -178,7 +242,7 @@ * Multicasts are looped back for other local users */ - if (rt->rt_flags&RTCF_MULTICAST && (!sk || sk->ip_mc_loop)) { + if (rt->rt_flags&RTCF_MULTICAST && (!sk || sk->protinfo.af_inet.mc_loop)) { #ifdef CONFIG_IP_MROUTE /* Small optimization: do not loopback not local frames, which returned after forwarding; they will be dropped @@ -190,7 +254,13 @@ */ if ((rt->rt_flags&RTCF_LOCAL) || !(IPCB(skb)->flags&IPSKB_FORWARDED)) #endif - dev_loopback_xmit(skb); + { + struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + if (newskb) + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, newskb, NULL, + newskb->dev, + ip_dev_loopback_xmit); + } /* Multicasts with ttl 0 must not go beyond the host */ @@ -200,8 +270,12 @@ } } - if (rt->rt_flags&RTCF_BROADCAST) - dev_loopback_xmit(skb); + if (rt->rt_flags&RTCF_BROADCAST) { + struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + if (newskb) + NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL, + newskb->dev, ip_dev_loopback_xmit); + } return ip_finish_output(skb); } @@ -231,82 +305,33 @@ * most likely make other reliable transport layers above IP easier * to implement under Linux. */ -void ip_queue_xmit(struct sk_buff *skb) +static inline int ip_queue_xmit2(struct sk_buff *skb) { struct sock *sk = skb->sk; - struct ip_options *opt = sk->opt; - struct rtable *rt; + struct rtable *rt = (struct rtable *)skb->dst; struct net_device *dev; - struct iphdr *iph; - unsigned int tot_len; - - /* Make sure we can route this packet. */ - rt = (struct rtable *) sk->dst_cache; - if(rt == NULL || rt->u.dst.obsolete) { - u32 daddr; - - sk->dst_cache = NULL; - ip_rt_put(rt); - - /* Use correct destination address if we have options. */ - daddr = sk->daddr; - if(opt && opt->srr) - daddr = opt->faddr; - - /* If this fails, retransmit mechanism of transport layer will - * keep trying until route appears or the connection times itself - * out. - */ - if(ip_route_output(&rt, daddr, sk->saddr, - RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute, - sk->bound_dev_if)) - goto drop; - sk->dst_cache = &rt->u.dst; - } - if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) - goto no_route; - - /* We have a route, so grab a reference. */ - skb->dst = dst_clone(sk->dst_cache); + struct iphdr *iph = skb->nh.iph; - /* OK, we know where to send it, allocate and build IP header. */ - iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); - iph->version = 4; - iph->ihl = 5; - iph->tos = sk->ip_tos; - iph->frag_off = 0; - iph->ttl = sk->ip_ttl; - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; - iph->protocol = sk->protocol; - skb->nh.iph = iph; - /* Transport layer set skb->h.foo itself. */ - - if(opt && opt->optlen) { - iph->ihl += opt->optlen >> 2; - ip_options_build(skb, opt, sk->daddr, rt, 0); +#ifdef CONFIG_NETFILTER + /* BLUE-PEN-FOR-ALEXEY. I don't understand; you mean I can't + hold the route as I pass the packet to userspace? -- RR + + You may hold it, if you really hold it. F.e. if netfilter + does not destroy handed skb with skb->dst attached, it + will be held. When it was stored in info->arg, then + it was not held apparently. Now (without second arg) it is evident, + that it is clean. --ANK + */ + if (rt==NULL || (skb->nfcache & NFC_ALTERED)) { + if (route_me_harder(skb) != 0) { + kfree_skb(skb); + return -EHOSTUNREACH; + } } - - tot_len = skb->len; - iph->tot_len = htons(tot_len); - iph->id = htons(ip_id_count++); +#endif dev = rt->u.dst.dev; -#ifdef CONFIG_FIREWALL - /* Now we have no better mechanism to notify about error. */ - switch (call_out_firewall(PF_INET, dev, iph, NULL, &skb)) { - case FW_REJECT: - start_bh_atomic(); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - end_bh_atomic(); - /* Fall thru... */ - case FW_BLOCK: - case FW_QUEUE: - goto drop; - } -#endif - /* This can happen when the transport layer has segments queued * with a cached route, and by the time we get here things are * re-routed to a device with a different MTU than the original @@ -318,17 +343,14 @@ skb2 = skb_realloc_headroom(skb, (dev->hard_header_len + 15) & ~15); kfree_skb(skb); if (skb2 == NULL) - return; + return -ENOMEM; if (sk) skb_set_owner_w(skb, sk); skb = skb2; iph = skb->nh.iph; } - /* Do we need to fragment. Again this is inefficient. We - * need to somehow lock the original buffer and use bits of it. - */ - if (tot_len > rt->u.dst.pmtu) + if (skb->len > rt->u.dst.pmtu) goto fragment; if (ip_dont_fragment(sk, &rt->u.dst)) @@ -338,37 +360,85 @@ ip_send_check(iph); skb->priority = sk->priority; - skb->dst->output(skb); - return; + return skb->dst->output(skb); fragment: - if (ip_dont_fragment(sk, &rt->u.dst) && - tot_len > (iph->ihl<<2) + sizeof(struct tcphdr)+16) { + if (ip_dont_fragment(sk, &rt->u.dst)) { /* Reject packet ONLY if TCP might fragment - it itself, if were careful enough. - Test is not precise (f.e. it does not take sacks - into account). Actually, tcp should make it. --ANK (980801) + * it itself, if were careful enough. */ iph->frag_off |= __constant_htons(IP_DF); NETDEBUG(printk(KERN_DEBUG "sending pkt_too_big to self\n")); - /* icmp_send is not reenterable, so that bh_atomic... --ANK */ - start_bh_atomic(); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(rt->u.dst.pmtu)); - end_bh_atomic(); - goto drop; + kfree_skb(skb); + return -EMSGSIZE; + } + return ip_fragment(skb, skb->dst->output); +} + +int ip_queue_xmit(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + struct ip_options *opt = sk->protinfo.af_inet.opt; + struct rtable *rt; + struct iphdr *iph; + + /* Make sure we can route this packet. */ + rt = (struct rtable *)sk_dst_check(sk, 0); + if (rt == NULL) { + u32 daddr; + + /* Use correct destination address if we have options. */ + daddr = sk->daddr; + if(opt && opt->srr) + daddr = opt->faddr; + + /* If this fails, retransmit mechanism of transport layer will + * keep trying until route appears or the connection times itself + * out. + */ + if (ip_route_output(&rt, daddr, sk->saddr, + RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute, + sk->bound_dev_if)) + goto no_route; + dst_clone(&rt->u.dst); + sk_dst_set(sk, &rt->u.dst); + } + skb->dst = &rt->u.dst; + + if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) + goto no_route; + + /* OK, we know where to send it, allocate and build IP header. */ + iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); + iph->version = 4; + iph->ihl = 5; + iph->tos = sk->protinfo.af_inet.tos; + iph->frag_off = 0; + iph->ttl = sk->protinfo.af_inet.ttl; + iph->daddr = rt->rt_dst; + iph->saddr = rt->rt_src; + iph->protocol = sk->protocol; + skb->nh.iph = iph; + /* Transport layer set skb->h.foo itself. */ + + if(opt && opt->optlen) { + iph->ihl += opt->optlen >> 2; + ip_options_build(skb, opt, sk->daddr, rt, 0); } - ip_fragment(skb, skb->dst->output); - return; + + iph->tot_len = htons(skb->len); + iph->id = htons(ip_id_count++); + + return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, + ip_queue_xmit2); no_route: - sk->dst_cache = NULL; - ip_rt_put(rt); ip_statistics.IpOutNoRoutes++; - /* Fall through... */ -drop: kfree_skb(skb); + return -EHOSTUNREACH; } /* @@ -391,7 +461,7 @@ * length to be copied. */ -int ip_build_xmit_slow(struct sock *sk, +static int ip_build_xmit_slow(struct sock *sk, int getfrag (const void *, char *, unsigned int, @@ -454,8 +524,7 @@ fraglen = maxfraglen; offset -= maxfraglen-fragheaderlen; } - - + /* * The last fragment will not have MF (more fragments) set. */ @@ -468,16 +537,12 @@ if (offset > 0 && df) { ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu); - return(-EMSGSIZE); + return -EMSGSIZE; } + if (flags&MSG_PROBE) + goto out; /* - * Lock the device lists. - */ - - dev_lock_list(); - - /* * Get an identifier */ @@ -528,15 +593,15 @@ ip_options_build(skb, opt, ipc->addr, rt, offset); } - iph->tos = sk->ip_tos; + iph->tos = sk->protinfo.af_inet.tos; iph->tot_len = htons(fraglen - fragheaderlen + iph->ihl*4); iph->id = id; iph->frag_off = htons(offset>>3); iph->frag_off |= mf|df; if (rt->rt_type == RTN_MULTICAST) - iph->ttl = sk->ip_mc_ttl; + iph->ttl = sk->protinfo.af_inet.mc_ttl; else - iph->ttl = sk->ip_ttl; + iph->ttl = sk->protinfo.af_inet.ttl; iph->protocol = sk->protocol; iph->check = 0; iph->saddr = rt->rt_src; @@ -566,38 +631,28 @@ nfrags++; -#ifdef CONFIG_FIREWALL - switch (call_out_firewall(PF_INET, rt->u.dst.dev, skb->nh.iph, NULL, &skb)) { - case FW_QUEUE: - kfree_skb(skb); - continue; - case FW_BLOCK: - case FW_REJECT: - kfree_skb(skb); - err = -EPERM; - goto error; + err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, + skb->dst->dev, output_maybe_reroute); + if (err) { + if (err > 0) + err = sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0; + if (err) + goto error; } -#endif - - err = -ENETDOWN; - if (rt->u.dst.output(skb)) - goto error; } while (offset >= 0); if (nfrags>1) ip_statistics.IpFragCreates += nfrags; - dev_unlock_list(); +out: return 0; error: ip_statistics.IpOutDiscards++; if (nfrags>1) ip_statistics.IpFragCreates += nfrags; - dev_unlock_list(); return err; } - /* * Fast path for unfragmented packets. */ @@ -622,7 +677,7 @@ * choice RAW frames within 20 bytes of maximum size(rare) to the long path */ - if (!sk->ip_hdrincl) { + if (!sk->protinfo.af_inet.hdrincl) { length += sizeof(struct iphdr); /* @@ -636,6 +691,8 @@ return -EMSGSIZE; } } + if (flags&MSG_PROBE) + goto out; /* * Do path mtu discovery if needed. @@ -662,18 +719,16 @@ skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length); - dev_lock_list(); - - if(!sk->ip_hdrincl) { + if(!sk->protinfo.af_inet.hdrincl) { iph->version=4; iph->ihl=5; - iph->tos=sk->ip_tos; + iph->tos=sk->protinfo.af_inet.tos; iph->tot_len = htons(length); iph->id=htons(ip_id_count++); iph->frag_off = df; - iph->ttl=sk->ip_mc_ttl; + iph->ttl=sk->protinfo.af_inet.mc_ttl; if (rt->rt_type != RTN_MULTICAST) - iph->ttl=sk->ip_ttl; + iph->ttl=sk->protinfo.af_inet.ttl; iph->protocol=sk->protocol; iph->saddr=rt->rt_src; iph->daddr=rt->rt_dst; @@ -684,25 +739,17 @@ else err = getfrag(frag, (void *)iph, 0, length); - dev_unlock_list(); - if (err) goto error_fault; -#ifdef CONFIG_FIREWALL - switch (call_out_firewall(PF_INET, rt->u.dst.dev, iph, NULL, &skb)) { - case FW_QUEUE: - kfree_skb(skb); - return 0; - case FW_BLOCK: - case FW_REJECT: - kfree_skb(skb); - err = -EPERM; + err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, + output_maybe_reroute); + if (err > 0) + err = sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0; + if (err) goto error; - } -#endif - - return rt->u.dst.output(skb); +out: + return 0; error_fault: err = -EFAULT; @@ -723,7 +770,7 @@ * Yes this is inefficient, feel free to submit a quicker one. */ -void ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) +int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; unsigned char *raw; @@ -734,6 +781,7 @@ int offset; int not_last_frag; struct rtable *rt = (struct rtable*)skb->dst; + int err = 0; dev = rt->u.dst.dev; @@ -754,19 +802,6 @@ ptr = raw + hlen; /* Where to start from */ /* - * The protocol doesn't seem to say what to do in the case that the - * frame + options doesn't fit the mtu. As it used to fall down dead - * in this case we were fortunate it didn't happen - * - * It is impossible, because mtu>=68. --ANK (980801) - */ - -#ifdef CONFIG_NET_PARANOIA - if (mtu<8) - goto fail; -#endif - - /* * Fragment the datagram. */ @@ -793,6 +828,7 @@ if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) == NULL) { NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n")); + err = -ENOMEM; goto fail; } @@ -862,15 +898,18 @@ ip_send_check(iph); - output(skb2); + err = output(skb2); + if (err) + goto fail; } kfree_skb(skb); ip_statistics.IpFragOKs++; - return; + return err; fail: kfree_skb(skb); - ip_statistics.IpFragFails++; + ip_statistics.IpFragFails++; + return err; } /* @@ -926,24 +965,31 @@ struct ipcm_cookie ipc; u32 daddr; struct rtable *rt = (struct rtable*)skb->dst; - + if (ip_options_echo(&replyopts.opt, skb)) return; - - sk->ip_tos = skb->nh.iph->tos; - sk->priority = skb->priority; - sk->protocol = skb->nh.iph->protocol; daddr = ipc.addr = rt->rt_src; ipc.opt = &replyopts.opt; - + if (ipc.opt->srr) daddr = replyopts.opt.faddr; if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) return; - /* And let IP do all the hard work. */ + /* And let IP do all the hard work. + + This chunk is not reenterable, hence spinlock. + Note that it uses the fact, that this function is called + with locally disabled BH and that sk cannot be already spinlocked. + */ + bh_lock_sock(sk); + sk->protinfo.af_inet.tos = skb->nh.iph->tos; + sk->priority = skb->priority; + sk->protocol = skb->nh.iph->protocol; ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT); + bh_unlock_sock(sk); + ip_rt_put(rt); } @@ -956,7 +1002,7 @@ __constant_htons(ETH_P_IP), NULL, /* All devices */ ip_rcv, - NULL, + (void*)1, NULL, }; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.3.14/linux/net/ipv4/ip_sockglue.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ip_sockglue.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.42 1999/04/22 10:07:34 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.44 1999/08/20 11:05:49 davem Exp $ * * Authors: see ip.c * @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -41,10 +40,6 @@ #include #endif -#ifdef CONFIG_IP_MASQUERADE -#include -#endif - #include #include @@ -117,7 +112,7 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) { - unsigned flags = skb->sk->ip_cmsg_flags; + unsigned flags = skb->sk->protinfo.af_inet.cmsg_flags; /* Ordered by supposed usage frequency */ if (flags & 1) @@ -193,6 +188,7 @@ sent to multicast group to reach destination designated router. */ struct ip_ra_chain *ip_ra_chain; +rwlock_t ip_ra_lock = RW_LOCK_UNLOCKED; int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)) { @@ -203,30 +199,36 @@ new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; + write_lock_bh(&ip_ra_lock); for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { if (ra->sk == sk) { if (on) { + write_unlock_bh(&ip_ra_lock); if (new_ra) kfree(new_ra); return -EADDRINUSE; } *rap = ra->next; - synchronize_bh(); + write_unlock_bh(&ip_ra_lock); if (ra->destructor) ra->destructor(sk); + sock_put(sk); kfree(ra); return 0; } } - if (new_ra == NULL) + if (new_ra == NULL) { + write_unlock_bh(&ip_ra_lock); return -ENOBUFS; + } new_ra->sk = sk; new_ra->destructor = destructor; new_ra->next = ra; - wmb(); *rap = new_ra; + sock_hold(sk); + write_unlock_bh(&ip_ra_lock); return 0; } @@ -236,7 +238,7 @@ { struct sock_exterr_skb *serr; - if (!sk->ip_recverr) + if (!sk->protinfo.af_inet.recverr) return; skb = skb_clone(skb, GFP_ATOMIC); @@ -267,7 +269,7 @@ struct iphdr *iph; struct sk_buff *skb; - if (!sk->ip_recverr) + if (!sk->protinfo.af_inet.recverr) return; skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC); @@ -340,7 +342,7 @@ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = skb->nh.iph->saddr; - if (sk->ip_cmsg_flags) + if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); } @@ -375,9 +377,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val=0,err; -#if defined(CONFIG_IP_FIREWALL) - char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))]; -#endif + if(optlen>=sizeof(int)) { if(get_user(val, (int *) optval)) return -EFAULT; @@ -397,18 +397,20 @@ return ip_mroute_setsockopt(sk,optname,optval,optlen); } #endif - + + err = 0; + lock_sock(sk); + switch(optname) { case IP_OPTIONS: { struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) - return -EINVAL; + goto e_inval; err = ip_options_get(&opt, optval, optlen, 1); if (err) - return err; - lock_sock(sk); + break; if (sk->type == SOCK_STREAM) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -423,194 +425,193 @@ } #endif } - opt = xchg(&sk->opt, opt); - release_sock(sk); + opt = xchg(&sk->protinfo.af_inet.opt, opt); if (opt) kfree_s(opt, sizeof(struct ip_options) + opt->optlen); - return 0; + break; } case IP_PKTINFO: if (val) - sk->ip_cmsg_flags |= IP_CMSG_PKTINFO; + sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_PKTINFO; else - sk->ip_cmsg_flags &= ~IP_CMSG_PKTINFO; - return 0; + sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_PKTINFO; + break; case IP_RECVTTL: if (val) - sk->ip_cmsg_flags |= IP_CMSG_TTL; + sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TTL; else - sk->ip_cmsg_flags &= ~IP_CMSG_TTL; - return 0; + sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TTL; + break; case IP_RECVTOS: if (val) - sk->ip_cmsg_flags |= IP_CMSG_TOS; + sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TOS; else - sk->ip_cmsg_flags &= ~IP_CMSG_TOS; - return 0; + sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TOS; + break; case IP_RECVOPTS: if (val) - sk->ip_cmsg_flags |= IP_CMSG_RECVOPTS; + sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RECVOPTS; else - sk->ip_cmsg_flags &= ~IP_CMSG_RECVOPTS; - return 0; + sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RECVOPTS; + break; case IP_RETOPTS: if (val) - sk->ip_cmsg_flags |= IP_CMSG_RETOPTS; + sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RETOPTS; else - sk->ip_cmsg_flags &= ~IP_CMSG_RETOPTS; - return 0; + sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RETOPTS; + break; case IP_TOS: /* This sets both TOS and Precedence */ /* Reject setting of unused bits */ if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK)) - return -EINVAL; + goto e_inval; if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && - !capable(CAP_NET_ADMIN)) - return -EPERM; - if (sk->ip_tos != val) { - lock_sock(sk); - sk->ip_tos=val; + !capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + if (sk->protinfo.af_inet.tos != val) { + sk->protinfo.af_inet.tos=val; sk->priority = rt_tos2priority(val); - dst_release(xchg(&sk->dst_cache, NULL)); - release_sock(sk); + sk_dst_reset(sk); } - return 0; + break; case IP_TTL: if (optlen<1) - return -EINVAL; + goto e_inval; if(val==-1) val = ip_statistics.IpDefaultTTL; if(val<1||val>255) - return -EINVAL; - sk->ip_ttl=val; - return 0; + goto e_inval; + sk->protinfo.af_inet.ttl=val; + break; case IP_HDRINCL: - if(sk->type!=SOCK_RAW) - return -ENOPROTOOPT; - sk->ip_hdrincl=val?1:0; - return 0; + if(sk->type!=SOCK_RAW) { + err = -ENOPROTOOPT; + break; + } + sk->protinfo.af_inet.hdrincl=val?1:0; + break; case IP_MTU_DISCOVER: if (val<0 || val>2) - return -EINVAL; - sk->ip_pmtudisc = val; - return 0; + goto e_inval; + sk->protinfo.af_inet.pmtudisc = val; + break; case IP_RECVERR: - sk->ip_recverr = !!val; + sk->protinfo.af_inet.recverr = !!val; if (!val) skb_queue_purge(&sk->error_queue); - return 0; - case IP_MULTICAST_TTL: + break; + case IP_MULTICAST_TTL: + if (sk->type == SOCK_STREAM) + goto e_inval; if (optlen<1) - return -EINVAL; + goto e_inval; if (val==-1) val = 1; if (val < 0 || val > 255) - return -EINVAL; - sk->ip_mc_ttl=val; - return 0; + goto e_inval; + sk->protinfo.af_inet.mc_ttl=val; + break; case IP_MULTICAST_LOOP: if (optlen<1) - return -EINVAL; - sk->ip_mc_loop = val ? 1 : 0; - return 0; + goto e_inval; + sk->protinfo.af_inet.mc_loop = val ? 1 : 0; + break; case IP_MULTICAST_IF: { struct ip_mreqn mreq; struct net_device *dev = NULL; - + + if (sk->type == SOCK_STREAM) + goto e_inval; /* * Check the arguments are allowable */ + err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { if (copy_from_user(&mreq,optval,sizeof(mreq))) - return -EFAULT; + break; } else { memset(&mreq, 0, sizeof(mreq)); if (optlen >= sizeof(struct in_addr) && copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr))) - return -EFAULT; + break; } if (!mreq.imr_ifindex) { if (mreq.imr_address.s_addr == INADDR_ANY) { - sk->ip_mc_index = 0; - sk->ip_mc_addr = 0; - return 0; + sk->protinfo.af_inet.mc_index = 0; + sk->protinfo.af_inet.mc_addr = 0; + err = 0; + break; } dev = ip_dev_find(mreq.imr_address.s_addr); + if (dev) { + mreq.imr_ifindex = dev->ifindex; + dev_put(dev); + } } else - dev = dev_get_by_index(mreq.imr_ifindex); + dev = __dev_get_by_index(mreq.imr_ifindex); - if (!dev) - return -EADDRNOTAVAIL; - if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if) - return -EINVAL; + err = -EADDRNOTAVAIL; + if (!dev) + break; - sk->ip_mc_index = mreq.imr_ifindex; - sk->ip_mc_addr = mreq.imr_address.s_addr; - return 0; + err = -EINVAL; + if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if) + break; + + sk->protinfo.af_inet.mc_index = mreq.imr_ifindex; + sk->protinfo.af_inet.mc_addr = mreq.imr_address.s_addr; + err = 0; + break; } case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { struct ip_mreqn mreq; - + if (optlen < sizeof(struct ip_mreq)) - return -EINVAL; + goto e_inval; + err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { if(copy_from_user(&mreq,optval,sizeof(mreq))) - return -EFAULT; + break; } else { memset(&mreq, 0, sizeof(mreq)); if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) - return -EFAULT; + break; } if (optname == IP_ADD_MEMBERSHIP) - return ip_mc_join_group(sk,&mreq); + err = ip_mc_join_group(sk,&mreq); else - return ip_mc_leave_group(sk,&mreq); + err = ip_mc_leave_group(sk,&mreq); + break; } case IP_ROUTER_ALERT: - return ip_ra_control(sk, val ? 1 : 0, NULL); - -#ifdef CONFIG_IP_FIREWALL - case IP_FW_MASQ_TIMEOUTS: - case IP_FW_APPEND: - case IP_FW_REPLACE: - case IP_FW_DELETE: - case IP_FW_DELETE_NUM: - case IP_FW_INSERT: - case IP_FW_FLUSH: - case IP_FW_ZERO: - case IP_FW_CHECK: - case IP_FW_CREATECHAIN: - case IP_FW_DELETECHAIN: - case IP_FW_POLICY: - if(!capable(CAP_NET_ADMIN)) - return -EACCES; - if(optlen>sizeof(tmp_fw) || optlen<1) - return -EINVAL; - if(copy_from_user(&tmp_fw,optval,optlen)) - return -EFAULT; - err=ip_fw_ctl(optname, &tmp_fw,optlen); - return -err; /* -0 is 0 after all */ -#endif /* CONFIG_IP_FIREWALL */ -#ifdef CONFIG_IP_MASQUERADE - case IP_FW_MASQ_CTL: - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - if(optlen<1) - return -EINVAL; - err=ip_masq_uctl(optname, optval ,optlen); - return err; - -#endif + err = ip_ra_control(sk, val ? 1 : 0, NULL); + break; + default: - return(-ENOPROTOOPT); +#ifdef CONFIG_NETFILTER + release_sock(sk); + return nf_setsockopt(PF_INET, optname, optval, + (unsigned int)optlen); +#else + err = -ENOPROTOOPT; + break; +#endif } + release_sock(sk); + return err; + +e_inval: + release_sock(sk); + return -EINVAL; } /* @@ -636,17 +637,20 @@ if(get_user(len,optlen)) return -EFAULT; - switch(optname) - { + lock_sock(sk); + + switch(optname) { case IP_OPTIONS: { unsigned char optbuf[sizeof(struct ip_options)+40]; struct ip_options * opt = (struct ip_options*)optbuf; - lock_sock(sk); opt->optlen = 0; - if (sk->opt) - memcpy(optbuf, sk->opt, sizeof(struct ip_options)+sk->opt->optlen); + if (sk->protinfo.af_inet.opt) + memcpy(optbuf, sk->protinfo.af_inet.opt, + sizeof(struct ip_options)+ + sk->protinfo.af_inet.opt->optlen); release_sock(sk); + if (opt->optlen == 0) return put_user(0, optlen); @@ -660,66 +664,104 @@ return 0; } case IP_PKTINFO: - val = (sk->ip_cmsg_flags & IP_CMSG_PKTINFO) != 0; + val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_PKTINFO) != 0; break; case IP_RECVTTL: - val = (sk->ip_cmsg_flags & IP_CMSG_TTL) != 0; + val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TTL) != 0; break; case IP_RECVTOS: - val = (sk->ip_cmsg_flags & IP_CMSG_TOS) != 0; + val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TOS) != 0; break; case IP_RECVOPTS: - val = (sk->ip_cmsg_flags & IP_CMSG_RECVOPTS) != 0; + val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RECVOPTS) != 0; break; case IP_RETOPTS: - val = (sk->ip_cmsg_flags & IP_CMSG_RETOPTS) != 0; + val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RETOPTS) != 0; break; case IP_TOS: - val=sk->ip_tos; + val=sk->protinfo.af_inet.tos; break; case IP_TTL: - val=sk->ip_ttl; + val=sk->protinfo.af_inet.ttl; break; case IP_HDRINCL: - val=sk->ip_hdrincl; + val=sk->protinfo.af_inet.hdrincl; break; case IP_MTU_DISCOVER: - val=sk->ip_pmtudisc; + val=sk->protinfo.af_inet.pmtudisc; break; case IP_MTU: - val = 0; - lock_sock(sk); - if (sk->dst_cache) - val = sk->dst_cache->pmtu; - release_sock(sk); - if (!val) + { + struct dst_entry *dst; + val = 0; + dst = sk_dst_get(sk); + if (dst) { + val = dst->pmtu; + dst_release(dst); + } + if (!val) { + release_sock(sk); return -ENOTCONN; + } break; + } case IP_RECVERR: - val=sk->ip_recverr; + val=sk->protinfo.af_inet.recverr; break; case IP_MULTICAST_TTL: - val=sk->ip_mc_ttl; + val=sk->protinfo.af_inet.mc_ttl; break; case IP_MULTICAST_LOOP: - val=sk->ip_mc_loop; + val=sk->protinfo.af_inet.mc_loop; break; case IP_MULTICAST_IF: { struct ip_mreqn mreq; len = min(len,sizeof(struct ip_mreqn)); + mreq.imr_ifindex = sk->protinfo.af_inet.mc_index; + mreq.imr_address.s_addr = sk->protinfo.af_inet.mc_addr; + mreq.imr_multiaddr.s_addr = 0; + release_sock(sk); + if(put_user(len, optlen)) return -EFAULT; - mreq.imr_ifindex = sk->ip_mc_index; - mreq.imr_address.s_addr = sk->ip_mc_addr; - mreq.imr_multiaddr.s_addr = 0; if(copy_to_user((void *)optval, &mreq, len)) return -EFAULT; return 0; } + case IP_PKTOPTIONS: + { + struct msghdr msg; + + release_sock(sk); + + if (sk->type != SOCK_STREAM) + return -ENOPROTOOPT; + + msg.msg_control = optval; + msg.msg_controllen = len; + msg.msg_flags = 0; + + if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_PKTINFO) { + struct in_pktinfo info; + + info.ipi_addr.s_addr = sk->rcv_saddr; + info.ipi_spec_dst.s_addr = sk->rcv_saddr; + info.ipi_ifindex = sk->protinfo.af_inet.mc_index; + put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); + } + if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_TTL) { + int hlim = sk->protinfo.af_inet.mc_ttl; + put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); + } + len -= msg.msg_controllen; + return put_user(len, optlen); + } default: - return(-ENOPROTOOPT); + release_sock(sk); + return -ENOPROTOOPT; } + release_sock(sk); if (len < sizeof(int) && len > 0 && val>=0 && val<255) { unsigned char ucval = (unsigned char)val; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.3.14/linux/net/ipv4/ipconfig.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/ipconfig.c Mon Aug 23 10:01:02 1999 @@ -1,5 +1,5 @@ /* - * $Id: ipconfig.c,v 1.23 1999/06/28 11:35:07 davem Exp $ + * $Id: ipconfig.c,v 1.24 1999/08/20 00:35:14 davem Exp $ * * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied * information to configure own IP address and routes. diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v2.3.14/linux/net/ipv4/ipip.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ipip.c Mon Aug 23 10:01:02 1999 @@ -1,7 +1,7 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.26 1999/03/25 10:04:32 davem Exp $ + * Version: $Id: ipip.c,v 1.28 1999/08/20 11:05:51 davem Exp $ * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 @@ -133,6 +133,8 @@ static struct ip_tunnel *tunnels_wc[1]; static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; +static rwlock_t ipip_lock = RW_LOCK_UNLOCKED; + static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) { unsigned h0 = HASH(remote); @@ -182,8 +184,9 @@ for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) { if (t == *tp) { + write_lock_bh(&ipip_lock); *tp = t->next; - synchronize_bh(); + write_unlock_bh(&ipip_lock); break; } } @@ -194,8 +197,9 @@ struct ip_tunnel **tp = ipip_bucket(t); t->next = *tp; - wmb(); + write_lock_bh(&ipip_lock); *tp = t; + write_unlock_bh(&ipip_lock); } struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) @@ -234,12 +238,13 @@ nt->dev = dev; dev->name = nt->parms.name; dev->init = ipip_tunnel_init; + dev->new_style = 1; memcpy(&nt->parms, parms, sizeof(*parms)); if (dev->name[0] == 0) { int i; for (i=1; i<100; i++) { sprintf(dev->name, "tunl%d", i); - if (dev_get(dev->name) == NULL) + if (__dev_get_by_name(dev->name) == NULL) break; } if (i==100) @@ -249,6 +254,7 @@ if (register_netdevice(dev) < 0) goto failed; + dev_hold(dev); ipip_tunnel_link(nt); /* Do not decrement MOD_USE_COUNT here. */ return nt; @@ -259,16 +265,23 @@ return NULL; } +static void ipip_tunnel_destructor(struct net_device *dev) +{ + if (dev != &ipip_fb_tunnel_dev) { + MOD_DEC_USE_COUNT; + } +} -static void ipip_tunnel_destroy(struct net_device *dev) +static void ipip_tunnel_uninit(struct net_device *dev) { if (dev == &ipip_fb_tunnel_dev) { + write_lock_bh(&ipip_lock); tunnels_wc[0] = NULL; - synchronize_bh(); + write_unlock_bh(&ipip_lock); + dev_put(dev); } else { ipip_tunnel_unlink((struct ip_tunnel*)dev->priv); - kfree(dev); - MOD_DEC_USE_COUNT; + dev_put(dev); } } @@ -316,17 +329,20 @@ break; } + read_lock(&ipip_lock); t = ipip_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) - return; + goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) - return; + goto out; if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO) t->err_count++; else t->err_count = 1; t->err_time = jiffies; +out: + read_unlock(&ipip_lock); return; #else struct iphdr *iph = (struct iphdr*)dp; @@ -460,6 +476,7 @@ skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; + read_lock(&ipip_lock); if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; @@ -467,8 +484,10 @@ dst_release(skb->dst); skb->dst = NULL; netif_rx(skb); + read_unlock(&ipip_lock); return 0; } + read_unlock(&ipip_lock); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); kfree_skb(skb); @@ -674,14 +693,12 @@ break; } t = (struct ip_tunnel*)dev->priv; - start_bh_atomic(); ipip_tunnel_unlink(t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); ipip_tunnel_link(t); - end_bh_atomic(); netdev_state_change(dev); } } @@ -744,7 +761,8 @@ { struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; - dev->destructor = ipip_tunnel_destroy; + dev->uninit = ipip_tunnel_uninit; + dev->destructor = ipip_tunnel_destructor; dev->hard_start_xmit = ipip_tunnel_xmit; dev->get_stats = ipip_tunnel_get_stats; dev->do_ioctl = ipip_tunnel_ioctl; @@ -783,7 +801,7 @@ } if (!tdev && tunnel->parms.link) - tdev = dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); @@ -823,6 +841,7 @@ iph->protocol = IPPROTO_IPIP; iph->ihl = 5; + dev_hold(dev); tunnels_wc[0] = &ipip_fb_tunnel; return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.3.14/linux/net/ipv4/ipmr.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/ipmr.c Mon Aug 23 10:01:02 1999 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.43 1999/06/09 10:10:59 davem Exp $ + * Version: $Id: ipmr.c,v 1.45 1999/08/20 11:05:53 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -57,8 +57,7 @@ #include #include #include -#include -#include +#include #include #include @@ -66,17 +65,44 @@ #define CONFIG_IP_PIMSM 1 #endif +static struct sock *mroute_socket; + + +/* Big lock, protecting vif table, mrt cache and mroute socket state. + Note that the changes are semaphored via rtnl_lock. + */ + +static rwlock_t mrt_lock = RW_LOCK_UNLOCKED; + /* * Multicast router control variables */ static struct vif_device vif_table[MAXVIFS]; /* Devices */ -static unsigned long vifc_map; /* Active device map */ static int maxvif; + +#define VIF_EXISTS(idx) (vif_table[idx].dev != NULL) + int mroute_do_assert = 0; /* Set in PIM assert */ int mroute_do_pim = 0; + static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */ -int cache_resolve_queue_len = 0; /* Size of unresolved */ + +static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */ +atomic_t cache_resolve_queue_len; /* Size of unresolved */ + +/* Special spinlock for queue of unresolved entries */ +static spinlock_t mfc_unres_lock = SPIN_LOCK_UNLOCKED; + +/* We return to original Alan's scheme. Hash table of resolved + entries is changed only in process context and protected + with weak lock mrt_lock. Queue of unresolved entries is protected + with strong spinlock mfc_unres_lock. + + In this case data path is free of exclusive locks at all. + */ + +kmem_cache_t *mrt_cachep; static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local); static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); @@ -84,13 +110,16 @@ extern struct inet_protocol pim_protocol; +static struct timer_list ipmr_expire_timer; + +/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ + static struct net_device *ipmr_new_tunnel(struct vifctl *v) { - struct net_device *dev = NULL; + struct net_device *dev; - rtnl_lock(); - dev = dev_get("tunl0"); + dev = __dev_get_by_name("tunl0"); if (dev) { int err; @@ -112,10 +141,12 @@ err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL); set_fs(oldfs); - if (err == 0 && (dev = dev_get(p.name)) != NULL) { + dev = NULL; + + if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) { dev->flags |= IFF_MULTICAST; - in_dev = dev->ip_ptr; + in_dev = __in_dev_get(dev); if (in_dev == NULL && (in_dev = inetdev_init(dev)) == NULL) goto failure; in_dev->cnf.rp_filter = 0; @@ -124,25 +155,24 @@ goto failure; } } - rtnl_unlock(); return dev; failure: unregister_netdevice(dev); - rtnl_unlock(); return NULL; } #ifdef CONFIG_IP_PIMSM static int reg_vif_num = -1; -static struct net_device * reg_dev; static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { + read_lock(&mrt_lock); ((struct net_device_stats*)dev->priv)->tx_bytes += skb->len; ((struct net_device_stats*)dev->priv)->tx_packets++; ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT); + read_unlock(&mrt_lock); kfree_skb(skb); return 0; } @@ -176,11 +206,9 @@ dev->flags = IFF_NOARP; dev->hard_start_xmit = reg_vif_xmit; dev->get_stats = reg_vif_get_stats; - - rtnl_lock(); + dev->new_style = 1; if (register_netdevice(dev)) { - rtnl_unlock(); kfree(dev); return NULL; } @@ -194,14 +222,10 @@ if (dev_open(dev)) goto failure; - rtnl_unlock(); - reg_dev = dev; return dev; failure: unregister_netdevice(dev); - rtnl_unlock(); - kfree(dev); return NULL; } #endif @@ -215,217 +239,275 @@ struct vif_device *v; struct net_device *dev; struct in_device *in_dev; - - if (vifi < 0 || vifi >= maxvif || !(vifc_map&(1<= maxvif) return -EADDRNOTAVAIL; v = &vif_table[vifi]; + write_lock_bh(&mrt_lock); dev = v->dev; v->dev = NULL; - vifc_map &= ~(1<ip_ptr) != NULL) - in_dev->cnf.mc_forwarding = 0; - - dev_set_allmulti(dev, -1); - ip_rt_multicast_event(in_dev); + if (!dev) { + write_unlock_bh(&mrt_lock); + return -EADDRNOTAVAIL; + } - if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) { #ifdef CONFIG_IP_PIMSM - if (vifi == reg_vif_num) { - reg_vif_num = -1; - reg_dev = NULL; - } + if (vifi == reg_vif_num) + reg_vif_num = -1; #endif - unregister_netdevice(dev); - if (v->flags&VIFF_REGISTER) - kfree(dev); - } if (vifi+1 == maxvif) { int tmp; for (tmp=vifi-1; tmp>=0; tmp--) { - if (vifc_map&(1<cnf.mc_forwarding--; + ip_rt_multicast_event(in_dev); + } + + if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) + unregister_netdevice(dev); + + dev_put(dev); return 0; } -static void ipmr_update_threshoulds(struct mfc_cache *cache, unsigned char *ttls) -{ - int vifi; +/* Destroy an unresolved cache entry, killing queued skbs + and reporting error to netlink readers. + */ - start_bh_atomic(); +static void ipmr_destroy_unres(struct mfc_cache *c) +{ + struct sk_buff *skb; - cache->mfc_minvif = MAXVIFS; - cache->mfc_maxvif = 0; - memset(cache->mfc_ttls, 255, MAXVIFS); + atomic_dec(&cache_resolve_queue_len); - for (vifi=0; vifimfc_ttls[vifi] = ttls[vifi]; - if (cache->mfc_minvif > vifi) - cache->mfc_minvif = vifi; - if (cache->mfc_maxvif <= vifi) - cache->mfc_maxvif = vifi + 1; - } + while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) { +#ifdef CONFIG_RTNETLINK + if (skb->nh.iph->version == 0) { + struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); + nlh->nlmsg_type = NLMSG_ERROR; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + skb_trim(skb, nlh->nlmsg_len); + ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; + netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); + } else +#endif + kfree_skb(skb); } - end_bh_atomic(); + + kmem_cache_free(mrt_cachep, c); } -/* - * Delete a multicast route cache entry - */ - -static void ipmr_cache_delete(struct mfc_cache *cache) + +/* Single timer process for all the unresolved queue. */ + +void ipmr_expire_process(unsigned long dummy) { - struct sk_buff *skb; - int line; - struct mfc_cache **cp; - - /* - * Find the right cache line - */ + unsigned long now; + unsigned long expires; + struct mfc_cache *c, **cp; - line=MFC_HASH(cache->mfc_mcastgrp,cache->mfc_origin); - cp=&(mfc_cache_array[line]); + if (!spin_trylock(&mfc_unres_lock)) { + mod_timer(&ipmr_expire_timer, jiffies + HZ/10); + return; + } - if(cache->mfc_flags&MFC_QUEUED) - del_timer(&cache->mfc_timer); - - /* - * Unlink the buffer - */ + if (atomic_read(&cache_resolve_queue_len) == 0) + goto out; - while(*cp!=NULL) - { - if(*cp==cache) - { - *cp=cache->next; - break; + now = jiffies; + expires = 10*HZ; + cp = &mfc_unres_queue; + + while ((c=*cp) != NULL) { + long interval = c->mfc_un.unres.expires - now; + + if (interval > 0) { + if (interval < expires) + expires = interval; + cp = &c->next; + continue; } - cp=&((*cp)->next); + + *cp = c->next; + + ipmr_destroy_unres(c); } - /* - * Free the buffer. If it is a pending resolution - * clean up the other resources. - */ + if (atomic_read(&cache_resolve_queue_len)) + mod_timer(&ipmr_expire_timer, jiffies + expires); - if(cache->mfc_flags&MFC_QUEUED) - { - cache_resolve_queue_len--; - while((skb=skb_dequeue(&cache->mfc_unresolved))) { -#ifdef CONFIG_RTNETLINK - if (skb->nh.iph->version == 0) { - struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); - nlh->nlmsg_type = NLMSG_ERROR; - nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); - skb_trim(skb, nlh->nlmsg_len); - ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; - netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); - } else -#endif - kfree_skb(skb); +out: + spin_unlock(&mfc_unres_lock); +} + +/* Fill oifs list. It is called under write locked mrt_lock. */ + +static void ipmr_update_threshoulds(struct mfc_cache *cache, unsigned char *ttls) +{ + int vifi; + + cache->mfc_un.res.minvif = MAXVIFS; + cache->mfc_un.res.maxvif = 0; + memset(cache->mfc_un.res.ttls, 255, MAXVIFS); + + for (vifi=0; vifimfc_un.res.ttls[vifi] = ttls[vifi]; + if (cache->mfc_un.res.minvif > vifi) + cache->mfc_un.res.minvif = vifi; + if (cache->mfc_un.res.maxvif <= vifi) + cache->mfc_un.res.maxvif = vifi + 1; } } - kfree_s(cache,sizeof(cache)); } -/* - * Cache expiry timer - */ - -static void ipmr_cache_timer(unsigned long data) +static int vif_add(struct vifctl *vifc, int mrtsock) { - struct mfc_cache *cache=(struct mfc_cache *)data; - ipmr_cache_delete(cache); -} + int vifi = vifc->vifc_vifi; + struct vif_device *v = &vif_table[vifi]; + struct net_device *dev; + struct in_device *in_dev; -/* - * Insert a multicast cache entry - */ + /* Is vif busy ? */ + if (VIF_EXISTS(vifi)) + return -EADDRINUSE; -static void ipmr_cache_insert(struct mfc_cache *c) -{ - int line=MFC_HASH(c->mfc_mcastgrp,c->mfc_origin); - c->next=mfc_cache_array[line]; - mfc_cache_array[line]=c; + switch (vifc->vifc_flags) { +#ifdef CONFIG_IP_PIMSM + case VIFF_REGISTER: + /* + * Special Purpose VIF in PIM + * All the packets will be sent to the daemon + */ + if (reg_vif_num >= 0) + return -EADDRINUSE; + dev = ipmr_reg_vif(vifc); + if (!dev) + return -ENOBUFS; + break; +#endif + case VIFF_TUNNEL: + dev = ipmr_new_tunnel(vifc); + if (!dev) + return -ENOBUFS; + break; + case 0: + dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr); + if (!dev) + return -EADDRNOTAVAIL; + __dev_put(dev); + break; + default: + return -EINVAL; + } + + if ((in_dev = __in_dev_get(dev)) == NULL) + return -EADDRNOTAVAIL; + in_dev->cnf.mc_forwarding++; + dev_set_allmulti(dev, +1); + ip_rt_multicast_event(in_dev); + + /* + * Fill in the VIF structures + */ + v->rate_limit=vifc->vifc_rate_limit; + v->local=vifc->vifc_lcl_addr.s_addr; + v->remote=vifc->vifc_rmt_addr.s_addr; + v->flags=vifc->vifc_flags; + if (!mrtsock) + v->flags |= VIFF_STATIC; + v->threshold=vifc->vifc_threshold; + v->bytes_in = 0; + v->bytes_out = 0; + v->pkt_in = 0; + v->pkt_out = 0; + v->link = dev->ifindex; + if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) + v->link = dev->iflink; + + /* And finish update writing critical data */ + write_lock_bh(&mrt_lock); + dev_hold(dev); + v->dev=dev; +#ifdef CONFIG_IP_PIMSM + if (v->flags&VIFF_REGISTER) + reg_vif_num = vifi; +#endif + if (vifi+1 > maxvif) + maxvif = vifi+1; + write_unlock_bh(&mrt_lock); + return 0; } - -/* - * Find a multicast cache entry - */ - -struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp) + +static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp) { int line=MFC_HASH(mcastgrp,origin); - struct mfc_cache *cache; + struct mfc_cache *c; - cache=mfc_cache_array[line]; - while(cache!=NULL) - { - if(cache->mfc_origin==origin && cache->mfc_mcastgrp==mcastgrp) - return cache; - cache=cache->next; + for (c=mfc_cache_array[line]; c; c = c->next) { + if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp) + break; } - return NULL; + return c; } /* * Allocate a multicast cache entry */ - -static struct mfc_cache *ipmr_cache_alloc(int priority) +static struct mfc_cache *ipmr_cache_alloc(void) { - struct mfc_cache *c=(struct mfc_cache *)kmalloc(sizeof(struct mfc_cache), priority); + struct mfc_cache *c=kmem_cache_alloc(mrt_cachep, GFP_KERNEL); if(c==NULL) return NULL; memset(c, 0, sizeof(*c)); - skb_queue_head_init(&c->mfc_unresolved); - init_timer(&c->mfc_timer); - c->mfc_timer.data=(long)c; - c->mfc_timer.function=ipmr_cache_timer; - c->mfc_minvif = MAXVIFS; + c->mfc_un.res.minvif = MAXVIFS; return c; } - + +static struct mfc_cache *ipmr_cache_alloc_unres(void) +{ + struct mfc_cache *c=kmem_cache_alloc(mrt_cachep, GFP_ATOMIC); + if(c==NULL) + return NULL; + memset(c, 0, sizeof(*c)); + skb_queue_head_init(&c->mfc_un.unres.unresolved); + c->mfc_un.unres.expires = jiffies + 10*HZ; + return c; +} + /* * A cache entry has gone into a resolved state from queued */ -static void ipmr_cache_resolve(struct mfc_cache *cache) +static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) { struct sk_buff *skb; - start_bh_atomic(); - - /* - * Kill the queue entry timer. - */ - - del_timer(&cache->mfc_timer); - - if (cache->mfc_flags&MFC_QUEUED) { - cache->mfc_flags&=~MFC_QUEUED; - cache_resolve_queue_len--; - } - - end_bh_atomic(); - /* * Play the pending entries through our router */ - while((skb=skb_dequeue(&cache->mfc_unresolved))) { + + while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { #ifdef CONFIG_RTNETLINK if (skb->nh.iph->version == 0) { int err; struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); - if (ipmr_fill_mroute(skb, cache, NLMSG_DATA(nlh)) > 0) { + if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { nlh->nlmsg_len = skb->tail - (u8*)nlh; } else { nlh->nlmsg_type = NLMSG_ERROR; @@ -436,13 +518,15 @@ err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else #endif - ip_mr_forward(skb, cache, 0); + ip_mr_forward(skb, c, 0); } } /* * Bounce a cache query up to mrouted. We could use netlink for this but mrouted - * expects the following bizarre scheme.. + * expects the following bizarre scheme. + * + * Called under mrt_lock. */ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) @@ -453,9 +537,6 @@ struct igmpmsg *msg; int ret; - if (mroute_socket==NULL) - return -EINVAL; - #ifdef CONFIG_IP_PIMSM if (assert == IGMPMSG_WHOLEPKT) skb = skb_realloc_headroom(pkt, sizeof(struct iphdr)); @@ -507,7 +588,12 @@ skb->nh.iph->tot_len=htons(skb->len); /* Fix the length */ skb->h.raw = skb->nh.raw; } - + + if (mroute_socket == NULL) { + kfree_skb(skb); + return -EINVAL; + } + /* * Deliver to mrouted */ @@ -521,154 +607,237 @@ } /* - * Queue a packet for resolution + * Queue a packet for resolution. It gets locked cache entry! */ -static int ipmr_cache_unresolved(struct mfc_cache *cache, vifi_t vifi, struct sk_buff *skb) +static int +ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) { - if(cache==NULL) - { + int err; + struct mfc_cache *c; + + spin_lock_bh(&mfc_unres_lock); + for (c=mfc_unres_queue; c; c=c->next) { + if (c->mfc_mcastgrp == skb->nh.iph->daddr && + c->mfc_origin == skb->nh.iph->saddr) + break; + } + + if (c == NULL) { /* * Create a new entry if allowable */ - if(cache_resolve_queue_len>=10 || (cache=ipmr_cache_alloc(GFP_ATOMIC))==NULL) - { + + if (atomic_read(&cache_resolve_queue_len)>=10 || + (c=ipmr_cache_alloc_unres())==NULL) { + spin_unlock_bh(&mfc_unres_lock); + kfree_skb(skb); return -ENOBUFS; } + /* * Fill in the new cache entry */ - cache->mfc_parent=ALL_VIFS; - cache->mfc_origin=skb->nh.iph->saddr; - cache->mfc_mcastgrp=skb->nh.iph->daddr; - cache->mfc_flags=MFC_QUEUED; - /* - * Link to the unresolved list - */ - ipmr_cache_insert(cache); - cache_resolve_queue_len++; - /* - * Fire off the expiry timer - */ - cache->mfc_timer.expires=jiffies+10*HZ; - add_timer(&cache->mfc_timer); + c->mfc_parent=-1; + c->mfc_origin=skb->nh.iph->saddr; + c->mfc_mcastgrp=skb->nh.iph->daddr; + /* * Reflect first query at mrouted. */ - if(mroute_socket) - { + if ((err = ipmr_cache_report(skb, vifi, IGMPMSG_NOCACHE))<0) { /* If the report failed throw the cache entry out - Brad Parker - - OK, OK, Brad. Only do not forget to free skb - and return :-) --ANK */ - if (ipmr_cache_report(skb, vifi, IGMPMSG_NOCACHE)<0) { - ipmr_cache_delete(cache); - kfree_skb(skb); - return -ENOBUFS; - } + spin_unlock_bh(&mfc_unres_lock); + + kmem_cache_free(mrt_cachep, c); + kfree_skb(skb); + return err; } + + atomic_inc(&cache_resolve_queue_len); + c->next = mfc_unres_queue; + mfc_unres_queue = c; + + if (!del_timer(&ipmr_expire_timer)) + ipmr_expire_timer.expires = c->mfc_un.unres.expires; + add_timer(&ipmr_expire_timer); } + /* * See if we can append the packet */ - if(cache->mfc_queuelen>3) - { + if (c->mfc_un.unres.unresolved.qlen>3) { kfree_skb(skb); - return -ENOBUFS; + err = -ENOBUFS; + } else { + skb_queue_tail(&c->mfc_un.unres.unresolved,skb); + err = 0; } - cache->mfc_queuelen++; - skb_queue_tail(&cache->mfc_unresolved,skb); - return 0; + + spin_unlock_bh(&mfc_unres_lock); + return err; } /* * MFC cache manipulation by user space mroute daemon */ - -int ipmr_mfc_modify(int action, struct mfcctl *mfc) + +int ipmr_mfc_delete(struct mfcctl *mfc) { - struct mfc_cache *cache; + int line; + struct mfc_cache *c, **cp; + + line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); + + for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) { + if (c->mfc_origin == mfc->mfcc_origin.s_addr && + c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) { + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + return 0; + } + } + return -ENOENT; +} + +int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock) +{ + int line; + struct mfc_cache *uc, *c, **cp; + + line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); + + for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) { + if (c->mfc_origin == mfc->mfcc_origin.s_addr && + c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) + break; + } + + if (c != NULL) { + write_lock_bh(&mrt_lock); + c->mfc_parent = mfc->mfcc_parent; + ipmr_update_threshoulds(c, mfc->mfcc_ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + write_unlock_bh(&mrt_lock); + return 0; + } if(!MULTICAST(mfc->mfcc_mcastgrp.s_addr)) return -EINVAL; - /* - * Find the cache line - */ - - start_bh_atomic(); - cache=ipmr_cache_find(mfc->mfcc_origin.s_addr,mfc->mfcc_mcastgrp.s_addr); - + c=ipmr_cache_alloc(); + if (c==NULL) + return -ENOMEM; + + c->mfc_origin=mfc->mfcc_origin.s_addr; + c->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr; + c->mfc_parent=mfc->mfcc_parent; + ipmr_update_threshoulds(c, mfc->mfcc_ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + + write_lock_bh(&mrt_lock); + c->next = mfc_cache_array[line]; + mfc_cache_array[line] = c; + write_unlock_bh(&mrt_lock); + /* - * Delete an entry + * Check to see if we resolved a queued list. If so we + * need to send on the frames and tidy up. */ - if(action==MRT_DEL_MFC) - { - if(cache) - { - ipmr_cache_delete(cache); - end_bh_atomic(); - return 0; + spin_lock_bh(&mfc_unres_lock); + for (cp = &mfc_unres_queue; (uc=*cp) != NULL; + cp = &uc->next) { + if (uc->mfc_origin == c->mfc_origin && + uc->mfc_mcastgrp == c->mfc_mcastgrp) { + *cp = uc->next; + if (atomic_dec_and_test(&cache_resolve_queue_len)) + del_timer(&ipmr_expire_timer); + break; } - end_bh_atomic(); - return -ENOENT; } - if(cache) - { + spin_unlock_bh(&mfc_unres_lock); - /* - * Update the cache, see if it frees a pending queue - */ + if (uc) { + ipmr_cache_resolve(uc, c); + kmem_cache_free(mrt_cachep, uc); + } + return 0; +} - cache->mfc_flags|=MFC_RESOLVED; - cache->mfc_parent=mfc->mfcc_parent; - ipmr_update_threshoulds(cache, mfc->mfcc_ttls); - - /* - * Check to see if we resolved a queued list. If so we - * need to send on the frames and tidy up. - */ - - if(cache->mfc_flags&MFC_QUEUED) - ipmr_cache_resolve(cache); /* Unhook & send the frames */ - end_bh_atomic(); - return 0; +/* + * Close the multicast socket, and clear the vif tables etc + */ + +static void mroute_clean_tables(struct sock *sk) +{ + int i; + + /* + * Shut down all active vif entries + */ + for(i=0; imfc_flags&MFC_STATIC) { + cp = &c->next; + continue; + } + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + } + } + + if (atomic_read(&cache_resolve_queue_len) != 0) { + struct mfc_cache *c; + + spin_lock_bh(&mfc_unres_lock); + while (mfc_unres_queue != NULL) { + c = mfc_unres_queue; + mfc_unres_queue = c->next; + spin_unlock_bh(&mfc_unres_lock); + + ipmr_destroy_unres(c); + + spin_lock_bh(&mfc_unres_lock); + } + spin_unlock_bh(&mfc_unres_lock); } - cache->mfc_flags=MFC_RESOLVED; - cache->mfc_origin=mfc->mfcc_origin.s_addr; - cache->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr; - cache->mfc_parent=mfc->mfcc_parent; - ipmr_update_threshoulds(cache, mfc->mfcc_ttls); - ipmr_cache_insert(cache); - end_bh_atomic(); - return 0; } static void mrtsock_destruct(struct sock *sk) { + rtnl_lock(); if (sk == mroute_socket) { - ipv4_devconf.mc_forwarding = 0; + ipv4_devconf.mc_forwarding--; + write_lock_bh(&mrt_lock); mroute_socket=NULL; - synchronize_bh(); + write_unlock_bh(&mrt_lock); - mroute_close(sk); + mroute_clean_tables(sk); } + rtnl_unlock(); } /* @@ -680,15 +849,16 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) { + int ret; struct vifctl vif; struct mfcctl mfc; if(optname!=MRT_INIT) { - if(sk!=mroute_socket) + if(sk!=mroute_socket && !capable(CAP_NET_ADMIN)) return -EACCES; } - + switch(optname) { case MRT_INIT: @@ -696,22 +866,26 @@ return -EOPNOTSUPP; if(optlen!=sizeof(int)) return -ENOPROTOOPT; - { - int opt; - if (get_user(opt,(int *)optval)) - return -EFAULT; - if (opt != 1) - return -ENOPROTOOPT; - } - if(mroute_socket) + + rtnl_lock(); + if (mroute_socket) { + rtnl_unlock(); return -EADDRINUSE; - mroute_socket=sk; - ipv4_devconf.mc_forwarding = 1; - if (ip_ra_control(sk, 1, mrtsock_destruct) == 0) - return 0; - mrtsock_destruct(sk); - return -EADDRINUSE; + } + + ret = ip_ra_control(sk, 1, mrtsock_destruct); + if (ret == 0) { + write_lock_bh(&mrt_lock); + mroute_socket=sk; + write_unlock_bh(&mrt_lock); + + ipv4_devconf.mc_forwarding++; + } + rtnl_unlock(); + return ret; case MRT_DONE: + if (sk!=mroute_socket) + return -EACCES; return ip_ra_control(sk, 0, NULL); case MRT_ADD_VIF: case MRT_DEL_VIF: @@ -721,88 +895,14 @@ return -EFAULT; if(vif.vifc_vifi >= MAXVIFS) return -ENFILE; - if(optname==MRT_ADD_VIF) - { - struct vif_device *v=&vif_table[vif.vifc_vifi]; - struct net_device *dev; - struct in_device *in_dev; - - /* Is vif busy ? */ - if (vifc_map&(1<= 0) - return -EADDRINUSE; - reg_vif_num = vif.vifc_vifi; - dev = ipmr_reg_vif(&vif); - if (!dev) { - reg_vif_num = -1; - return -ENOBUFS; - } - break; -#endif - case VIFF_TUNNEL: - dev = ipmr_new_tunnel(&vif); - if (!dev) - return -ENOBUFS; - break; - case 0: - dev=ip_dev_find(vif.vifc_lcl_addr.s_addr); - if (!dev) - return -EADDRNOTAVAIL; - break; - default: -#if 0 - printk(KERN_DEBUG "ipmr_add_vif: flags %02x\n", vif.vifc_flags); -#endif - return -EINVAL; - } - - if ((in_dev = dev->ip_ptr) == NULL) - return -EADDRNOTAVAIL; - if (in_dev->cnf.mc_forwarding) - return -EADDRINUSE; - in_dev->cnf.mc_forwarding = 1; - dev_set_allmulti(dev, +1); - ip_rt_multicast_event(in_dev); - - /* - * Fill in the VIF structures - */ - start_bh_atomic(); - v->rate_limit=vif.vifc_rate_limit; - v->local=vif.vifc_lcl_addr.s_addr; - v->remote=vif.vifc_rmt_addr.s_addr; - v->flags=vif.vifc_flags; - v->threshold=vif.vifc_threshold; - v->dev=dev; - v->bytes_in = 0; - v->bytes_out = 0; - v->pkt_in = 0; - v->pkt_out = 0; - v->link = dev->ifindex; - if (vif.vifc_flags&(VIFF_TUNNEL|VIFF_REGISTER)) - v->link = dev->iflink; - vifc_map|=(1< maxvif) - maxvif = vif.vifc_vifi+1; - end_bh_atomic(); - return 0; + rtnl_lock(); + if (optname==MRT_ADD_VIF) { + ret = vif_add(&vif, sk==mroute_socket); } else { - int ret; - rtnl_lock(); ret = vif_delete(vif.vifc_vifi); - rtnl_unlock(); - return ret; } + rtnl_unlock(); + return ret; /* * Manipulate the forwarding caches. These live @@ -814,7 +914,13 @@ return -EINVAL; if (copy_from_user(&mfc,optval, sizeof(mfc))) return -EFAULT; - return ipmr_mfc_modify(optname, &mfc); + rtnl_lock(); + if (optname==MRT_DEL_MFC) + ret = ipmr_mfc_delete(&mfc); + else + ret = ipmr_mfc_add(&mfc, sk==mroute_socket); + rtnl_unlock(); + return ret; /* * Control PIM assert. */ @@ -833,6 +939,7 @@ if(get_user(v,(int *)optval)) return -EFAULT; v = (v)?1:0; + rtnl_lock(); if (v != mroute_do_pim) { mroute_do_pim = v; mroute_do_assert = v; @@ -843,6 +950,7 @@ inet_del_protocol(&pim_protocol); #endif } + rtnl_unlock(); return 0; } #endif @@ -864,15 +972,13 @@ int olr; int val; - if(sk!=mroute_socket) - return -EACCES; if(optname!=MRT_VERSION && #ifdef CONFIG_IP_PIMSM optname!=MRT_PIM && #endif optname!=MRT_ASSERT) return -ENOPROTOOPT; - + if(get_user(olr, optlen)) return -EFAULT; @@ -910,66 +1016,44 @@ return -EFAULT; if(vr.vifi>=maxvif) return -EINVAL; + read_lock(&mrt_lock); vif=&vif_table[vr.vifi]; - if(vifc_map&(1<pkt_in; vr.ocount=vif->pkt_out; vr.ibytes=vif->bytes_in; vr.obytes=vif->bytes_out; + read_unlock(&mrt_lock); + if (copy_to_user((void *)arg,&vr,sizeof(vr))) return -EFAULT; return 0; } + read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT: if (copy_from_user(&sr,(void *)arg,sizeof(sr))) - return -EFAULT; - for (c = mfc_cache_array[MFC_HASH(sr.grp.s_addr, sr.src.s_addr)]; - c; c = c->next) { - if (sr.grp.s_addr == c->mfc_mcastgrp && - sr.src.s_addr == c->mfc_origin) { - sr.pktcnt = c->mfc_pkt; - sr.bytecnt = c->mfc_bytes; - sr.wrong_if = c->mfc_wrong_if; - if (copy_to_user((void *)arg,&sr,sizeof(sr))) - return -EFAULT; - return 0; - } + return -EFAULT; + + read_lock(&mrt_lock); + c = ipmr_cache_find(sr.src.s_addr, sr.grp.s_addr); + if (c) { + sr.pktcnt = c->mfc_un.res.pkt; + sr.bytecnt = c->mfc_un.res.bytes; + sr.wrong_if = c->mfc_un.res.wrong_if; + read_unlock(&mrt_lock); + + if (copy_to_user((void *)arg,&sr,sizeof(sr))) + return -EFAULT; + return 0; } + read_unlock(&mrt_lock); return -EADDRNOTAVAIL; default: return -ENOIOCTLCMD; } } -/* - * Close the multicast socket, and clear the vif tables etc - */ - -void mroute_close(struct sock *sk) -{ - int i; - - /* - * Shut down all active vif entries - */ - rtnl_lock(); - for(i=0; idev==ptr) + for(ct=0;ctdev==ptr) vif_delete(ct); - v++; } return NOTIFY_DONE; } @@ -1019,6 +1102,16 @@ skb->nh.iph = iph; } +static inline int ipmr_forward_finish(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + + if (skb->len <= dst->pmtu) + return dst->output(skb); + else + return ip_fragment(skb, dst->output); +} + /* * Processing handlers for ipmr_forward */ @@ -1033,6 +1126,9 @@ int encap = 0; struct sk_buff *skb2; + if (vif->dev == NULL) + return; + #ifdef CONFIG_IP_PIMSM if (vif->flags & VIFF_REGISTER) { vif->pkt_out++; @@ -1090,34 +1186,17 @@ iph = skb2->nh.iph; ip_decrease_ttl(iph); -#ifdef CONFIG_FIREWALL - if (call_fw_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { - kfree_skb(skb2); - return; - } - if (call_out_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { - kfree_skb(skb2); - return; - } -#endif + /* FIXME: forward and output firewalls used to be called here. + * What do we do with netfilter? -- RR */ if (vif->flags & VIFF_TUNNEL) { ip_encap(skb2, vif->local, vif->remote); -#ifdef CONFIG_FIREWALL - /* Double output firewalling on tunnels: one is on tunnel - another one is on real device. - */ - if (call_out_firewall(PF_INET, dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { - kfree_skb(skb2); - return; - } -#endif + /* FIXME: extra output firewall step used to be here. --RR */ ((struct ip_tunnel *)vif->dev->priv)->stat.tx_packets++; ((struct ip_tunnel *)vif->dev->priv)->stat.tx_bytes+=skb2->len; } IPCB(skb2)->flags |= IPSKB_FORWARDED; - /* * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally * not only before forwarding, but after forwarding on all output @@ -1129,20 +1208,18 @@ * not mrouter) cannot join to more than one interface - it will * result in receiving multiple packets. */ - if (skb2->len <= rt->u.dst.pmtu) - skb2->dst->output(skb2); - else - ip_fragment(skb2, skb2->dst->output); + NF_HOOK(PF_INET, NF_IP_FORWARD, skb2, skb->dev, dev, + ipmr_forward_finish); } int ipmr_find_vif(struct net_device *dev) { int ct; - for (ct=0; ct=0; ct--) { + if (vif_table[ct].dev == dev) + break; } - return ALL_VIFS; + return ct; } /* "local" means that we should preserve one skb (for local delivery) */ @@ -1153,8 +1230,8 @@ int vif, ct; vif = cache->mfc_parent; - cache->mfc_pkt++; - cache->mfc_bytes += skb->len; + cache->mfc_un.res.pkt++; + cache->mfc_un.res.bytes += skb->len; /* * Wrong interface: drop packet and (maybe) send PIM assert. @@ -1177,18 +1254,18 @@ goto dont_forward; } - cache->mfc_wrong_if++; + cache->mfc_un.res.wrong_if++; true_vifi = ipmr_find_vif(skb->dev); - if (true_vifi < MAXVIFS && mroute_do_assert && + if (true_vifi >= 0 && mroute_do_assert && /* pimsm uses asserts, when switching from RPT to SPT, so that we cannot check that packet arrived on an oif. It is bad, but otherwise we would need to move pretty large chunk of pimd to kernel. Ough... --ANK */ - (mroute_do_pim || cache->mfc_ttls[true_vifi] < 255) && - jiffies - cache->mfc_last_assert > MFC_ASSERT_THRESH) { - cache->mfc_last_assert = jiffies; + (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) && + jiffies - cache->mfc_un.res.last_assert > MFC_ASSERT_THRESH) { + cache->mfc_un.res.last_assert = jiffies; ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF); } goto dont_forward; @@ -1200,8 +1277,8 @@ /* * Forward the frame */ - for (ct = cache->mfc_maxvif-1; ct >= cache->mfc_minvif; ct--) { - if (skb->nh.iph->ttl > cache->mfc_ttls[ct]) { + for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) { + if (skb->nh.iph->ttl > cache->mfc_un.res.ttls[ct]) { if (psend != -1) ipmr_queue_xmit(skb, cache, psend, 0); psend=ct; @@ -1236,48 +1313,61 @@ if (IPCB(skb)->opt.router_alert) { if (ip_call_ra_chain(skb)) return 0; - } else if (skb->nh.iph->protocol == IPPROTO_IGMP && mroute_socket) { + } else if (skb->nh.iph->protocol == IPPROTO_IGMP){ /* IGMPv1 (and broken IGMPv2 implementations sort of Cisco IOS <= 11.2(8)) do not put router alert option to IGMP packets destined to routable groups. It is very bad, because it means that we can forward NO IGMP messages. */ - raw_rcv(mroute_socket, skb); - return 0; + read_lock(&mrt_lock); + if (mroute_socket) { + raw_rcv(mroute_socket, skb); + read_unlock(&mrt_lock); + return 0; + } + read_unlock(&mrt_lock); } } + read_lock(&mrt_lock); cache = ipmr_cache_find(skb->nh.iph->saddr, skb->nh.iph->daddr); /* * No usable cache entry */ - - if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) { + if (cache==NULL) { int vif; if (local) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); ip_local_deliver(skb); - if (skb2 == NULL) + if (skb2 == NULL) { + read_unlock(&mrt_lock); return -ENOBUFS; + } skb = skb2; } vif = ipmr_find_vif(skb->dev); - if (vif != ALL_VIFS) { - ipmr_cache_unresolved(cache, vif, skb); - return -EAGAIN; + if (vif >= 0) { + int err = ipmr_cache_unresolved(vif, skb); + read_unlock(&mrt_lock); + + return err; } + read_unlock(&mrt_lock); kfree_skb(skb); - return 0; + return -ENODEV; } ip_mr_forward(skb, cache, local); + read_unlock(&mrt_lock); + if (local) return ip_local_deliver(skb); + return 0; dont_forward: @@ -1296,11 +1386,11 @@ { struct igmphdr *pim = (struct igmphdr*)skb->h.raw; struct iphdr *encap; + struct net_device *reg_dev = NULL; if (!mroute_do_pim || len < sizeof(*pim) + sizeof(*encap) || - pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER || - reg_dev == NULL) { + pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) { kfree_skb(skb); return -EINVAL; } @@ -1318,6 +1408,19 @@ kfree_skb(skb); return -EINVAL; } + + read_lock(&mrt_lock); + if (reg_vif_num >= 0) + reg_dev = vif_table[reg_vif_num].dev; + if (reg_dev) + dev_hold(reg_dev); + read_unlock(&mrt_lock); + + if (reg_dev == NULL) { + kfree_skb(skb); + return -EINVAL; + } + skb->mac.raw = skb->nh.raw; skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; @@ -1331,6 +1434,7 @@ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; netif_rx(skb); + dev_put(reg_dev); return 0; } #endif @@ -1340,11 +1444,11 @@ { struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw; struct iphdr *encap; + struct net_device *reg_dev = NULL; if (len < sizeof(*pim) + sizeof(*encap) || pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || - reg_dev == NULL || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && ip_compute_csum((void *)pim, len))) { kfree_skb(skb); @@ -1359,6 +1463,19 @@ kfree_skb(skb); return -EINVAL; } + + read_lock(&mrt_lock); + if (reg_vif_num >= 0) + reg_dev = vif_table[reg_vif_num].dev; + if (reg_dev) + dev_hold(reg_dev); + read_unlock(&mrt_lock); + + if (reg_dev == NULL) { + kfree_skb(skb); + return -EINVAL; + } + skb->mac.raw = skb->nh.raw; skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; @@ -1372,6 +1489,7 @@ ((struct net_device_stats*)reg_dev->priv)->rx_packets++; skb->dst = NULL; netif_rx(skb); + dev_put(reg_dev); return 0; } #endif @@ -1392,13 +1510,13 @@ mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0)); - for (ct = c->mfc_minvif; ct < c->mfc_maxvif; ct++) { - if (c->mfc_ttls[ct] < 255) { + for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { + if (c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); nhp->rtnh_flags = 0; - nhp->rtnh_hops = c->mfc_ttls[ct]; + nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; nhp->rtnh_ifindex = vif_table[ct].dev->ifindex; nhp->rtnh_len = sizeof(*nhp); } @@ -1415,24 +1533,25 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) { + int err; struct mfc_cache *cache; struct rtable *rt = (struct rtable*)skb->dst; - start_bh_atomic(); + read_lock(&mrt_lock); cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); - if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) { + + if (cache==NULL) { struct net_device *dev; int vif; - int err; if (nowait) { - end_bh_atomic(); + read_unlock(&mrt_lock); return -EAGAIN; } dev = skb->dev; - if (dev == NULL || (vif = ipmr_find_vif(dev)) == ALL_VIFS) { - end_bh_atomic(); + if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) { + read_unlock(&mrt_lock); return -ENODEV; } skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); @@ -1440,18 +1559,16 @@ skb->nh.iph->saddr = rt->rt_src; skb->nh.iph->daddr = rt->rt_dst; skb->nh.iph->version = 0; - err = ipmr_cache_unresolved(cache, vif, skb); - end_bh_atomic(); + err = ipmr_cache_unresolved(vif, skb); + read_unlock(&mrt_lock); return err; } - /* Resolved cache entry is not changed by net bh, - so that we are allowed to enable it. - */ - end_bh_atomic(); if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) cache->mfc_flags |= MFC_NOTIFY; - return ipmr_fill_mroute(skb, cache, rtm); + err = ipmr_fill_mroute(skb, cache, rtm); + read_unlock(&mrt_lock); + return err; } #endif @@ -1472,11 +1589,12 @@ "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n"); pos=len; + read_lock(&mrt_lock); for (ct=0;ctdev) name = vif->dev->name; @@ -1493,11 +1611,14 @@ if(pos>offset+length) break; } + read_unlock(&mrt_lock); *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; + if (len<0) + len = 0; return len; } @@ -1513,12 +1634,11 @@ len += sprintf(buffer, "Group Origin Iif Pkts Bytes Wrong Oifs\n"); pos=len; - + + read_lock(&mrt_lock); for (ct=0;ctnext) { int n; @@ -1528,14 +1648,14 @@ size = sprintf(buffer+len, "%08lX %08lX %-3d %8ld %8ld %8ld", (unsigned long)mfc->mfc_mcastgrp, (unsigned long)mfc->mfc_origin, - mfc->mfc_parent == ALL_VIFS ? -1 : mfc->mfc_parent, - (mfc->mfc_flags & MFC_QUEUED) ? mfc->mfc_unresolved.qlen : mfc->mfc_pkt, - mfc->mfc_bytes, - mfc->mfc_wrong_if); - for(n=mfc->mfc_minvif;nmfc_maxvif;n++) + mfc->mfc_parent, + mfc->mfc_un.res.pkt, + mfc->mfc_un.res.bytes, + mfc->mfc_un.res.wrong_if); + for(n=mfc->mfc_un.res.minvif;nmfc_un.res.maxvif;n++) { - if(vifc_map&(1<mfc_ttls[n] < 255) - size += sprintf(buffer+len+size, " %2d:%-3d", n, mfc->mfc_ttls[n]); + if(VIF_EXISTS(n) && mfc->mfc_un.res.ttls[n] < 255) + size += sprintf(buffer+len+size, " %2d:%-3d", n, mfc->mfc_un.res.ttls[n]); } size += sprintf(buffer+len+size, "\n"); len+=size; @@ -1546,15 +1666,32 @@ begin=pos; } if(pos>offset+length) - { - end_bh_atomic(); goto done; - } - mfc=mfc->next; } - end_bh_atomic(); } + + spin_lock_bh(&mfc_unres_lock); + for(mfc=mfc_unres_queue; mfc; mfc=mfc->next) { + size = sprintf(buffer+len, "%08lX %08lX %-3d %8ld %8ld %8ld\n", + (unsigned long)mfc->mfc_mcastgrp, + (unsigned long)mfc->mfc_origin, + -1, + (long)mfc->mfc_un.unres.unresolved.qlen, + 0L, 0L); + len+=size; + pos+=size; + if(posoffset+length) + break; + } + spin_unlock_bh(&mfc_unres_lock); + done: + read_unlock(&mrt_lock); *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) @@ -1601,6 +1738,12 @@ __initfunc(void ip_mr_init(void)) { printk(KERN_INFO "Linux IP multicast router 0.06 plus PIM-SM\n"); + mrt_cachep = kmem_cache_create("ip_mrt_cache", + sizeof(struct mfc_cache), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + init_timer(&ipmr_expire_timer); + ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier); #ifdef CONFIG_PROC_FS proc_net_register(&proc_net_ipmr_vif); diff -u --recursive --new-file v2.3.14/linux/net/ipv4/protocol.c linux/net/ipv4/protocol.c --- v2.3.14/linux/net/ipv4/protocol.c Sun Nov 30 14:00:39 1997 +++ linux/net/ipv4/protocol.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * INET protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.9 1997/10/29 20:27:34 kuznet Exp $ + * Version: $Id: protocol.c,v 1.10 1999/08/20 11:05:55 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -116,25 +116,7 @@ NULL }; - -/* - * Find a protocol in the protocol tables given its - * IP type. - */ - -struct inet_protocol *inet_get_protocol(unsigned char prot) -{ - unsigned char hash; - struct inet_protocol *p; - - hash = prot & (MAX_INET_PROTOS - 1); - for (p = inet_protos[hash] ; p != NULL; p=p->next) - { - if (p->protocol == prot) - return((struct inet_protocol *) p); - } - return(NULL); -} +rwlock_t inet_protocol_lock = RW_LOCK_UNLOCKED; /* * Add a protocol handler to the hash tables @@ -146,6 +128,7 @@ struct inet_protocol *p2; hash = prot->protocol & (MAX_INET_PROTOS - 1); + write_lock_bh(&inet_protocol_lock); prot ->next = inet_protos[hash]; inet_protos[hash] = prot; prot->copy = 0; @@ -164,6 +147,7 @@ } p2 = (struct inet_protocol *) p2->next; } + write_unlock_bh(&inet_protocol_lock); } /* @@ -177,9 +161,11 @@ unsigned char hash; hash = prot->protocol & (MAX_INET_PROTOS - 1); + write_lock_bh(&inet_protocol_lock); if (prot == inet_protos[hash]) { inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next; + write_unlock_bh(&inet_protocol_lock); return(0); } @@ -200,6 +186,7 @@ if (p->copy == 0 && lp != NULL) lp->copy = 0; p->next = prot->next; + write_unlock_bh(&inet_protocol_lock); return(0); } if (p->next != NULL && p->next->protocol == prot->protocol) @@ -207,5 +194,6 @@ p = (struct inet_protocol *) p->next; } + write_unlock_bh(&inet_protocol_lock); return(-1); } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v2.3.14/linux/net/ipv4/rarp.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/rarp.c Wed Dec 31 16:00:00 1969 @@ -1,606 +0,0 @@ -/* linux/net/inet/rarp.c - * - * Copyright (C) 1994 by Ross Martin - * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche - * - * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $ - * - * This module implements the Reverse Address Resolution Protocol - * (RARP, RFC 903), which is used to convert low level addresses such - * as Ethernet addresses into high level addresses such as IP addresses. - * The most common use of RARP is as a means for a diskless workstation - * to discover its IP address during a network boot. - * - ** - *** WARNING:::::::::::::::::::::::::::::::::WARNING - **** - ***** SUN machines seem determined to boot solely from the person who - **** answered their RARP query. NEVER add a SUN to your RARP table - *** unless you have all the rest to boot the box from it. - ** - * - * Currently, only Ethernet address -> IP address is likely to work. - * (Is RARP ever used for anything else?) - * - * This code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes - * Alan Cox : Rarp delete on device down needed as - * reported by Walter Wolfgang. - * Mike McLagan : Routing by source - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) -#include -#endif -#include -#include - -extern int (*rarp_ioctl_hook)(unsigned int,void*); - -/* - * This structure defines the RARP mapping cache. As long as we make - * changes in this structure, we keep interrupts off. - */ - -struct rarp_table -{ - struct rarp_table *next; /* Linked entry list */ - unsigned long ip; /* ip address of entry */ - unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ - unsigned char hlen; /* Length of hardware address */ - unsigned char htype; /* Type of hardware in use */ - struct net_device *dev; /* Device the entry is tied to */ -}; - -struct rarp_table *rarp_tables = NULL; - -static int rarp_rcv(struct sk_buff *, struct net_device *, struct packet_type *); - -static struct packet_type rarp_packet_type = -{ - 0, /* Should be: __constant_htons(ETH_P_RARP) - but this _doesn't_ come out constant! */ - 0, /* copy */ - rarp_rcv, - NULL, - NULL -}; - -static int initflag = 1; - - -/* - * Release the memory for this entry. - */ - -static inline void rarp_release_entry(struct rarp_table *entry) -{ - kfree_s(entry, sizeof(struct rarp_table)); - MOD_DEC_USE_COUNT; - return; -} - -/* - * Delete a RARP mapping entry in the cache. - */ - -static void rarp_destroy(unsigned long ip_addr) -{ - struct rarp_table *entry; - struct rarp_table **pentry; - - start_bh_atomic(); - pentry = &rarp_tables; - while ((entry = *pentry) != NULL) - { - if (entry->ip == ip_addr) - { - *pentry = entry->next; - end_bh_atomic(); - rarp_release_entry(entry); - return; - } - pentry = &entry->next; - } - end_bh_atomic(); -} - -/* - * Flush a device. - */ - -static void rarp_destroy_dev(struct net_device *dev) -{ - struct rarp_table *entry; - struct rarp_table **pentry; - - start_bh_atomic(); - pentry = &rarp_tables; - while ((entry = *pentry) != NULL) - { - if (entry->dev == dev) - { - *pentry = entry->next; - rarp_release_entry(entry); - } - else - pentry = &entry->next; - } - end_bh_atomic(); -} - -static int rarp_device_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - if(event!=NETDEV_DOWN) - return NOTIFY_DONE; - rarp_destroy_dev((struct net_device *)ptr); - return NOTIFY_DONE; -} - -/* - * Called once when data first added to rarp cache with ioctl. - */ - -static struct notifier_block rarp_dev_notifier={ - rarp_device_event, - NULL, - 0 -}; - -static int rarp_pkt_inited=0; - -static void rarp_init_pkt (void) -{ - /* Register the packet type */ - rarp_packet_type.type=htons(ETH_P_RARP); - dev_add_pack(&rarp_packet_type); - register_netdevice_notifier(&rarp_dev_notifier); - rarp_pkt_inited=1; -} - -#ifdef MODULE - -static void rarp_end_pkt(void) -{ - if(!rarp_pkt_inited) - return; - dev_remove_pack(&rarp_packet_type); - unregister_netdevice_notifier(&rarp_dev_notifier); - rarp_pkt_inited=0; -} - -#endif - -/* - * Receive an arp request by the device layer. Maybe it should be - * rewritten to use the incoming packet for the reply. The current - * "overhead" time isn't that high... - */ - -static int rarp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) -{ -/* - * We shouldn't use this type conversion. Check later. - */ - struct arphdr *rarp = (struct arphdr *) skb->data; - unsigned char *rarp_ptr = skb_pull(skb,sizeof(struct arphdr)); - struct rarp_table *entry; - struct in_device *in_dev = dev->ip_ptr; - long sip,tip; - unsigned char *sha,*tha; /* s for "source", t for "target" */ - -/* - * If this test doesn't pass, it's not IP, or we should ignore it anyway - */ - - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) - || dev->flags&IFF_NOARP || !in_dev || !in_dev->ifa_list) - { - kfree_skb(skb); - return 0; - } - -/* - * If it's not a RARP request, delete it. - */ - if (rarp->ar_op != htons(ARPOP_RREQUEST)) - { - kfree_skb(skb); - return 0; - } - -/* - * For now we will only deal with IP addresses. - */ - - if ( -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || -#endif - (rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) - || rarp->ar_pln != 4) - { - /* - * This packet is not for us. Remove it. - */ - kfree_skb(skb); - return 0; - } - -/* - * Extract variable width fields - */ - - sha=rarp_ptr; - rarp_ptr+=dev->addr_len; - memcpy(&sip,rarp_ptr,4); - rarp_ptr+=4; - tha=rarp_ptr; - rarp_ptr+=dev->addr_len; - memcpy(&tip,rarp_ptr,4); - -/* - * Process entry. Use tha for table lookup according to RFC903. - */ - - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (!memcmp(entry->ha, tha, rarp->ar_hln)) - break; - - if (entry != NULL) - { - sip=entry->ip; - - arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, in_dev->ifa_list->ifa_address, sha, - dev->dev_addr, sha); - } - - kfree_skb(skb); - return 0; -} - - -/* - * Set (create) a RARP cache entry. - */ - -static int rarp_req_set(struct arpreq *req) -{ - struct arpreq r; - struct rarp_table *entry; - struct sockaddr_in *si; - int htype, hlen; - unsigned long ip; - struct rtable *rt; - struct net_device * dev; - int err; - - err = copy_from_user(&r, req, sizeof(r)); - if (err) - return -EFAULT; - - /* - * We only understand about IP addresses... - */ - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - - switch (r.arp_ha.sa_family) - { - case ARPHRD_ETHER: - htype = ARPHRD_ETHER; - hlen = ETH_ALEN; - break; -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - case ARPHRD_AX25: - htype = ARPHRD_AX25; - hlen = 7; - break; -#endif - default: - return -EPFNOSUPPORT; - } - - si = (struct sockaddr_in *) &r.arp_pa; - ip = si->sin_addr.s_addr; - if (ip == 0) - { - printk(KERN_DEBUG "RARP: SETRARP: requested PA is 0.0.0.0 !\n"); - return -EINVAL; - } - -/* - * Is it reachable directly ? - */ - - err = ip_route_output(&rt, ip, 0, 1, 0); - if (err) - return err; - if (rt->rt_flags&(RTCF_LOCAL|RTCF_BROADCAST|RTCF_MULTICAST|RTCF_DNAT)) { - ip_rt_put(rt); - return -EINVAL; - } - dev = rt->u.dst.dev; - -/* - * Is there an existing entry for this address? Find out... - */ - - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (entry->ip == ip) - break; - -/* - * If no entry was found, create a new one. - */ - - if (entry == NULL) - { - entry = (struct rarp_table *) kmalloc(sizeof(struct rarp_table), - GFP_ATOMIC); - if (entry == NULL) - { - return -ENOMEM; - } - if (initflag) - { - rarp_init_pkt(); - initflag=0; - } - - /* Block interrupts until table modification is finished */ - - cli(); - entry->next = rarp_tables; - rarp_tables = entry; - } - cli(); - entry->ip = ip; - entry->hlen = hlen; - entry->htype = htype; - memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); - entry->dev = dev; - sti(); - - /* Don't unlink if we have entries to serve. */ - MOD_INC_USE_COUNT; - - return 0; -} - - -/* - * Get a RARP cache entry. - */ - -static int rarp_req_get(struct arpreq *req) -{ - struct arpreq r; - struct rarp_table *entry; - struct sockaddr_in *si; - unsigned long ip; - int err; - -/* - * We only understand about IP addresses... - */ - - err = copy_from_user(&r, req, sizeof(r)); - if (err) - return -EFAULT; - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - -/* - * Is there an existing entry for this address? - */ - - si = (struct sockaddr_in *) &r.arp_pa; - ip = si->sin_addr.s_addr; - - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (entry->ip == ip) - break; - - if (entry == NULL) - { - return -ENXIO; - } - -/* - * We found it; copy into structure. - */ - - memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen); - r.arp_ha.sa_family = entry->htype; - -/* - * Copy the information back - */ - - return copy_to_user(req, &r, sizeof(r)) ? -EFAULT : 0; -} - - -/* - * Handle a RARP layer I/O control request. - */ - -int rarp_ioctl(unsigned int cmd, void *arg) -{ - struct arpreq r; - struct sockaddr_in *si; - int err; - - switch(cmd) - { - case SIOCDRARP: - if (!suser()) - return -EPERM; - err = copy_from_user(&r, arg, sizeof(r)); - if (err) - return -EFAULT; - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - si = (struct sockaddr_in *) &r.arp_pa; - rarp_destroy(si->sin_addr.s_addr); - return 0; - - case SIOCGRARP: - - return rarp_req_get((struct arpreq *)arg); - case SIOCSRARP: - if (!suser()) - return -EPERM; - return rarp_req_set((struct arpreq *)arg); - default: - return -EINVAL; - } - - /*NOTREACHED*/ - return 0; -} - -#ifdef CONFIG_PROC_FS -int rarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - int len=0; - off_t begin=0; - off_t pos=0; - int size; - struct rarp_table *entry; - char ipbuffer[20]; - unsigned long netip; - if (initflag) - { - size = sprintf(buffer,"RARP disabled until entries added to cache.\n"); - pos+=size; - len+=size; - } - else - { - size = sprintf(buffer, - "IP address HW type HW address\n"); - pos+=size; - len+=size; - - for(entry=rarp_tables; entry!=NULL; entry=entry->next) - { - netip=htonl(entry->ip); /* switch to network order */ - sprintf(ipbuffer,"%d.%d.%d.%d", - (unsigned int)(netip>>24)&255, - (unsigned int)(netip>>16)&255, - (unsigned int)(netip>>8)&255, - (unsigned int)(netip)&255); - - size = sprintf(buffer+len, - "%-17s%-20s%02x:%02x:%02x:%02x:%02x:%02x\n", - ipbuffer, - "10Mbps Ethernet", - (unsigned int)entry->ha[0], - (unsigned int)entry->ha[1], - (unsigned int)entry->ha[2], - (unsigned int)entry->ha[3], - (unsigned int)entry->ha[4], - (unsigned int)entry->ha[5]); - - len+=size; - pos=begin+len; - - if(posoffset+length) - break; - } - } - - *start = buffer+(offset-begin); /* Start of wanted data */ - len -= (offset-begin); /* Start slop */ - if (len>length) - len = length; /* Ending slop */ - return len; -} - -struct proc_dir_entry proc_net_rarp = { - PROC_NET_RARP, 4, "rarp", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - rarp_get_info -}; -#endif - -__initfunc(void -rarp_init(void)) -{ -#ifdef CONFIG_PROC_FS - proc_net_register(&proc_net_rarp); -#endif - rarp_ioctl_hook = rarp_ioctl; -} - -#ifdef MODULE - -int init_module(void) -{ - rarp_init(); - return 0; -} - -void cleanup_module(void) -{ - struct rarp_table *rt, *rt_next; -#ifdef CONFIG_PROC_FS - proc_net_unregister(PROC_NET_RARP); -#endif - rarp_ioctl_hook = NULL; - cli(); - /* Destroy the RARP-table */ - rt = rarp_tables; - rarp_tables = NULL; - sti(); - /* ... and free it. */ - for ( ; rt != NULL; rt = rt_next) { - rt_next = rt->next; - rarp_release_entry(rt); - } - rarp_end_pkt(); -} -#endif diff -u --recursive --new-file v2.3.14/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.3.14/linux/net/ipv4/raw.c Sat Jul 3 17:57:23 1999 +++ linux/net/ipv4/raw.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.42 1999/07/02 11:26:26 davem Exp $ + * Version: $Id: raw.c,v 1.43 1999/08/20 11:05:57 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -60,19 +60,17 @@ #include #include #include +#include #include -#ifdef CONFIG_IP_MROUTE -struct sock *mroute_socket=NULL; -#endif - struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE]; +rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED; static void raw_v4_hash(struct sock *sk) { struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)]; - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&raw_v4_lock); if ((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -80,31 +78,32 @@ sk->prot->inuse++; if(sk->prot->highestinuse < sk->prot->inuse) sk->prot->highestinuse = sk->prot->inuse; - SOCKHASH_UNLOCK_WRITE(); + sock_hold(sk); + write_unlock_bh(&raw_v4_lock); } static void raw_v4_unhash(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&raw_v4_lock); if (sk->pprev) { if (sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->prot->inuse--; + __sock_put(sk); } - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&raw_v4_lock); } -static __inline__ struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, - unsigned long raddr, unsigned long laddr, - int dif) +struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, + unsigned long raddr, unsigned long laddr, + int dif) { struct sock *s = sk; for(s = sk; s; s = s->next) { if((s->num == num) && - !(s->dead && (s->state == TCP_CLOSE)) && !(s->daddr && s->daddr != raddr) && !(s->rcv_saddr && s->rcv_saddr != laddr) && !(s->bound_dev_if && s->bound_dev_if != dif)) @@ -113,17 +112,6 @@ return s; } -struct sock *raw_v4_lookup(struct sock *sk, unsigned short num, - unsigned long raddr, unsigned long laddr, - int dif) -{ - SOCKHASH_LOCK_READ(); - sk = __raw_v4_lookup(sk, num, raddr, laddr, dif); - SOCKHASH_UNLOCK_READ(); - - return sk; -} - /* * 0 - deliver * 1 - block @@ -151,17 +139,17 @@ { struct sock *sk; - SOCKHASH_LOCK_READ_BH(); + read_lock(&raw_v4_lock); if ((sk = raw_v4_htable[hash]) == NULL) goto out; sk = __raw_v4_lookup(sk, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); + while(sk != NULL) { struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); - if (iph->protocol != IPPROTO_ICMP || ! icmp_filter(sk, skb)) { struct sk_buff *clone; @@ -169,16 +157,16 @@ if(sknext == NULL) break; clone = skb_clone(skb, GFP_ATOMIC); - if(clone) { - SOCKHASH_UNLOCK_READ_BH(); + /* Not releasing hash table! */ + if(clone) raw_rcv(sk, clone); - SOCKHASH_LOCK_READ_BH(); - } } sk = sknext; } out: - SOCKHASH_UNLOCK_READ_BH(); + if (sk) + sock_hold(sk); + read_unlock(&raw_v4_lock); return sk; } @@ -196,7 +184,7 @@ 2. Socket is connected (otherwise the error indication is useless without ip_recverr and error is hard. */ - if (!sk->ip_recverr && sk->state != TCP_ESTABLISHED) + if (!sk->protinfo.af_inet.recverr && sk->state != TCP_ESTABLISHED) return; switch (type) { @@ -218,16 +206,16 @@ err = icmp_err_convert[code].errno; harderr = icmp_err_convert[code].fatal; if (code == ICMP_FRAG_NEEDED) { - harderr = (sk->ip_pmtudisc != IP_PMTUDISC_DONT); + harderr = (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT); err = EMSGSIZE; info = ntohs(skb->h.icmph->un.frag.mtu); } } - if (sk->ip_recverr) + if (sk->protinfo.af_inet.recverr) ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1)); - if (sk->ip_recverr || harderr) { + if (sk->protinfo.af_inet.recverr || harderr) { sk->err = err; sk->error_report(sk); } @@ -345,9 +333,6 @@ if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; - if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT)) - return(-EINVAL); - /* * Get and verify the address. */ @@ -390,14 +375,14 @@ ipc.addr = daddr; if (!ipc.opt) - ipc.opt = sk->opt; + ipc.opt = sk->protinfo.af_inet.opt; if (ipc.opt) { err = -EINVAL; /* Linux does not mangle headers on raw sockets, * so that IP options + IP_HDRINCL is non-sense. */ - if (sk->ip_hdrincl) + if (sk->protinfo.af_inet.hdrincl) goto done; if (ipc.opt->srr) { if (!daddr) @@ -405,15 +390,15 @@ daddr = ipc.opt->faddr; } } - tos = RT_TOS(sk->ip_tos) | sk->localroute; + tos = RT_TOS(sk->protinfo.af_inet.tos) | sk->localroute; if (msg->msg_flags&MSG_DONTROUTE) tos |= RTO_ONLINK; if (MULTICAST(daddr)) { if (!ipc.oif) - ipc.oif = sk->ip_mc_index; + ipc.oif = sk->protinfo.af_inet.mc_index; if (!rfh.saddr) - rfh.saddr = sk->ip_mc_addr; + rfh.saddr = sk->protinfo.af_inet.mc_addr; } err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif); @@ -425,11 +410,15 @@ if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) goto done; + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + rfh.iov = msg->msg_iov; rfh.saddr = rt->rt_src; if (!ipc.addr) ipc.addr = rt->rt_dst; - err=ip_build_xmit(sk, sk->ip_hdrincl ? raw_getrawfrag : raw_getfrag, + err=ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag : raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags); done: @@ -438,39 +427,23 @@ ip_rt_put(rt); return err<0 ? err : len; + +do_confirm: + dst_confirm(&rt->u.dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto done; } static void raw_close(struct sock *sk, long timeout) { - bh_lock_sock(sk); - - /* Observation: when raw_close is called, processes have - no access to socket anymore. But net still has. - Step one, detach it from networking: - - A. Remove from hash tables. - */ - sk->state = TCP_CLOSE; - raw_v4_unhash(sk); /* - B. Raw sockets may have direct kernel refereneces. Kill them. + * Raw sockets may have direct kernel refereneces. Kill them. */ ip_ra_control(sk, 0, NULL); - /* In this point socket cannot receive new packets anymore */ - - - /* But we still have packets pending on receive - queue and probably, our own packets waiting in device queues. - sock_destroy will drain receive queue, but transmitted - packets will delay socket destruction. - Set sk->dead=1 in order to prevent wakeups, when these - packet will be freed. - */ - sk->dead=1; - destroy_sock(sk); - - /* That's all. No races here. */ + inet_sock_release(sk); } /* This gets rid of all the nasties in af_inet. -DaveM */ @@ -483,17 +456,12 @@ return -EINVAL; chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); if(addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { -#ifdef CONFIG_IP_TRANSPARENT_PROXY - /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) -#endif - return -EADDRNOTAVAIL; - } + chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) + return -EADDRNOTAVAIL; sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr; if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) sk->saddr = 0; /* Use device */ - dst_release(xchg(&sk->dst_cache, NULL)); + sk_dst_reset(sk); return 0; } @@ -541,7 +509,7 @@ sin->sin_family = AF_INET; sin->sin_addr.s_addr = skb->nh.iph->saddr; } - if (sk->ip_cmsg_flags) + if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); done: skb_free_datagram(sk, skb); @@ -621,17 +589,18 @@ dest = sp->daddr; src = sp->rcv_saddr; - destp = ntohs(sp->dport); - srcp = ntohs(sp->sport); + destp = 0; + srcp = sp->num; timer_active = (sp->timer.prev != NULL) ? 2 : 0; timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src, srcp, dest, destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + sp->socket->inode->i_uid, 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy) @@ -646,7 +615,7 @@ " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout inode"); pos = 128; - SOCKHASH_LOCK_READ(); + read_lock(&raw_v4_lock); for (i = 0; i < RAWV4_HTABLE_SIZE; i++) { struct sock *sk; @@ -663,7 +632,7 @@ } } out: - SOCKHASH_UNLOCK_READ(); + read_unlock(&raw_v4_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; @@ -677,6 +646,7 @@ struct proto raw_prot = { raw_close, /* close */ udp_connect, /* connect */ + udp_disconnect, /* disconnect */ NULL, /* accept */ NULL, /* retransmit */ NULL, /* write_wakeup */ diff -u --recursive --new-file v2.3.14/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.3.14/linux/net/ipv4/route.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/route.c Wed Aug 25 14:46:05 1999 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.69 1999/06/09 10:11:02 davem Exp $ + * Version: $Id: route.c,v 1.71 1999/08/20 11:05:58 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,8 @@ int ip_rt_error_burst = 5*HZ; int ip_rt_gc_elasticity = 8; int ip_rt_mtu_expires = 10*60*HZ; +int ip_rt_min_pmtu = 512+20+20; +int ip_rt_min_advmss = 536; static unsigned long rt_deadline = 0; @@ -148,6 +151,7 @@ NULL, ipv4_negative_advice, ipv4_link_failure, + sizeof(struct rtable), }; __u8 ip_tos2prio[16] = { @@ -233,12 +237,13 @@ (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway, r->rt_flags, - atomic_read(&r->u.dst.use), - atomic_read(&r->u.dst.refcnt), + atomic_read(&r->u.dst.__refcnt), + r->u.dst.__use, 0, - (unsigned long)r->rt_src, (int)r->u.dst.pmtu, + (unsigned long)r->rt_src, (int)r->u.dst.advmss + 40, r->u.dst.window, - (int)r->u.dst.rtt, r->key.tos, + (int)((r->u.dst.rtt>>3) + r->u.dst.rttvar), + r->key.tos, r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, r->u.dst.hh ? (r->u.dst.hh->hh_output == dev_queue_xmit) : 0, r->rt_spec_dst); @@ -289,7 +294,7 @@ { int age; - if (atomic_read(&rth->u.dst.use)) + if (atomic_read(&rth->u.dst.__refcnt)) return 0; if (rth->u.dst.expires && (long)(rth->u.dst.expires - jiffies) <= 0) @@ -361,13 +366,11 @@ for (i=0; iu.rt_next; - rth->u.rt_next = NULL; rt_free(rth); } } @@ -492,7 +495,6 @@ continue; } *rthp = rth->u.rt_next; - rth->u.rt_next = NULL; rt_free(rth); goal--; } @@ -560,8 +562,8 @@ rth->u.rt_next = rt_hash_table[hash]; rt_hash_table[hash] = rth; - atomic_inc(&rth->u.dst.refcnt); - atomic_inc(&rth->u.dst.use); + rth->u.dst.__use++; + dst_hold(&rth->u.dst); rth->u.dst.lastuse = now; write_unlock_bh(&rt_hash_lock); @@ -595,9 +597,14 @@ goto restart; } + if (net_ratelimit()) { + if ((rt->u.dst.dev->flags&IFF_UP) && + __in_dev_get(rt->u.dst.dev)) + printk("Neighbour table overflow.\n"); + else + printk("Device %s is down.\n", rt->u.dst.dev->name); + } rt_drop(rt); - if (net_ratelimit()) - printk("neighbour table overflow\n"); return -ENOBUFS; } } @@ -618,11 +625,27 @@ return 0; } +static void rt_del(unsigned hash, struct rtable *rt) +{ + struct rtable **rthp; + + write_lock_bh(&rt_hash_lock); + ip_rt_put(rt); + for (rthp = &rt_hash_table[hash]; *rthp; rthp = &(*rthp)->u.rt_next) { + if (*rthp == rt) { + *rthp = rt->u.rt_next; + rt_free(rt); + break; + } + } + write_unlock_bh(&rt_hash_lock); +} + void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw, u32 saddr, u8 tos, struct net_device *dev) { int i, k; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = in_dev_get(dev); struct rtable *rth, **rthp; u32 skeys[2] = { saddr, 0 }; int ikeys[2] = { dev->ifindex, 0 }; @@ -652,7 +675,7 @@ rthp=&rt_hash_table[hash]; - write_lock_bh(&rt_hash_lock); + read_lock(&rt_hash_lock); while ( (rth = *rthp) != NULL) { struct rtable *rt; @@ -673,11 +696,12 @@ break; dst_clone(&rth->u.dst); + read_unlock(&rt_hash_lock); - rt = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); + rt = dst_alloc(&ipv4_dst_ops); if (rt == NULL) { ip_rt_put(rth); - write_unlock_bh(&rt_hash_lock); + in_dev_put(in_dev); return; } @@ -685,11 +709,14 @@ * Copy all the information. */ *rt = *rth; - atomic_set(&rt->u.dst.refcnt, 1); - atomic_set(&rt->u.dst.use, 1); + rt->u.dst.__use = 1; + atomic_set(&rt->u.dst.__refcnt, 1); + if (rt->u.dst.dev) + dev_hold(rt->u.dst.dev); rt->u.dst.lastuse = jiffies; rt->u.dst.neighbour = NULL; rt->u.dst.hh = NULL; + rt->u.dst.obsolete = 0; rt->rt_flags |= RTCF_REDIRECTED; @@ -705,21 +732,20 @@ neigh_event_send(rt->u.dst.neighbour, NULL); ip_rt_put(rth); rt_drop(rt); - break; + goto do_next; } - *rthp = rth->u.rt_next; - write_unlock_bh(&rt_hash_lock); + rt_del(hash, rt); if (!rt_intern_hash(hash, rt, &rt)) ip_rt_put(rt); - rt_drop(rth); goto do_next; } - write_unlock_bh(&rt_hash_lock); + read_unlock(&rt_hash_lock); do_next: ; } } + in_dev_put(in_dev); return; reject_redirect: @@ -730,6 +756,7 @@ ntohl(old_gw), dev->name, ntohl(new_gw), ntohl(saddr), ntohl(daddr), tos); #endif + in_dev_put(in_dev); } static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) @@ -743,20 +770,10 @@ } if ((rt->rt_flags&RTCF_REDIRECTED) || rt->u.dst.expires) { unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos); - struct rtable **rthp; #if RT_CACHE_DEBUG >= 1 printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos); #endif - ip_rt_put(rt); - write_lock_bh(&rt_hash_lock); - for (rthp = &rt_hash_table[hash]; *rthp; rthp = &(*rthp)->u.rt_next) { - if (*rthp == rt) { - *rthp = rt->u.rt_next; - rt_free(rt); - break; - } - } - write_unlock_bh(&rt_hash_lock); + rt_del(hash, rt); return NULL; } } @@ -782,11 +799,14 @@ void ip_rt_send_redirect(struct sk_buff *skb) { struct rtable *rt = (struct rtable*)skb->dst; - struct in_device *in_dev = (struct in_device*)rt->u.dst.dev->ip_ptr; + struct in_device *in_dev = in_dev_get(rt->u.dst.dev); - if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) + if (!in_dev) return; + if (!IN_DEV_TX_REDIRECTS(in_dev)) + goto out; + /* No redirected packets during ip_rt_redirect_silence; * reset the algorithm. */ @@ -798,7 +818,7 @@ */ if (rt->u.dst.rate_tokens >= ip_rt_redirect_number) { rt->u.dst.rate_last = jiffies; - return; + goto out; } /* Check for load limit; set rate_last to the latest sent @@ -815,6 +835,8 @@ rt->rt_src, rt->rt_iif, rt->rt_dst, rt->rt_gateway); #endif } +out: + in_dev_put(in_dev); } static int ip_error(struct sk_buff *skb) @@ -886,7 +908,7 @@ for (i=0; i<2; i++) { unsigned hash = rt_hash_code(daddr, skeys[i], tos); - read_lock_bh(&rt_hash_lock); + read_lock(&rt_hash_lock); for (rth = rt_hash_table[hash]; rth; rth = rth->u.rt_next) { if (rth->key.dst == daddr && rth->key.src == skeys[i] && @@ -909,6 +931,10 @@ if (mtu <= rth->u.dst.pmtu) { if (mtu < rth->u.dst.pmtu) { dst_confirm(&rth->u.dst); + if (mtu < ip_rt_min_pmtu) { + mtu = ip_rt_min_pmtu; + rth->u.dst.mxlock |= (1<u.dst.pmtu = mtu; dst_set_expires(&rth->u.dst, ip_rt_mtu_expires); } @@ -916,7 +942,7 @@ } } } - read_unlock_bh(&rt_hash_lock); + read_unlock(&rt_hash_lock); } return est_mtu ? : new_mtu; } @@ -925,6 +951,10 @@ { if (dst->pmtu > mtu && mtu >= 68 && !(dst->mxlock&(1<mxlock |= (1<pmtu = mtu; dst_set_expires(dst, ip_rt_mtu_expires); } @@ -977,9 +1007,15 @@ if (rt->key.iif == 0) src = rt->rt_src; - else if (fib_lookup(&rt->key, &res) == 0) - src = FIB_RES_PREFSRC(res); - else + else if (fib_lookup(&rt->key, &res) == 0) { +#ifdef CONFIG_IP_ROUTE_NAT + if (res.type == RTN_NAT) + src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE); + else +#endif + src = FIB_RES_PREFSRC(res); + fib_res_put(&res); + } else src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE); memcpy(addr, &src, 4); } @@ -1001,8 +1037,7 @@ if (fi) { if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) rt->rt_gateway = FIB_RES_GW(*res); - rt->u.dst.mxlock = fi->fib_metrics[RTAX_LOCK-1]; - rt->u.dst.pmtu = fi->fib_mtu; + memcpy(&rt->u.dst.mxlock, fi->fib_metrics, sizeof(fi->fib_metrics)); if (fi->fib_mtu == 0) { rt->u.dst.pmtu = rt->u.dst.dev->mtu; if (rt->u.dst.pmtu > IP_MAX_MTU) @@ -1012,8 +1047,6 @@ rt->u.dst.pmtu > 576) rt->u.dst.pmtu = 576; } - rt->u.dst.window= fi->fib_window ? : 0; - rt->u.dst.rtt = fi->fib_rtt ? : TCP_TIMEOUT_INIT; #ifdef CONFIG_NET_CLS_ROUTE rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid; #endif @@ -1021,9 +1054,12 @@ rt->u.dst.pmtu = rt->u.dst.dev->mtu; if (rt->u.dst.pmtu > IP_MAX_MTU) rt->u.dst.pmtu = IP_MAX_MTU; - rt->u.dst.window= 0; - rt->u.dst.rtt = TCP_TIMEOUT_INIT; } + if (rt->u.dst.advmss == 0) + rt->u.dst.advmss = max(rt->u.dst.dev->mtu-40, ip_rt_min_advmss); + if (rt->u.dst.advmss > 65535-40) + rt->u.dst.advmss = 65535-40; + #ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_IP_MULTIPLE_TABLES set_class_tag(rt, fib_rules_tclass(res)); @@ -1040,34 +1076,40 @@ unsigned hash; struct rtable *rth; u32 spec_dst; - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev = in_dev_get(dev); u32 itag = 0; /* Primary sanity checks. */ - if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) || - in_dev == NULL || skb->protocol != __constant_htons(ETH_P_IP)) + if (in_dev == NULL) return -EINVAL; + if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) || + skb->protocol != __constant_htons(ETH_P_IP)) + goto e_inval; + if (ZERONET(saddr)) { if (!LOCAL_MCAST(daddr)) - return -EINVAL; + goto e_inval; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag) < 0) - return -EINVAL; + goto e_inval; - rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); + rth = dst_alloc(&ipv4_dst_ops); if (!rth) - return -ENOBUFS; + goto e_nobufs; rth->u.dst.output= ip_rt_bug; - atomic_set(&rth->u.dst.use, 1); + atomic_set(&rth->u.dst.__refcnt, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark = skb->fwmark; + if (skb->nfreason == NF_REASON_FOR_ROUTING) + rth->key.fwmark = skb->nfmark; + else + rth->key.fwmark = 0; #endif rth->key.src = saddr; rth->rt_src = saddr; @@ -1081,6 +1123,7 @@ rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; + dev_hold(rth->u.dst.dev); rth->key.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; @@ -1096,8 +1139,17 @@ rth->u.dst.input = ip_mr_input; #endif + in_dev_put(in_dev); hash = rt_hash_code(daddr, saddr^(dev->ifindex<<5), tos); return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + +e_nobufs: + in_dev_put(in_dev); + return -ENOBUFS; + +e_inval: + in_dev_put(in_dev); + return -EINVAL; } /* @@ -1115,14 +1167,15 @@ { struct rt_key key; struct fib_result res; - struct in_device *in_dev = dev->ip_ptr; - struct in_device *out_dev; + struct in_device *in_dev = in_dev_get(dev); + struct in_device *out_dev = NULL; unsigned flags = 0; u32 itag = 0; struct rtable * rth; unsigned hash; u32 spec_dst; int err = -EINVAL; + int free_res = 0; /* * IP on this device is disabled. @@ -1135,7 +1188,10 @@ key.src = saddr; key.tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - key.fwmark = skb->fwmark; + if (skb->nfreason == NF_REASON_FOR_ROUTING) + key.fwmark = skb->nfmark; + else + key.fwmark = 0; #endif key.iif = dev->ifindex; key.oif = 0; @@ -1165,11 +1221,12 @@ /* * Now we are ready to route packet. */ - if ((err = fib_lookup(&key, &res))) { + if ((err = fib_lookup(&key, &res)) != 0) { if (!IN_DEV_FORWARD(in_dev)) - return -EINVAL; + goto e_inval; goto no_route; } + free_res = 1; #ifdef CONFIG_IP_ROUTE_NAT /* Policy is applied before mapping destination, @@ -1183,8 +1240,13 @@ if (res.type == RTN_NAT) { key.dst = fib_rules_map_destination(daddr, &res); - if (fib_lookup(&key, &res) || res.type != RTN_UNICAST) - return -EINVAL; + fib_res_put(&res); + free_res = 0; + if (fib_lookup(&key, &res)) + goto e_inval; + free_res = 1; + if (res.type != RTN_UNICAST) + goto e_inval; flags |= RTCF_DNAT; } key.src = src_map; @@ -1207,7 +1269,7 @@ } if (!IN_DEV_FORWARD(in_dev)) - return -EINVAL; + goto e_inval; if (res.type != RTN_UNICAST) goto martian_destination; @@ -1215,11 +1277,11 @@ if (res.fi->fib_nhs > 1 && key.oif == 0) fib_select_multipath(&key, &res); #endif - out_dev = FIB_RES_DEV(res)->ip_ptr; + out_dev = in_dev_get(FIB_RES_DEV(res)); if (out_dev == NULL) { if (net_ratelimit()) printk(KERN_CRIT "Bug in ip_route_input_slow(). Please, report\n"); - return -EINVAL; + goto e_inval; } err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, &spec_dst, &itag); @@ -1239,19 +1301,22 @@ * invalid for proxy arp. DNAT routes are always valid. */ if (out_dev == in_dev && !(flags&RTCF_DNAT)) - return -EINVAL; + goto e_inval; } - rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); + rth = dst_alloc(&ipv4_dst_ops); if (!rth) - return -ENOBUFS; + goto e_nobufs; - atomic_set(&rth->u.dst.use, 1); + atomic_set(&rth->u.dst.__refcnt, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark = skb->fwmark; + if (skb->nfreason == NF_REASON_FOR_ROUTING) + rth->key.fwmark = skb->nfmark; + else + rth->key.fwmark = 0; #endif rth->key.src = saddr; rth->rt_src = saddr; @@ -1265,6 +1330,7 @@ rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = out_dev->dev; + dev_hold(rth->u.dst.dev); rth->key.oif = 0; rth->rt_spec_dst= spec_dst; @@ -1286,11 +1352,19 @@ } #endif - return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); +intern: + err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); +done: + in_dev_put(in_dev); + if (out_dev) + in_dev_put(out_dev); + if (free_res) + fib_res_put(&res); + return err; brd_input: if (skb->protocol != __constant_htons(ETH_P_IP)) - return -EINVAL; + goto e_inval; if (ZERONET(saddr)) { spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); @@ -1305,18 +1379,21 @@ res.type = RTN_BROADCAST; local_input: - rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); + rth = dst_alloc(&ipv4_dst_ops); if (!rth) - return -ENOBUFS; + goto e_nobufs; rth->u.dst.output= ip_rt_bug; - atomic_set(&rth->u.dst.use, 1); + atomic_set(&rth->u.dst.__refcnt, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark = skb->fwmark; + if (skb->nfreason == NF_REASON_FOR_ROUTING) + rth->key.fwmark = skb->nfmark; + else + rth->key.fwmark = 0; #endif rth->key.src = saddr; rth->rt_src = saddr; @@ -1330,6 +1407,7 @@ rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; + dev_hold(rth->u.dst.dev); rth->key.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; @@ -1341,7 +1419,7 @@ rth->rt_flags &= ~RTCF_LOCAL; } rth->rt_type = res.type; - return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + goto intern; no_route: spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); @@ -1356,7 +1434,13 @@ if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_WARNING "martian destination %08x from %08x, dev %s\n", daddr, saddr, dev->name); #endif - return -EINVAL; +e_inval: + err = -EINVAL; + goto done; + +e_nobufs: + err = -ENOBUFS; + goto done; martian_source: #ifdef CONFIG_IP_ROUTE_VERBOSE @@ -1376,7 +1460,7 @@ } } #endif - return -EINVAL; + goto e_inval; } int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, @@ -1396,12 +1480,14 @@ rth->key.iif == iif && rth->key.oif == 0 && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark == skb->fwmark && + rth->key.fwmark + == (skb->nfreason == NF_REASON_FOR_ROUTING + ? skb->nfmark : 0) && #endif rth->key.tos == tos) { rth->u.dst.lastuse = jiffies; - atomic_inc(&rth->u.dst.use); - atomic_inc(&rth->u.dst.refcnt); + dst_hold(&rth->u.dst); + rth->u.dst.__use++; read_unlock_bh(&rt_hash_lock); skb->dst = (struct dst_entry*)rth; return 0; @@ -1421,14 +1507,22 @@ route cache entry is created eventually. */ if (MULTICAST(daddr)) { - int our = ip_check_mc(dev, daddr); - if (!our + struct in_device *in_dev; + + read_lock(&inetdev_lock); + if ((in_dev = __in_dev_get(dev)) != NULL) { + int our = ip_check_mc(in_dev, daddr); + if (our #ifdef CONFIG_IP_MROUTE - && (LOCAL_MCAST(daddr) || !dev->ip_ptr || - !IN_DEV_MFORWARD((struct in_device*)dev->ip_ptr)) + || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) #endif - ) return -EINVAL; - return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); + ) { + read_unlock(&inetdev_lock); + return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); + } + } + read_unlock(&inetdev_lock); + return -EINVAL; } return ip_route_input_slow(skb, daddr, saddr, tos, dev); } @@ -1445,9 +1539,8 @@ struct rtable *rth; struct net_device *dev_out = NULL; unsigned hash; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - u32 nochecksrc = (tos & RTO_TPROXY); -#endif + int free_res = 0; + int err; tos &= IPTOS_TOS_MASK|RTO_ONLINK; key.dst = daddr; @@ -1467,19 +1560,8 @@ /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(saddr); -#ifdef CONFIG_IP_TRANSPARENT_PROXY - /* If address is not local, test for transparent proxy flag; - if address is local --- clear the flag. - */ - if (dev_out == NULL) { - if (nochecksrc == 0 || inet_addr_type(saddr) != RTN_UNICAST) - return -EINVAL; - flags |= RTCF_TPROXY; - } -#else if (dev_out == NULL) return -EINVAL; -#endif /* I removed check for oif == dev_out->oif here. It was wrong by three reasons: @@ -1490,9 +1572,6 @@ */ if (oif == 0 && -#ifdef CONFIG_IP_TRANSPARENT_PROXY - dev_out && -#endif (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { /* Special hack: user can direct multicasts and limited broadcast via necessary interface @@ -1512,14 +1591,18 @@ key.oif = dev_out->ifindex; goto make_route; } + if (dev_out) + dev_put(dev_out); dev_out = NULL; } if (oif) { dev_out = dev_get_by_index(oif); if (dev_out == NULL) return -ENODEV; - if (dev_out->ip_ptr == NULL) + if (__in_dev_get(dev_out) == NULL) { + dev_put(dev_out); return -ENODEV; /* Wrong error code */ + } if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) { if (!key.src) @@ -1538,7 +1621,10 @@ key.dst = key.src; if (!key.dst) key.dst = key.src = htonl(INADDR_LOOPBACK); + if (dev_out) + dev_put(dev_out); dev_out = &loopback_dev; + dev_hold(dev_out); key.oif = loopback_dev.ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; @@ -1571,17 +1657,25 @@ res.type = RTN_UNICAST; goto make_route; } + if (dev_out) + dev_put(dev_out); return -ENETUNREACH; } + free_res = 1; if (res.type == RTN_NAT) - return -EINVAL; + goto e_inval; if (res.type == RTN_LOCAL) { if (!key.src) key.src = key.dst; + if (dev_out) + dev_put(dev_out); dev_out = &loopback_dev; + dev_hold(dev_out); key.oif = dev_out->ifindex; + if (res.fi) + fib_info_put(res.fi); res.fi = NULL; flags |= RTCF_LOCAL; goto make_route; @@ -1598,43 +1692,53 @@ if (!key.src) key.src = FIB_RES_PREFSRC(res); + if (dev_out) + dev_put(dev_out); dev_out = FIB_RES_DEV(res); + dev_hold(dev_out); key.oif = dev_out->ifindex; make_route: if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) - return -EINVAL; + goto e_inval; if (key.dst == 0xFFFFFFFF) res.type = RTN_BROADCAST; else if (MULTICAST(key.dst)) res.type = RTN_MULTICAST; else if (BADCLASS(key.dst) || ZERONET(key.dst)) - return -EINVAL; + goto e_inval; if (dev_out->flags&IFF_LOOPBACK) flags |= RTCF_LOCAL; if (res.type == RTN_BROADCAST) { flags |= RTCF_BROADCAST|RTCF_LOCAL; - res.fi = NULL; + if (res.fi) { + fib_info_put(res.fi); + res.fi = NULL; + } } else if (res.type == RTN_MULTICAST) { flags |= RTCF_MULTICAST|RTCF_LOCAL; - if (!ip_check_mc(dev_out, daddr)) + read_lock(&inetdev_lock); + if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), daddr)) flags &= ~RTCF_LOCAL; + read_unlock(&inetdev_lock); /* If multicast route do not exist use default one, but do not gateway in this case. Yes, it is hack. */ - if (res.fi && res.prefixlen < 4) + if (res.fi && res.prefixlen < 4) { + fib_info_put(res.fi); res.fi = NULL; + } } - rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); + rth = dst_alloc(&ipv4_dst_ops); if (!rth) - return -ENOBUFS; + goto e_nobufs; - atomic_set(&rth->u.dst.use, 1); + atomic_set(&rth->u.dst.__refcnt, 1); rth->key.dst = daddr; rth->key.tos = tos; rth->key.src = saddr; @@ -1648,6 +1752,7 @@ #endif rth->rt_iif = oif ? : dev_out->ifindex; rth->u.dst.dev = dev_out; + dev_hold(dev_out); rth->rt_gateway = key.dst; rth->rt_spec_dst= key.src; @@ -1662,11 +1767,14 @@ if (flags&RTCF_LOCAL && !(dev_out->flags&IFF_LOOPBACK)) rth->u.dst.output = ip_mc_output; #ifdef CONFIG_IP_MROUTE - if (res.type == RTN_MULTICAST && dev_out->ip_ptr) { - struct in_device *in_dev = dev_out->ip_ptr; - if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) { - rth->u.dst.input = ip_mr_input; - rth->u.dst.output = ip_mc_output; + if (res.type == RTN_MULTICAST) { + struct in_device *in_dev = in_dev_get(dev_out); + if (in_dev) { + if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) { + rth->u.dst.input = ip_mr_input; + rth->u.dst.output = ip_mc_output; + } + in_dev_put(in_dev); } } #endif @@ -1677,7 +1785,20 @@ rth->rt_flags = flags; hash = rt_hash_code(daddr, saddr^(oif<<5), tos); - return rt_intern_hash(hash, rth, rp); + err = rt_intern_hash(hash, rth, rp); +done: + if (free_res) + fib_res_put(&res); + if (dev_out) + dev_put(dev_out); + return err; + +e_inval: + err = -EINVAL; + goto done; +e_nobufs: + err = -ENOBUFS; + goto done; } int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) @@ -1693,16 +1814,12 @@ rth->key.src == saddr && rth->key.iif == 0 && rth->key.oif == oif && -#ifndef CONFIG_IP_TRANSPARENT_PROXY - rth->key.tos == tos -#else !((rth->key.tos^tos)&(IPTOS_TOS_MASK|RTO_ONLINK)) && ((tos&RTO_TPROXY) || !(rth->rt_flags&RTCF_TPROXY)) -#endif ) { rth->u.dst.lastuse = jiffies; - atomic_inc(&rth->u.dst.use); - atomic_inc(&rth->u.dst.refcnt); + dst_hold(&rth->u.dst); + rth->u.dst.__use++; read_unlock_bh(&rt_hash_lock); *rp = rth; return 0; @@ -1725,7 +1842,6 @@ #ifdef CONFIG_IP_MROUTE struct rtattr *eptr; #endif - struct rtattr *mx; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r)); r = NLMSG_DATA(nlh); @@ -1758,22 +1874,11 @@ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); if (rt->rt_dst != rt->rt_gateway) RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); - mx = (struct rtattr*)skb->tail; - RTA_PUT(skb, RTA_METRICS, 0, NULL); - if (rt->u.dst.mxlock) - RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock); - if (rt->u.dst.pmtu) - RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu); - if (rt->u.dst.window) - RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window); - if (rt->u.dst.rtt) - RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt); - mx->rta_len = skb->tail - (u8*)mx; - if (mx->rta_len == RTA_LENGTH(0)) - skb_trim(skb, (u8*)mx - skb->data); + if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) + goto rtattr_failure; ci.rta_lastuse = jiffies - rt->u.dst.lastuse; - ci.rta_used = atomic_read(&rt->u.dst.refcnt); - ci.rta_clntref = atomic_read(&rt->u.dst.use); + ci.rta_used = rt->u.dst.__use; + ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); if (rt->u.dst.expires) ci.rta_expires = rt->u.dst.expires - jiffies; else @@ -1846,7 +1951,7 @@ if (iif) { struct net_device *dev; - dev = dev_get_by_index(iif); + dev = __dev_get_by_index(iif); if (!dev) return -ENODEV; skb->protocol = __constant_htons(ETH_P_IP); @@ -1944,16 +2049,30 @@ return -EINVAL; } +static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context) +{ + int delay; + if (newlen != sizeof(int)) + return -EINVAL; + if (get_user(delay,(int *)newval)) + return -EFAULT; + rt_cache_flush(delay); + return 0; +} + ctl_table ipv4_route_table[] = { {NET_IPV4_ROUTE_FLUSH, "flush", - &flush_delay, sizeof(int), 0200, NULL, - &ipv4_sysctl_rtcache_flush}, + &flush_delay, sizeof(int), 0644, NULL, + &ipv4_sysctl_rtcache_flush, &ipv4_sysctl_rtcache_flush_strategy }, {NET_IPV4_ROUTE_MIN_DELAY, "min_delay", &ip_rt_min_delay, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_ROUTE_MAX_DELAY, "max_delay", &ip_rt_max_delay, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_ROUTE_GC_THRESH, "gc_thresh", &ipv4_dst_ops.gc_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -1962,13 +2081,13 @@ &proc_dointvec}, {NET_IPV4_ROUTE_GC_MIN_INTERVAL, "gc_min_interval", &ip_rt_gc_min_interval, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_ROUTE_GC_TIMEOUT, "gc_timeout", &ip_rt_gc_timeout, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_ROUTE_GC_INTERVAL, "gc_interval", &ip_rt_gc_interval, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_ROUTE_REDIRECT_LOAD, "redirect_load", &ip_rt_redirect_load, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -1989,7 +2108,13 @@ &proc_dointvec}, {NET_IPV4_ROUTE_MTU_EXPIRES, "mtu_expires", &ip_rt_mtu_expires, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_IPV4_ROUTE_MIN_PMTU, "min_pmtu", + &ip_rt_min_pmtu, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_ROUTE_MIN_ADVMSS, "min_adv_mss", + &ip_rt_min_advmss, sizeof(int), 0644, NULL, + &proc_dointvec}, {0} }; #endif @@ -2020,13 +2145,18 @@ #endif -__initfunc(void ip_rt_init(void)) +void __init ip_rt_init(void) { #ifdef CONFIG_PROC_FS #ifdef CONFIG_NET_CLS_ROUTE struct proc_dir_entry *ent; #endif #endif + ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache", + sizeof(struct rtable), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + devinet_init(); ip_fib_init(); rt_periodic_timer.function = rt_check_expire; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c --- v2.3.14/linux/net/ipv4/syncookies.c Tue Mar 16 21:52:05 1999 +++ linux/net/ipv4/syncookies.c Mon Aug 23 10:01:02 1999 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: syncookies.c,v 1.7 1999/03/17 02:34:57 davem Exp $ + * $Id: syncookies.c,v 1.9 1999/08/23 06:30:34 davem Exp $ * * Missing: IPv6 support. */ @@ -104,12 +104,20 @@ { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + /* Oops! It was missing, syn_recv_sock decreases it. */ + tp->syn_backlog++; + sk = tp->af_specific->syn_recv_sock(sk, skb, req, dst); - req->sk = sk; - - /* Queue up for accept() */ - tcp_synq_queue(tp, req); - + if (sk) { + req->sk = sk; + + /* Queue up for accept() */ + tcp_synq_queue(tp, req); + } else { + tp->syn_backlog--; + req->class->destructor(req); + tcp_openreq_free(req); + } return sk; } @@ -179,7 +187,7 @@ opt && opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, req->af.v4_req.loc_addr, - sk->ip_tos | RTO_CONN, + sk->protinfo.af_inet.tos | RTO_CONN, 0)) { tcp_openreq_free(req); return NULL; @@ -187,7 +195,7 @@ /* Try to redo what tcp_v4_send_synack did. */ req->window_clamp = rt->u.dst.window; - tcp_select_initial_window(sock_rspace(sk)/2,req->mss, + tcp_select_initial_window(tcp_full_space(sk),req->mss, &req->rcv_wnd, &req->window_clamp, 0, &rcv_wscale); req->rcv_wscale = rcv_wscale; diff -u --recursive --new-file v2.3.14/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.3.14/linux/net/ipv4/sysctl_net_ipv4.c Mon Jan 4 15:31:35 1999 +++ linux/net/ipv4/sysctl_net_ipv4.c Mon Aug 23 10:01:02 1999 @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.38 1999/01/02 16:51:48 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.39 1999/08/20 11:06:00 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -50,7 +50,6 @@ extern int sysctl_tcp_retrans_collapse; extern int sysctl_tcp_keepalive_time; extern int sysctl_tcp_keepalive_probes; -extern int sysctl_tcp_max_ka_probes; extern int sysctl_tcp_retries1; extern int sysctl_tcp_retries2; extern int sysctl_tcp_fin_timeout; @@ -60,6 +59,7 @@ extern int sysctl_tcp_rfc1337; extern int sysctl_tcp_syn_taildrop; extern int sysctl_max_syn_backlog; +extern int sysctl_tcp_tw_recycle; /* From icmp.c */ extern int sysctl_icmp_destunreach_time; @@ -90,9 +90,23 @@ if (write && ipv4_devconf.forwarding != val) inet_forward_change(); - return ret; + return ret; } +static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context) +{ + int new; + if (newlen != sizeof(int)) + return -EINVAL; + if (get_user(new,(int *)newval)) + return -EFAULT; + if (new != ipv4_devconf.forwarding) + inet_forward_change(); + return 0; /* caller does change again and handles handles oldval */ +} ctl_table ipv4_table[] = { {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps", @@ -109,7 +123,7 @@ &proc_dointvec}, {NET_IPV4_FORWARD, "ip_forward", &ipv4_devconf.forwarding, sizeof(int), 0644, NULL, - &ipv4_sysctl_forward}, + &ipv4_sysctl_forward,&ipv4_sysctl_forward_strategy}, {NET_IPV4_DEFAULT_TTL, "ip_default_ttl", &ip_statistics.IpDefaultTTL, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -127,17 +141,12 @@ &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_DYNADDR, "ip_dynaddr", &sysctl_ip_dynaddr, sizeof(int), 0644, NULL, &proc_dointvec}, -#ifdef CONFIG_IP_MASQUERADE - {NET_IPV4_IP_MASQ_DEBUG, "ip_masq_debug", - &sysctl_ip_masq_debug, sizeof(int), 0644, NULL, &proc_dointvec}, -#endif {NET_IPV4_IPFRAG_TIME, "ipfrag_time", - &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, - {NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes", - &sysctl_tcp_max_ka_probes, sizeof(int), 0644, NULL, &proc_dointvec}, + &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, + &sysctl_jiffies}, {NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time", &sysctl_tcp_keepalive_time, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes", &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -148,10 +157,14 @@ &sysctl_tcp_retries2, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout", &sysctl_tcp_fin_timeout, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, + &proc_dointvec_jiffies, &sysctl_jiffies}, #ifdef CONFIG_SYN_COOKIES {NET_TCP_SYNCOOKIES, "tcp_syncookies", &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_TCP_TW_RECYCLE + {NET_TCP_TW_RECYCLE, "tcp_tw_recycle", + &sysctl_tcp_tw_recycle, sizeof(int), 0644, NULL, &proc_dointvec}, #endif {NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg, sizeof(int), 0644, NULL, &proc_dointvec}, diff -u --recursive --new-file v2.3.14/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.3.14/linux/net/ipv4/tcp.c Mon Jul 5 20:22:09 1999 +++ linux/net/ipv4/tcp.c Mon Aug 23 13:44:03 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.145 1999/06/29 12:35:56 davem Exp $ + * Version: $Id: tcp.c,v 1.148 1999/08/23 05:16:11 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -412,6 +412,7 @@ * (Updated by AK, but not complete yet.) **/ +#include #include #include #include @@ -563,6 +564,11 @@ if (sk->state == TCP_LISTEN) return tcp_listen_poll(sk, wait); + /* Socket is not locked. We are protected from async events + by poll logic and correct handling of state changes + made by another threads is impossible in any case. + */ + mask = 0; if (sk->err) mask = POLLERR; @@ -607,17 +613,22 @@ /* * Socket write_space callback. - * This (or rather the sock_wake_async) should agree with poll. + * This (or rather the sock_wake_async) should agree with poll. + * + * WARNING. This callback is called from any context (process, + * bh or irq). Do not make anything more smart from it. */ void tcp_write_space(struct sock *sk) { - if (sk->dead) - return; + read_lock(&sk->callback_lock); + if (!sk->dead) { + /* Why??!! Does it really not overshedule? --ANK */ + wake_up_interruptible(sk->sleep); - wake_up_interruptible(sk->sleep); - if (sock_wspace(sk) >= - tcp_min_write_space(sk)) - sock_wake_async(sk->socket, 2); + if (sock_wspace(sk) >= tcp_min_write_space(sk)) + sock_wake_async(sk->socket, 2); + } + read_unlock(&sk->callback_lock); } @@ -657,8 +668,7 @@ /* * Wait for a socket to get into the connected state * - * Note: Must be called with the socket locked, and it - * runs with the kernel fully unlocked. + * Note: Must be called with the socket locked. */ static int wait_for_tcp_connect(struct sock * sk, int flags) { @@ -681,15 +691,15 @@ tsk->state = TASK_INTERRUPTIBLE; add_wait_queue(sk->sleep, &wait); - release_sock(sk); + sk->tp_pinfo.af_tcp.write_pending++; - if (((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT)) && - sk->err == 0) - schedule(); + release_sock(sk); + schedule(); + lock_sock(sk); tsk->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); - lock_sock(sk); + sk->tp_pinfo.af_tcp.write_pending--; } return 0; } @@ -701,33 +711,33 @@ /* * Wait for more memory for a socket - * - * NOTE: This runs with the kernel fully unlocked. */ static void wait_for_tcp_memory(struct sock * sk) { - release_sock(sk); if (!tcp_memory_free(sk)) { DECLARE_WAITQUEUE(wait, current); sk->socket->flags &= ~SO_NOSPACE; add_wait_queue(sk->sleep, &wait); for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (signal_pending(current)) break; - current->state = TASK_INTERRUPTIBLE; if (tcp_memory_free(sk)) break; if (sk->shutdown & SEND_SHUTDOWN) break; if (sk->err) break; - schedule(); + release_sock(sk); + if (!tcp_memory_free(sk)) + schedule(); + lock_sock(sk); } current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); } - lock_sock(sk); } /* When all user supplied data has been queued set the PSH bit */ @@ -749,8 +759,6 @@ int mss_now; int err, copied; - lock_sock(sk); - err = 0; tp = &(sk->tp_pinfo.af_tcp); @@ -974,7 +982,6 @@ err = -EFAULT; out: tcp_push_pending_frames(sk, tp); - release_sock(sk); return err; } @@ -1010,9 +1017,6 @@ if (sk->urginline || !tp->urg_data || tp->urg_data == URG_READ) return -EINVAL; /* Yes this is right ! */ - if (sk->err) - return sock_error(sk); - if (sk->done) return -ENOTCONN; @@ -1021,14 +1025,13 @@ return 0; } - lock_sock(sk); if (tp->urg_data & URG_VALID) { int err = 0; char c = tp->urg_data; if (!(flags & MSG_PEEK)) tp->urg_data = URG_READ; - + if(msg->msg_name) tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) msg->msg_name); @@ -1038,21 +1041,15 @@ /* Read urgent data. */ msg->msg_flags|=MSG_OOB; - release_sock(sk); - if(len>0) - { + if(len>0) { err = memcpy_toiovec(msg->msg_iov, &c, 1); - /* N.B. already set above ... */ - msg->msg_flags|=MSG_OOB; - } - else + len = 1; + } else msg->msg_flags|=MSG_TRUNC; - - /* N.B. Is this right?? If len == 0 we didn't read any data */ - return err ? -EFAULT : 1; + + return err ? -EFAULT : len; } - release_sock(sk); /* Fixed the recv(..., MSG_OOB) behaviour. BSD docs and * the available implementations agree in this case: @@ -1072,7 +1069,7 @@ static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb) { __skb_unlink(skb, &sk->receive_queue); - kfree_skb(skb); + __kfree_skb(skb); } /* Clean up the receive buffer for full frames taken by the user, @@ -1114,6 +1111,30 @@ } } +/* Now socket state including sk->err is changed only under lock, + hence we should check only pending signals. + */ + +static void tcp_data_wait(struct sock *sk) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(sk->sleep, &wait); + + current->state = TASK_INTERRUPTIBLE; + + sk->socket->flags |= SO_WAITDATA; + release_sock(sk); + + if (skb_queue_empty(&sk->receive_queue)) + schedule(); + + lock_sock(sk); + sk->socket->flags &= ~SO_WAITDATA; + + remove_wait_queue(sk->sleep, &wait); + current->state = TASK_RUNNING; +} /* * This routine copies from a sock struct into the user buffer. @@ -1123,23 +1144,25 @@ int len, int nonblock, int flags, int *addr_len) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - DECLARE_WAITQUEUE(wait, current); int copied = 0; u32 peek_seq; volatile u32 *seq; /* So gcc doesn't overoptimise */ unsigned long used; - int err = 0; + int err; int target = 1; /* Read at least this many bytes */ + lock_sock(sk); + if (sk->err) - return sock_error(sk); + goto out_err; + err = -ENOTCONN; if (sk->state == TCP_LISTEN) - return -ENOTCONN; + goto out; /* Urgent data needs to be handled specially. */ if (flags & MSG_OOB) - return tcp_recv_urg(sk, nonblock, msg, len, flags, addr_len); + goto recv_urg; /* Copying sequence to update. This is volatile to handle * the multi-reader case neatly (memcpy_to/fromfs might be @@ -1149,13 +1172,11 @@ seq = &tp->copied_seq; if (flags & MSG_PEEK) seq = &peek_seq; - + /* Handle the POSIX bogosity MSG_WAITALL. */ if (flags & MSG_WAITALL) target=len; - add_wait_queue(sk->sleep, &wait); - lock_sock(sk); /* * BUG BUG BUG @@ -1185,7 +1206,6 @@ } /* Next get a buffer. */ - current->state = TASK_INTERRUPTIBLE; skb = skb_peek(&sk->receive_queue); do { @@ -1215,16 +1235,9 @@ if (copied >= target) break; - /* - These three lines and clause if (sk->state == TCP_CLOSE) - are unlikely to be correct, if target > 1. - I DO NOT FIX IT, because I have no idea, what - POSIX prescribes to make here. Probably, it really - wants to lose data 8), if not all target is received. - --ANK - */ if (sk->err && !(flags&MSG_PEEK)) { - copied = sock_error(sk); + if (!copied) + copied = sock_error(sk); break; } @@ -1238,7 +1251,8 @@ sk->done = 1; break; } - copied = -ENOTCONN; + if (!copied) + copied = -ENOTCONN; break; } @@ -1248,11 +1262,7 @@ } cleanup_rbuf(sk, copied); - release_sock(sk); - sk->socket->flags |= SO_WAITDATA; - schedule(); - sk->socket->flags &= ~SO_WAITDATA; - lock_sock(sk); + tcp_data_wait(sk); continue; found_ok_skb: @@ -1339,20 +1349,28 @@ break; } - if (copied > 0 && msg->msg_name) + if (copied >= 0 && msg->msg_name) tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) msg->msg_name); if(addr_len) *addr_len = tp->af_specific->sockaddr_len; - remove_wait_queue(sk->sleep, &wait); - current->state = TASK_RUNNING; - /* Clean up data we have read: This will do ACK frames. */ cleanup_rbuf(sk, copied); release_sock(sk); return copied; + +out_err: + err = sock_error(sk); + +out: + release_sock(sk); + return err; + +recv_urg: + err = tcp_recv_urg(sk, nonblock, msg, len, flags, addr_len); + goto out; } /* @@ -1360,8 +1378,8 @@ */ static inline void tcp_check_fin_timer(struct sock *sk) { - if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev) - tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); + if (sk->state == TCP_FIN_WAIT2) + tcp_reset_keepalive_timer(sk, sysctl_tcp_fin_timeout); } /* @@ -1423,7 +1441,6 @@ return; /* If we've already sent a FIN, or it's a closed state, skip this. */ - lock_sock(sk); if ((1 << sk->state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE_WAIT)) { @@ -1431,7 +1448,6 @@ if (tcp_close_state(sk,0)) tcp_send_fin(sk); } - release_sock(sk); } @@ -1447,7 +1463,7 @@ /* * This routine closes sockets which have been at least partially * opened, but not yet accepted. Currently it is only called by - * tcp_close, and timeout mirrors the value there. + * tcp_close. */ static void tcp_close_pending (struct sock *sk) @@ -1463,47 +1479,85 @@ iter = req; req = req->dl_next; - + + if (iter->sk) { + sk->ack_backlog--; + } else { + tcp_dec_slow_timer(TCP_SLT_SYNACK); + tp->syn_backlog--; + } (*iter->class->destructor)(iter); - tcp_dec_slow_timer(TCP_SLT_SYNACK); - sk->ack_backlog--; tcp_openreq_free(iter); } - + BUG_TRAP(tp->syn_backlog == 0); + BUG_TRAP(sk->ack_backlog == 0); tcp_synq_init(tp); } +static __inline__ void tcp_kill_sk_queues(struct sock *sk) +{ + /* First the read buffer. */ + skb_queue_purge(&sk->receive_queue); + + /* Next, the error queue. */ + skb_queue_purge(&sk->error_queue); + + /* Next, the write queue. */ + BUG_TRAP(skb_queue_empty(&sk->write_queue)); + + /* It is _impossible_ for the backlog to contain anything + * when we get here. All user references to this socket + * have gone away, only the net layer knows can touch it. + */ +} + +/* + * At this point, there should be no process reference to this + * socket, and thus no user references at all. Therefore we + * can assume the socket waitqueue is inactive and nobody will + * try to jump onto it. + */ +void tcp_destroy_sock(struct sock *sk) +{ + BUG_TRAP(sk->state==TCP_CLOSE); + BUG_TRAP(sk->dead); + + /* It cannot be in hash table! */ + BUG_TRAP(sk->pprev==NULL); + + /* It it has not 0 sk->num, it must be bound */ + BUG_TRAP(!sk->num || sk->prev!=NULL); + + sk->prot->destroy(sk); + + tcp_kill_sk_queues(sk); + +#ifdef INET_REFCNT_DEBUG + if (atomic_read(&sk->refcnt) != 1) { + printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n", sk, atomic_read(&sk->refcnt)); + } +#endif + + sock_put(sk); +} + void tcp_close(struct sock *sk, long timeout) { struct sk_buff *skb; int data_was_unread = 0; - /* We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - */ lock_sock(sk); if(sk->state == TCP_LISTEN) { - /* Special case. */ tcp_set_state(sk, TCP_CLOSE); + + /* Special case. */ tcp_close_pending(sk); - release_sock(sk); - sk->dead = 1; - return; - } - unlock_kernel(); + goto adjudge_to_death; + } - /* It is questionable, what the role of this is now. - * In any event either it should be removed, or - * increment of SLT_KEEPALIVE be done, this is causing - * big problems. For now I comment it out. -DaveM - */ - /* sk->keepopen = 1; */ sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); - /* We need to flush the recv. buffs. We do this only on the * descriptor close, not protocol-sourced closes, because the * reader process may not have drained the data yet! @@ -1547,7 +1601,7 @@ release_sock(sk); timeout = schedule_timeout(timeout); lock_sock(sk); - if (signal_pending(tsk) || !timeout) + if (!signal_pending(tsk) || timeout) break; } @@ -1560,10 +1614,97 @@ */ tcp_check_fin_timer(sk); +adjudge_to_death: + /* It is the last release_sock in its life. It will remove backlog. */ + release_sock(sk); + + + /* Now socket is owned by kernel and we acquire BH lock + to finish close. No need to check for user refs. + */ + local_bh_disable(); + bh_lock_sock(sk); + BUG_TRAP(sk->lock.users==0); + + sock_hold(sk); + + /* Announce socket dead, detach it from wait queue and inode. */ + write_lock_irq(&sk->callback_lock); sk->dead = 1; + sk->socket = NULL; + sk->sleep = NULL; + write_unlock_irq(&sk->callback_lock); - release_sock(sk); - lock_kernel(); + if (sk->state == TCP_CLOSE) + tcp_destroy_sock(sk); + /* Otherwise, socket is reprieved until protocol close. */ + + bh_unlock_sock(sk); + local_bh_enable(); + sock_put(sk); +} + +int tcp_disconnect(struct sock *sk, int flags) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + int old_state; + int err = 0; + + old_state = sk->state; + if (old_state != TCP_CLOSE) + tcp_set_state(sk, TCP_CLOSE); + + /* ABORT function of RFC793 */ + if (old_state == TCP_LISTEN) { + tcp_close_pending(sk); + } else if (tcp_connected(old_state)) { + tcp_send_active_reset(sk); + sk->err = ECONNRESET; + } else if (old_state == TCP_SYN_SENT) + sk->err = ECONNRESET; + + tcp_clear_xmit_timers(sk); + __skb_queue_purge(&sk->receive_queue); + __skb_queue_purge(&sk->write_queue); + __skb_queue_purge(&tp->out_of_order_queue); + + sk->dport = 0; + + sk->rcv_saddr = 0; + sk->saddr = 0; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + memset(&sk->net_pinfo.af_inet6.saddr, 0, 16); + memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16); +#endif + + sk->zapped = 0; + sk->shutdown = 0; + sk->done = 0; + sk->write_space = tcp_write_space; + tp->srtt = 0; +#ifdef CONFIG_TCP_TW_RECYCLE + if ((tp->write_seq += 2) == 0) + tp->write_seq = 1; +#else + tp->write_seq = 0; +#endif + tp->ato = 0; + tp->backoff = 0; + tp->snd_cwnd = 2; + tp->probes_out = 0; + tp->high_seq = 0; + tp->snd_ssthresh = 0x7fffffff; + tp->snd_cwnd_cnt = 0; + tp->dup_acks = 0; + tp->delayed_acks = 0; + tp->send_head = tp->retrans_head = NULL; + tp->saw_tstamp = 0; + __sk_dst_reset(sk); + + BUG_TRAP(!sk->num || sk->prev); + + sk->error_report(sk); + return err; } /* @@ -1614,20 +1755,19 @@ * Be careful about race conditions here - this is subtle. */ -struct sock *tcp_accept(struct sock *sk, int flags) +struct sock *tcp_accept(struct sock *sk, int flags, int *err) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct open_request *req, *prev; - struct sock *newsk = NULL; + struct sock *newsk; int error; - unlock_kernel(); lock_sock(sk); /* We need to make sure that this socket is listening, * and that it has something pending. */ - error = EINVAL; + error = -EINVAL; if (sk->state != TCP_LISTEN) goto out; @@ -1635,13 +1775,13 @@ req = tcp_find_established(tp, &prev); if (!req) { /* If this is a non blocking socket don't sleep */ - error = EAGAIN; + error = -EAGAIN; if (flags & O_NONBLOCK) goto out; - - error = ERESTARTSYS; + + error = -ERESTARTSYS; req = wait_for_connect(sk, &prev); - if (!req) + if (!req) goto out; } @@ -1650,20 +1790,13 @@ req->class->destructor(req); tcp_openreq_free(req); sk->ack_backlog--; - if(sk->keepopen) - tcp_inc_slow_timer(TCP_SLT_KEEPALIVE); release_sock(sk); - lock_kernel(); return newsk; out: - /* sk should be in LISTEN state, thus accept can use sk->err for - * internal purposes without stomping on anyone's feed. - */ - sk->err = error; release_sock(sk); - lock_kernel(); - return newsk; + *err = error; + return NULL; } /* @@ -1675,36 +1808,43 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int val; + int err = 0; if (level != SOL_TCP) return tp->af_specific->setsockopt(sk, level, optname, optval, optlen); - + if(optlen MAX_WINDOW) - return -EINVAL; + if(val < 1 || val > MAX_WINDOW) { + err = -EINVAL; + break; + } tp->user_mss = val; - return 0; + break; case TCP_NODELAY: /* You cannot try to use this and TCP_CORK in * tandem, so let the user know. */ - if (sk->nonagle == 2) - return -EINVAL; + if (sk->nonagle == 2) { + err = -EINVAL; + break; + } sk->nonagle = (val == 0) ? 0 : 1; - return 0; + break; case TCP_CORK: /* When set indicates to always queue non-full frames. @@ -1718,22 +1858,25 @@ * You cannot try to use TCP_NODELAY and this mechanism * at the same time, so let the user know. */ - if (sk->nonagle == 1) - return -EINVAL; + if (sk->nonagle == 1) { + err = -EINVAL; + break; + } if (val != 0) { sk->nonagle = 2; } else { sk->nonagle = 0; - lock_sock(sk); tcp_push_pending_frames(sk, tp); - release_sock(sk); } - return 0; + break; default: - return -ENOPROTOOPT; + err = -ENOPROTOOPT; + break; }; + release_sock(sk); + return err; } int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, @@ -1772,13 +1915,6 @@ return 0; } -void tcp_set_keepalive(struct sock *sk, int val) -{ - if (!sk->keepopen && val) - tcp_inc_slow_timer(TCP_SLT_KEEPALIVE); - else if (sk->keepopen && !val) - tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); -} extern void __skb_cb_too_small_for_tcp(int, int); @@ -1786,7 +1922,7 @@ { struct sk_buff *skb = NULL; unsigned long goal; - int order; + int order, i; if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)) __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb), @@ -1818,31 +1954,51 @@ * * The methodology is similar to that of the buffer cache. */ - goal = num_physpages >> (20 - PAGE_SHIFT); - for(order = 5; (1UL << order) < goal; order++) + goal = num_physpages >> (23 - PAGE_SHIFT); + + for(order = 0; (1UL << order) < goal; order++) ; do { tcp_ehash_size = (1UL << order) * PAGE_SIZE / - sizeof(struct sock *); - tcp_ehash = (struct sock **) + sizeof(struct tcp_ehash_bucket); + tcp_ehash_size >>= 1; + while (tcp_ehash_size & (tcp_ehash_size-1)) + tcp_ehash_size--; + tcp_ehash = (struct tcp_ehash_bucket *) __get_free_pages(GFP_ATOMIC, order); - } while (tcp_ehash == NULL && --order > 4); + } while (tcp_ehash == NULL && --order > 0); if (!tcp_ehash) panic("Failed to allocate TCP established hash table\n"); - memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *)); + for (i = 0; i < (tcp_ehash_size<<1); i++) { + tcp_ehash[i].lock = RW_LOCK_UNLOCKED; + tcp_ehash[i].chain = NULL; + } do { tcp_bhash_size = (1UL << order) * PAGE_SIZE / - sizeof(struct tcp_bind_bucket *); - tcp_bhash = (struct tcp_bind_bucket **) + sizeof(struct tcp_bind_hashbucket); + if ((tcp_bhash_size > (64 * 1024)) && order > 0) + continue; + tcp_bhash = (struct tcp_bind_hashbucket *) __get_free_pages(GFP_ATOMIC, order); - } while (tcp_bhash == NULL && --order > 4); + } while (tcp_bhash == NULL && --order >= 0); if (!tcp_bhash) panic("Failed to allocate TCP bind hash table\n"); - memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *)); + for (i = 0; i < tcp_bhash_size; i++) { + tcp_bhash[i].lock = SPIN_LOCK_UNLOCKED; + tcp_bhash[i].chain = NULL; + } + + if (order > 4) { + sysctl_local_port_range[0] = 32768; + sysctl_local_port_range[1] = 61000; + } else if (order < 3) { + sysctl_local_port_range[0] = 1024*(3-order); + } + tcp_port_rover = sysctl_local_port_range[0] - 1; printk("TCP: Hash tables configured (established %d bind %d)\n", - tcp_ehash_size, tcp_bhash_size); + tcp_ehash_size<<1, tcp_bhash_size); } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.3.14/linux/net/ipv4/tcp_input.c Sat Jul 3 17:57:23 1999 +++ linux/net/ipv4/tcp_input.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.170 1999/07/02 11:26:28 davem Exp $ + * Version: $Id: tcp_input.c,v 1.172 1999/08/23 06:30:35 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -61,6 +61,7 @@ #include #include #include +#include #include #ifdef CONFIG_SYSCTL @@ -70,6 +71,7 @@ #endif extern int sysctl_tcp_fin_timeout; +extern int sysctl_tcp_keepalive_time; /* These are on by default so the code paths get tested. * For the final 2.2 this may be undone at our discretion. -DaveM @@ -81,6 +83,7 @@ int sysctl_tcp_syncookies = SYNC_INIT; int sysctl_tcp_stdurg; int sysctl_tcp_rfc1337; +int sysctl_tcp_tw_recycle; static int prune_queue(struct sock *sk); @@ -133,7 +136,7 @@ /* Tiny-grams with PSH set artifically deflate our * ato measurement, but with a lower bound. */ - if(th->psh && (skb->len < (tp->mss_cache >> 1))) { + if(th->psh && (skb->len < (tp->rcv_mss >> 1))) { /* Preserve the quickack state. */ if((tp->ato & 0x7fffffff) > HZ/50) tp->ato = ((tp->ato & 0x80000000) | @@ -187,6 +190,9 @@ static __inline__ void tcp_set_rto(struct tcp_opt *tp) { tp->rto = (tp->srtt >> 3) + tp->mdev; + /* I am not enough educated to understand this magic. + * However, it smells bad. snd_cwnd>31 is common case. + */ tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1)); } @@ -209,42 +215,196 @@ tp->rto = HZ/5; } -/* WARNING: this must not be called if tp->saw_timestamp was false. */ -extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp, - __u32 start_seq, __u32 end_seq) -{ - /* From draft-ietf-tcplw-high-performance: the correct - * test is last_ack_sent <= end_seq. - * (RFC1323 stated last_ack_sent < end_seq.) +/* Save metrics learned by this TCP session. + This function is called only, when TCP finishes sucessfully + i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE. + */ +static void tcp_update_metrics(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct dst_entry *dst = __sk_dst_get(sk); + + if (dst) { + int m; + + if (tp->backoff || !tp->srtt) { + /* This session failed to estimate rtt. Why? + * Probably, no packets returned in time. + * Reset our results. + */ + if (!(dst->mxlock&(1<rtt = 0; + return; + } + + dst_confirm(dst); + + m = dst->rtt - tp->srtt; + + /* If newly calculated rtt larger than stored one, + * store new one. Otherwise, use EWMA. Remember, + * rtt overestimation is always better than underestimation. + */ + if (!(dst->mxlock&(1<rtt = tp->srtt; + else + dst->rtt -= (m>>3); + } + + if (!(dst->mxlock&(1<>= 1; + if (m < tp->mdev) + m = tp->mdev; + + if (m >= dst->rttvar) + dst->rttvar = m; + else + dst->rttvar -= (dst->rttvar - m)>>2; + } + + if (tp->snd_ssthresh == 0x7FFFFFFF) { + /* Slow start still did not finish. */ + if (dst->ssthresh && + !(dst->mxlock&(1<snd_cwnd > dst->ssthresh) + dst->ssthresh = tp->snd_cwnd; + if (!(dst->mxlock&(1<snd_cwnd > dst->cwnd) + dst->cwnd = tp->snd_cwnd; + } else if (tp->snd_cwnd >= tp->snd_ssthresh && !tp->high_seq) { + /* Cong. avoidance phase, cwnd is reliable. */ + if (!(dst->mxlock&(1<ssthresh = tp->snd_cwnd; + if (!(dst->mxlock&(1<cwnd = (dst->cwnd + tp->snd_cwnd)>>1; + } else { + /* Else slow start did not finish, cwnd is non-sense, + ssthresh may be also invalid. + */ + if (!(dst->mxlock&(1<cwnd = (dst->cwnd + tp->snd_ssthresh)>>1; + if (dst->ssthresh && + !(dst->mxlock&(1<snd_ssthresh > dst->ssthresh) + dst->ssthresh = tp->snd_ssthresh; + } + } +} + +/* Initialize metrics on socket. */ + +static void tcp_init_metrics(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct dst_entry *dst = __sk_dst_get(sk); + + if (dst == NULL) + goto reset; + + dst_confirm(dst); + + if (dst->rtt == 0) + goto reset; + + if (!tp->srtt || !tp->saw_tstamp) + goto reset; + + /* Initial rtt is determined from SYN,SYN-ACK. + * The segment is small and rtt may appear much + * less than real one. Use per-dst memory + * to make it more realistic. * - * HOWEVER: The current check contradicts the draft statements. - * It has been done for good reasons. - * The implemented check improves security and eliminates - * unnecessary RTT overestimation. - * 1998/06/27 Andrey V. Savochkin + * A bit of theory. RTT is time passed after "normal" sized packet + * is sent until it is ACKed. In normal curcumstances sending small + * packets force peer to delay ACKs and calculation is correct too. + * The algorithm is adaptive and, provided we follow specs, it + * NEVER underestimate RTT. BUT! If peer tries to make some clever + * tricks sort of "quick acks" for time long enough to decrease RTT + * to low value, and then abruptly stops to do it and starts to delay + * ACKs, wait for troubles. + */ + if (dst->rtt > tp->srtt) + tp->srtt = dst->rtt; + if (dst->rttvar > tp->mdev) + tp->mdev = dst->rttvar; + tcp_set_rto(tp); + tcp_bound_rto(tp); + + if (dst->mxlock&(1<snd_cwnd_clamp = dst->cwnd; + if (dst->ssthresh) { + tp->snd_ssthresh = dst->ssthresh; + if (tp->snd_ssthresh > tp->snd_cwnd_clamp) + tp->snd_ssthresh = tp->snd_cwnd_clamp; + } + return; + + +reset: + /* Play conservative. If timestamps are not + * supported, TCP will fail to recalculate correct + * rtt, if initial rto is too small. FORGET ALL AND RESET! */ - if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) && - !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) { + if (!tp->saw_tstamp && tp->srtt) { + tp->srtt = 0; + tp->mdev = TCP_TIMEOUT_INIT; + tp->rto = TCP_TIMEOUT_INIT; + } +} + +#define PAWS_24DAYS (60 * 60 * 24 * 24) + + +/* WARNING: this must not be called if tp->saw_tstamp was false. */ +extern __inline__ void +tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp, u32 seq) +{ + if (!after(seq, tp->last_ack_sent)) { /* PAWS bug workaround wrt. ACK frames, the PAWS discard * extra check below makes sure this can only happen * for pure ACK frames. -DaveM + * + * Not only, also it occurs for expired timestamps + * and RSTs with bad timestamp option. --ANK */ - if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) { + + if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 || + xtime.tv_sec >= tp->ts_recent_stamp + PAWS_24DAYS) { tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = tcp_time_stamp; + tp->ts_recent_stamp = xtime.tv_sec; } } } -#define PAWS_24DAYS (HZ * 60 * 60 * 24 * 24) - -extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, unsigned len) +extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb) { - /* ts_recent must be younger than 24 days */ - return (((s32)(tcp_time_stamp - tp->ts_recent_stamp) >= PAWS_24DAYS) || - (((s32)(tp->rcv_tsval - tp->ts_recent) < 0) && - /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM */ - (len != (th->doff * 4)))); + return ((s32)(tp->rcv_tsval - tp->ts_recent) < 0 && + xtime.tv_sec < tp->ts_recent_stamp + PAWS_24DAYS + + /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM + + I cannot see quitely as all the idea behind PAWS + is destroyed 8) + + The problem is only in reordering duplicate ACKs. + Hence, we can check this rare case more carefully. + + 1. Check that it is really duplicate ACK (ack==snd_una) + 2. Give it some small "replay" window (~RTO) + + We do not know units of foreign ts values, but make conservative + assumption that they are >=1ms. It solves problem + noted in Dave's mail to tcpimpl and does not harm PAWS. --ANK + */ + && (TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq || + TCP_SKB_CB(skb)->ack_seq != tp->snd_una || + !skb->h.th->ack || + (s32)(tp->ts_recent - tp->rcv_tsval) > (tp->rto*1024)/HZ)); } @@ -283,13 +443,14 @@ case TCP_CLOSE_WAIT: sk->err = EPIPE; break; + case TCP_CLOSE: + return; default: sk->err = ECONNRESET; }; tcp_set_state(sk, TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); + tcp_clear_xmit_timers(sk); + tcp_done(sk); } /* This tags the retransmission queue when SACKs arrive. */ @@ -345,7 +506,6 @@ { unsigned char *ptr; int length=(th->doff*4)-sizeof(struct tcphdr); - int saw_mss = 0; ptr = (unsigned char *)(th + 1); tp->saw_tstamp = 0; @@ -370,11 +530,11 @@ case TCPOPT_MSS: if(opsize==TCPOLEN_MSS && th->syn) { u16 in_mss = ntohs(*(__u16 *)ptr); - if (in_mss == 0) - in_mss = 536; - if (tp->mss_clamp > in_mss) + if (in_mss) { + if (tp->user_mss && tp->user_mss < in_mss) + in_mss = tp->user_mss; tp->mss_clamp = in_mss; - saw_mss = 1; + } } break; case TCPOPT_WINDOW: @@ -428,8 +588,6 @@ length-=opsize; }; } - if(th->syn && saw_mss == 0) - tp->mss_clamp = 536; } /* Fast parse options. This hopes to only see timestamps. @@ -448,8 +606,10 @@ if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { tp->saw_tstamp = 1; - tp->rcv_tsval = ntohl(*++ptr); - tp->rcv_tsecr = ntohl(*++ptr); + ++ptr; + tp->rcv_tsval = ntohl(*ptr); + ++ptr; + tp->rcv_tsecr = ntohl(*ptr); return 1; } } @@ -461,6 +621,7 @@ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ #define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged new data. */ static __inline__ void clear_fast_retransmit(struct tcp_opt *tp) { @@ -498,6 +659,8 @@ tp->dup_acks++; if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) { tp->snd_ssthresh = tcp_recalc_ssthresh(tp); + if (tp->snd_ssthresh > tp->snd_cwnd_clamp) + tp->snd_ssthresh = tp->snd_cwnd_clamp; tp->snd_cwnd = (tp->snd_ssthresh + 3); tp->high_seq = tp->snd_nxt; if(!tp->fackets_out) @@ -595,11 +758,12 @@ * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd */ if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { - tp->snd_cwnd++; + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; tp->snd_cwnd_cnt=0; } else tp->snd_cwnd_cnt++; - } + } } /* Remove acknowledged frames from the retransmission queue. */ @@ -645,9 +809,10 @@ if(tp->fackets_out) tp->fackets_out--; } else { + acked |= FLAG_SYN_ACKED; /* This is pure paranoia. */ tp->retrans_head = NULL; - } + } tp->packets_out--; *seq = scb->seq; *seq_rtt = now - scb->when; @@ -721,7 +886,7 @@ * See draft-ietf-tcplw-high-performance-00, section 3.3. * 1998/04/10 Andrey V. Savochkin */ - if (!(flag & FLAG_DATA_ACKED)) + if (!(flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED))) return; seq_rtt = tcp_time_stamp - tp->rcv_tsecr; @@ -856,7 +1021,7 @@ * where the network delay has increased suddenly. * I.e. Karn's algorithm. (SIGCOMM '87, p5.) */ - if (flag & FLAG_DATA_ACKED) { + if (flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)) { if(!(flag & FLAG_RETRANS_DATA_ACKED)) { tp->backoff = 0; tcp_rtt_estimator(tp, seq_rtt); @@ -910,37 +1075,50 @@ } /* New-style handling of TIME_WAIT sockets. */ -extern void tcp_tw_schedule(struct tcp_tw_bucket *tw); -extern void tcp_tw_reschedule(struct tcp_tw_bucket *tw); -extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw); /* Must be called only from BH context. */ void tcp_timewait_kill(struct tcp_tw_bucket *tw) { - struct tcp_bind_bucket *tb = tw->tb; - - SOCKHASH_LOCK_WRITE_BH(); - - /* Disassociate with bind bucket. */ - if(tw->bind_next) - tw->bind_next->bind_pprev = tw->bind_pprev; - *(tw->bind_pprev) = tw->bind_next; - if (tb->owners == NULL) { - if (tb->next) - tb->next->pprev = tb->pprev; - *(tb->pprev) = tb->next; - kmem_cache_free(tcp_bucket_cachep, tb); - } + struct tcp_ehash_bucket *ehead; + struct tcp_bind_hashbucket *bhead; + struct tcp_bind_bucket *tb; /* Unlink from established hashes. */ + ehead = &tcp_ehash[tw->hashent]; + write_lock(&ehead->lock); + if (!tw->pprev) { + write_unlock(&ehead->lock); + return; + } if(tw->next) tw->next->pprev = tw->pprev; - *tw->pprev = tw->next; + *(tw->pprev) = tw->next; + tw->pprev = NULL; + write_unlock(&ehead->lock); - SOCKHASH_UNLOCK_WRITE_BH(); - - /* Ok, now free it up. */ - kmem_cache_free(tcp_timewait_cachep, tw); + /* Disassociate with bind bucket. */ + bhead = &tcp_bhash[tcp_bhashfn(tw->num)]; + spin_lock(&bhead->lock); + if ((tb = tw->tb) != NULL) { + if(tw->bind_next) + tw->bind_next->bind_pprev = tw->bind_pprev; + *(tw->bind_pprev) = tw->bind_next; + tw->tb = NULL; + if (tb->owners == NULL) { + if (tb->next) + tb->next->pprev = tb->pprev; + *(tb->pprev) = tb->next; + kmem_cache_free(tcp_bucket_cachep, tb); + } + } + spin_unlock(&bhead->lock); + +#ifdef INET_REFCNT_DEBUG + if (atomic_read(&tw->refcnt) != 1) { + printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, atomic_read(&tw->refcnt)); + } +#endif + tcp_tw_put(tw); } /* We come here as a special case from the AF specific TCP input processing, @@ -949,9 +1127,36 @@ * entire timeout period. The only special cases are for BSD TIME_WAIT * reconnects and SYN/RST bits being set in the TCP header. */ -int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, - struct tcphdr *th, unsigned len) + +/* + * * Main purpose of TIME-WAIT state is to close connection gracefully, + * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN + * (and, probably, tail of data) and one or more our ACKs are lost. + * * What is TIME-WAIT timeout? It is associated with maximal packet + * lifetime in the internet, which results in wrong conclusion, that + * it is set to catch "old duplicate segments" wandering out of their path. + * It is not quite correct. This timeout is calculated so that it exceeds + * maximal retransmision timeout enough to allow to lose one (or more) + * segments sent by peer and our ACKs. This time may be calculated from RTO. + * * When TIME-WAIT socket receives RST, it means that another end + * finally closed and we are allowed to kill TIME-WAIT too. + * * Second purpose of TIME-WAIT is catching old duplicate segments. + * Well, certainly it is pure paranoia, but if we load TIME-WAIT + * with this semantics, we MUST NOT kill TIME-WAIT state with RSTs. + * * If we invented some more clever way to catch duplicates + * (f.e. based on PAWS), we could truncate TIME-WAIT to several RTOs. + * + * The algorithm below is based on FORMAL INTERPRETATION of RFCs. + * When you compare it to RFCs, please, read section SEGMENT ARRIVES + * from the very beginning. + */ +enum tcp_tw_status +tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, + struct tcphdr *th, unsigned len) { + struct tcp_opt tp; + int paws_reject = 0; + /* RFC 1122: * "When a connection is [...] on TIME-WAIT state [...] * [a TCP] MAY accept a new SYN from the remote TCP to @@ -965,58 +1170,101 @@ * (2) returns to TIME-WAIT state if the SYN turns out * to be an old duplicate". */ - if(th->syn && !th->rst && after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) { - struct sock *sk; - struct tcp_func *af_specific = tw->af_specific; - __u32 isn; - int ret; - isn = tw->rcv_nxt + 128000; - if(isn == 0) - isn++; - tcp_tw_deschedule(tw); - tcp_timewait_kill(tw); - sk = af_specific->get_sock(skb, th); - if(sk == NULL || - !ipsec_sk_policy(sk,skb)) - return 0; + tp.saw_tstamp = 0; + if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) { + tcp_parse_options(NULL, th, &tp, 0); + + paws_reject = tp.saw_tstamp && + ((s32)(tp.rcv_tsval - tw->ts_recent) < 0 && + xtime.tv_sec < tw->ts_recent_stamp + PAWS_24DAYS); + } + + if (!paws_reject && + (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && + TCP_SKB_CB(skb)->seq == tw->rcv_nxt)) { + /* In window segment, it may be only reset or bare ack. */ + + if (th->rst) { +#ifdef CONFIG_TCP_TW_RECYCLE + /* When recycling, always follow rfc1337, + * but mark bucket as ready to recycling immediately. + */ + if (sysctl_tcp_tw_recycle) { + /* May kill it now. */ + tw->rto = 0; + tw->ttd = jiffies; + } else +#endif + /* This is TIME_WAIT assasination, in two flavors. + * Oh well... nobody has a sufficient solution to this + * protocol bug yet. + */ + if(sysctl_tcp_rfc1337 == 0) { + tcp_tw_deschedule(tw); + tcp_timewait_kill(tw); + } + } else { + tcp_tw_reschedule(tw); + } - bh_lock_sock(sk); + if (tp.saw_tstamp) { + tw->ts_recent = tp.rcv_tsval; + tw->ts_recent_stamp = xtime.tv_sec; + } + tcp_tw_put(tw); + return TCP_TW_SUCCESS; + } - /* Default is to discard the frame. */ - ret = 0; + /* Out of window segment. - if(sk->lock.users) - goto out_unlock; + All the segments are ACKed immediately. - skb_set_owner_r(skb, sk); - af_specific = sk->tp_pinfo.af_tcp.af_specific; + The only exception is new SYN. We accept it, if it is + not old duplicate and we are not in danger to be killed + by delayed old duplicates. RFC check is that it has + newer sequence number works at rates <40Mbit/sec. + However, if paws works, it is reliable AND even more, + we even may relax silly seq space cutoff. + + RED-PEN: we violate main RFC requirement, if this SYN will appear + old duplicate (i.e. we receive RST in reply to SYN-ACK), + we must return socket to time-wait state. It is not good, + but not fatal yet. + */ - if(af_specific->conn_request(sk, skb, isn) < 0) - ret = 1; /* Toss a reset back. */ - out_unlock: - bh_unlock_sock(sk); - return ret; + if (th->syn && !th->rst && !th->ack && !paws_reject && + (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) || + (tp.saw_tstamp && tw->ts_recent != tp.rcv_tsval))) { + u32 isn = tw->snd_nxt + 2; + if (isn == 0) + isn++; + TCP_SKB_CB(skb)->when = isn; + return TCP_TW_SYN; } - /* Check RST or SYN */ - if(th->rst || th->syn) { - /* This is TIME_WAIT assasination, in two flavors. - * Oh well... nobody has a sufficient solution to this - * protocol bug yet. + if(!th->rst) { + /* In this case we must reset the TIMEWAIT timer. + + If it is ACKless SYN it may be both old duplicate + and new good SYN with random sequence number rst) - return 1; /* toss a reset back */ - } else { - /* In this case we must reset the TIMEWAIT timer. */ - if(th->ack) + if (paws_reject || th->ack) { tcp_tw_reschedule(tw); +#ifdef CONFIG_TCP_TW_RECYCLE + tw->rto = min(120*HZ, tw->rto<<1); + tw->ttd = jiffies + tw->rto; +#endif + } + + /* Send ACK. Note, we do not put the bucket, + * it will be released by caller. + */ + return TCP_TW_ACK; } - return 0; /* Discard the frame. */ + tcp_tw_put(tw); + return TCP_TW_SUCCESS; } /* Enter the time wait state. This is always called from BH @@ -1024,37 +1272,54 @@ * relevant info into it from the SK, and mess with hash chains * and list linkage. */ -static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) +static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) { + struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent]; + struct tcp_bind_hashbucket *bhead; struct sock **head, *sktw; - /* Step 1: Remove SK from established hash. */ - if(sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - tcp_reg_zap(sk); - - /* Step 2: Put TW into bind hash where SK was. */ - tw->tb = (struct tcp_bind_bucket *)sk->prev; - if((tw->bind_next = sk->bind_next) != NULL) - sk->bind_next->bind_pprev = &tw->bind_next; - tw->bind_pprev = sk->bind_pprev; - *sk->bind_pprev = (struct sock *)tw; - sk->prev = NULL; + write_lock(&ehead->lock); - /* Step 3: Un-charge protocol socket in-use count. */ - sk->prot->inuse--; + /* Step 1: Remove SK from established hash. */ + if (sk->pprev) { + if(sk->next) + sk->next->pprev = sk->pprev; + *sk->pprev = sk->next; + sk->pprev = NULL; + } - /* Step 4: Hash TW into TIMEWAIT half of established hash table. */ - head = &tcp_ehash[sk->hashent + (tcp_ehash_size >> 1)]; + /* Step 2: Hash TW into TIMEWAIT half of established hash table. */ + head = &(ehead + tcp_ehash_size)->chain; sktw = (struct sock *)tw; if((sktw->next = *head) != NULL) (*head)->pprev = &sktw->next; *head = sktw; sktw->pprev = head; + atomic_inc(&tw->refcnt); + + write_unlock(&ehead->lock); + + /* Step 3: Put TW into bind hash. Original socket stays there too. + Note, that any socket with sk->num!=0 MUST be bound in binding + cache, even if it is closed. + */ + bhead = &tcp_bhash[tcp_bhashfn(sk->num)]; + spin_lock(&bhead->lock); + tw->tb = (struct tcp_bind_bucket *)sk->prev; + BUG_TRAP(sk->prev!=NULL); + if ((tw->bind_next = tw->tb->owners) != NULL) + tw->tb->owners->bind_pprev = &tw->bind_next; + tw->tb->owners = (struct sock*)tw; + tw->bind_pprev = &tw->tb->owners; + spin_unlock(&bhead->lock); + + /* Step 4: Un-charge protocol socket in-use count. */ + sk->prot->inuse--; } +/* + * Move a socket to time-wait. + */ void tcp_time_wait(struct sock *sk) { struct tcp_tw_bucket *tw; @@ -1071,8 +1336,16 @@ tw->dport = sk->dport; tw->family = sk->family; tw->reuse = sk->reuse; + tw->hashent = sk->hashent; tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt; - tw->af_specific = sk->tp_pinfo.af_tcp.af_specific; + tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt; + tw->ts_recent = sk->tp_pinfo.af_tcp.ts_recent; + tw->ts_recent_stamp= sk->tp_pinfo.af_tcp.ts_recent_stamp; +#ifdef CONFIG_TCP_TW_RECYCLE + tw->rto = sk->tp_pinfo.af_tcp.rto; + tw->ttd = jiffies + 2*tw->rto; +#endif + atomic_set(&tw->refcnt, 0); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if(tw->family == PF_INET6) { @@ -1085,9 +1358,7 @@ } #endif /* Linkage updates. */ - SOCKHASH_LOCK_WRITE(); - tcp_tw_hashdance(sk, tw); - SOCKHASH_UNLOCK_WRITE(); + __tcp_tw_hashdance(sk, tw); /* Get the TIME_WAIT timeout firing. */ tcp_tw_schedule(tw); @@ -1096,8 +1367,6 @@ if(sk->state == TCP_ESTABLISHED) tcp_statistics.TcpCurrEstab--; sk->state = TCP_CLOSE; - net_reset_timer(sk, TIME_DONE, - min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME)); } else { /* Sorry, we're out of memory, just CLOSE this * socket up. We've got bigger problems than @@ -1106,10 +1375,9 @@ tcp_set_state(sk, TCP_CLOSE); } - /* Prevent rcvmsg/sndmsg calls, and wake people up. */ - sk->shutdown = SHUTDOWN_MASK; - if(!sk->dead) - sk->state_change(sk); + tcp_update_metrics(sk); + tcp_clear_xmit_timers(sk); + tcp_done(sk); } /* @@ -1134,7 +1402,7 @@ tcp_send_ack(sk); if (!sk->dead) { - sk->state_change(sk); + wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket, 1); } @@ -1143,8 +1411,6 @@ case TCP_ESTABLISHED: /* Move to CLOSE_WAIT */ tcp_set_state(sk, TCP_CLOSE_WAIT); - if (th->rst) - sk->shutdown = SHUTDOWN_MASK; break; case TCP_CLOSE_WAIT: @@ -1161,12 +1427,6 @@ /* This case occurs when a simultaneous close * happens, we must ack the received FIN and * enter the CLOSING state. - * - * This causes a WRITE timeout, which will either - * move on to TIME_WAIT when we timeout, or resend - * the FIN properly (maybe we get rid of that annoying - * FIN lost hang). The TIME_WRITE code is already - * correct for handling this timeout. */ tcp_set_state(sk, TCP_CLOSING); break; @@ -1423,7 +1683,7 @@ /* Turn on fast path. */ if (skb_queue_len(&tp->out_of_order_queue) == 0) tp->pred_flags = htonl(((tp->tcp_header_len >> 2) << 28) | - (0x10 << 16) | + ntohl(TCP_FLAG_ACK) | tp->snd_wnd); return; } @@ -1545,8 +1805,8 @@ * Now tell the user we may have some data. */ if (!sk->dead) { - SOCK_DEBUG(sk, "Data wakeup.\n"); - sk->data_ready(sk,0); + wake_up_interruptible(sk->sleep); + sock_wake_async(sk->socket,1); } return(1); } @@ -1575,28 +1835,59 @@ /* * Adapt the MSS value used to make delayed ack decision to the - * real world. + * real world. + * + * The constant 536 hasn't any good meaning. In IPv4 world + * MTU may be smaller, though it contradicts to RFC1122, which + * states that MSS must be at least 536. + * We use the constant to do not ACK each second + * packet in a stream of tiny size packets. + * It means that super-low mtu links will be aggressively delacked. + * Seems, it is even good. If they have so low mtu, they are weirdly + * slow. + * + * AK: BTW it may be useful to add an option to lock the rcv_mss. + * this way the beowulf people wouldn't need ugly patches to get the + * ack frequencies they want and it would be an elegant way to tune delack. */ static __inline__ void tcp_measure_rcv_mss(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - unsigned int len = skb->len, lss; + unsigned int len, lss; - if (len > tp->rcv_mss) - tp->rcv_mss = len; lss = tp->last_seg_size; tp->last_seg_size = 0; - if (len >= 536) { - if (len == lss) - tp->rcv_mss = len; - tp->last_seg_size = len; + + /* skb->len may jitter because of SACKs, even if peer + * sends good full-sized frames. + */ + len = skb->len; + if (len >= tp->rcv_mss) { + tp->rcv_mss = len; + } else { + /* Otherwise, we make more careful check taking into account, + * that SACKs block is variable. + * + * "len" is invariant segment length, including TCP header. + */ + len = skb->tail - skb->h.raw; + if (len >= 536 + sizeof(struct tcphdr)) { + /* Subtract also invariant (if peer is RFC compliant), + * tcp header plus fixed timestamp option length. + * Resulting "len" is MSS free of SACK jitter. + */ + len -= tp->tcp_header_len; + if (len == lss) + tp->rcv_mss = len; + tp->last_seg_size = len; + } } } /* * Check if sending an ack is needed. */ -static __inline__ void __tcp_ack_snd_check(struct sock *sk) +static __inline__ void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -1621,12 +1912,12 @@ /* We entered "quick ACK" mode or... */ tcp_in_quickack_mode(tp) || /* We have out of order data */ - (skb_peek(&tp->out_of_order_queue) != NULL)) { + (ofo_possible && (skb_peek(&tp->out_of_order_queue) != NULL))) { /* Then ack it now */ tcp_send_ack(sk); } else { /* Else, send delayed ack. */ - tcp_send_delayed_ack(tp, HZ/2); + tcp_send_delayed_ack(sk, HZ/2); } } @@ -1637,7 +1928,7 @@ /* We sent a data segment already. */ return; } - __tcp_ack_snd_check(sk); + __tcp_ack_snd_check(sk, 1); } @@ -1767,6 +2058,13 @@ * complex for anyones sanity. So we don't do it anymore. But * if we are really having our buffer space abused we stop accepting * new receive data. + * + * FIXME: it should recompute SACK state and only remove enough + * buffers to get into bounds again. The current scheme loses + * badly sometimes on links with large RTT, especially when + * the driver has high overhead per skb. + * (increasing the rcvbuf is not enough because it inflates the + * the window too, disabling flow control effectively) -AK */ if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1)) return 0; @@ -1782,7 +2080,7 @@ * disabled when: * - A zero window was announced from us - zero window probing * is only handled properly in the slow path. - * - Out of order segments arrived. + * - Out of order segments arrived. * - Urgent data is expected. * - There is no buffer space left * - Unexpected TCP flags/window values/header lengths are received @@ -1790,6 +2088,7 @@ * - Data is sent in both directions. Fast path only supports pure senders * or pure receivers (this means either the sequence number or the ack * value must stay constant) + * - Unexpected TCP option. * * When these conditions are not satisfied it drops into a standard * receive procedure patterned after RFC793 to handle all cases. @@ -1801,12 +2100,10 @@ struct tcphdr *th, unsigned len) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int queued; - u32 flg; /* * Header prediction. - * The code follows the one in the famous + * The code losely follows the one in the famous * "30 instruction TCP receive" Van Jacobson mail. * * Van's trick is to deposit buffers into socket queue @@ -1819,39 +2116,63 @@ * We do checksum and copy also but from device to kernel. */ - /* - * RFC1323: H1. Apply PAWS check first. - */ - if (tcp_fast_parse_options(sk, th, tp)) { - if (tp->saw_tstamp) { - if (tcp_paws_discard(tp, th, len)) { - tcp_statistics.TcpInErrs++; - if (!th->rst) { - tcp_send_ack(sk); - goto discard; - } - } - tcp_replace_ts_recent(sk, tp, - TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq); - } - } - flg = *(((u32 *)th) + 3) & ~htonl(0xFC8 << 16); + /* RED-PEN. Using static variables to pass function arguments + * cannot be good idea... + */ + tp->saw_tstamp = 0; /* pred_flags is 0xS?10 << 16 + snd_wnd * if header_predition is to be made * 'S' will always be tp->tcp_header_len >> 2 - * '?' will be 0 else it will be !0 - * (when there are holes in the receive + * '?' will be 0 for the fast path, otherwise pred_flags is 0 to + * turn it off (when there are holes in the receive * space for instance) * PSH flag is ignored. - */ + */ - if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { - if (len <= th->doff*4) { + if ((tcp_flag_word(th) & ~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) == tp->pred_flags && + TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { + int tcp_header_len = th->doff*4; + + /* Timestamp header prediction */ + + /* Non-standard header f.e. SACKs -> slow path */ + if (tcp_header_len != tp->tcp_header_len) + goto slow_path; + + /* Check timestamp */ + if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) { + __u32 *ptr = (__u32 *)(th + 1); + + /* No? Slow path! */ + if (*ptr != __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) + goto slow_path; + + tp->saw_tstamp = 1; + ++ptr; + tp->rcv_tsval = ntohl(*ptr); + ++ptr; + tp->rcv_tsecr = ntohl(*ptr); + + /* If PAWS failed, check it more carefully in slow path */ + if ((s32)(tp->rcv_tsval - tp->ts_recent) < 0) + goto slow_path; + + /* Predicted packet is in window by definition. + seq == rcv_nxt and last_ack_sent <= rcv_nxt. + Hence, check seq<=last_ack_sent reduces to: + */ + if (tp->rcv_nxt == tp->last_ack_sent) { + tp->ts_recent = tp->rcv_tsval; + tp->ts_recent_stamp = xtime.tv_sec; + } + } + + if (len <= tcp_header_len) { /* Bulk data transfer: sender */ - if (len == th->doff*4) { + if (len == tcp_header_len) { tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len); kfree_skb(skb); @@ -1864,12 +2185,14 @@ } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una && atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { /* Bulk data transfer: receiver */ - __skb_pull(skb,th->doff*4); + __skb_pull(skb,tcp_header_len); + /* Is it possible to simplify this? */ tcp_measure_rcv_mss(sk, skb); /* DO NOT notify forward progress here. * It saves dozen of CPU instructions in fast path. --ANK + * And where is it signaled then ? -AK */ __skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; @@ -1877,14 +2200,37 @@ /* FIN bit check is not done since if FIN is set in * this frame, the pred_flags won't match up. -DaveM */ - sk->data_ready(sk, 0); + wake_up_interruptible(sk->sleep); + sock_wake_async(sk->socket,1); tcp_delack_estimator(tp); tcp_remember_ack(tp, th, skb); - __tcp_ack_snd_check(sk); + __tcp_ack_snd_check(sk, 0); return 0; } + /* Packet is in sequence, flags are trivial; + * only ACK is strange or we are tough on memory. + * Jump to step 5. + */ + goto step5; + } + +slow_path: + /* + * RFC1323: H1. Apply PAWS check first. + */ + if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp && + tcp_paws_discard(tp, skb)) { + if (!th->rst) { + tcp_send_ack(sk); + goto discard; + } + /* Resets are accepted even if PAWS failed. + + ts_recent update must be made after we are sure + that the packet is in window. + */ } /* @@ -1909,44 +2255,34 @@ goto discard; } + if(th->rst) { + tcp_reset(sk); + goto discard; + } + + if (tp->saw_tstamp) { + tcp_replace_ts_recent(sk, tp, + TCP_SKB_CB(skb)->seq); + } + if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { SOCK_DEBUG(sk, "syn in established state\n"); tcp_statistics.TcpInErrs++; tcp_reset(sk); return 1; } - - if(th->rst) { - tcp_reset(sk); - goto discard; - } +step5: if(th->ack) tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len); /* Process urgent data. */ tcp_urg(sk, th, len); + { /* step 7: process the segment text */ - queued = tcp_data(skb, sk, len); + int queued = tcp_data(skb, sk, len); - /* This must be after tcp_data() does the skb_pull() to - * remove the header size from skb->len. - * - * Dave!!! Phrase above (and all about rcv_mss) has - * nothing to do with reality. rcv_mss must measure TOTAL - * size, including sacks, IP options etc. Hence, measure_rcv_mss - * must occure before pulling etc, otherwise it will flap - * like hell. Even putting it before tcp_data is wrong, - * it should use skb->tail - skb->nh.raw instead. - * --ANK (980805) - * - * BTW I broke it. Now all TCP options are handled equally - * in mss_clamp calculations (i.e. ignored, rfc1122), - * and mss_cache does include all of them (i.e. tstamps) - * except for sacks, to calulate effective mss faster. - * --ANK (980805) - */ tcp_measure_rcv_mss(sk, skb); /* Be careful, tcp_data() may have put this into TIME_WAIT. */ @@ -1959,76 +2295,541 @@ discard: kfree_skb(skb); } + } return 0; } + +/* This is not only more efficient than what we used to do, it eliminates + * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM + * + * Actually, we could lots of memory writes here. tp of listening + * socket contains all necessary default parameters. + */ +struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb) +{ + struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0); + + if(newsk != NULL) { + struct tcp_opt *newtp; +#ifdef CONFIG_FILTER + struct sk_filter *filter; +#endif + + memcpy(newsk, sk, sizeof(*newsk)); + newsk->state = TCP_SYN_RECV; + + /* SANITY */ + newsk->pprev = NULL; + newsk->prev = NULL; + + /* Clone the TCP header template */ + newsk->dport = req->rmt_port; + + sock_lock_init(newsk); + + atomic_set(&newsk->rmem_alloc, 0); + skb_queue_head_init(&newsk->receive_queue); + atomic_set(&newsk->wmem_alloc, 0); + skb_queue_head_init(&newsk->write_queue); + atomic_set(&newsk->omem_alloc, 0); + + newsk->done = 0; + newsk->proc = 0; + newsk->backlog.head = newsk->backlog.tail = NULL; + skb_queue_head_init(&newsk->error_queue); + newsk->write_space = tcp_write_space; +#ifdef CONFIG_FILTER + if ((filter = newsk->filter) != NULL) + sk_filter_charge(newsk, filter); +#endif + + /* Now setup tcp_opt */ + newtp = &(newsk->tp_pinfo.af_tcp); + newtp->pred_flags = 0; + newtp->rcv_nxt = req->rcv_isn + 1; + newtp->snd_nxt = req->snt_isn + 1; + newtp->snd_una = req->snt_isn + 1; + newtp->srtt = 0; + newtp->ato = 0; + newtp->snd_wl1 = req->rcv_isn; + newtp->snd_wl2 = req->snt_isn; + + /* RFC1323: The window in SYN & SYN/ACK segments + * is never scaled. + */ + newtp->snd_wnd = ntohs(skb->h.th->window); + + newtp->max_window = newtp->snd_wnd; + newtp->pending = 0; + newtp->retransmits = 0; + newtp->last_ack_sent = req->rcv_isn + 1; + newtp->backoff = 0; + newtp->mdev = TCP_TIMEOUT_INIT; + + /* So many TCP implementations out there (incorrectly) count the + * initial SYN frame in their delayed-ACK and congestion control + * algorithms that we must have the following bandaid to talk + * efficiently to them. -DaveM + */ + newtp->snd_cwnd = 2; + + newtp->rto = TCP_TIMEOUT_INIT; + newtp->packets_out = 0; + newtp->fackets_out = 0; + newtp->retrans_out = 0; + newtp->high_seq = 0; + newtp->snd_ssthresh = 0x7fffffff; + newtp->snd_cwnd_cnt = 0; + newtp->dup_acks = 0; + newtp->delayed_acks = 0; + init_timer(&newtp->retransmit_timer); + newtp->retransmit_timer.function = &tcp_retransmit_timer; + newtp->retransmit_timer.data = (unsigned long) newsk; + init_timer(&newtp->delack_timer); + newtp->delack_timer.function = &tcp_delack_timer; + newtp->delack_timer.data = (unsigned long) newsk; + skb_queue_head_init(&newtp->out_of_order_queue); + newtp->send_head = newtp->retrans_head = NULL; + newtp->rcv_wup = req->rcv_isn + 1; + newtp->write_seq = req->snt_isn + 1; + newtp->copied_seq = req->rcv_isn + 1; + + newtp->saw_tstamp = 0; + + init_timer(&newtp->probe_timer); + newtp->probe_timer.function = &tcp_probe_timer; + newtp->probe_timer.data = (unsigned long) newsk; + newtp->probes_out = 0; + newtp->syn_seq = req->rcv_isn; + newtp->fin_seq = req->rcv_isn; + newtp->urg_data = 0; + tcp_synq_init(newtp); + newtp->syn_backlog = 0; + if (skb->len >= 536) + newtp->last_seg_size = skb->len; + + /* Back to base struct sock members. */ + newsk->err = 0; + newsk->ack_backlog = 0; + newsk->max_ack_backlog = SOMAXCONN; + newsk->priority = 0; + atomic_set(&newsk->refcnt, 1); + atomic_inc(&inet_sock_nr); + + spin_lock_init(&sk->timer_lock); + init_timer(&newsk->timer); + newsk->timer.function = &tcp_keepalive_timer; + newsk->timer.data = (unsigned long) newsk; + if (newsk->keepopen) + tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time); + newsk->socket = NULL; + newsk->sleep = NULL; + + newtp->tstamp_ok = req->tstamp_ok; + if((newtp->sack_ok = req->sack_ok) != 0) + newtp->num_sacks = 0; + newtp->window_clamp = req->window_clamp; + newtp->rcv_wnd = req->rcv_wnd; + newtp->wscale_ok = req->wscale_ok; + if (newtp->wscale_ok) { + newtp->snd_wscale = req->snd_wscale; + newtp->rcv_wscale = req->rcv_wscale; + } else { + newtp->snd_wscale = newtp->rcv_wscale = 0; + newtp->window_clamp = min(newtp->window_clamp,65535); + } + if (newtp->tstamp_ok) { + newtp->ts_recent = req->ts_recent; + newtp->ts_recent_stamp = xtime.tv_sec; + newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + } else { + newtp->ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } + newtp->mss_clamp = req->mss; + } + return newsk; +} + +static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) +{ + if (seq == s_win) + return 1; + if (after(end_seq, s_win) && before(seq, e_win)) + return 1; + return (seq == e_win && seq == end_seq); +} + + /* - * Process an incoming SYN or SYN-ACK for SYN_RECV sockets represented - * as an open_request. + * Process an incoming packet for SYN_RECV sockets represented + * as an open_request. */ -struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, - struct open_request *req) +struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, + struct open_request *req, + struct open_request *prev) { + struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - u32 flg; + u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + int paws_reject = 0; + struct tcp_opt ttp; + + /* If socket has already been created, process + packet in its context. + + We fall here only due to race, when packets were enqueued + to backlog of listening socket. + */ + if (req->sk) + return req->sk; + + ttp.saw_tstamp = 0; + if (th->doff > (sizeof(struct tcphdr)>>2)) { + + tcp_parse_options(NULL, th, &ttp, 0); + + paws_reject = ttp.saw_tstamp && + (s32)(ttp.rcv_tsval - req->ts_recent) < 0; + } + + /* Check for pure retransmited SYN. */ + if (TCP_SKB_CB(skb)->seq == req->rcv_isn && + flg == TCP_FLAG_SYN && + !paws_reject) { + /* + * RFC793 draws (Incorrectly! It was fixed in RFC1122) + * this case on figure 6 and figure 8, but formal + * protocol description says NOTHING. + * To be more exact, it says that we should send ACK, + * because this segment (at least, if it has no data) + * is out of window. + * + * CONCLUSION: RFC793 (even with RFC1122) DOES NOT + * describe SYN-RECV state. All the description + * is wrong, we cannot believe to it and should + * rely only on common sense and implementation + * experience. + * + * Enforce "SYN-ACK" according to figure 8, figure 6 + * of RFC793, fixed by RFC1122. + */ + req->class->rtx_syn_ack(sk, req); + return NULL; + } + + /* Further reproduces section "SEGMENT ARRIVES" + for state SYN-RECEIVED of RFC793. + It is broken, however, it does not work only + when SYNs are crossed, which is impossible in our + case. + + But generally, we should (RFC lies!) to accept ACK + from SYNACK both here and in tcp_rcv_state_process(). + tcp_rcv_state_process() does not, hence, we do not too. - /* assumption: the socket is not in use. - * as we checked the user count on tcp_rcv and we're - * running from a soft interrupt. + Note that the case is absolutely generic: + we cannot optimize anything here without + violating protocol. All the checks must be made + before attempt to create socket. */ - /* Check for syn retransmission */ - flg = *(((u32 *)skb->h.th) + 3); - - flg &= __constant_htonl(0x00170000); - /* Only SYN set? */ - if (flg == __constant_htonl(0x00020000)) { - if (!after(TCP_SKB_CB(skb)->seq, req->rcv_isn)) { - /* retransmited syn. + /* RFC793: "first check sequence number". */ + + if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, + req->rcv_isn+1, req->rcv_isn+1+req->rcv_wnd)) { + /* Out of window: send ACK and drop. */ + if (!(flg & TCP_FLAG_RST)) + req->class->send_ack(skb, req); + return NULL; + } + + /* In sequence, PAWS is OK. */ + + if (ttp.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1)) + req->ts_recent = ttp.rcv_tsval; + + if (TCP_SKB_CB(skb)->seq == req->rcv_isn) { + /* Truncate SYN, it is out of window starting + at req->rcv_isn+1. */ + flg &= ~TCP_FLAG_SYN; + } + + /* RFC793: "second check the RST bit" and + * "fourth, check the SYN bit" + */ + if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) + goto embryonic_reset; + + /* RFC793: "fifth check the ACK field" */ + + if (!(flg & TCP_FLAG_ACK)) + return NULL; + + /* Invalid ACK: reset will be sent by listening socket */ + if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1) + return sk; + + /* OK, ACK is valid, create big socket and + feed this segment to it. It will repeat all + the tests. THIS SEGMENT MUST MOVE SOCKET TO + ESTABLISHED STATE. If it will be dropped after + socket is created, wait for troubles. + */ + sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL); + if (sk == NULL) + return NULL; + + tcp_dec_slow_timer(TCP_SLT_SYNACK); + req->sk = sk; + return sk; + +embryonic_reset: + tcp_synq_unlink(tp, req, prev); + tp->syn_backlog--; + tcp_dec_slow_timer(TCP_SLT_SYNACK); + + net_statistics.EmbryonicRsts++; + if (!(flg & TCP_FLAG_RST)) + req->class->send_reset(skb); + + req->class->destructor(req); + tcp_openreq_free(req); + return NULL; +} + +static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, + struct tcphdr *th, unsigned len) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + tcp_parse_options(sk, th, tp, 0); + +#ifdef CONFIG_TCP_TW_RECYCLE + if (tp->ts_recent_stamp && tp->saw_tstamp && !th->rst && + (s32)(tp->rcv_tsval - tp->ts_recent) < 0 && + xtime.tv_sec < tp->ts_recent_stamp + PAWS_24DAYS) { + /* Old duplicate segment. We remember last + ts_recent from this host in timewait bucket. + + Actually, we could implement per host cache + to truncate timewait state after RTO. Paranoidal arguments + of rfc1337 are not enough to close this nice possibility. + */ + if (net_ratelimit()) + printk(KERN_DEBUG "TCP: tw recycle, PAWS worked. Good.\n"); + if (th->ack) + return 1; + goto discard; + } +#endif + + if (th->ack) { + /* rfc793: + * "If the state is SYN-SENT then + * first check the ACK bit + * If the ACK bit is set + * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send + * a reset (unless the RST bit is set, if so drop + * the segment and return)" + * + * I cite this place to emphasize one essential + * detail, this check is different of one + * in established state: SND.UNA <= SEG.ACK <= SND.NXT. + * SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT, + * because we have no previous data sent before SYN. + * --ANK(990513) + * + * We do not send data with SYN, so that RFC-correct + * test reduces to: + */ + if (sk->zapped || + TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt) + return 1; + + /* Now ACK is acceptable. + * + * "If the RST bit is set + * If the ACK was acceptable then signal the user "error: + * connection reset", drop the segment, enter CLOSED state, + * delete TCB, and return." + */ + + if (th->rst) { + tcp_reset(sk); + goto discard; + } + + /* rfc793: + * "fifth, if neither of the SYN or RST bits is set then + * drop the segment and return." + * + * See note below! + * --ANK(990513) + */ + if (!th->syn) + goto discard; + + /* rfc793: + * "If the SYN bit is on ... + * are acceptable then ... + * (our SYN has been ACKed), change the connection + * state to ESTABLISHED..." + * + * Do you see? SYN-less ACKs in SYN-SENT state are + * completely ignored. + * + * The bug causing stalled SYN-SENT sockets + * was here: tcp_ack advanced snd_una and canceled + * retransmit timer, so that bare ACK received + * in SYN-SENT state (even with invalid ack==ISS, + * because tcp_ack check is too weak for SYN-SENT) + * causes moving socket to invalid semi-SYN-SENT, + * semi-ESTABLISHED state and connection hangs. + * + * There exist buggy stacks, which really send + * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp) + * Actually, if this host did not try to get something + * from ftp.inr.ac.ru I'd never find this bug 8) + * + * --ANK (990514) + * + * I was wrong, I apologize. Bare ACK is valid. + * Actually, RFC793 requires to send such ACK + * in reply to any out of window packet. + * It is wrong, but Linux also does it sometimes. + * --ANK (990724) + */ + + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; + tcp_ack(sk,th, TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(skb)->ack_seq, len); + + /* Ok.. it's good. Set up sequence numbers and + * move to established. + */ + tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1; + tp->rcv_wup = TCP_SKB_CB(skb)->seq+1; + + /* RFC1323: The window in SYN & SYN/ACK segments is + * never scaled. + */ + tp->snd_wnd = htons(th->window); + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; + tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; + tp->fin_seq = TCP_SKB_CB(skb)->seq; + + tcp_set_state(sk, TCP_ESTABLISHED); + + if (tp->wscale_ok == 0) { + tp->snd_wscale = tp->rcv_wscale = 0; + tp->window_clamp = min(tp->window_clamp,65535); + } + + if (tp->tstamp_ok) { + tp->tcp_header_len = + sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + } else + tp->tcp_header_len = sizeof(struct tcphdr); + if (tp->saw_tstamp) { + tp->ts_recent = tp->rcv_tsval; + tp->ts_recent_stamp = xtime.tv_sec; + } + tcp_sync_mss(sk, tp->pmtu_cookie); + tcp_initialize_rcv_mss(sk); + tcp_init_metrics(sk); + + if (tp->write_pending) { + /* Save one ACK. Data will be ready after + * several ticks, if write_pending is set. + * + * How to make this correctly? */ - req->class->rtx_syn_ack(sk, req); - return NULL; + tp->delayed_acks++; + if (tp->ato == 0) + tp->ato = tp->rto; + tcp_send_delayed_ack(sk, tp->rto); } else { - return sk; /* Pass new SYN to the listen socket. */ + tcp_send_ack(sk); } + + tp->copied_seq = tp->rcv_nxt; + + if(!sk->dead) { + wake_up_interruptible(sk->sleep); + sock_wake_async(sk->socket, 0); + } + return -1; + } + + /* No ACK in the segment */ + + if (th->rst) { + /* rfc793: + * "If the RST bit is set + * + * Otherwise (no ACK) drop the segment and return." + */ + + goto discard; } - /* We know it's an ACK here */ - if (req->sk) { - /* socket already created but not - * yet accepted()... + if (th->syn) { + /* We see SYN without ACK. It is attempt of + * simultaneous connect with crossed SYNs. + * + * The previous version of the code + * checked for "connecting to self" + * here. that check is done now in + * tcp_connect. + * + * RED-PEN: BTW, it does not. 8) */ - sk = req->sk; - } else { - /* In theory the packet could be for a cookie, but - * TIME_WAIT should guard us against this. - * XXX: Nevertheless check for cookies? - * This sequence number check is done again later, - * but we do it here to prevent syn flood attackers - * from creating big SYN_RECV sockets. - */ - if (!between(TCP_SKB_CB(skb)->ack_seq, req->snt_isn, req->snt_isn+1) || - !between(TCP_SKB_CB(skb)->seq, req->rcv_isn, - req->rcv_isn+1+req->rcv_wnd)) { - req->class->send_reset(skb); - return NULL; + tcp_set_state(sk, TCP_SYN_RECV); + if (tp->saw_tstamp) { + tp->ts_recent = tp->rcv_tsval; + tp->ts_recent_stamp = xtime.tv_sec; } - - sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL); - tcp_dec_slow_timer(TCP_SLT_SYNACK); - if (sk == NULL) - return NULL; - - req->expires = 0UL; - req->sk = sk; + + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; + + /* RFC1323: The window in SYN & SYN/ACK segments is + * never scaled. + */ + tp->snd_wnd = htons(th->window); + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; + + tcp_sync_mss(sk, tp->pmtu_cookie); + tcp_initialize_rcv_mss(sk); + + tcp_send_synack(sk); +#if 0 + /* Note, we could accept data and URG from this segment. + * There are no obstacles to make this. + * + * However, if we ignore data in ACKless segments sometimes, + * we have no reasons to accept it sometimes. + * Also, seems the code doing it in step6 of tcp_rcv_state_process + * is not flawless. So, discard packet for sanity. + * Uncomment this return to process the data. + */ + return -1; +#endif } - skb_orphan(skb); - skb_set_owner_r(skb, sk); - return sk; + /* "fifth, if neither of the SYN or RST bits is set then + * drop the segment and return." + */ + +discard: + kfree_skb(skb); + return 0; } + /* * This function implements the receiving procedure of RFC 793 for * all states except ESTABLISHED and TIME_WAIT. @@ -2042,6 +2843,8 @@ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int queued = 0; + tp->saw_tstamp = 0; + switch (sk->state) { case TCP_CLOSE: /* When state == CLOSED, hash lookup always fails. @@ -2061,35 +2864,26 @@ * a TCP_CLOSE socket does not exist. Drop the frame * and send a RST back to the other end. */ - return 1; - case TCP_LISTEN: - /* These use the socket TOS.. - * might want to be the received TOS + /* 1. The socket may be moved to TIME-WAIT state. + 2. While this socket was locked, another socket + with the same identity could be created. + 3. To continue? + + CONCLUSION: discard and only discard! + + Alternative would be relookup and recurse into tcp_v?_rcv + (not *_do_rcv) to work with timewait and listen states + correctly. */ - if(th->ack) { - struct sock *realsk; - int ret; + goto discard; - realsk = tp->af_specific->get_sock(skb, th); - if(realsk == sk) - return 1; + case TCP_LISTEN: + if(th->ack) + return 1; - bh_lock_sock(realsk); - ret = 0; - if(realsk->lock.users != 0) { - skb_orphan(skb); - sk_add_backlog(realsk, skb); - } else { - ret = tcp_rcv_state_process(realsk, skb, - skb->h.th, skb->len); - } - bh_unlock_sock(realsk); - return ret; - } - if(th->syn) { - if(tp->af_specific->conn_request(sk, skb, 0) < 0) + if(tp->af_specific->conn_request(sk, skb) < 0) return 1; /* Now we have several options: In theory there is @@ -2110,172 +2904,14 @@ */ goto discard; } - goto discard; - break; case TCP_SYN_SENT: - /* SYN sent means we have to look for a suitable ack and - * either reset for bad matches or go to connected. - * The SYN_SENT case is unusual and should - * not be in line code. [AC] - */ - if(th->ack) { - /* rfc793: - * "If the state is SYN-SENT then - * first check the ACK bit - * If the ACK bit is set - * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send - * a reset (unless the RST bit is set, if so drop - * the segment and return)" - * - * I cite this place to emphasize one essential - * detail, this check is different of one - * in established state: SND.UNA <= SEG.ACK <= SND.NXT. - * SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT, - * because we have no previous data sent before SYN. - * --ANK(990513) - * - * We do not send data with SYN, so that RFC-correct - * test reduces to: - */ - if (sk->zapped || - TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt) - return 1; - - /* Now ACK is acceptable. - * - * "If the RST bit is set - * If the ACK was acceptable then signal the user "error: - * connection reset", drop the segment, enter CLOSED state, - * delete TCB, and return." - */ - - if (th->rst) { - tcp_reset(sk); - goto discard; - } - - /* rfc793: - * "fifth, if neither of the SYN or RST bits is set then - * drop the segment and return." - * - * See note below! - * --ANK(990513) - */ - - if (!th->syn) - goto discard; - - /* rfc793: - * "If the SYN bit is on ... - * are acceptable then ... - * (our SYN has been ACKed), change the connection - * state to ESTABLISHED..." - * - * Do you see? SYN-less ACKs in SYN-SENT state are - * completely ignored. - * - * The bug causing stalled SYN-SENT sockets - * was here: tcp_ack advanced snd_una and canceled - * retransmit timer, so that bare ACK received - * in SYN-SENT state (even with invalid ack==ISS, - * because tcp_ack check is too weak for SYN-SENT) - * causes moving socket to invalid semi-SYN-SENT, - * semi-ESTABLISHED state and connection hangs. - * - * There exist buggy stacks, which really send - * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp) - * Actually, if this host did not try to get something - * from ftp.inr.ac.ru I'd never find this bug 8) - * - * --ANK (990514) - */ - - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tcp_ack(sk,th, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->ack_seq, len); - - /* Ok.. it's good. Set up sequence numbers and - * move to established. - */ - tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1; - tp->rcv_wup = TCP_SKB_CB(skb)->seq+1; - - /* RFC1323: The window in SYN & SYN/ACK segments is - * never scaled. - */ - tp->snd_wnd = htons(th->window); - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; - tp->fin_seq = TCP_SKB_CB(skb)->seq; - - tcp_set_state(sk, TCP_ESTABLISHED); - tcp_parse_options(sk, th, tp, 0); - - if (tp->wscale_ok == 0) { - tp->snd_wscale = tp->rcv_wscale = 0; - tp->window_clamp = min(tp->window_clamp,65535); - } - - if (tp->tstamp_ok) { - tp->tcp_header_len = - sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - } else - tp->tcp_header_len = sizeof(struct tcphdr); - if (tp->saw_tstamp) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = tcp_time_stamp; - } - - /* Can't be earlier, doff would be wrong. */ - tcp_send_ack(sk); - - sk->dport = th->source; - tp->copied_seq = tp->rcv_nxt; - - if(!sk->dead) { - sk->state_change(sk); - sock_wake_async(sk->socket, 0); - } - } else { - if(th->syn && !th->rst) { - /* The previous version of the code - * checked for "connecting to self" - * here. that check is done now in - * tcp_connect. - */ - tcp_set_state(sk, TCP_SYN_RECV); - tcp_parse_options(sk, th, tp, 0); - if (tp->saw_tstamp) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = tcp_time_stamp; - } - - tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; - - /* RFC1323: The window in SYN & SYN/ACK segments is - * never scaled. - */ - tp->snd_wnd = htons(th->window); - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - - tcp_send_synack(sk); - } else - break; - } - - /* tp->tcp_header_len and tp->mss_clamp - probably changed, synchronize mss. - */ - tcp_sync_mss(sk, tp->pmtu_cookie); - tp->rcv_mss = tp->mss_cache; - - if (sk->state == TCP_SYN_RECV) - goto discard; - - goto step6; + queued = tcp_rcv_synsent_state_process(sk, skb, th, len); + if (queued >= 0) + return queued; + queued = 0; + goto step6; } /* Parse the tcp_options present on this header. @@ -2283,23 +2919,13 @@ * Note that this really has to be here and not later for PAWS * (RFC1323) to work. */ - if (tcp_fast_parse_options(sk, th, tp)) { - /* NOTE: assumes saw_tstamp is never set if we didn't - * negotiate the option. tcp_fast_parse_options() must - * guarantee this. - */ - if (tp->saw_tstamp) { - if (tcp_paws_discard(tp, th, len)) { - tcp_statistics.TcpInErrs++; - if (!th->rst) { - tcp_send_ack(sk); - goto discard; - } - } - tcp_replace_ts_recent(sk, tp, - TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq); + if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp && + tcp_paws_discard(tp, skb)) { + if (!th->rst) { + tcp_send_ack(sk); + goto discard; } + /* Reset is accepted even if it did not pass PAWS. */ } /* The silly FIN test here is necessary to see an advancing ACK in @@ -2313,11 +2939,26 @@ * At this point the connection will deadlock with host1 believing * that his FIN is never ACK'd, and thus it will retransmit it's FIN * forever. The following fix is from Taral (taral@taral.net). + * + * RED-PEN. Seems, the above is not true. + * If at least one end is RFC compliant, it will send ACK to + * out of window FIN and, hence, move peer to TIME-WAIT. + * I comment out this line. --ANK + * + * RED-PEN. DANGER! tcp_sequence check rejects also SYN-ACKs + * received in SYN-RECV. The problem is that description of + * segment processing in SYN-RECV state in RFC792 is WRONG. + * Correct check would accept ACK from this SYN-ACK, see + * figures 6 and 8 (fixed by RFC1122). Compare this + * to problem with FIN, they smell similarly. --ANK */ /* step 1: check sequence number */ - if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq) && - !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)) { + if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq) +#if 0 + && !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt) +#endif + ) { if (!th->rst) { tcp_send_ack(sk); } @@ -2330,6 +2971,11 @@ goto discard; } + if (tp->saw_tstamp) { + tcp_replace_ts_recent(sk, tp, + TCP_SKB_CB(skb)->seq); + } + /* step 3: check security and precedence [ignored] */ /* step 4: @@ -2357,22 +3003,36 @@ if (th->ack) { int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len); - + switch(sk->state) { case TCP_SYN_RECV: if (acceptable) { tcp_set_state(sk, TCP_ESTABLISHED); - sk->dport = th->source; tp->copied_seq = tp->rcv_nxt; - if(!sk->dead) - sk->state_change(sk); + /* Note, that this wakeup is only for marginal + crossed SYN case. Passively open sockets + are not waked up, because sk->sleep == NULL + and sk->socket == NULL. + */ + if (!sk->dead && sk->sleep) { + wake_up_interruptible(sk->sleep); + sock_wake_async(sk->socket, 1); + } tp->snd_una = TCP_SKB_CB(skb)->ack_seq; tp->snd_wnd = htons(th->window) << tp->snd_wscale; tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; + /* tcp_ack considers this ACK as duplicate + * and does not calculate rtt. It is wrong. + * Fix it at least with timestamps. + */ + if (tp->saw_tstamp && !tp->srtt) + tcp_ack_saw_tstamp(sk, tp, 0, 0, FLAG_SYN_ACKED); + + tcp_init_metrics(sk); } else { SOCK_DEBUG(sk, "bad ack\n"); return 1; @@ -2386,7 +3046,8 @@ if (!sk->dead) sk->state_change(sk); else - tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); + tcp_reset_keepalive_timer(sk, sysctl_tcp_fin_timeout); + dst_confirm(sk->dst_cache); } break; @@ -2399,10 +3060,9 @@ case TCP_LAST_ACK: if (tp->snd_una == tp->write_seq) { - sk->shutdown = SHUTDOWN_MASK; tcp_set_state(sk,TCP_CLOSE); - if (!sk->dead) - sk->state_change(sk); + tcp_update_metrics(sk); + tcp_done(sk); goto discard; } break; @@ -2444,8 +3104,11 @@ break; } - tcp_data_snd_check(sk); - tcp_ack_snd_check(sk); + /* tcp_data could move socket to TIME-WAIT */ + if (sk->state != TCP_CLOSE) { + tcp_data_snd_check(sk); + tcp_ack_snd_check(sk); + } if (!queued) { discard: diff -u --recursive --new-file v2.3.14/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.3.14/linux/net/ipv4/tcp_ipv4.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv4/tcp_ipv4.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.182 1999/07/05 01:34:07 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.186 1999/08/21 21:46:29 davem Exp $ * * IPv4 specific functions * @@ -57,6 +57,7 @@ #include #include #include +#include #include @@ -67,6 +68,7 @@ extern int sysctl_tcp_window_scaling; extern int sysctl_tcp_sack; extern int sysctl_tcp_syncookies; +extern int sysctl_tcp_tw_recycle; extern int sysctl_ip_dynaddr; extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; @@ -90,23 +92,30 @@ * First half of the table is for sockets not in TIME_WAIT, second half * is for TIME_WAIT sockets only. */ -struct sock **tcp_ehash; -int tcp_ehash_size; +struct tcp_ehash_bucket *tcp_ehash = NULL; /* Ok, let's try this, I give up, we do need a local binding * TCP hash as well as the others for fast bind/connect. */ -struct tcp_bind_bucket **tcp_bhash; -int tcp_bhash_size; +struct tcp_bind_hashbucket *tcp_bhash = NULL; + +int tcp_bhash_size = 0; +int tcp_ehash_size = 0; /* All sockets in TCP_LISTEN state will be in here. This is the only table * where wildcard'd TCP sockets can exist. Hash function here is just local * port number. */ -struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE]; +struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE] = { NULL, }; +char __tcp_clean_cacheline_pad[(SMP_CACHE_BYTES - + (((sizeof(void *) * (TCP_LHTABLE_SIZE + 2)) + + (sizeof(int) * 2)) % SMP_CACHE_BYTES))] = { 0, }; + +rwlock_t tcp_lhash_lock = RW_LOCK_UNLOCKED; +atomic_t tcp_lhash_users = ATOMIC_INIT(0); +DECLARE_WAIT_QUEUE_HEAD(tcp_lhash_wait); -/* Register cache. */ -struct sock *tcp_regs[TCP_NUM_REGS]; +spinlock_t tcp_portalloc_lock = SPIN_LOCK_UNLOCKED; /* * This array holds the first and last local port number. @@ -119,7 +128,10 @@ static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport, __u32 faddr, __u16 fport) { - return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size >> 1) - 1); + int h = ((laddr ^ lport) ^ (faddr ^ fport)); + h ^= h>>16; + h ^= h>>8; + return h & (tcp_ehash_size - 1); } static __inline__ int tcp_sk_hashfn(struct sock *sk) @@ -133,67 +145,47 @@ } /* Allocate and initialize a new TCP local port bind bucket. - * The sockhash lock must be held as a writer here. + * The bindhash mutex for snum's hash chain must be held here. */ -struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum) +struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head, + unsigned short snum) { struct tcp_bind_bucket *tb; tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC); if(tb != NULL) { - struct tcp_bind_bucket **head = - &tcp_bhash[tcp_bhashfn(snum)]; tb->port = snum; tb->fastreuse = 0; tb->owners = NULL; - if((tb->next = *head) != NULL) + if((tb->next = head->chain) != NULL) tb->next->pprev = &tb->next; - *head = tb; - tb->pprev = head; + head->chain = tb; + tb->pprev = &head->chain; } return tb; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY -/* Ensure that the bound bucket for the port exists. - * Return 0 on success. - */ -static __inline__ int tcp_bucket_check(unsigned short snum) -{ - struct tcp_bind_bucket *tb; - int ret = 0; - - SOCKHASH_LOCK_WRITE(); - tb = tcp_bhash[tcp_bhashfn(snum)]; - for( ; (tb && (tb->port != snum)); tb = tb->next) - ; - ret = 0; - if (tb == NULL) { - if ((tb = tcp_bucket_create(snum)) == NULL) - ret = 1; - } - SOCKHASH_UNLOCK_WRITE(); - - return ret; -} -#endif - +/* Caller must disable local BH processing. */ static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child) { - struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev; + struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(child->num)]; + struct tcp_bind_bucket *tb; + spin_lock(&head->lock); + tb = (struct tcp_bind_bucket *)sk->prev; if ((child->bind_next = tb->owners) != NULL) tb->owners->bind_pprev = &child->bind_next; tb->owners = child; child->bind_pprev = &tb->owners; child->prev = (struct sock *) tb; + spin_unlock(&head->lock); } __inline__ void tcp_inherit_port(struct sock *sk, struct sock *child) { - SOCKHASH_LOCK_WRITE(); + local_bh_disable(); __tcp_inherit_port(sk, child); - SOCKHASH_UNLOCK_WRITE(); + local_bh_enable(); } /* Obtain a reference to a local port for the given sock, @@ -201,38 +193,48 @@ */ static int tcp_v4_get_port(struct sock *sk, unsigned short snum) { + struct tcp_bind_hashbucket *head; struct tcp_bind_bucket *tb; + int ret; - SOCKHASH_LOCK_WRITE(); + local_bh_disable(); if (snum == 0) { - int rover = tcp_port_rover; int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; + int rover; + spin_lock(&tcp_portalloc_lock); + rover = tcp_port_rover; do { rover++; if ((rover < low) || (rover > high)) rover = low; - tb = tcp_bhash[tcp_bhashfn(rover)]; - for ( ; tb; tb = tb->next) + head = &tcp_bhash[tcp_bhashfn(rover)]; + spin_lock(&head->lock); + for (tb = head->chain; tb; tb = tb->next) if (tb->port == rover) goto next; break; next: + spin_unlock(&head->lock); } while (--remaining > 0); tcp_port_rover = rover; + spin_unlock(&tcp_portalloc_lock); /* Exhausted local port range during search? */ + ret = 1; if (remaining <= 0) goto fail; - /* OK, here is the one we will use. */ + /* OK, here is the one we will use. HEAD is + * non-NULL and we hold it's mutex. + */ snum = rover; tb = NULL; } else { - for (tb = tcp_bhash[tcp_bhashfn(snum)]; - tb != NULL; - tb = tb->next) + head = &tcp_bhash[tcp_bhashfn(snum)]; + spin_lock(&head->lock); + for (tb = head->chain; tb != NULL; tb = tb->next) if (tb->port == snum) break; } @@ -256,13 +258,15 @@ } } /* If we found a conflict, fail. */ + ret = 1; if (sk2 != NULL) - goto fail; + goto fail_unlock; } } + ret = 1; if (tb == NULL && - (tb = tcp_bucket_create(snum)) == NULL) - goto fail; + (tb = tcp_bucket_create(head, snum)) == NULL) + goto fail_unlock; if (tb->owners == NULL) { if (sk->reuse && sk->state != TCP_LISTEN) tb->fastreuse = 1; @@ -278,13 +282,13 @@ tb->owners = sk; sk->bind_pprev = &tb->owners; sk->prev = (struct sock *) tb; + ret = 0; - SOCKHASH_UNLOCK_WRITE(); - return 0; - +fail_unlock: + spin_unlock(&head->lock); fail: - SOCKHASH_UNLOCK_WRITE(); - return 1; + local_bh_enable(); + return ret; } /* Get rid of any references to a local port held by the @@ -292,8 +296,10 @@ */ __inline__ void __tcp_put_port(struct sock *sk) { + struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(sk->num)]; struct tcp_bind_bucket *tb; + spin_lock(&head->lock); tb = (struct tcp_bind_bucket *) sk->prev; if (sk->bind_next) sk->bind_next->bind_pprev = sk->bind_pprev; @@ -305,24 +311,136 @@ *(tb->pprev) = tb->next; kmem_cache_free(tcp_bucket_cachep, tb); } + spin_unlock(&head->lock); } void tcp_put_port(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + local_bh_disable(); __tcp_put_port(sk); - SOCKHASH_UNLOCK_WRITE(); + local_bh_enable(); +} + +#ifdef CONFIG_TCP_TW_RECYCLE +/* + Very stupid pseudo-"algoritm". If the approach will be successful + (and it will!), we have to make it more reasonable. + Now it eats lots of CPU, when we are tough on ports. + + Apparently, it should be hash table indexed by daddr/dport. + + How does it work? We allow to truncate time-wait state, if: + 1. PAWS works on it. + 2. timewait bucket did not receive data for timeout: + - initially timeout := 2*RTO, so that if our ACK to first + transmitted peer's FIN is lost, we will see first retransmit. + - if we receive anything, the timout is increased exponentially + to follow normal TCP backoff pattern. + It is important that minimal RTO (HZ/5) > minimal timestamp + step (1ms). + 3. When creating new socket, we inherit sequence number + and ts_recent of time-wait bucket, increasinf them a bit. + + These two conditions guarantee, that data will not be corrupted + both by retransmitted and by delayed segments. They do not guarantee + that peer will leave LAST-ACK/CLOSING state gracefully, it will be + reset sometimes, namely, when more than two our ACKs to its FINs are lost. + This reset is harmless and even good. + */ + +int tcp_v4_tw_recycle(struct sock *sk, u32 daddr, u16 dport) +{ + static int tw_rover; + + struct tcp_tw_bucket *tw; + struct tcp_bind_hashbucket *head; + struct tcp_bind_bucket *tb; + + int low = sysctl_local_port_range[0]; + int high = sysctl_local_port_range[1]; + unsigned long now = jiffies; + int i, rover; + + rover = tw_rover; + + local_bh_disable(); + for (i=0; ilock); + for (tb = head->chain; tb; tb = tb->next) { + tw = (struct tcp_tw_bucket*)tb->owners; + + if (tw->state != TCP_TIME_WAIT || + tw->dport != dport || + tw->daddr != daddr || + tw->rcv_saddr != sk->rcv_saddr || + tb->port < low || + tb->port >= high || + !TCP_INET_FAMILY(tw->family) || + tw->ts_recent_stamp == 0 || + (long)(now - tw->ttd) <= 0) + continue; + tw_rover = rover; + goto hit; + } + spin_unlock(&head->lock); + } + local_bh_enable(); + tw_rover = rover; + return -EAGAIN; + +hit: + sk->num = tw->num; + if ((sk->bind_next = tb->owners) != NULL) + tb->owners->bind_pprev = &sk->bind_next; + tb->owners = sk; + sk->bind_pprev = &tb->owners; + sk->prev = (struct sock *) tb; + spin_unlock_bh(&head->lock); + return 0; +} +#endif + + +void tcp_listen_wlock(void) +{ + write_lock(&tcp_lhash_lock); + + if (atomic_read(&tcp_lhash_users)) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&tcp_lhash_wait, &wait); + do { + current->state = TASK_UNINTERRUPTIBLE; + if (atomic_read(&tcp_lhash_users) == 0) + break; + write_unlock_bh(&tcp_lhash_lock); + schedule(); + write_lock_bh(&tcp_lhash_lock); + } while (atomic_read(&tcp_lhash_users)); + + current->state = TASK_RUNNING; + remove_wait_queue(&tcp_lhash_wait, &wait); + } } static __inline__ void __tcp_v4_hash(struct sock *sk) { struct sock **skp; + rwlock_t *lock; - if(sk->state == TCP_LISTEN) + BUG_TRAP(sk->pprev==NULL); + if(sk->state == TCP_LISTEN) { skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; - else - skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))]; - + lock = &tcp_lhash_lock; + tcp_listen_wlock(); + } else { + skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))].chain; + lock = &tcp_ehash[sk->hashent].lock; + write_lock(lock); + } if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -330,30 +448,40 @@ sk->prot->inuse++; if(sk->prot->highestinuse < sk->prot->inuse) sk->prot->highestinuse = sk->prot->inuse; + write_unlock(lock); } static void tcp_v4_hash(struct sock *sk) { if (sk->state != TCP_CLOSE) { - SOCKHASH_LOCK_WRITE(); + local_bh_disable(); __tcp_v4_hash(sk); - SOCKHASH_UNLOCK_WRITE(); + local_bh_enable(); } } -static void tcp_v4_unhash(struct sock *sk) +void tcp_unhash(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + rwlock_t *lock; + + if (sk->state == TCP_LISTEN) { + local_bh_disable(); + tcp_listen_wlock(); + lock = &tcp_lhash_lock; + } else { + struct tcp_ehash_bucket *head = &tcp_ehash[sk->hashent]; + lock = &head->lock; + write_lock_bh(&head->lock); + } + if(sk->pprev) { if(sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->prot->inuse--; - tcp_reg_zap(sk); - __tcp_put_port(sk); } - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(lock); } /* Don't inline this cruft. Here are some nice properties to @@ -362,14 +490,13 @@ * connection. So always assume those are both wildcarded * during the search since they can never be otherwise. */ -struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif) +static struct sock *__tcp_v4_lookup_listener(struct sock *sk, u32 daddr, unsigned short hnum, int dif) { - struct sock *sk; struct sock *result = NULL; int score, hiscore; hiscore=0; - for(sk = tcp_listening_hash[tcp_lhashfn(hnum)]; sk; sk = sk->next) { + for(; sk; sk = sk->next) { if(sk->num == hnum) { __u32 rcv_saddr = sk->rcv_saddr; @@ -395,41 +522,62 @@ return result; } +/* Optimize the common listener case. */ +__inline__ struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif) +{ + struct sock *sk; + + read_lock(&tcp_lhash_lock); + sk = tcp_listening_hash[tcp_lhashfn(hnum)]; + if (sk) { + if (sk->num == hnum && sk->next == NULL) + goto sherry_cache; + sk = __tcp_v4_lookup_listener(sk, daddr, hnum, dif); + } + if (sk) { +sherry_cache: + sock_hold(sk); + } + read_unlock(&tcp_lhash_lock); + return sk; +} + /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM * - * The sockhash lock must be held as a reader here. + * Local BH must be disabled here. */ static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 hnum, int dif) { + struct tcp_ehash_bucket *head; TCP_V4_ADDR_COOKIE(acookie, saddr, daddr) __u32 ports = TCP_COMBINED_PORTS(sport, hnum); struct sock *sk; int hash; - /* Check TCP register quick cache first. */ - sk = TCP_RHASH(sport); - if(sk && TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) - goto hit; - /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ hash = tcp_hashfn(daddr, hnum, saddr, sport); - for(sk = tcp_ehash[hash]; sk; sk = sk->next) { - if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) { - if (sk->state == TCP_ESTABLISHED) - TCP_RHASH(sport) = sk; + head = &tcp_ehash[hash]; + read_lock(&head->lock); + for(sk = head->chain; sk; sk = sk->next) { + if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) goto hit; /* You sunk my battleship! */ - } } + /* Must check for a TIME_WAIT'er before going to listener hash. */ - for(sk = tcp_ehash[hash+(tcp_ehash_size >> 1)]; sk; sk = sk->next) + for(sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) goto hit; - sk = tcp_v4_lookup_listener(daddr, hnum, dif); + read_unlock(&head->lock); + + return tcp_v4_lookup_listener(daddr, hnum, dif); + hit: + sock_hold(sk); + read_unlock(&head->lock); return sk; } @@ -437,138 +585,137 @@ { struct sock *sk; - SOCKHASH_LOCK_READ(); + local_bh_disable(); sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif); - SOCKHASH_UNLOCK_READ(); + local_bh_enable(); return sk; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY -/* Cleaned up a little and adapted to new bind bucket scheme. - * Oddly, this should increase performance here for - * transparent proxy, as tests within the inner loop have - * been eliminated. -DaveM - */ -static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr, - unsigned short rnum, unsigned long laddr, - struct net_device *dev, unsigned short pnum, - int dif) -{ - struct sock *s, *result = NULL; - int badness = -1; - u32 paddr = 0; - unsigned short hnum = ntohs(num); - unsigned short hpnum = ntohs(pnum); - int firstpass = 1; - - if(dev && dev->ip_ptr) { - struct in_device *idev = dev->ip_ptr; +static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) +{ + return secure_tcp_sequence_number(sk->saddr, sk->daddr, + skb->h.th->dest, + skb->h.th->source); +} - if(idev->ifa_list) - paddr = idev->ifa_list->ifa_local; - } +static int tcp_v4_check_established(struct sock *sk) +{ + u32 daddr = sk->rcv_saddr; + u32 saddr = sk->daddr; + int dif = sk->bound_dev_if; + TCP_V4_ADDR_COOKIE(acookie, saddr, daddr) + __u32 ports = TCP_COMBINED_PORTS(sk->dport, sk->num); + int hash = tcp_hashfn(daddr, sk->num, saddr, sk->dport); + struct tcp_ehash_bucket *head = &tcp_ehash[hash]; + struct sock *sk2, **skp; +#ifdef CONFIG_TCP_TW_RECYCLE + struct tcp_tw_bucket *tw; +#endif - /* We must obtain the sockhash lock here, we are always - * in BH context. - */ - SOCKHASH_LOCK_READ_BH(); - { - struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)]; - for( ; (tb && tb->port != hnum); tb = tb->next) - ; - if(tb == NULL) - goto next; - s = tb->owners; - } -pass2: - for(; s; s = s->bind_next) { - int score = 0; - if(s->rcv_saddr) { - if((s->num != hpnum || s->rcv_saddr != paddr) && - (s->num != hnum || s->rcv_saddr != laddr)) - continue; - score++; - } - if(s->daddr) { - if(s->daddr != raddr) - continue; - score++; - } - if(s->dport) { - if(s->dport != rnum) - continue; - score++; - } - if(s->bound_dev_if) { - if(s->bound_dev_if != dif) - continue; - score++; - } - if(score == 4 && s->num == hnum) { - result = s; - goto gotit; - } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { - result = s; - badness = score; + write_lock_bh(&head->lock); + + /* Check TIME-WAIT sockets first. */ + for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp) != NULL; + skp = &sk2->next) { +#ifdef CONFIG_TCP_TW_RECYCLE + tw = (struct tcp_tw_bucket*)sk2; +#endif + + if(TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { +#ifdef CONFIG_TCP_TW_RECYCLE + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + /* With PAWS, it is safe from the viewpoint + of data integrity. Even without PAWS it + is safe provided sequence spaces do not + overlap i.e. at data rates <= 80Mbit/sec. + + Actually, the idea is close to VJ's (rfc1332) + one, only timestamp cache is held not per host, + but per port pair and TW bucket is used + as state holder. + */ + if (sysctl_tcp_tw_recycle && tw->ts_recent_stamp) { + if ((tp->write_seq = tw->snd_nxt + 2) == 0) + tp->write_seq = 1; + tp->ts_recent = tw->ts_recent; + tp->ts_recent_stamp = tw->ts_recent_stamp; + sock_hold(sk2); + skp = &head->chain; + goto unique; + } else +#endif + goto not_unique; } } -next: - if(firstpass--) { - struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)]; - for( ; (tb && tb->port != hpnum); tb = tb->next) - ; - if(tb) { - s = tb->owners; - goto pass2; - } +#ifdef CONFIG_TCP_TW_RECYCLE + tw = NULL; +#endif + + /* And established part... */ + for(skp = &head->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { + if(TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) + goto not_unique; } -gotit: - SOCKHASH_UNLOCK_READ_BH(); - return result; -} -#endif /* CONFIG_IP_TRANSPARENT_PROXY */ -static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) -{ - return secure_tcp_sequence_number(sk->saddr, sk->daddr, - skb->h.th->dest, - skb->h.th->source); +#ifdef CONFIG_TCP_TW_RECYCLE +unique: +#endif + BUG_TRAP(sk->pprev==NULL); + if ((sk->next = *skp) != NULL) + (*skp)->pprev = &sk->next; + + *skp = sk; + sk->pprev = skp; + sk->prot->inuse++; + if(sk->prot->highestinuse < sk->prot->inuse) + sk->prot->highestinuse = sk->prot->inuse; + write_unlock_bh(&head->lock); + +#ifdef CONFIG_TCP_TW_RECYCLE + if (tw) { + /* Silly. Should hash-dance instead... */ + local_bh_disable(); + tcp_tw_deschedule(tw); + tcp_timewait_kill(tw); + local_bh_enable(); + + tcp_tw_put(tw); + } +#endif + return 0; + +not_unique: + write_unlock_bh(&head->lock); + return -EADDRNOTAVAIL; } -/* Check that a TCP address is unique, don't allow multiple - * connects to/from the same address. Actually we can optimize - * quite a bit, since the socket about to connect is still - * in TCP_CLOSE, a tcp_bind_bucket for the local port he will - * use will exist, with a NULL owners list. So check for that. - * The good_socknum and verify_bind scheme we use makes this - * work. +/* Hash SYN-SENT socket to established hash table after + * checking that it is unique. Note, that without kernel lock + * we MUST make these two operations atomically. + * + * Optimization: if it is bound and tcp_bind_bucket has the only + * owner (us), we need not to scan established bucket. */ -static int tcp_v4_unique_address(struct sock *sk) + +int tcp_v4_hash_connecting(struct sock *sk) { - struct tcp_bind_bucket *tb; unsigned short snum = sk->num; - int retval = 1; + struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)]; + struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev; - /* Freeze the hash while we snoop around. */ - SOCKHASH_LOCK_READ(); - tb = tcp_bhash[tcp_bhashfn(snum)]; - for(; tb; tb = tb->next) { - if(tb->port == snum && tb->owners != NULL) { - /* Almost certainly the re-use port case, search the real hashes - * so it actually scales. - */ - sk = __tcp_v4_lookup(sk->daddr, sk->dport, - sk->rcv_saddr, snum, sk->bound_dev_if); - SOCKHASH_UNLOCK_READ(); - - if((sk != NULL) && (sk->state != TCP_LISTEN)) - retval = 0; - return retval; - } + spin_lock_bh(&head->lock); + if (tb->owners == sk && sk->bind_next == NULL) { + __tcp_v4_hash(sk); + spin_unlock_bh(&head->lock); + return 0; + } else { + spin_unlock_bh(&head->lock); + + /* No definite answer... Walk to established hash table */ + return tcp_v4_check_established(sk); } - SOCKHASH_UNLOCK_READ(); - return retval; } /* This will initiate an outgoing connection. */ @@ -580,34 +727,26 @@ struct rtable *rt; u32 daddr, nexthop; int tmp; + int err; if (sk->state != TCP_CLOSE) return(-EISCONN); - /* Don't allow a double connect. */ - if (sk->daddr) - return -EINVAL; - if (addr_len < sizeof(struct sockaddr_in)) return(-EINVAL); - if (usin->sin_family != AF_INET) { - static int complained; - if (usin->sin_family) - return(-EAFNOSUPPORT); - if (!complained++) - printk(KERN_DEBUG "%s forgot to set AF_INET in " __FUNCTION__ "\n", current->comm); - } + if (usin->sin_family != AF_INET) + return(-EAFNOSUPPORT); nexthop = daddr = usin->sin_addr.s_addr; - if (sk->opt && sk->opt->srr) { + if (sk->protinfo.af_inet.opt && sk->protinfo.af_inet.opt->srr) { if (daddr == 0) return -EINVAL; - nexthop = sk->opt->faddr; + nexthop = sk->protinfo.af_inet.opt->faddr; } tmp = ip_route_connect(&rt, nexthop, sk->saddr, - RT_TOS(sk->ip_tos)|RTO_CONN|sk->localroute, sk->bound_dev_if); + RT_TOS(sk->protinfo.af_inet.tos)|RTO_CONN|sk->localroute, sk->bound_dev_if); if (tmp < 0) return tmp; @@ -616,63 +755,73 @@ return -ENETUNREACH; } - dst_release(xchg(&sk->dst_cache, rt)); + __sk_dst_set(sk, &rt->u.dst); + + if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr) + daddr = rt->rt_dst; + err = -ENOBUFS; buff = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header), 0, GFP_KERNEL); if (buff == NULL) - return -ENOBUFS; + goto failure; - /* Socket has no identity, so lock_sock() is useless. Also - * since state==TCP_CLOSE (checked above) the socket cannot - * possibly be in the hashes. TCP hash locking is only - * needed while checking quickly for a unique address. - * However, the socket does need to be (and is) locked - * in tcp_connect(). - * Perhaps this addresses all of ANK's concerns. 8-) -DaveM - */ - sk->dport = usin->sin_port; - sk->daddr = rt->rt_dst; - if (sk->opt && sk->opt->srr) - sk->daddr = daddr; if (!sk->saddr) sk->saddr = rt->rt_src; sk->rcv_saddr = sk->saddr; - if (!tcp_v4_unique_address(sk)) { - kfree_skb(buff); - sk->daddr = 0; - return -EADDRNOTAVAIL; + if (!sk->num) { + if (sk->prot->get_port(sk, 0) +#ifdef CONFIG_TCP_TW_RECYCLE + && (!sysctl_tcp_tw_recycle || + tcp_v4_tw_recycle(sk, daddr, usin->sin_port)) +#endif + ) { + kfree_skb(buff); + err = -EAGAIN; + goto failure; + } + sk->sport = htons(sk->num); + } +#ifdef CONFIG_TCP_TW_RECYCLE + else if (tp->ts_recent_stamp && sk->daddr != daddr) { + /* Reset inherited state */ + tp->ts_recent = 0; + tp->ts_recent_stamp = 0; + tp->write_seq = 0; } +#endif - tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr, - sk->sport, usin->sin_port); + sk->dport = usin->sin_port; + sk->daddr = daddr; + + if (!tp->write_seq) + tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr, + sk->sport, usin->sin_port); tp->ext_header_len = 0; - if (sk->opt) - tp->ext_header_len = sk->opt->optlen; + if (sk->protinfo.af_inet.opt) + tp->ext_header_len = sk->protinfo.af_inet.opt->optlen; - /* Reset mss clamp */ - tp->mss_clamp = ~0; + tp->mss_clamp = 536; - if (!ip_dont_fragment(sk, &rt->u.dst) && - rt->u.dst.pmtu > 576 && rt->rt_dst != rt->rt_gateway) { - /* Clamp mss at maximum of 536 and user_mss. - Probably, user ordered to override tiny segment size - in gatewayed case. - */ - tp->mss_clamp = max(tp->user_mss, 536); - } + err = tcp_connect(sk, buff); + if (err == 0) + return 0; - tcp_connect(sk, buff, rt->u.dst.pmtu); - return 0; +failure: + __sk_dst_reset(sk); + sk->dport = 0; + return err; } static int tcp_v4_sendmsg(struct sock *sk, struct msghdr *msg, int len) { int retval = -EINVAL; + lock_sock(sk); + /* Do sanity checking for sendmsg/sendto/send. */ if (msg->msg_flags & ~(MSG_OOB|MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL)) goto out; @@ -695,6 +844,7 @@ retval = tcp_do_sendmsg(sk, msg); out: + release_sock(sk); return retval; } @@ -719,12 +869,27 @@ for (req = prev->dl_next; req; req = req->dl_next) { if (req->af.v4_req.rmt_addr == iph->saddr && req->af.v4_req.loc_addr == iph->daddr && - req->rmt_port == rport -#ifdef CONFIG_IP_TRANSPARENT_PROXY - && req->lcl_port == th->dest -#endif - ) { - *prevp = prev; + req->rmt_port == rport && + TCP_INET_FAMILY(req->class->family)) { + if (req->sk) { + /* Weird case: connection was established + and then killed by RST before user accepted + it. This connection is dead, but we cannot + kill openreq to avoid blocking in accept(). + + accept() will collect this garbage, + but such reqs must be ignored, when talking + to network. + */ + bh_lock_sock(req->sk); + BUG_TRAP(req->sk->lock.users==0); + if (req->sk->state == TCP_CLOSE) { + bh_unlock_sock(req->sk); + prev = req; + continue; + } + } + *prevp = prev; return req; } prev = req; @@ -738,6 +903,7 @@ */ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, unsigned mtu) { + struct dst_entry *dst; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; /* We are not interested in TCP_LISTEN and open_requests (SYN-ACKs @@ -747,23 +913,26 @@ if (sk->state == TCP_LISTEN) return; - bh_lock_sock(sk); - if(sk->lock.users != 0) - goto out; - /* We don't check in the destentry if pmtu discovery is forbidden * on this route. We just assume that no packet_to_big packets * are send back when pmtu discovery is not active. * There is a small race when the user changes this flag in the * route, but I think that's acceptable. */ - if (sk->dst_cache == NULL) - goto out; + if ((dst = __sk_dst_check(sk, 0)) == NULL) + return; + + ip_rt_update_pmtu(dst, mtu); + + /* Something is about to be wrong... Remember soft error + * for the case, if this connection will not able to recover. + */ + if (mtu < dst->pmtu && ip_dont_fragment(sk, dst)) + sk->err_soft = EMSGSIZE; - ip_rt_update_pmtu(sk->dst_cache, mtu); - if (sk->ip_pmtudisc != IP_PMTUDISC_DONT && - tp->pmtu_cookie > sk->dst_cache->pmtu) { - tcp_sync_mss(sk, sk->dst_cache->pmtu); + if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT && + tp->pmtu_cookie > dst->pmtu) { + tcp_sync_mss(sk, dst->pmtu); /* Resend the TCP packet because it's * clear that the old packet has been @@ -772,8 +941,6 @@ */ tcp_simple_retransmit(sk); } /* else let the usual retransmit timer handle it */ -out: - bh_unlock_sock(sk); } /* @@ -790,7 +957,6 @@ * A more general error queue to queue errors for later handling * is probably better. * - * sk->err and sk->err_soft should be atomic_t. */ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) @@ -821,37 +987,51 @@ th = (struct tcphdr*)(dp+(iph->ihl<<2)); sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex); - if (sk == NULL || sk->state == TCP_TIME_WAIT) { + if (sk == NULL) { icmp_statistics.IcmpInErrors++; - return; + return; + } + if (sk->state == TCP_TIME_WAIT) { + tcp_tw_put((struct tcp_tw_bucket*)sk); + return; } + bh_lock_sock(sk); + /* If too many ICMPs get dropped on busy + * servers this needs to be solved differently. + */ + if (sk->lock.users != 0) + net_statistics.LockDroppedIcmps++; + tp = &sk->tp_pinfo.af_tcp; seq = ntohl(th->seq); if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { net_statistics.OutOfWindowIcmps++; - return; + goto out; } switch (type) { case ICMP_SOURCE_QUENCH: #ifndef OLD_SOURCE_QUENCH /* This is deprecated */ - tp->snd_ssthresh = tcp_recalc_ssthresh(tp); - tp->snd_cwnd = tp->snd_ssthresh; - tp->snd_cwnd_cnt = 0; - tp->high_seq = tp->snd_nxt; + if (sk->lock.users == 0) { + tp->snd_ssthresh = tcp_recalc_ssthresh(tp); + tp->snd_cwnd = tp->snd_ssthresh; + tp->snd_cwnd_cnt = 0; + tp->high_seq = tp->snd_nxt; + } #endif - return; + goto out; case ICMP_PARAMETERPROB: err = EPROTO; break; case ICMP_DEST_UNREACH: if (code > NR_ICMP_UNREACH) - return; + goto out; if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ - do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu)); - return; + if (sk->lock.users == 0) + do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu)); + goto out; } err = icmp_err_convert[code].errno; @@ -860,12 +1040,15 @@ err = EHOSTUNREACH; break; default: - return; + goto out; } switch (sk->state) { struct open_request *req, *prev; case TCP_LISTEN: + if (sk->lock.users != 0) + goto out; + /* The final ACK of the handshake should be already * handled in the new socket context, not here. * Strictly speaking - an ICMP error for the final @@ -873,28 +1056,15 @@ * complicated right now. */ if (!no_flags && !th->syn && !th->ack) - return; - - /* Prevent race conditions with accept() - - * ICMP is unreliable. - */ - bh_lock_sock(sk); - if (sk->lock.users != 0) { - net_statistics.LockDroppedIcmps++; - /* If too many ICMPs get dropped on busy - * servers this needs to be solved differently. - */ - goto out_unlock; - } + goto out; req = tcp_v4_search_req(tp, iph, th, &prev); if (!req) - goto out_unlock; - if (seq != req->snt_isn) { - net_statistics.OutOfWindowIcmps++; - goto out_unlock; - } - if (req->sk) { + goto out; + + if (req->sk) { + struct sock *nsk = req->sk; + /* * Already in ESTABLISHED and a big socket is created, * set error code there. @@ -902,9 +1072,23 @@ * but only with the next operation on the socket after * accept. */ + sock_hold(nsk); bh_unlock_sock(sk); - sk = req->sk; + sock_put(sk); + sk = nsk; + + BUG_TRAP(sk->lock.users == 0); + tp = &sk->tp_pinfo.af_tcp; + if (!between(seq, tp->snd_una, tp->snd_nxt)) { + net_statistics.OutOfWindowIcmps++; + goto out; + } } else { + if (seq != req->snt_isn) { + net_statistics.OutOfWindowIcmps++; + goto out; + } + /* * Still in SYN_RECV, just remove it silently. * There is no good way to pass the error to the newly @@ -913,23 +1097,30 @@ */ tp->syn_backlog--; tcp_synq_unlink(tp, req, prev); + tcp_dec_slow_timer(TCP_SLT_SYNACK); req->class->destructor(req); tcp_openreq_free(req); - out_unlock: - bh_unlock_sock(sk); - return; + goto out; } break; case TCP_SYN_SENT: - case TCP_SYN_RECV: /* Cannot happen */ + case TCP_SYN_RECV: /* Cannot happen. + It can f.e. if SYNs crossed. + */ if (!no_flags && !th->syn) - return; - tcp_statistics.TcpAttemptFails++; - sk->err = err; - sk->zapped = 1; - mb(); - sk->error_report(sk); - return; + goto out; + if (sk->lock.users == 0) { + tcp_statistics.TcpAttemptFails++; + sk->err = err; + /* Wake people up to see the error (see connect in sock.c) */ + sk->error_report(sk); + + tcp_set_state(sk, TCP_CLOSE); + tcp_done(sk); + } else { + sk->err_soft = err; + } + goto out; } /* If we've already connected we will keep trying @@ -948,18 +1139,16 @@ * --ANK (980905) */ - if (sk->ip_recverr) { - /* This code isn't serialized with the socket code */ - /* ANK (980927) ... which is harmless now, - sk->err's may be safely lost. - */ + if (sk->lock.users == 0 && sk->protinfo.af_inet.recverr) { sk->err = err; - mb(); - sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + sk->error_report(sk); } else { /* Only an error on timeout */ sk->err_soft = err; - mb(); } + +out: + bh_unlock_sock(sk); + sock_put(sk); } /* This routine computes an IPv4 TCP checksum. */ @@ -994,14 +1183,8 @@ if (th->rst) return; - if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL) { -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (((struct rtable*)skb->dst)->rt_type == RTN_UNICAST) - icmp_send(skb, ICMP_DEST_UNREACH, - ICMP_PORT_UNREACH, 0); -#endif + if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL) return; - } /* Swap the send and the receive. */ memset(&rth, 0, sizeof(struct tcphdr)); @@ -1014,7 +1197,8 @@ rth.seq = th->ack_seq; } else { rth.ack = 1; - rth.ack_seq = th->syn ? htonl(ntohl(th->seq)+1) : th->seq; + rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + + skb->len - (th->doff<<2)); } memset(&arg, 0, sizeof arg); @@ -1034,71 +1218,69 @@ tcp_statistics.TcpOutRsts++; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY +/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states + outside socket context is ugly, certainly. What can I do? + */ -/* - Seems, I never wrote nothing more stupid. - I hope Gods will forgive me, but I cannot forgive myself 8) - --ANK (981001) - */ - -static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4); - struct sock *sk = NULL; - int i; - - SOCKHASH_LOCK_READ(); - for (i=0; inext) { - struct open_request *dummy; - if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, iph, - th, &dummy) && - (!sk->bound_dev_if || - sk->bound_dev_if == skb->dev->ifindex)) - goto out; - } +static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +{ + struct tcphdr *th = skb->h.th; + struct { + struct tcphdr th; + u32 tsopt[3]; + } rep; + struct ip_reply_arg arg; + + memset(&rep.th, 0, sizeof(struct tcphdr)); + memset(&arg, 0, sizeof arg); + + arg.iov[0].iov_base = (unsigned char *)&rep; + arg.iov[0].iov_len = sizeof(rep.th); + arg.n_iov = 1; + if (ts) { + rep.tsopt[0] = __constant_htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + rep.tsopt[1] = htonl(tcp_time_stamp); + rep.tsopt[2] = htonl(ts); + arg.iov[0].iov_len = sizeof(rep); } -out: - SOCKHASH_UNLOCK_READ(); - return sk; -} -/* - * Check whether a received TCP packet might be for one of our - * connections. - */ + /* Swap the send and the receive. */ + rep.th.dest = th->source; + rep.th.source = th->dest; + rep.th.doff = arg.iov[0].iov_len/4; + rep.th.seq = htonl(seq); + rep.th.ack_seq = htonl(ack); + rep.th.ack = 1; + rep.th.window = htons(win); -int tcp_chkaddr(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4); - struct sock *sk; + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, + skb->nh.iph->saddr, /*XXX*/ + arg.iov[0].iov_len, + IPPROTO_TCP, + 0); + arg.csumoffset = offsetof(struct tcphdr, check) / 2; - sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, - th->dest, skb->dev->ifindex); + ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); - if (!sk) - return tcp_v4_search_proxy_openreq(skb) != NULL; + tcp_statistics.TcpOutSegs++; +} - if (sk->state == TCP_LISTEN) { - struct open_request *dummy; - if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, skb->nh.iph, - th, &dummy) && - (!sk->bound_dev_if || - sk->bound_dev_if == skb->dev->ifindex)) - return 1; - } +static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; - /* 0 means accept all LOCAL addresses here, not all the world... */ + tcp_v4_send_ack(skb, tw->snd_nxt, tw->rcv_nxt, 0, tw->ts_recent); - if (sk->rcv_saddr == 0) - return 0; + tcp_tw_put(tw); +} - return 1; +static void tcp_v4_or_send_ack(struct sk_buff *skb, struct open_request *req) +{ + tcp_v4_send_ack(skb, req->snt_isn+1, req->rcv_isn+1, req->rcv_wnd, req->ts_recent); } -#endif /* * Send a SYN-ACK after having received an ACK. @@ -1110,7 +1292,6 @@ struct rtable *rt; struct ip_options *opt; struct sk_buff * skb; - int mss; /* First, grab a route. */ opt = req->af.v4_req.opt; @@ -1118,7 +1299,7 @@ opt->faddr : req->af.v4_req.rmt_addr), req->af.v4_req.loc_addr, - RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute, + RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute, sk->bound_dev_if)) { ip_statistics.IpOutNoRoutes++; return; @@ -1129,16 +1310,11 @@ return; } - mss = rt->u.dst.pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr); + skb = tcp_make_synack(sk, &rt->u.dst, req); - skb = tcp_make_synack(sk, &rt->u.dst, req, mss); if (skb) { struct tcphdr *th = skb->h.th; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - th->source = req->lcl_port; /* LVE */ -#endif - th->check = tcp_v4_check(th, skb->len, req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr, csum_partial((char *)th, skb->len, skb->csum)); @@ -1202,7 +1378,9 @@ int sysctl_max_syn_backlog = 128; struct or_calltable or_ipv4 = { + PF_INET, tcp_v4_send_synack, + tcp_v4_or_send_ack, tcp_v4_or_free, tcp_v4_send_reset }; @@ -1210,23 +1388,20 @@ #define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */ #define BACKLOGMAX(sk) sysctl_max_syn_backlog -int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn) +int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { struct tcp_opt tp; struct open_request *req; struct tcphdr *th = skb->h.th; __u32 saddr = skb->nh.iph->saddr; __u32 daddr = skb->nh.iph->daddr; + __u32 isn = TCP_SKB_CB(skb)->when; #ifdef CONFIG_SYN_COOKIES int want_cookie = 0; #else #define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */ #endif - /* If the socket is dead, don't accept the connection. */ - if (sk->dead) - goto dead; - /* Never answer to SYNs send to broadcast or multicast */ if (((struct rtable *)skb->dst)->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) @@ -1235,7 +1410,7 @@ /* XXX: Check against a global syn pool counter. */ if (BACKLOG(sk) > BACKLOGMAX(sk)) { #ifdef CONFIG_SYN_COOKIES - if (sysctl_tcp_syncookies) { + if (sysctl_tcp_syncookies && !isn) { syn_flood_warning(skb); want_cookie = 1; } else @@ -1257,30 +1432,29 @@ req->rcv_isn = TCP_SKB_CB(skb)->seq; tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0; - tp.mss_clamp = 65535; + tp.mss_clamp = 536; + tp.user_mss = sk->tp_pinfo.af_tcp.user_mss; + tcp_parse_options(NULL, th, &tp, want_cookie); - if (tp.mss_clamp == 65535) - tp.mss_clamp = 576 - sizeof(struct iphdr) - sizeof(struct iphdr); - if (sk->tp_pinfo.af_tcp.user_mss && sk->tp_pinfo.af_tcp.user_mss < tp.mss_clamp) - tp.mss_clamp = sk->tp_pinfo.af_tcp.user_mss; req->mss = tp.mss_clamp; - - if (tp.saw_tstamp) - req->ts_recent = tp.rcv_tsval; + req->ts_recent = tp.saw_tstamp ? tp.rcv_tsval : 0; req->tstamp_ok = tp.tstamp_ok; req->sack_ok = tp.sack_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; req->rmt_port = th->source; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - req->lcl_port = th->dest ; /* LVE */ -#endif req->af.v4_req.loc_addr = daddr; req->af.v4_req.rmt_addr = saddr; /* Note that we ignore the isn passed from the TIME_WAIT * state here. That's the price we pay for cookies. + * + * RED-PEN. The price is high... Then we cannot kill TIME-WAIT + * and should reject connection attempt, duplicates with random + * sequence number can corrupt data. Right? + * I disabled sending cookie to request matching to a timewait + * bucket. */ if (want_cookie) isn = cookie_v4_init_sequence(sk, skb, &req->mss); @@ -1308,11 +1482,6 @@ return 0; -dead: - SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk); - tcp_statistics.TcpAttemptFails++; - return -ENOTCONN; /* send reset */ - dropbacklog: if (!want_cookie) BACKLOG(sk)--; @@ -1321,147 +1490,6 @@ return 0; } -/* This is not only more efficient than what we used to do, it eliminates - * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM - * - * This function wants to be moved to a common for IPv[46] file. --ANK - */ -struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb) -{ - struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0); - - if(newsk != NULL) { - struct tcp_opt *newtp; -#ifdef CONFIG_FILTER - struct sk_filter *filter; -#endif - - memcpy(newsk, sk, sizeof(*newsk)); - newsk->state = TCP_SYN_RECV; - - /* Clone the TCP header template */ - newsk->dport = req->rmt_port; - - sock_lock_init(newsk); - - atomic_set(&newsk->rmem_alloc, 0); - skb_queue_head_init(&newsk->receive_queue); - atomic_set(&newsk->wmem_alloc, 0); - skb_queue_head_init(&newsk->write_queue); - atomic_set(&newsk->omem_alloc, 0); - - newsk->done = 0; - newsk->proc = 0; - newsk->backlog.head = newsk->backlog.tail = NULL; - skb_queue_head_init(&newsk->error_queue); - newsk->write_space = tcp_write_space; -#ifdef CONFIG_FILTER - if ((filter = newsk->filter) != NULL) - sk_filter_charge(newsk, filter); -#endif - - /* Now setup tcp_opt */ - newtp = &(newsk->tp_pinfo.af_tcp); - newtp->pred_flags = 0; - newtp->rcv_nxt = req->rcv_isn + 1; - newtp->snd_nxt = req->snt_isn + 1; - newtp->snd_una = req->snt_isn + 1; - newtp->srtt = 0; - newtp->ato = 0; - newtp->snd_wl1 = req->rcv_isn; - newtp->snd_wl2 = req->snt_isn; - - /* RFC1323: The window in SYN & SYN/ACK segments - * is never scaled. - */ - newtp->snd_wnd = ntohs(skb->h.th->window); - - newtp->max_window = newtp->snd_wnd; - newtp->pending = 0; - newtp->retransmits = 0; - newtp->last_ack_sent = req->rcv_isn + 1; - newtp->backoff = 0; - newtp->mdev = TCP_TIMEOUT_INIT; - - /* So many TCP implementations out there (incorrectly) count the - * initial SYN frame in their delayed-ACK and congestion control - * algorithms that we must have the following bandaid to talk - * efficiently to them. -DaveM - */ - newtp->snd_cwnd = 2; - - newtp->rto = TCP_TIMEOUT_INIT; - newtp->packets_out = 0; - newtp->fackets_out = 0; - newtp->retrans_out = 0; - newtp->high_seq = 0; - newtp->snd_ssthresh = 0x7fffffff; - newtp->snd_cwnd_cnt = 0; - newtp->dup_acks = 0; - newtp->delayed_acks = 0; - init_timer(&newtp->retransmit_timer); - newtp->retransmit_timer.function = &tcp_retransmit_timer; - newtp->retransmit_timer.data = (unsigned long) newsk; - init_timer(&newtp->delack_timer); - newtp->delack_timer.function = &tcp_delack_timer; - newtp->delack_timer.data = (unsigned long) newsk; - skb_queue_head_init(&newtp->out_of_order_queue); - newtp->send_head = newtp->retrans_head = NULL; - newtp->rcv_wup = req->rcv_isn + 1; - newtp->write_seq = req->snt_isn + 1; - newtp->copied_seq = req->rcv_isn + 1; - - newtp->saw_tstamp = 0; - newtp->mss_clamp = req->mss; - - init_timer(&newtp->probe_timer); - newtp->probe_timer.function = &tcp_probe_timer; - newtp->probe_timer.data = (unsigned long) newsk; - newtp->probes_out = 0; - newtp->syn_seq = req->rcv_isn; - newtp->fin_seq = req->rcv_isn; - newtp->urg_data = 0; - tcp_synq_init(newtp); - newtp->syn_backlog = 0; - if (skb->len >= 536) - newtp->last_seg_size = skb->len; - - /* Back to base struct sock members. */ - newsk->err = 0; - newsk->ack_backlog = 0; - newsk->max_ack_backlog = SOMAXCONN; - newsk->priority = 0; - - /* IP layer stuff */ - newsk->timeout = 0; - init_timer(&newsk->timer); - newsk->timer.function = &net_timer; - newsk->timer.data = (unsigned long) newsk; - newsk->socket = NULL; - - newtp->tstamp_ok = req->tstamp_ok; - if((newtp->sack_ok = req->sack_ok) != 0) - newtp->num_sacks = 0; - newtp->window_clamp = req->window_clamp; - newtp->rcv_wnd = req->rcv_wnd; - newtp->wscale_ok = req->wscale_ok; - if (newtp->wscale_ok) { - newtp->snd_wscale = req->snd_wscale; - newtp->rcv_wscale = req->rcv_wscale; - } else { - newtp->snd_wscale = newtp->rcv_wscale = 0; - newtp->window_clamp = min(newtp->window_clamp,65535); - } - if (newtp->tstamp_ok) { - newtp->ts_recent = req->ts_recent; - newtp->ts_recent_stamp = tcp_time_stamp; - newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - } else { - newtp->tcp_header_len = sizeof(struct tcphdr); - } - } - return newsk; -} /* * The three way handshake has completed - we got a valid synack - @@ -1482,23 +1510,13 @@ if (ip_route_output(&rt, opt && opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, - req->af.v4_req.loc_addr, sk->ip_tos|RTO_CONN, 0)) + req->af.v4_req.loc_addr, sk->protinfo.af_inet.tos|RTO_CONN, 0)) return NULL; dst = &rt->u.dst; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY - /* The new socket created for transparent proxy may fall - * into a non-existed bind bucket because sk->num != newsk->num. - * Ensure existance of the bucket now. The placement of the check - * later will require to destroy just created newsk in the case of fail. - * 1998/04/22 Andrey V. Savochkin - */ - if (tcp_bucket_check(ntohs(skb->h.th->dest))) - goto exit; -#endif newsk = tcp_create_openreq_child(sk, req, skb); - if (!newsk) + if (!newsk) goto exit; sk->tp_pinfo.af_tcp.syn_backlog--; @@ -1510,30 +1528,25 @@ newsk->daddr = req->af.v4_req.rmt_addr; newsk->saddr = req->af.v4_req.loc_addr; newsk->rcv_saddr = req->af.v4_req.loc_addr; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - newsk->num = ntohs(skb->h.th->dest); - newsk->sport = req->lcl_port; -#endif - newsk->opt = req->af.v4_req.opt; + newsk->protinfo.af_inet.opt = req->af.v4_req.opt; + newsk->protinfo.af_inet.mc_index = ((struct rtable*)skb->dst)->rt_iif; + newsk->protinfo.af_inet.mc_ttl = skb->nh.iph->ttl; newtp->ext_header_len = 0; - if (newsk->opt) - newtp->ext_header_len = newsk->opt->optlen; + if (newsk->protinfo.af_inet.opt) + newtp->ext_header_len = newsk->protinfo.af_inet.opt->optlen; tcp_sync_mss(newsk, dst->pmtu); - newtp->rcv_mss = newtp->mss_clamp; + tcp_initialize_rcv_mss(newsk); + + if (newsk->rcvbuf < (3 * (dst->advmss+40+MAX_HEADER+15))) + newsk->rcvbuf = min ((3 * (dst->advmss+40+MAX_HEADER+15)), sysctl_rmem_max); + if (newsk->sndbuf < (3 * (newtp->mss_clamp+40+MAX_HEADER+15))) + newsk->sndbuf = min ((3 * (newtp->mss_clamp+40+MAX_HEADER+15)), sysctl_wmem_max); - /* It would be better to use newtp->mss_clamp here */ - if (newsk->rcvbuf < (3 * newtp->pmtu_cookie)) - newsk->rcvbuf = min ((3 * newtp->pmtu_cookie), sysctl_rmem_max); - if (newsk->sndbuf < (3 * newtp->pmtu_cookie)) - newsk->sndbuf = min ((3 * newtp->pmtu_cookie), sysctl_wmem_max); + bh_lock_sock(newsk); - SOCKHASH_LOCK_WRITE(); __tcp_v4_hash(newsk); __tcp_inherit_port(sk, newsk); - SOCKHASH_UNLOCK_WRITE(); - - sk->data_ready(sk, 0); /* Deliver SIGIO */ return newsk; @@ -1542,62 +1555,51 @@ return NULL; } -static void tcp_v4_rst_req(struct sock *sk, struct sk_buff *skb) + +static struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct open_request *req, *prev; + struct tcphdr *th = skb->h.th; + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - req = tcp_v4_search_req(tp,skb->nh.iph, skb->h.th, &prev); - if (!req) - return; - /* Sequence number check required by RFC793 */ - if (before(TCP_SKB_CB(skb)->seq, req->rcv_isn) || - after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1)) - return; - tcp_synq_unlink(tp, req, prev); - (req->sk ? sk->ack_backlog : tp->syn_backlog)--; - req->class->destructor(req); - tcp_openreq_free(req); + /* Find possible connection requests. */ + req = tcp_v4_search_req(tp, skb->nh.iph, th, &prev); + if (req) + return tcp_check_req(sk, skb, req, prev); - net_statistics.EmbryonicRsts++; +#ifdef CONFIG_SYN_COOKIES + if (!th->rst && (th->syn || th->ack)) + sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); +#endif + return sk; } -/* Check for embryonic sockets (open_requests) We check packets with - * only the SYN bit set against the open_request queue too: This - * increases connection latency a bit, but is required to detect - * retransmitted SYNs. - */ -static inline struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb) +static int tcp_csum_verify(struct sk_buff *skb) { - struct tcphdr *th = skb->h.th; - u32 flg = ((u32 *)th)[3]; - - /* Check for RST */ - if (flg & __constant_htonl(0x00040000)) { - tcp_v4_rst_req(sk, skb); - return NULL; - } - - /* Check for SYN|ACK */ - flg &= __constant_htonl(0x00120000); - if (flg) { - struct open_request *req, *dummy; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - - /* Find possible connection requests. */ - req = tcp_v4_search_req(tp, skb->nh.iph, th, &dummy); - if (req) { - sk = tcp_check_req(sk, skb, req); - } -#ifdef CONFIG_SYN_COOKIES - else { - sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); + switch (skb->ip_summed) { + case CHECKSUM_NONE: + skb->csum = csum_partial((char *)skb->h.th, skb->len, 0); + case CHECKSUM_HW: + if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) { + NETDEBUG(printk(KERN_DEBUG "TCPv4 bad checksum " + "from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, " + "len=%d/%d\n", + NIPQUAD(skb->nh.iph->saddr), + ntohs(skb->h.th->source), + NIPQUAD(skb->nh.iph->daddr), + ntohs(skb->h.th->dest), + skb->len, + ntohs(skb->nh.iph->tot_len))); + return 1; } -#endif + skb->ip_summed = CHECKSUM_UNNECESSARY; + default: + /* CHECKSUM_UNNECESSARY */ } - return sk; + return 0; } + /* The socket must have it's spinlock held when we get * here. * @@ -1608,7 +1610,6 @@ */ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { - int need_unlock = 0; #ifdef CONFIG_FILTER struct sk_filter *filter = sk->filter; if (filter && sk_filter(skb, filter)) @@ -1623,16 +1624,22 @@ skb_set_owner_r(skb, sk); if (sk->state == TCP_ESTABLISHED) { /* Fast path */ + /* Ready to move deeper ... */ + if (tcp_csum_verify(skb)) + goto csum_err; if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) goto reset; return 0; } + if (tcp_csum_verify(skb)) + goto csum_err; + if (sk->state == TCP_LISTEN) { struct sock *nsk; - + nsk = tcp_v4_hnd_req(sk, skb); - if (!nsk) + if (!nsk) goto discard; /* @@ -1641,21 +1648,35 @@ * the new socket.. */ if (nsk != sk) { - bh_lock_sock(nsk); - if (nsk->lock.users != 0) { - skb_orphan(skb); - sk_add_backlog(nsk, skb); - bh_unlock_sock(nsk); - return 0; - } - need_unlock = 1; - sk = nsk; + int ret; + int state = nsk->state; + + skb_orphan(skb); + + BUG_TRAP(nsk->lock.users == 0); + skb_set_owner_r(skb, nsk); + ret = tcp_rcv_state_process(nsk, skb, skb->h.th, skb->len); + + /* Wakeup parent, send SIGIO, if this packet changed + socket state from SYN-RECV. + + It still looks ugly, however it is much better + than miracleous double wakeup in syn_recv_sock() + and tcp_rcv_state_process(). + */ + if (state == TCP_SYN_RECV && nsk->state != state) + sk->data_ready(sk, 0); + + bh_unlock_sock(nsk); + if (ret) + goto reset; + return 0; } } if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) goto reset; - goto out_maybe_unlock; + return 0; reset: tcp_v4_send_reset(skb); @@ -1666,10 +1687,11 @@ * might be destroyed here. This current version compiles correctly, * but you have been warned. */ -out_maybe_unlock: - if(need_unlock) - bh_unlock_sock(sk); return 0; + +csum_err: + tcp_statistics.TcpInErrs++; + goto discard; } /* @@ -1696,57 +1718,23 @@ if (len < sizeof(struct tcphdr)) goto bad_packet; - /* Try to use the device checksum if provided. */ - switch (skb->ip_summed) { - case CHECKSUM_NONE: - skb->csum = csum_partial((char *)th, len, 0); - case CHECKSUM_HW: - if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) { - NETDEBUG(printk(KERN_DEBUG "TCPv4 bad checksum " - "from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, " - "len=%d/%d/%d\n", - NIPQUAD(skb->nh.iph->saddr), - ntohs(th->source), - NIPQUAD(skb->nh.iph->daddr), - ntohs(th->dest), - len, skb->len, - ntohs(skb->nh.iph->tot_len))); - bad_packet: - tcp_statistics.TcpInErrs++; - goto discard_it; - } - default: - /* CHECKSUM_UNNECESSARY */ - } - -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (IPCB(skb)->redirport) - sk = tcp_v4_proxy_lookup(th->dest, skb->nh.iph->saddr, th->source, - skb->nh.iph->daddr, skb->dev, - IPCB(skb)->redirport, skb->dev->ifindex); - else { -#endif - SOCKHASH_LOCK_READ_BH(); - sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, - skb->nh.iph->daddr, ntohs(th->dest), skb->dev->ifindex); - SOCKHASH_UNLOCK_READ_BH(); -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (!sk) - sk = tcp_v4_search_proxy_openreq(skb); - } -#endif - if (!sk) - goto no_tcp_socket; - if(!ipsec_sk_policy(sk,skb)) - goto discard_it; - TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); - + TCP_SKB_CB(skb)->when = 0; skb->used = 0; + sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, + skb->nh.iph->daddr, ntohs(th->dest), skb->dev->ifindex); + + if (!sk) + goto no_tcp_socket; + +process: + if(!ipsec_sk_policy(sk,skb)) + goto discard_and_relse; + if (sk->state == TCP_TIME_WAIT) goto do_time_wait; @@ -1758,40 +1746,78 @@ sk_add_backlog(sk, skb); bh_unlock_sock(sk); + sock_put(sk); + return ret; no_tcp_socket: - tcp_v4_send_reset(skb); + if (tcp_csum_verify(skb)) { +bad_packet: + tcp_statistics.TcpInErrs++; + } else { + tcp_v4_send_reset(skb); + } discard_it: /* Discard frame. */ kfree_skb(skb); return 0; +discard_and_relse: + sock_put(sk); + goto discard_it; + do_time_wait: - if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, - skb, th, skb->len)) + if (tcp_csum_verify(skb)) { + tcp_statistics.TcpInErrs++; + goto discard_and_relse; + } + switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, + skb, th, skb->len)) { + case TCP_TW_SYN: + { + struct sock *sk2; + + sk2 = tcp_v4_lookup_listener(skb->nh.iph->daddr, ntohs(th->dest), skb->dev->ifindex); + if (sk2 != NULL) { + tcp_tw_deschedule((struct tcp_tw_bucket *)sk); + tcp_timewait_kill((struct tcp_tw_bucket *)sk); + tcp_tw_put((struct tcp_tw_bucket *)sk); + sk = sk2; + goto process; + } + /* Fall through to ACK */ + } + case TCP_TW_ACK: + tcp_v4_timewait_ack(sk, skb); + break; + case TCP_TW_RST: goto no_tcp_socket; + case TCP_TW_SUCCESS: + } goto discard_it; } static void __tcp_v4_rehash(struct sock *sk) { - struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))]; + struct tcp_ehash_bucket *oldhead = &tcp_ehash[sk->hashent]; + struct tcp_ehash_bucket *head = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))]; + struct sock **skp = &head->chain; - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&oldhead->lock); if(sk->pprev) { if(sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - tcp_reg_zap(sk); } + write_unlock(&oldhead->lock); + write_lock(&head->lock); if((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&head->lock); } int tcp_v4_rebuild_header(struct sock *sk) @@ -1815,7 +1841,7 @@ /* Query new route using another rt buffer */ tmp = ip_route_connect(&new_rt, rt->rt_dst, 0, - RT_TOS(sk->ip_tos)|sk->localroute, + RT_TOS(sk->protinfo.af_inet.tos)|sk->localroute, sk->bound_dev_if); /* Only useful if different source addrs */ @@ -1824,11 +1850,10 @@ * Only useful if different source addrs */ if (new_rt->rt_src != old_saddr ) { - dst_release(sk->dst_cache); - sk->dst_cache = &new_rt->u.dst; + __sk_dst_set(sk, &new_rt->u.dst); rt = new_rt; goto do_rewrite; - } + } dst_release(&new_rt->u.dst); } } @@ -1840,7 +1865,7 @@ sk->error_report(sk); return -1; } - dst_release(xchg(&sk->dst_cache, &rt->u.dst)); + __sk_dst_set(sk, &rt->u.dst); } return 0; @@ -1871,6 +1896,9 @@ /* XXX The only one ugly spot where we need to * XXX really change the sockets identity after * XXX it has entered the hashes. -DaveM + * + * Besides that, it does not check for connetion + * uniqueness. Wait for troubles. */ __tcp_v4_rehash(sk); } @@ -1878,12 +1906,6 @@ return 0; } -static struct sock * tcp_v4_get_sock(struct sk_buff *skb, struct tcphdr *th) -{ - return tcp_v4_lookup(skb->nh.iph->saddr, th->source, - skb->nh.iph->daddr, th->dest, skb->dev->ifindex); -} - static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) { struct sockaddr_in *sin = (struct sockaddr_in *) uaddr; @@ -1899,7 +1921,7 @@ tcp_v4_rebuild_header, tcp_v4_conn_request, tcp_v4_syn_recv_sock, - tcp_v4_get_sock, + tcp_v4_hash_connecting, sizeof(struct iphdr), ip_setsockopt, @@ -1918,9 +1940,8 @@ skb_queue_head_init(&tp->out_of_order_queue); tcp_init_xmit_timers(sk); - tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ + tp->rto = TCP_TIMEOUT_INIT; tp->mdev = TCP_TIMEOUT_INIT; - tp->mss_clamp = ~0; /* So many TCP implementations out there (incorrectly) count the * initial SYN frame in their delayed-ACK and congestion control @@ -1934,10 +1955,11 @@ */ tp->snd_cwnd_cnt = 0; tp->snd_ssthresh = 0x7fffffff; /* Infinity */ + tp->snd_cwnd_clamp = ~0; + tp->mss_cache = 536; sk->state = TCP_CLOSE; sk->max_ack_backlog = SOMAXCONN; - tp->rcv_mss = 536; sk->write_space = tcp_write_space; @@ -1952,20 +1974,14 @@ static int tcp_v4_destroy_sock(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff *skb; tcp_clear_xmit_timers(sk); - if (sk->keepopen) - tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); - /* Cleanup up the write buffer. */ - while((skb = __skb_dequeue(&sk->write_queue)) != NULL) - kfree_skb(skb); + __skb_queue_purge(&sk->write_queue); /* Cleans up our, hopefuly empty, out_of_order_queue. */ - while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL) - kfree_skb(skb); + __skb_queue_purge(&tp->out_of_order_queue); /* Clean up a referenced TCP bind bucket, this only happens if a * port is allocated for a socket, but it never fully connects. @@ -1980,7 +1996,7 @@ static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i) { sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p", i, (long unsigned int)req->af.v4_req.loc_addr, ntohs(sk->sport), @@ -1993,7 +2009,9 @@ req->retrans, sk->socket ? sk->socket->inode->i_uid : 0, 0, /* non standard timer */ - 0 /* open_requests have no inode */ + 0, /* open_requests have no inode */ + atomic_read(&sk->refcnt), + req ); } @@ -2025,19 +2043,19 @@ timer_expires = jiffies; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src, srcp, dest, destp, sp->state, tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, timer_active, timer_expires-jiffies, tp->retransmits, sp->socket ? sp->socket->inode->i_uid : 0, - timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) { - extern int tcp_tw_death_row_slot; unsigned int dest, src; __u16 destp, srcp; int slot_dist; @@ -2054,9 +2072,10 @@ slot_dist = tcp_tw_death_row_slot - slot_dist; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08X %08X %5d %8d %d", + " %02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p", i, src, srcp, dest, destp, TCP_TIME_WAIT, 0, 0, - 3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0); + 3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0, + atomic_read(&tw->refcnt), tw); } int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) @@ -2071,9 +2090,9 @@ "rx_queue tr tm->when retrnsmt uid timeout inode"); pos = 128; - SOCKHASH_LOCK_READ(); /* First, walk listening socket table. */ + tcp_listen_lock(); for(i = 0; i < TCP_LHTABLE_SIZE; i++) { struct sock *sk = tcp_listening_hash[i]; @@ -2081,66 +2100,86 @@ struct open_request *req; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - if (sk->family != PF_INET) - continue; + if (!TCP_INET_FAMILY(sk->family)) + goto skip_listen; + pos += 128; if (pos >= offset) { get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-127s\n", tmpbuf); - if (len >= length) - goto out; + if (len >= length) { + tcp_listen_unlock(); + goto out_no_bh; + } } + +skip_listen: + lock_sock(sk); for (req = tp->syn_wait_queue; req; req = req->dl_next, num++) { if (req->sk) continue; + if (!TCP_INET_FAMILY(req->class->family)) + continue; + pos += 128; if (pos < offset) continue; get_openreq(sk, req, tmpbuf, num); len += sprintf(buffer+len, "%-127s\n", tmpbuf); - if(len >= length) - goto out; + if(len >= length) { + tcp_listen_unlock(); + release_sock(sk); + goto out_no_bh; + } } + release_sock(sk); } } + tcp_listen_unlock(); + + local_bh_disable(); /* Next, walk established hash chain. */ - for (i = 0; i < (tcp_ehash_size >> 1); i++) { + for (i = 0; i < tcp_ehash_size; i++) { + struct tcp_ehash_bucket *head = &tcp_ehash[i]; struct sock *sk; + struct tcp_tw_bucket *tw; - for(sk = tcp_ehash[i]; sk; sk = sk->next, num++) { - if (sk->family != PF_INET) + read_lock(&head->lock); + for(sk = head->chain; sk; sk = sk->next, num++) { + if (!TCP_INET_FAMILY(sk->family)) continue; pos += 128; if (pos < offset) continue; get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-127s\n", tmpbuf); - if(len >= length) + if(len >= length) { + read_unlock(&head->lock); goto out; + } } - } - - /* Finally, walk time wait buckets. */ - for (i = (tcp_ehash_size>>1); i < tcp_ehash_size; i++) { - struct tcp_tw_bucket *tw; - for (tw = (struct tcp_tw_bucket *)tcp_ehash[i]; + for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain; tw != NULL; tw = (struct tcp_tw_bucket *)tw->next, num++) { - if (tw->family != PF_INET) + if (!TCP_INET_FAMILY(tw->family)) continue; pos += 128; if (pos < offset) continue; get_timewait_sock(tw, tmpbuf, num); len += sprintf(buffer+len, "%-127s\n", tmpbuf); - if(len >= length) + if(len >= length) { + read_unlock(&head->lock); goto out; + } } + read_unlock(&head->lock); } out: - SOCKHASH_UNLOCK_READ(); + local_bh_enable(); +out_no_bh: begin = len - (pos - offset); *start = buffer + begin; @@ -2155,6 +2194,7 @@ struct proto tcp_prot = { tcp_close, /* close */ tcp_v4_connect, /* connect */ + tcp_disconnect, /* disconnect */ tcp_accept, /* accept */ NULL, /* retransmit */ tcp_write_wakeup, /* write_wakeup */ @@ -2171,7 +2211,7 @@ NULL, /* bind */ tcp_v4_do_rcv, /* backlog_rcv */ tcp_v4_hash, /* hash */ - tcp_v4_unhash, /* unhash */ + tcp_unhash, /* unhash */ tcp_v4_get_port, /* get_port */ 128, /* max_header */ 0, /* retransmits */ @@ -2200,7 +2240,7 @@ if ((err=ops->create(tcp_socket, IPPROTO_TCP))<0) panic("Failed to create the TCP control socket.\n"); tcp_socket->sk->allocation=GFP_ATOMIC; - tcp_socket->sk->ip_ttl = MAXTTL; + tcp_socket->sk->protinfo.af_inet.ttl = MAXTTL; /* Unhash it so that IP input processing does not even * see it, we do not wish this socket to see incoming diff -u --recursive --new-file v2.3.14/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.3.14/linux/net/ipv4/tcp_output.c Wed May 26 18:14:38 1999 +++ linux/net/ipv4/tcp_output.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.110 1999/05/27 00:37:45 davem Exp $ + * Version: $Id: tcp_output.c,v 1.112 1999/08/23 06:30:37 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -65,6 +65,50 @@ tp->send_head = NULL; } +/* Calculate mss to advertise in SYN segment. + RFC1122, RFC1063, draft-ietf-tcpimpl-pmtud-01 state that: + + 1. It is independent of path mtu. + 2. Ideally, it is maximal possible segment size i.e. 65535-40. + 3. For IPv4 it is reasonable to calculate it from maximal MTU of + attached devices, because some buggy hosts are confused by + large MSS. + 4. We do not make 3, we advertise MSS, calculated from first + hop device mtu, but allow to raise it to ip_rt_min_advmss. + This may be overriden via information stored in routing table. + 5. Value 65535 for MSS is valid in IPv6 and means "as large as possible, + probably even Jumbo". + */ +static __u16 tcp_advertise_mss(struct sock *sk) +{ + struct dst_entry *dst = __sk_dst_get(sk); + int mss; + + if (dst) { + mss = dst->advmss; + } else { + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + /* No dst. It is bad. Guess some reasonable value. + * Actually, this case should not be possible. + * SANITY. + */ + BUG_TRAP(dst!=NULL); + + mss = tp->mss_cache; + mss += (tp->tcp_header_len - sizeof(struct tcphdr)) + + tp->ext_header_len; + + /* Minimal MSS to include full set of of TCP/IP options + plus 8 bytes of data. It corresponds to mtu 128. + */ + if (mss < 88) + mss = 88; + } + + return (__u16)mss; +} + /* This routine actually transmits TCP packets queued in by * tcp_do_sendmsg(). This is used by both the initial * transmission and possible later retransmissions. @@ -124,8 +168,6 @@ th->doff = (tcp_header_size >> 2); th->res1 = 0; *(((__u8 *)th) + 13) = tcb->flags; - if(!(tcb->flags & TCPCB_FLAG_SYN)) - th->window = htons(tcp_select_window(sk)); th->check = 0; th->urg_ptr = ntohs(tcb->urg_ptr); if(tcb->flags & TCPCB_FLAG_SYN) { @@ -133,7 +175,8 @@ * is never scaled. */ th->window = htons(tp->rcv_wnd); - tcp_syn_build_options((__u32 *)(th + 1), tp->mss_clamp, + tcp_syn_build_options((__u32 *)(th + 1), + tcp_advertise_mss(sk), (sysctl_flags & SYSCTL_FLAG_TSTAMPS), (sysctl_flags & SYSCTL_FLAG_SACK), (sysctl_flags & SYSCTL_FLAG_WSCALE), @@ -141,6 +184,7 @@ TCP_SKB_CB(skb)->when, tp->ts_recent); } else { + th->window = htons(tcp_select_window(sk)); tcp_build_and_update_options((__u32 *)(th + 1), tp, TCP_SKB_CB(skb)->when); } @@ -283,7 +327,8 @@ /* Calculate base mss without TCP options: It is MMS_S - sizeof(tcphdr) of rfc1122 - */ + */ + mss_now = pmtu - tp->af_specific->net_header_len - sizeof(struct tcphdr); /* Clamp it (mss_clamp does not include tcp options) */ @@ -415,30 +460,30 @@ * a multiple of the mss when it is feasible to do so. * * Note, we don't "adjust" for TIMESTAMP or SACK option bytes. + * Regular options like TIMESTAMP are taken into account. */ u32 __tcp_select_window(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - unsigned int mss = tp->mss_cache; + /* MSS for the peer's data. Previous verions used mss_clamp + * here. I don't know if the value based on our guesses + * of peer's MSS is better for the performance. It's more correct + * but may be worse for the performance because of rcv_mss + * fluctuations. --SAW 1998/11/1 + */ + unsigned int mss = tp->rcv_mss; int free_space; u32 window; /* Sometimes free_space can be < 0. */ - free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2; - if (tp->window_clamp) { - if (free_space > ((int) tp->window_clamp)) - free_space = tp->window_clamp; - mss = min(tp->window_clamp, mss); - } else { - printk("tcp_select_window: tp->window_clamp == 0.\n"); - } - - if (mss < 1) { - mss = 1; - printk("tcp_select_window: sk->mss fell to 0.\n"); - } + free_space = tcp_space(sk); + if (free_space > ((int) tp->window_clamp)) + free_space = tp->window_clamp; + if (tp->window_clamp < mss) + mss = tp->window_clamp; - if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) { + if ((free_space < (tcp_full_space(sk) / 2)) && + (free_space < ((int) (mss/2)))) { window = 0; tp->pred_flags = 0; } else { @@ -741,7 +786,7 @@ */ if(tp->send_head == skb && !sk->nonagle && - skb->len < (tp->mss_cache >> 1) && + skb->len < (tp->rcv_mss >> 1) && tp->packets_out && !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG)) { update_send_head(sk); @@ -813,7 +858,7 @@ { struct tcp_opt* tp = &(sk->tp_pinfo.af_tcp); struct sk_buff* skb; - + skb = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header), 1, GFP_ATOMIC); if (skb == NULL) @@ -840,7 +885,7 @@ * Prepare a SYN-ACK. */ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, - struct open_request *req, int mss) + struct open_request *req) { struct tcphdr *th; int tcp_header_size; @@ -855,17 +900,6 @@ skb->dst = dst_clone(dst); - /* Don't offer more than they did. - * This way we don't have to memorize who said what. - * FIXME: maybe this should be changed for better performance - * with syncookies. - */ - req->mss = min(mss, req->mss); - if (req->mss < 8) { - printk(KERN_DEBUG "initial req->mss below 8\n"); - req->mss = 8; - } - tcp_header_size = (sizeof(struct tcphdr) + TCPOLEN_MSS + (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) + (req->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + @@ -886,7 +920,9 @@ __u8 rcv_wscale; /* Set this up on the first call only */ req->window_clamp = skb->dst->window; - tcp_select_initial_window(sock_rspace(sk)/2,req->mss, + /* tcp_full_space because it is guaranteed to be the first packet */ + tcp_select_initial_window(tcp_full_space(sk), + dst->advmss - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), &req->rcv_wnd, &req->window_clamp, req->wscale_ok, @@ -898,18 +934,18 @@ th->window = htons(req->rcv_wnd); TCP_SKB_CB(skb)->when = tcp_time_stamp; - tcp_syn_build_options((__u32 *)(th + 1), req->mss, req->tstamp_ok, + tcp_syn_build_options((__u32 *)(th + 1), dst->advmss, req->tstamp_ok, req->sack_ok, req->wscale_ok, req->rcv_wscale, TCP_SKB_CB(skb)->when, req->ts_recent); skb->csum = 0; th->doff = (tcp_header_size >> 2); - tcp_statistics.TcpOutSegs++; + tcp_statistics.TcpOutSegs++; return skb; } -void tcp_connect(struct sock *sk, struct sk_buff *buff, int mtu) +int tcp_connect(struct sock *sk, struct sk_buff *buff) { struct dst_entry *dst = sk->dst_cache; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -917,14 +953,6 @@ /* Reserve space for headers. */ skb_reserve(buff, MAX_HEADER + sk->prot->max_header); - tp->snd_wnd = 0; - tp->snd_wl1 = 0; - tp->snd_wl2 = tp->write_seq; - tp->snd_una = tp->write_seq; - tp->rcv_nxt = 0; - - sk->err = 0; - /* We'll fix this up when we get a response from the other end. * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. */ @@ -934,77 +962,72 @@ /* If user gave his TCP_MAXSEG, record it to clamp */ if (tp->user_mss) tp->mss_clamp = tp->user_mss; - tcp_sync_mss(sk, mtu); - - /* Now unpleasant action: if initial pmtu is too low - set lower clamp. I am not sure that it is good. - To be more exact, I do not think that clamping at value, which - is apparently transient and may improve in future is good idea. - It would be better to wait until peer will returns its MSS - (probably 65535 too) and now advertise something sort of 65535 - or at least first hop device mtu. Is it clear, what I mean? - We should tell peer what maximal mss we expect to RECEIVE, - it has nothing to do with pmtu. - I am afraid someone will be confused by such huge value. - --ANK (980731) - */ - if (tp->mss_cache + tp->tcp_header_len - sizeof(struct tcphdr) < tp->mss_clamp ) - tp->mss_clamp = tp->mss_cache + tp->tcp_header_len - sizeof(struct tcphdr); - - TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; - TCP_SKB_CB(buff)->sacked = 0; - TCP_SKB_CB(buff)->urg_ptr = 0; - buff->csum = 0; - TCP_SKB_CB(buff)->seq = tp->write_seq++; - TCP_SKB_CB(buff)->end_seq = tp->write_seq; - tp->snd_nxt = TCP_SKB_CB(buff)->end_seq; + tcp_sync_mss(sk, dst->pmtu); tp->window_clamp = dst->window; - tcp_select_initial_window(sock_rspace(sk)/2,tp->mss_clamp, + + tcp_select_initial_window(tcp_full_space(sk), + dst->advmss - (tp->tcp_header_len - sizeof(struct tcphdr)), &tp->rcv_wnd, &tp->window_clamp, sysctl_tcp_window_scaling, &tp->rcv_wscale); - /* Ok, now lock the socket before we make it visible to - * the incoming packet engine. - */ - unlock_kernel(); - lock_sock(sk); /* Socket identity change complete, no longer * in TCP_CLOSE, so enter ourselves into the * hash tables. */ tcp_set_state(sk,TCP_SYN_SENT); - sk->prot->hash(sk); + if (tp->af_specific->hash_connecting(sk)) + goto err_out; - tp->rto = dst->rtt; + sk->err = 0; + tp->snd_wnd = 0; + tp->snd_wl1 = 0; + tp->snd_wl2 = tp->write_seq; + tp->snd_una = tp->write_seq; + tp->rcv_nxt = 0; + tp->rcv_wup = 0; + tp->copied_seq = 0; + + tp->rto = TCP_TIMEOUT_INIT; tcp_init_xmit_timers(sk); tp->retransmits = 0; tp->fackets_out = 0; tp->retrans_out = 0; + TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; + TCP_SKB_CB(buff)->sacked = 0; + TCP_SKB_CB(buff)->urg_ptr = 0; + buff->csum = 0; + TCP_SKB_CB(buff)->seq = tp->write_seq++; + TCP_SKB_CB(buff)->end_seq = tp->write_seq; + tp->snd_nxt = tp->write_seq; + /* Send it off. */ - __skb_queue_tail(&sk->write_queue, buff); TCP_SKB_CB(buff)->when = tcp_time_stamp; + __skb_queue_tail(&sk->write_queue, buff); tp->packets_out++; tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL)); tcp_statistics.TcpActiveOpens++; /* Timer for repeating the SYN until an answer. */ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); + return 0; - /* Now, it is safe to release the socket. */ - release_sock(sk); - lock_kernel(); +err_out: + tcp_set_state(sk,TCP_CLOSE); + kfree_skb(buff); + return -EADDRNOTAVAIL; } /* Send out a delayed ack, the caller does the policy checking * to see if we should even be here. See tcp_input.c:tcp_ack_snd_check() * for details. */ -void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout) +void tcp_send_delayed_ack(struct sock *sk, int max_timeout) { + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; unsigned long timeout; /* Stay within the limit we were given */ @@ -1014,13 +1037,16 @@ timeout += jiffies; /* Use new timeout only if there wasn't a older one earlier. */ - if (!tp->delack_timer.prev) { + spin_lock_bh(&sk->timer_lock); + if (!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) { + sock_hold(sk); tp->delack_timer.expires = timeout; - add_timer(&tp->delack_timer); - } else { + } else { if (time_before(timeout, tp->delack_timer.expires)) - mod_timer(&tp->delack_timer, timeout); + tp->delack_timer.expires = timeout; } + add_timer(&tp->delack_timer); + spin_unlock_bh(&sk->timer_lock); } /* This routine sends an ack and also updates the window. */ @@ -1048,7 +1074,7 @@ */ if(tcp_in_quickack_mode(tp)) tcp_exit_quickack_mode(tp); - tcp_send_delayed_ack(tp, HZ/2); + tcp_send_delayed_ack(sk, HZ/2); return; } @@ -1082,7 +1108,7 @@ */ if ((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1| - TCPF_LAST_ACK|TCPF_CLOSING)) + TCPF_FIN_WAIT2|TCPF_LAST_ACK|TCPF_CLOSING)) return; if (before(tp->snd_nxt, tp->snd_una + tp->snd_wnd) && diff -u --recursive --new-file v2.3.14/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.3.14/linux/net/ipv4/tcp_timer.c Sat Jul 3 17:57:23 1999 +++ linux/net/ipv4/tcp_timer.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.65 1999/07/02 11:26:35 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.66 1999/08/20 11:06:10 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -28,9 +28,9 @@ int sysctl_tcp_retries1 = TCP_RETR1; int sysctl_tcp_retries2 = TCP_RETR2; + static void tcp_sltimer_handler(unsigned long); static void tcp_syn_recv_timer(unsigned long); -static void tcp_keepalive(unsigned long data); static void tcp_twkill(unsigned long); struct timer_list tcp_slow_timer = { @@ -42,7 +42,6 @@ struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = { {ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK */ - {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}, /* KEEPALIVE */ {ATOMIC_INIT(0), TCP_TWKILL_PERIOD, 0, tcp_twkill} /* TWKILL */ }; @@ -77,6 +76,7 @@ { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + spin_lock_bh(&sk->timer_lock); switch (what) { case TIME_RETRANS: /* When seting the transmit timer the probe timer @@ -84,16 +84,26 @@ * The delayed ack timer can be set if we are changing the * retransmit timer when removing acked frames. */ - if(tp->probe_timer.prev) - del_timer(&tp->probe_timer); + if(tp->probe_timer.prev && del_timer(&tp->probe_timer)) + __sock_put(sk); + if (!tp->retransmit_timer.prev || !del_timer(&tp->retransmit_timer)) + sock_hold(sk); + if (when > 120*HZ) { + printk(KERN_DEBUG "reset_xmit_timer sk=%p when=0x%lx, caller=%p\n", sk, when, NET_CALLER(sk)); + when = 120*HZ; + } mod_timer(&tp->retransmit_timer, jiffies+when); break; case TIME_DACK: + if (!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) + sock_hold(sk); mod_timer(&tp->delack_timer, jiffies+when); break; case TIME_PROBE0: + if (!tp->probe_timer.prev || !del_timer(&tp->probe_timer)) + sock_hold(sk); mod_timer(&tp->probe_timer, jiffies+when); break; @@ -104,40 +114,44 @@ default: printk(KERN_DEBUG "bug: unknown timer value\n"); }; + spin_unlock_bh(&sk->timer_lock); } void tcp_clear_xmit_timers(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - if(tp->retransmit_timer.prev) - del_timer(&tp->retransmit_timer); - if(tp->delack_timer.prev) - del_timer(&tp->delack_timer); - if(tp->probe_timer.prev) - del_timer(&tp->probe_timer); + spin_lock_bh(&sk->timer_lock); + if(tp->retransmit_timer.prev && del_timer(&tp->retransmit_timer)) + __sock_put(sk); + if(tp->delack_timer.prev && del_timer(&tp->delack_timer)) + __sock_put(sk); + if(tp->probe_timer.prev && del_timer(&tp->probe_timer)) + __sock_put(sk); + if(sk->timer.prev && del_timer(&sk->timer)) + __sock_put(sk); + spin_unlock_bh(&sk->timer_lock); } -static int tcp_write_err(struct sock *sk, int force) +static void tcp_write_err(struct sock *sk, int force) { sk->err = sk->err_soft ? sk->err_soft : ETIMEDOUT; sk->error_report(sk); - + tcp_clear_xmit_timers(sk); - - /* Time wait the socket. */ - if (!force && ((1<state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) { - tcp_time_wait(sk); - } else { - /* Clean up time. */ - tcp_set_state(sk, TCP_CLOSE); - return 0; - } - return 1; + + /* Do not time wait the socket. It is timed out and, hence, + * idle for 120*HZ. "force" argument is ignored, delete + * it eventually. + */ + + /* Clean up time. */ + tcp_set_state(sk, TCP_CLOSE); + tcp_done(sk); } /* A write timeout has occurred. Process the after effects. */ -static int tcp_write_timeout(struct sock *sk) +static void tcp_write_timeout(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -145,6 +159,26 @@ if ((sk->state == TCP_ESTABLISHED && tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) || (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) { + /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black + hole detection. :-( + + It is place to make it. It is not made. I do not want + to make it. It is disguisting. It does not work in any + case. Let me to cite the same draft, which requires for + us to implement this: + + "The one security concern raised by this memo is that ICMP black holes + are often caused by over-zealous security administrators who block + all ICMP messages. It is vitally important that those who design and + deploy security systems understand the impact of strict filtering on + upper-layer protocols. The safest web site in the world is worthless + if most TCP implementations cannot transfer data from it. It would + be far nicer to have all of the black holes fixed rather than fixing + all of the TCP implementations." + + Golden words :-). + */ + dst_negative_advice(&sk->dst_cache); } @@ -152,14 +186,10 @@ if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) { tcp_write_err(sk, 1); /* Don't FIN, we got nothing back */ - return 0; + } else if (tp->retransmits > sysctl_tcp_retries2) { + /* Has it gone just too far? */ + tcp_write_err(sk, 0); } - - /* Has it gone just too far? */ - if (tp->retransmits > sysctl_tcp_retries2) - return tcp_write_err(sk, 0); - - return 1; } void tcp_delack_timer(unsigned long data) @@ -167,15 +197,20 @@ struct sock *sk = (struct sock*)data; bh_lock_sock(sk); + if (sk->lock.users) { + /* Try again later. */ + tcp_reset_xmit_timer(sk, TIME_DACK, HZ/5); + goto out_unlock; + } + if(!sk->zapped && sk->tp_pinfo.af_tcp.delayed_acks && - sk->state != TCP_CLOSE) { - if (!sk->lock.users) - tcp_send_ack(sk); - else - tcp_send_delayed_ack(&(sk->tp_pinfo.af_tcp), HZ/10); - } + sk->state != TCP_CLOSE) + tcp_send_ack(sk); + +out_unlock: bh_unlock_sock(sk); + sock_put(sk); } void tcp_probe_timer(unsigned long data) @@ -183,79 +218,50 @@ struct sock *sk = (struct sock*)data; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - if(sk->zapped) - return; - + if(sk->zapped) + goto out; + bh_lock_sock(sk); if (sk->lock.users) { /* Try again later. */ tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5); - bh_unlock_sock(sk); - return; + goto out_unlock; } - /* *WARNING* RFC 1122 forbids this + /* *WARNING* RFC 1122 forbids this + * * It doesn't AFAIK, because we kill the retransmit timer -AK + * * FIXME: We ought not to do it, Solaris 2.5 actually has fixing * this behaviour in Solaris down as a bug fix. [AC] + * + * Let me to explain. probes_out is zeroed by incoming ACKs + * even if they advertise zero window. Hence, connection is killed only + * if we received no ACKs for normal connection timeout. It is not killed + * only because window stays zero for some time, window may be zero + * until armageddon and even later. We are in full accordance + * with RFCs, only probe timer combines both retransmission timeout + * and probe timeout in one bottle. --ANK */ if (tp->probes_out > sysctl_tcp_retries2) { - if(sk->err_soft) - sk->err = sk->err_soft; - else - sk->err = ETIMEDOUT; - sk->error_report(sk); - - if ((1<state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) { - /* Time wait the socket. */ - tcp_time_wait(sk); - } else { - /* Clean up time. */ - tcp_set_state(sk, TCP_CLOSE); - } + tcp_write_err(sk, 0); } else { /* Only send another probe if we didn't close things up. */ tcp_send_probe0(sk); } +out_unlock: bh_unlock_sock(sk); +out: + sock_put(sk); } -static __inline__ int tcp_keepopen_proc(struct sock *sk) -{ - int res = 0; - - if ((1<state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2)) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp; - - if (elapsed >= sysctl_tcp_keepalive_time) { - if (tp->probes_out > sysctl_tcp_keepalive_probes) { - if(sk->err_soft) - sk->err = sk->err_soft; - else - sk->err = ETIMEDOUT; - - tcp_set_state(sk, TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); - } else { - tp->probes_out++; - tp->pending = TIME_KEEPOPEN; - tcp_write_wakeup(sk); - res = 1; - } - } - } - return res; -} /* Kill off TIME_WAIT sockets once their lifetime has expired. */ int tcp_tw_death_row_slot = 0; static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static spinlock_t tw_death_lock = SPIN_LOCK_UNLOCKED; -extern void tcp_timewait_kill(struct tcp_tw_bucket *tw); static void tcp_twkill(unsigned long data) { @@ -263,17 +269,20 @@ int killed = 0; /* The death-row tw chains are only ever touched - * in BH context so no locking is needed. + * in BH context so no BH disabling (for now) is needed. */ + spin_lock(&tw_death_lock); tw = tcp_tw_death_row[tcp_tw_death_row_slot]; tcp_tw_death_row[tcp_tw_death_row_slot] = NULL; tcp_tw_death_row_slot = ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1)); + spin_unlock(&tw_death_lock); while(tw != NULL) { struct tcp_tw_bucket *next = tw->next_death; tcp_timewait_kill(tw); + tcp_tw_put(tw); killed++; tw = next; } @@ -288,17 +297,20 @@ */ void tcp_tw_schedule(struct tcp_tw_bucket *tw) { - int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1); - struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot]; + struct tcp_tw_bucket **tpp; + int slot; - SOCKHASH_LOCK_WRITE_BH(); + spin_lock(&tw_death_lock); + slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1); + tpp = &tcp_tw_death_row[slot]; if((tw->next_death = *tpp) != NULL) (*tpp)->pprev_death = &tw->next_death; *tpp = tw; tw->pprev_death = tpp; tw->death_slot = slot; - SOCKHASH_UNLOCK_WRITE_BH(); + atomic_inc(&tw->refcnt); + spin_unlock(&tw_death_lock); tcp_inc_slow_timer(TCP_SLT_TWKILL); } @@ -309,11 +321,14 @@ struct tcp_tw_bucket **tpp; int slot; - SOCKHASH_LOCK_WRITE_BH(); - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; + spin_lock(&tw_death_lock); + if (tw->pprev_death) { + if(tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; + *tw->pprev_death = tw->next_death; + tw->pprev_death = NULL; + } else + atomic_inc(&tw->refcnt); slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1); tpp = &tcp_tw_death_row[slot]; @@ -323,7 +338,7 @@ tw->pprev_death = tpp; tw->death_slot = slot; - SOCKHASH_UNLOCK_WRITE_BH(); + spin_unlock(&tw_death_lock); /* Timer was incremented when we first entered the table. */ } @@ -331,91 +346,28 @@ /* This is for handling early-kills of TIME_WAIT sockets. */ void tcp_tw_deschedule(struct tcp_tw_bucket *tw) { - SOCKHASH_LOCK_WRITE_BH(); - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; - SOCKHASH_UNLOCK_WRITE_BH(); + spin_lock(&tw_death_lock); + if (tw->pprev_death) { + if(tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; + *tw->pprev_death = tw->next_death; + tw->pprev_death = NULL; + tcp_tw_put(tw); + } + spin_unlock(&tw_death_lock); tcp_dec_slow_timer(TCP_SLT_TWKILL); } -/* - * Check all sockets for keepalive timer - * Called every 75 seconds - * This timer is started by af_inet init routine and is constantly - * running. - * - * It might be better to maintain a count of sockets that need it using - * setsockopt/tcp_destroy_sk and only set the timer when needed. - */ /* - * don't send over 5 keepopens at a time to avoid burstiness - * on big servers [AC] - */ -#define MAX_KA_PROBES 5 - -int sysctl_tcp_max_ka_probes = MAX_KA_PROBES; - -/* Keepopen's are only valid for "established" TCP's, nicely our listener - * hash gets rid of most of the useless testing, so we run through a couple - * of the established hash chains each clock tick. -DaveM - * - * And now, even more magic... TIME_WAIT TCP's cannot have keepalive probes - * going off for them, so we only need check the first half of the established - * hash table, even less testing under heavy load. - * - * I _really_ would rather do this by adding a new timer_struct to struct sock, - * and this way only those who set the keepalive option will get the overhead. - * The idea is you set it for 2 hours when the sock is first connected, when it - * does fire off (if at all, most sockets die earlier) you check for the keepalive - * option and also if the sock has been idle long enough to start probing. - */ -static void tcp_keepalive(unsigned long data) -{ - static int chain_start = 0; - int count = 0; - int i; - - SOCKHASH_LOCK_READ_BH(); - for(i = chain_start; i < (chain_start + ((tcp_ehash_size >> 1) >> 2)); i++) { - struct sock *sk; - - sk = tcp_ehash[i]; - while(sk) { - struct sock *next = sk->next; - - bh_lock_sock(sk); - if (sk->keepopen && !sk->lock.users) { - SOCKHASH_UNLOCK_READ_BH(); - count += tcp_keepopen_proc(sk); - SOCKHASH_LOCK_READ_BH(); - } - bh_unlock_sock(sk); - if(count == sysctl_tcp_max_ka_probes) - goto out; - sk = next; - } - } -out: - SOCKHASH_UNLOCK_READ_BH(); - chain_start = ((chain_start + ((tcp_ehash_size >> 1)>>2)) & - ((tcp_ehash_size >> 1) - 1)); -} - -/* - * The TCP retransmit timer. This lacks a few small details. + * The TCP retransmit timer. * * 1. An initial rtt timeout on the probe0 should cause what we can * of the first write queue buffer to be split and sent. - * 2. On a 'major timeout' as defined by RFC1122 we shouldn't report + * 2. On a 'major timeout' as defined by RFC1122 we do not report * ETIMEDOUT if we know an additional 'soft' error caused this. - * tcp_err should save a 'soft error' for us. - * [Unless someone has broken it then it does, except for one 2.0 - * broken case of a send when the route/device is directly unreachable, - * and we error but should retry! - FIXME] [AC] + * tcp_err saves a 'soft error' for us. */ void tcp_retransmit_timer(unsigned long data) @@ -424,17 +376,14 @@ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; /* We are reset. We will send no more retransmits. */ - if(sk->zapped) { - tcp_clear_xmit_timer(sk, TIME_RETRANS); - return; - } + if(sk->zapped) + goto out; bh_lock_sock(sk); if (sk->lock.users) { /* Try again later */ tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ/20); - bh_unlock_sock(sk); - return; + goto out_unlock; } /* Clear delay ack timer. */ @@ -501,7 +450,10 @@ tcp_write_timeout(sk); +out_unlock: bh_unlock_sock(sk); +out: + sock_put(sk); } /* @@ -516,7 +468,7 @@ for(req = tp->syn_wait_queue; req; ) { struct open_request *next = req->dl_next; - if (! req->sk) { + if (!req->sk && (long)(now - req->expires) >= 0) { tcp_synq_unlink(tp, req, prev); if(req->retrans >= sysctl_tcp_retries1) { (*req->class->destructor)(req); @@ -552,7 +504,7 @@ unsigned long now = jiffies; int i; - SOCKHASH_LOCK_READ_BH(); + read_lock(&tcp_lhash_lock); for(i = 0; i < TCP_LHTABLE_SIZE; i++) { sk = tcp_listening_hash[i]; while(sk) { @@ -566,7 +518,7 @@ sk = sk->next; } } - SOCKHASH_UNLOCK_READ_BH(); + read_unlock(&tcp_lhash_lock); } void tcp_sltimer_handler(unsigned long data) @@ -613,4 +565,85 @@ tcp_slow_timer.expires = when; add_timer(&tcp_slow_timer); } +} + +void tcp_delete_keepalive_timer (struct sock *sk) +{ + spin_lock_bh(&sk->timer_lock); + if (sk->timer.prev && del_timer (&sk->timer)) + __sock_put(sk); + spin_unlock_bh(&sk->timer_lock); +} + +void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len) +{ + spin_lock_bh(&sk->timer_lock); + if(!sk->timer.prev || !del_timer(&sk->timer)) + sock_hold(sk); + mod_timer(&sk->timer, jiffies+len); + spin_unlock_bh(&sk->timer_lock); +} + +void tcp_set_keepalive(struct sock *sk, int val) +{ + if (val && !sk->keepopen) + tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time); + else if (!val) + tcp_delete_keepalive_timer(sk); +} + + +void tcp_keepalive_timer (unsigned long data) +{ + struct sock *sk = (struct sock *) data; + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + __u32 elapsed; + + /* Only process if socket is not in use. */ + bh_lock_sock(sk); + if (sk->lock.users) { + /* Try again later. */ + tcp_reset_keepalive_timer (sk, HZ/20); + goto out; + } + + if (sk->state == TCP_FIN_WAIT2 && sk->dead) + goto death; + + if (!sk->keepopen) + goto out; + + elapsed = sysctl_tcp_keepalive_time; + if (!((1<state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2))) + goto resched; + + elapsed = tcp_time_stamp - tp->rcv_tstamp; + + if (elapsed >= sysctl_tcp_keepalive_time) { + if (tp->probes_out > sysctl_tcp_keepalive_probes) { + tcp_write_err(sk, 1); + goto out; + } + tp->probes_out++; + tp->pending = TIME_KEEPOPEN; + tcp_write_wakeup(sk); + /* Randomize to avoid synchronization */ + elapsed = (TCP_KEEPALIVE_PERIOD>>1) + (net_random()%TCP_KEEPALIVE_PERIOD); + } else { + /* It is tp->rcv_tstamp + sysctl_tcp_keepalive_time */ + elapsed = sysctl_tcp_keepalive_time - elapsed; + } + +resched: + tcp_reset_keepalive_timer (sk, elapsed); + goto out; + +death: + tcp_set_state(sk, TCP_CLOSE); + tcp_clear_xmit_timers(sk); + tcp_done(sk); + +out: + bh_unlock_sock(sk); + sock_put(sk); } diff -u --recursive --new-file v2.3.14/linux/net/ipv4/timer.c linux/net/ipv4/timer.c --- v2.3.14/linux/net/ipv4/timer.c Wed May 26 18:14:38 1999 +++ linux/net/ipv4/timer.c Wed Dec 31 16:00:00 1969 @@ -1,132 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * TIMER - implementation of software timers for IP. - * - * Version: $Id: timer.c,v 1.16 1999/05/27 00:37:39 davem Exp $ - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * Fred Baumgarten, - * Florian La Roche, - * - * Fixes: - * Alan Cox : To avoid destroying a wait queue as we use it - * we defer destruction until the destroy timer goes - * off. - * Alan Cox : Destroy socket doesn't write a status value to the - * socket buffer _AFTER_ freeing it! Also sock ensures - * the socket will get removed BEFORE this is called - * otherwise if the timer TIME_DESTROY occurs inside - * of inet_bh() with this socket being handled it goes - * BOOM! Have to stop timer going off if net_bh is - * active or the destroy causes crashes. - * Alan Cox : Cleaned up unused code. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void net_delete_timer (struct sock *t) -{ - if(t->timer.prev) - del_timer (&t->timer); - t->timeout = 0; -} - -void net_reset_timer (struct sock *t, int timeout, unsigned long len) -{ - t->timeout = timeout; - mod_timer(&t->timer, jiffies+len); -} - -/* Now we will only be called whenever we need to do - * something, but we must be sure to process all of the - * sockets that need it. - */ -void net_timer (unsigned long data) -{ - struct sock *sk = (struct sock *) data; - int why = sk->timeout; - - /* Only process if socket is not in use. */ - bh_lock_sock(sk); - if (sk->lock.users) { - /* Try again later. */ - mod_timer(&sk->timer, jiffies+HZ/20); - bh_unlock_sock(sk); - return; - } - - /* Always see if we need to send an ack. */ - if (sk->tp_pinfo.af_tcp.delayed_acks && !sk->zapped) { - sk->prot->read_wakeup (sk); - if (!sk->dead) - sk->data_ready(sk,0); - } - - /* Now we need to figure out why the socket was on the timer. */ - switch (why) { - case TIME_DONE: - /* If the socket hasn't been closed off, re-try a bit later. */ - if (!sk->dead) { - net_reset_timer(sk, TIME_DONE, TCP_DONE_TIME); - break; - } - - if (sk->state != TCP_CLOSE) { - printk (KERN_DEBUG "non CLOSE socket in time_done\n"); - break; - } - destroy_sock(sk); - return; - - case TIME_DESTROY: - /* We've waited for a while for all the memory associated with - * the socket to be freed. - */ - destroy_sock(sk); - return; - - case TIME_CLOSE: - /* We've waited long enough, close the socket. */ - tcp_set_state(sk, TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); - net_reset_timer (sk, TIME_DONE, TCP_DONE_TIME); - break; - - default: - /* I want to see these... */ - printk ("net_timer: timer expired - reason %d is unknown\n", why); - break; - } - - /* We only need to unlock if the socket was not destroyed. */ - bh_unlock_sock(sk); -} - diff -u --recursive --new-file v2.3.14/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.3.14/linux/net/ipv4/udp.c Wed Aug 18 11:38:48 1999 +++ linux/net/ipv4/udp.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.71 1999/07/02 11:26:33 davem Exp $ + * Version: $Id: udp.c,v 1.74 1999/08/20 11:06:12 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -113,6 +113,7 @@ #include #include #include +#include #include /* @@ -122,13 +123,14 @@ struct udp_mib udp_statistics; struct sock *udp_hash[UDP_HTABLE_SIZE]; +rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; /* Shared by v4/v6 udp. */ int udp_port_rover = 0; static int udp_v4_get_port(struct sock *sk, unsigned short snum) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if (snum == 0) { int best_size_so_far, best, result, i; @@ -186,11 +188,11 @@ } } sk->num = snum; - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); return 0; fail: - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); return 1; } @@ -198,7 +200,7 @@ { struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)]; - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if ((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -206,20 +208,22 @@ sk->prot->inuse++; if(sk->prot->highestinuse < sk->prot->inuse) sk->prot->highestinuse = sk->prot->inuse; - SOCKHASH_UNLOCK_WRITE(); + sock_hold(sk); + write_unlock_bh(&udp_hash_lock); } static void udp_v4_unhash(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if (sk->pprev) { if (sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->prot->inuse--; + __sock_put(sk); } - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); } /* UDP is nearly always wildcards out the wazoo, it makes no sense to try @@ -232,7 +236,7 @@ int badness = -1; for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { - if((sk->num == hnum) && !(sk->dead && (sk->state == TCP_CLOSE))) { + if(sk->num == hnum) { int score = 0; if(sk->rcv_saddr) { if(sk->rcv_saddr != daddr) @@ -270,94 +274,14 @@ { struct sock *sk; - SOCKHASH_LOCK_READ(); + read_lock(&udp_hash_lock); sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); - SOCKHASH_UNLOCK_READ(); + if (sk) + sock_hold(sk); + read_unlock(&udp_hash_lock); return sk; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY -#define secondlist(hpnum, sk, fpass) \ -({ struct sock *s1; if(!(sk) && (fpass)--) \ - s1 = udp_hash[(hpnum) & (UDP_HTABLE_SIZE - 1)]; \ - else \ - s1 = (sk); \ - s1; \ -}) - -#define udp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \ - secondlist((hpnum), udp_hash[(hnum)&(UDP_HTABLE_SIZE-1)],(fpass)) - -#define udp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \ - secondlist((hpnum),(sk)->next,(fpass)) - -static struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr, - unsigned short rnum, unsigned long laddr, - struct net_device *dev, unsigned short pnum, - int dif) -{ - struct sock *s, *result = NULL; - int badness = -1; - u32 paddr = 0; - unsigned short hnum = ntohs(num); - unsigned short hpnum = ntohs(pnum); - int firstpass = 1; - - if(dev && dev->ip_ptr) { - struct in_device *idev = dev->ip_ptr; - - if(idev->ifa_list) - paddr = idev->ifa_list->ifa_local; - } - - SOCKHASH_LOCK_READ(); - for(s = udp_v4_proxy_loop_init(hnum, hpnum, s, firstpass); - s != NULL; - s = udp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) { - if(s->num == hnum || s->num == hpnum) { - int score = 0; - if(s->dead && (s->state == TCP_CLOSE)) - continue; - if(s->rcv_saddr) { - if((s->num != hpnum || s->rcv_saddr != paddr) && - (s->num != hnum || s->rcv_saddr != laddr)) - continue; - score++; - } - if(s->daddr) { - if(s->daddr != raddr) - continue; - score++; - } - if(s->dport) { - if(s->dport != rnum) - continue; - score++; - } - if(s->bound_dev_if) { - if(s->bound_dev_if != dif) - continue; - score++; - } - if(score == 4 && s->num == hnum) { - result = s; - break; - } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { - result = s; - badness = score; - } - } - } - SOCKHASH_UNLOCK_READ(); - return result; -} - -#undef secondlist -#undef udp_v4_proxy_loop_init -#undef udp_v4_proxy_loop_next - -#endif - static inline struct sock *udp_v4_mcast_next(struct sock *sk, unsigned short num, unsigned long raddr, @@ -369,7 +293,6 @@ unsigned short hnum = ntohs(num); for(; s; s = s->next) { if ((s->num != hnum) || - (s->dead && (s->state == TCP_CLOSE)) || (s->daddr && s->daddr!=raddr) || (s->dport != rnum && s->dport != 0) || (s->rcv_saddr && s->rcv_saddr != laddr) || @@ -423,7 +346,7 @@ err = EHOSTUNREACH; break; case ICMP_SOURCE_QUENCH: - return; + goto out; case ICMP_PARAMETERPROB: err = EPROTO; info = ntohl(skb->h.icmph->un.gateway)>>24; @@ -431,13 +354,13 @@ break; case ICMP_DEST_UNREACH: if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) { + if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) { err = EMSGSIZE; info = ntohs(skb->h.icmph->un.frag.mtu); harderr = 1; break; } - return; + goto out; } err = EHOSTUNREACH; if (code <= NR_ICMP_UNREACH) { @@ -460,20 +383,22 @@ * 4.1.3.3. After the comment above, that should be no surprise. */ - if (!harderr && !sk->ip_recverr) - return; + if (!harderr && !sk->protinfo.af_inet.recverr) + goto out; /* * 4.x BSD compatibility item. Break RFC1122 to * get BSD socket semantics. */ - if(sk->bsdism && sk->state!=TCP_ESTABLISHED) - return; + if(sk->bsdism && sk->state!=TCP_ESTABLISHED && !sk->protinfo.af_inet.recverr) + goto out; - if (sk->ip_recverr) + if (sk->protinfo.af_inet.recverr) ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); sk->err = err; sk->error_report(sk); +out: + sock_put(sk); } @@ -574,16 +499,6 @@ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_PROXY|MSG_NOSIGNAL)) - return -EINVAL; - if ((msg->msg_flags&MSG_PROXY) && !capable(CAP_NET_ADMIN)) - return -EPERM; -#else - if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL)) - return -EINVAL; -#endif - /* * Get and verify the address. */ @@ -592,8 +507,12 @@ struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; if (msg->msg_namelen < sizeof(*usin)) return -EINVAL; - if (usin->sin_family != AF_INET) - return -EINVAL; + if (usin->sin_family != AF_INET) { + if (usin->sin_family != AF_UNSPEC) + return -EINVAL; + if (net_ratelimit()) + printk("Remind Kuznetsov, he has to repair %s eventually\n", current->comm); + } ufh.daddr = usin->sin_addr.s_addr; ufh.uh.dest = usin->sin_port; @@ -609,27 +528,8 @@ */ connected = 1; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (msg->msg_flags&MSG_PROXY) { - /* - * We map the first 8 bytes of a second sockaddr_in - * into the last 8 (unused) bytes of a sockaddr_in. - */ - struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name; - from = (struct sockaddr_in *)&from->sin_zero; - if (from->sin_family != AF_INET) - return -EINVAL; - ipc.addr = from->sin_addr.s_addr; - ufh.uh.source = from->sin_port; - if (ipc.addr == 0) - ipc.addr = sk->saddr; - connected = 0; - } else -#endif - { - ipc.addr = sk->saddr; - ufh.uh.source = sk->sport; - } + ipc.addr = sk->saddr; + ufh.uh.source = sk->sport; ipc.opt = NULL; ipc.oif = sk->bound_dev_if; @@ -642,7 +542,7 @@ connected = 0; } if (!ipc.opt) - ipc.opt = sk->opt; + ipc.opt = sk->protinfo.af_inet.opt; ufh.saddr = ipc.addr; ipc.addr = daddr = ufh.daddr; @@ -653,7 +553,7 @@ daddr = ipc.opt->faddr; connected = 0; } - tos = RT_TOS(sk->ip_tos); + tos = RT_TOS(sk->protinfo.af_inet.tos); if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || (ipc.opt && ipc.opt->is_strictroute)) { tos |= RTO_ONLINK; @@ -662,29 +562,31 @@ if (MULTICAST(daddr)) { if (!ipc.oif) - ipc.oif = sk->ip_mc_index; + ipc.oif = sk->protinfo.af_inet.mc_index; if (!ufh.saddr) - ufh.saddr = sk->ip_mc_addr; + ufh.saddr = sk->protinfo.af_inet.mc_addr; connected = 0; } if (connected) - rt = (struct rtable*)dst_clone(sk->dst_cache); + rt = (struct rtable*)sk_dst_check(sk, 0); if (rt == NULL) { - err = ip_route_output(&rt, daddr, ufh.saddr, -#ifdef CONFIG_IP_TRANSPARENT_PROXY - (msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) | -#endif - tos, ipc.oif); - if (err) + err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); + if (err) goto out; err = -EACCES; if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) goto out; + if (connected) + sk_dst_set(sk, dst_clone(&rt->u.dst)); } + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + ufh.saddr = rt->rt_src; if (!ipc.addr) ufh.daddr = ipc.addr = rt->rt_dst; @@ -712,6 +614,13 @@ return len; } return err; + +do_confirm: + dst_confirm(&rt->u.dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; } /* @@ -736,9 +645,7 @@ unsigned long amount; amount = 0; - /* N.B. Is this interrupt safe?? - -> Yes. Interrupts do not remove skbs. --ANK (980725) - */ + spin_lock_irq(&sk->receive_queue.lock); skb = skb_peek(&sk->receive_queue); if (skb != NULL) { /* @@ -748,6 +655,7 @@ */ amount = skb->len - sizeof(struct udphdr); } + spin_unlock_irq(&sk->receive_queue.lock); return put_user(amount, (int *)arg); } @@ -832,25 +740,8 @@ sin->sin_family = AF_INET; sin->sin_port = skb->h.uh->source; sin->sin_addr.s_addr = skb->nh.iph->saddr; -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (flags&MSG_PROXY) - { - /* - * We map the first 8 bytes of a second sockaddr_in - * into the last 8 (unused) bytes of a sockaddr_in. - * This _is_ ugly, but it's the only way to do it - * easily, without adding system calls. - */ - struct sockaddr_in *sinto = - (struct sockaddr_in *) sin->sin_zero; - - sinto->sin_family = AF_INET; - sinto->sin_port = skb->h.uh->dest; - sinto->sin_addr.s_addr = skb->nh.iph->daddr; - } -#endif } - if (sk->ip_cmsg_flags) + if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); err = copied; @@ -862,6 +753,20 @@ #ifdef CONFIG_UDP_DELAY_CSUM csum_copy_err: udp_statistics.UdpInErrors++; + + /* Clear queue. */ + if (flags&MSG_PEEK) { + int clear = 0; + spin_lock_irq(&sk->receive_queue.lock); + if (skb == skb_peek(&sk->receive_queue)) { + __skb_unlink(skb, &sk->receive_queue); + clear = 1; + } + spin_unlock_irq(&sk->receive_queue.lock); + if (clear) + kfree_skb(skb); + } + skb_free_datagram(sk, skb); /* @@ -882,26 +787,13 @@ if (addr_len < sizeof(*usin)) return -EINVAL; - /* - * 1003.1g - break association. - */ - - if (usin->sin_family==AF_UNSPEC) - { - sk->saddr=INADDR_ANY; - sk->rcv_saddr=INADDR_ANY; - sk->daddr=INADDR_ANY; - sk->state = TCP_CLOSE; - return 0; - } - - if (usin->sin_family && usin->sin_family != AF_INET) + if (usin->sin_family != AF_INET) return -EAFNOSUPPORT; - dst_release(xchg(&sk->dst_cache, NULL)); + sk_dst_reset(sk); err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr, - sk->ip_tos|sk->localroute, sk->bound_dev_if); + sk->protinfo.af_inet.tos|sk->localroute, sk->bound_dev_if); if (err) return err; if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) { @@ -916,20 +808,27 @@ sk->dport = usin->sin_port; sk->state = TCP_ESTABLISHED; - sk->dst_cache = &rt->u.dst; + sk_dst_set(sk, &rt->u.dst); return(0); } +int udp_disconnect(struct sock *sk, int flags) +{ + /* + * 1003.1g - break association. + */ + + sk->state = TCP_CLOSE; + sk->rcv_saddr = 0; + sk->daddr = 0; + sk->dport = 0; + sk_dst_reset(sk); + return 0; +} static void udp_close(struct sock *sk, long timeout) { - bh_lock_sock(sk); - - /* See for explanation: raw_close in ipv4/raw.c */ - sk->state = TCP_CLOSE; - udp_v4_unhash(sk); - sk->dead = 1; - destroy_sock(sk); + inet_sock_release(sk); } static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) @@ -980,6 +879,7 @@ struct sock *sk; int dif; + read_lock(&udp_hash_lock); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, dif); @@ -1000,33 +900,10 @@ } while(sknext); } else kfree_skb(skb); + read_unlock(&udp_hash_lock); return 0; } -#ifdef CONFIG_IP_TRANSPARENT_PROXY -/* - * Check whether a received UDP packet might be for one of our - * sockets. - */ - -int udp_chkaddr(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4); - struct sock *sk; - - sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev->ifindex); - if (!sk) - return 0; - - /* 0 means accept all LOCAL addresses here, not all the world... */ - if (sk->rcv_saddr == 0) - return 0; - - return 1; -} -#endif - static int udp_checksum_verify(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, u32 saddr, u32 daddr, int full_csum_deferred) @@ -1068,11 +945,6 @@ u32 daddr = skb->nh.iph->daddr; /* - * First time through the loop.. Do all the setup stuff - * (including finding out the socket we go to etc) - */ - - /* * Get the header. */ @@ -1108,26 +980,18 @@ return udp_v4_mcast_deliver(skb, uh, saddr, daddr); } -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (IPCB(skb)->redirport) - sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source, - daddr, skb->dev, IPCB(skb)->redirport, - skb->dev->ifindex); - else -#endif sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); if (sk == NULL) { -#ifdef CONFIG_UDP_DELAY_CSUM - if (skb->ip_summed != CHECKSUM_UNNECESSARY && - (unsigned short)csum_fold(csum_partial((char*)uh, ulen, skb->csum))) + /* No socket. Drop packet silently, if checksum is wrong */ + if (udp_checksum_verify(skb, uh, ulen, saddr, daddr, 0)) goto csum_error; -#endif + udp_statistics.UdpNoPorts++; icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* - * Hmm. We got an UDP broadcast to a port to which we + * Hmm. We got an UDP packet to a port to which we * don't wanna listen. Ignore it. */ kfree_skb(skb); @@ -1139,10 +1003,13 @@ #else (sk->no_check & UDP_CSUM_NORCV) != 0 #endif - )) + )) { + sock_put(sk); goto csum_error; + } udp_deliver(sk, skb); + __sock_put(sk); return 0; csum_error: @@ -1175,12 +1042,13 @@ timer_active = (sp->timer.prev != NULL) ? 2 : 0; timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src, srcp, dest, destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + sp->socket->inode->i_uid, 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) @@ -1195,7 +1063,7 @@ " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout inode"); pos = 128; - SOCKHASH_LOCK_READ(); + read_lock(&udp_hash_lock); for (i = 0; i < UDP_HTABLE_SIZE; i++) { struct sock *sk; @@ -1212,7 +1080,7 @@ } } out: - SOCKHASH_UNLOCK_READ(); + read_unlock(&udp_hash_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; @@ -1226,6 +1094,7 @@ struct proto udp_prot = { udp_close, /* close */ udp_connect, /* connect */ + udp_disconnect, /* disconnect */ NULL, /* accept */ NULL, /* retransmit */ NULL, /* write_wakeup */ diff -u --recursive --new-file v2.3.14/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.3.14/linux/net/ipv6/addrconf.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/addrconf.c Mon Aug 23 10:01:02 1999 @@ -4,8 +4,9 @@ * * Authors: * Pedro Roque + * Alexey Kuznetsov * - * $Id: addrconf.c,v 1.50 1999/06/09 10:11:09 davem Exp $ + * $Id: addrconf.c,v 1.52 1999/08/20 11:06:14 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -69,17 +70,17 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p); #endif -/* - * Configured unicast address list - */ -static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; +int inet6_dev_count; +int inet6_ifa_count; /* - * AF_INET6 device list + * Configured unicast address hash table */ -static struct inet6_dev *inet6_dev_lst[IN6_ADDR_HSIZE]; +static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; +static rwlock_t addrconf_hash_lock = RW_LOCK_UNLOCKED; -static atomic_t addr_list_lock = ATOMIC_INIT(0); +/* Protects inet6 devices */ +rwlock_t addrconf_lock = RW_LOCK_UNLOCKED; void addrconf_verify(unsigned long); @@ -88,32 +89,6 @@ 0, 0, addrconf_verify }; -/* These locks protect only against address deletions, - but not against address adds or status updates. - It is OK. The only race is when address is selected, - which becomes invalid immediately after selection. - It is harmless, because this address could be already invalid - several usecs ago. - - Its important, that: - - 1. The result of inet6_add_addr() is used only inside lock - or from bh_atomic context. - - 2. The result of ipv6_chk_addr() is not used outside of bh protected context. - */ - -static __inline__ void addrconf_lock(void) -{ - atomic_inc(&addr_list_lock); - synchronize_bh(); -} - -static __inline__ void addrconf_unlock(void) -{ - atomic_dec(&addr_list_lock); -} - static int addrconf_ifdown(struct net_device *dev, int how); static void addrconf_dad_start(struct inet6_ifaddr *ifp); @@ -206,10 +181,64 @@ return IPV6_ADDR_RESERVED; } +static void addrconf_del_timer(struct inet6_ifaddr *ifp) +{ + if (del_timer(&ifp->timer)) + __in6_ifa_put(ifp); +} + +enum addrconf_timer_t +{ + AC_NONE, + AC_DAD, + AC_RS, +}; + +static void addrconf_mod_timer(struct inet6_ifaddr *ifp, + enum addrconf_timer_t what, + unsigned long when) +{ + if (!del_timer(&ifp->timer)) + in6_ifa_hold(ifp); + + switch (what) { + case AC_DAD: + ifp->timer.function = addrconf_dad_timer; + break; + case AC_RS: + ifp->timer.function = addrconf_rs_timer; + break; + default: + } + ifp->timer.expires = jiffies + when; + add_timer(&ifp->timer); +} + + +/* Nobody refers to this device, we may destroy it. */ + +void in6_dev_finish_destroy(struct inet6_dev *idev) +{ + struct net_device *dev = idev->dev; + BUG_TRAP(idev->addr_list==NULL); + BUG_TRAP(idev->mc_list==NULL); +#ifdef NET_REFCNT_DEBUG + printk(KERN_DEBUG "in6_dev_finish_destroy: %s\n", dev ? dev->name : "NIL"); +#endif + dev_put(dev); + if (!idev->dead) { + printk("Freeing alive inet6 device %p\n", idev); + return; + } + inet6_dev_count--; + kfree(idev); +} + static struct inet6_dev * ipv6_add_dev(struct net_device *dev) { - struct inet6_dev *ndev, **bptr, *iter; - int hash; + struct inet6_dev *ndev; + + ASSERT_RTNL(); if (dev->mtu < IPV6_MIN_MTU) return NULL; @@ -219,6 +248,7 @@ if (ndev) { memset(ndev, 0, sizeof(struct inet6_dev)); + ndev->lock = RW_LOCK_UNLOCKED; ndev->dev = dev; memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); ndev->cnf.mtu6 = dev->mtu; @@ -228,19 +258,20 @@ kfree(ndev); return NULL; } + inet6_dev_count++; + /* We refer to the device */ + dev_hold(dev); + + write_lock_bh(&addrconf_lock); + dev->ip6_ptr = ndev; + /* One reference from device */ + in6_dev_hold(ndev); + write_unlock_bh(&addrconf_lock); + #ifdef CONFIG_SYSCTL neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6"); addrconf_sysctl_register(ndev, &ndev->cnf); #endif - hash = ipv6_devindex_hash(dev->ifindex); - bptr = &inet6_dev_lst[hash]; - iter = *bptr; - - for (; iter; iter = iter->next) - bptr = &iter->next; - - *bptr = ndev; - } return ndev; } @@ -249,9 +280,10 @@ { struct inet6_dev *idev; - if ((idev = ipv6_get_idev(dev)) == NULL) { - idev = ipv6_add_dev(dev); - if (idev == NULL) + ASSERT_RTNL(); + + if ((idev = __in6_dev_get(dev)) == NULL) { + if ((idev = ipv6_add_dev(dev)) == NULL) return NULL; if (dev->flags&IFF_UP) ipv6_mc_up(idev); @@ -261,33 +293,48 @@ static void addrconf_forward_change(struct inet6_dev *idev) { - int i; + struct net_device *dev; if (idev) return; - for (i = 0; i < IN6_ADDR_HSIZE; i++) { - for (idev = inet6_dev_lst[i]; idev; idev = idev->next) + read_lock(&dev_base_lock); + for (dev=dev_base; dev; dev=dev->next) { + read_lock(&addrconf_lock); + idev = __in6_dev_get(dev); + if (idev) idev->cnf.forwarding = ipv6_devconf.forwarding; + read_unlock(&addrconf_lock); } + read_unlock(&dev_base_lock); } -struct inet6_dev * ipv6_get_idev(struct net_device *dev) +/* Nobody refers to this ifaddr, destroy it */ + +void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) { - struct inet6_dev *idev; - int hash; + BUG_TRAP(ifp->if_next==NULL); + BUG_TRAP(ifp->lst_next==NULL); + printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); + + in6_dev_put(ifp->idev); - hash = ipv6_devindex_hash(dev->ifindex); + if (del_timer(&ifp->timer)) + printk("Timer is still running, when freeing ifa=%p\n", ifp); - for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) { - if (idev->dev == dev) - return idev; + if (!ifp->dead) { + printk("Freeing alive inet6 address %p\n", ifp); + return; } - return NULL; + inet6_ifa_count--; + kfree(ifp); } +/* On success it returns ifp with increased reference count */ + static struct inet6_ifaddr * -ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int scope) +ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen, + int scope, unsigned flags) { struct inet6_ifaddr *ifa; int hash; @@ -300,70 +347,90 @@ } memset(ifa, 0, sizeof(struct inet6_ifaddr)); - memcpy(&ifa->addr, addr, sizeof(struct in6_addr)); + ipv6_addr_copy(&ifa->addr, addr); + spin_lock_init(&ifa->lock); init_timer(&ifa->timer); ifa->timer.data = (unsigned long) ifa; ifa->scope = scope; + ifa->prefix_len = pfxlen; + ifa->flags = flags | IFA_F_TENTATIVE; + + read_lock(&addrconf_lock); + if (idev->dead) { + read_unlock(&addrconf_lock); + kfree(ifa); + return NULL; + } + + inet6_ifa_count++; ifa->idev = idev; + in6_dev_hold(idev); + /* For caller */ + in6_ifa_hold(ifa); - /* Add to list. */ + /* Add to big hash table */ hash = ipv6_addr_hash(addr); + write_lock_bh(&addrconf_hash_lock); ifa->lst_next = inet6_addr_lst[hash]; inet6_addr_lst[hash] = ifa; + in6_ifa_hold(ifa); + write_unlock_bh(&addrconf_hash_lock); + write_lock_bh(&idev->lock); /* Add to inet6_dev unicast addr list. */ ifa->if_next = idev->addr_list; idev->addr_list = ifa; + in6_ifa_hold(ifa); + write_unlock_bh(&idev->lock); + read_unlock(&addrconf_lock); return ifa; } +/* This function wants to get referenced ifp and releases it before return */ + static void ipv6_del_addr(struct inet6_ifaddr *ifp) { - struct inet6_ifaddr *iter, **back; + struct inet6_ifaddr *ifa, **ifap; + struct inet6_dev *idev = ifp->idev; int hash; - if (atomic_read(&addr_list_lock)) { - ifp->flags |= ADDR_INVALID; - ipv6_ifa_notify(RTM_DELADDR, ifp); - return; - } - hash = ipv6_addr_hash(&ifp->addr); - iter = inet6_addr_lst[hash]; - back = &inet6_addr_lst[hash]; - - for (; iter; iter = iter->lst_next) { - if (iter == ifp) { - *back = ifp->lst_next; - synchronize_bh(); + ifp->dead = 1; - ifp->lst_next = NULL; + write_lock_bh(&addrconf_hash_lock); + for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; + ifap = &ifa->lst_next) { + if (ifa == ifp) { + *ifap = ifa->lst_next; + __in6_ifa_put(ifp); + ifa->lst_next = NULL; break; } - back = &(iter->lst_next); } + write_unlock_bh(&addrconf_hash_lock); - iter = ifp->idev->addr_list; - back = &ifp->idev->addr_list; - - for (; iter; iter = iter->if_next) { - if (iter == ifp) { - *back = ifp->if_next; - synchronize_bh(); - - ifp->if_next = NULL; + write_lock_bh(&idev->lock); + for (ifap = &idev->addr_list; (ifa=*ifap) != NULL; + ifap = &ifa->if_next) { + if (ifa == ifp) { + *ifap = ifa->if_next; + __in6_ifa_put(ifp); + ifa->if_next = NULL; break; } - back = &(iter->if_next); } + write_unlock_bh(&idev->lock); ipv6_ifa_notify(RTM_DELADDR, ifp); - - kfree(ifp); + + + addrconf_del_timer(ifp); + + in6_ifa_put(ifp); } /* @@ -381,15 +448,13 @@ struct inet6_ifaddr *ifp = NULL; struct inet6_ifaddr *match = NULL; struct net_device *dev = NULL; + struct inet6_dev *idev; struct rt6_info *rt; int err; - int i; rt = (struct rt6_info *) dst; if (rt) dev = rt->rt6i_dev; - - addrconf_lock(); scope = ipv6_addr_scope(daddr); if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) { @@ -406,27 +471,31 @@ */ if (dev) { - struct inet6_dev *idev; - int hash; - if (dev->flags & IFF_LOOPBACK) scope = IFA_HOST; - hash = ipv6_devindex_hash(dev->ifindex); - for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) { - if (idev->dev == dev) { - for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->scope == scope) { - if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS))) - goto out; + read_lock(&addrconf_lock); + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { + if (ifp->scope == scope) { + if (!(ifp->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))) { + in6_ifa_hold(ifp); + read_unlock_bh(&idev->lock); + read_unlock(&addrconf_lock); + goto out; + } - if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS))) - match = ifp; + if (!match && !(ifp->flags & IFA_F_TENTATIVE)) { + match = ifp; + in6_ifa_hold(ifp); } } - break; } + read_unlock_bh(&idev->lock); } + read_unlock(&addrconf_lock); } if (scope == IFA_LINK) @@ -436,85 +505,126 @@ * dev == NULL or search failed for specified dev */ - for (i=0; i < IN6_ADDR_HSIZE; i++) { - for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { - if (ifp->scope == scope) { - if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS))) - goto out; + read_lock(&dev_base_lock); + read_lock(&addrconf_lock); + for (dev = dev_base; dev; dev=dev->next) { + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { + if (ifp->scope == scope) { + if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) { + in6_ifa_hold(ifp); + read_unlock_bh(&idev->lock); + goto out_unlock_base; + } - if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS))) - match = ifp; + if (!match && !(ifp->flags&IFA_F_TENTATIVE)) { + match = ifp; + in6_ifa_hold(ifp); + } + } } + read_unlock_bh(&idev->lock); } } +out_unlock_base: + read_unlock(&addrconf_lock); + read_unlock(&dev_base_lock); + out: - if (ifp == NULL) + if (ifp == NULL) { ifp = match; + match = NULL; + } - err = -ENETUNREACH; + err = -EADDRNOTAVAIL; if (ifp) { - memcpy(saddr, &ifp->addr, sizeof(struct in6_addr)); + ipv6_addr_copy(saddr, &ifp->addr); err = 0; + in6_ifa_put(ifp); } - addrconf_unlock(); + if (match) + in6_ifa_put(match); + return err; } int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) { - struct inet6_ifaddr *ifp = NULL; struct inet6_dev *idev; + int err = -EADDRNOTAVAIL; + + read_lock(&addrconf_lock); + if ((idev = __in6_dev_get(dev)) != NULL) { + struct inet6_ifaddr *ifp; - if ((idev = ipv6_get_idev(dev)) != NULL) { - addrconf_lock(); + read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->scope == IFA_LINK) { + if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { ipv6_addr_copy(addr, &ifp->addr); - addrconf_unlock(); - return 0; + err = 0; + break; } } - addrconf_unlock(); + read_unlock_bh(&idev->lock); } - return -EADDRNOTAVAIL; + read_unlock(&addrconf_lock); + return err; } -/* - * Retrieve the ifaddr struct from an v6 address - * Called from ipv6_rcv to check if the address belongs - * to the host. - */ - -struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int nd) +int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev) { struct inet6_ifaddr * ifp; - u8 hash; - unsigned flags = 0; + u8 hash = ipv6_addr_hash(addr); - if (!nd) - flags |= DAD_STATUS|ADDR_INVALID; + read_lock_bh(&addrconf_hash_lock); + for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { + if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && + !(ifp->flags&IFA_F_TENTATIVE)) { + if (dev == NULL || ifp->idev->dev == dev || + !(ifp->scope&(IFA_LINK|IFA_HOST))) + break; + } + } + read_unlock_bh(&addrconf_hash_lock); + return ifp != NULL; +} - addrconf_lock(); +struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev) +{ + struct inet6_ifaddr * ifp; + u8 hash = ipv6_addr_hash(addr); - hash = ipv6_addr_hash(addr); + read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && !(ifp->flags&flags)) { + if (ipv6_addr_cmp(&ifp->addr, addr) == 0) { if (dev == NULL || ifp->idev->dev == dev || - !(ifp->scope&(IFA_LINK|IFA_HOST))) + !(ifp->scope&(IFA_LINK|IFA_HOST))) { + in6_ifa_hold(ifp); break; + } } } + read_unlock_bh(&addrconf_hash_lock); - addrconf_unlock(); return ifp; } +/* Gets referenced address, destroys ifaddr */ + void addrconf_dad_failure(struct inet6_ifaddr *ifp) { printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); - del_timer(&ifp->timer); - ipv6_del_addr(ifp); + if (ifp->flags&IFA_F_PERMANENT) { + spin_lock_bh(&ifp->lock); + addrconf_del_timer(ifp); + ifp->flags |= IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); + in6_ifa_put(ifp); + } else + ipv6_del_addr(ifp); } @@ -648,6 +758,8 @@ { struct inet6_dev *idev; + ASSERT_RTNL(); + if ((idev = ipv6_find_idev(dev)) == NULL) return NULL; @@ -667,12 +779,7 @@ __u32 prefered_lft; int addr_type; unsigned long rt_expires; - struct inet6_dev *in6_dev = ipv6_get_idev(dev); - - if (in6_dev == NULL) { - printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name); - return; - } + struct inet6_dev *in6_dev; pinfo = (struct prefix_info *) opt; @@ -698,6 +805,13 @@ return; } + in6_dev = in6_dev_get(dev); + + if (in6_dev == NULL) { + printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name); + return; + } + /* * Two things going on here: * 1) Add routes for on-link prefixes @@ -720,6 +834,7 @@ if (rt->rt6i_flags&RTF_EXPIRES) { if (pinfo->onlink == 0 || valid_lft == 0) { ip6_del_rt(rt); + rt = NULL; } else { rt->rt6i_expires = rt_expires; } @@ -743,8 +858,10 @@ #ifdef CONFIG_IPV6_EUI64 if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); - if (ipv6_generate_eui64(addr.s6_addr + 8, dev)) + if (ipv6_generate_eui64(addr.s6_addr + 8, dev)) { + in6_dev_put(in6_dev); return; + } goto ok; } #endif @@ -757,20 +874,21 @@ } #endif printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len); + in6_dev_put(in6_dev); return; ok: - ifp = ipv6_chk_addr(&addr, dev, 1); - if ((ifp == NULL || (ifp->flags&ADDR_INVALID)) && valid_lft) { + ifp = ipv6_get_ifaddr(&addr, dev); - if (ifp == NULL) - ifp = ipv6_add_addr(in6_dev, &addr, addr_type & IPV6_ADDR_SCOPE_MASK); + if (ifp == NULL && valid_lft) { + ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, + addr_type&IPV6_ADDR_SCOPE_MASK, 0); - if (ifp == NULL) + if (ifp == NULL) { + in6_dev_put(in6_dev); return; - - ifp->prefix_len = pinfo->prefix_len; + } addrconf_dad_start(ifp); } @@ -781,16 +899,23 @@ } if (ifp) { - int event = 0; + int flags; + + spin_lock(&ifp->lock); ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; ifp->tstamp = jiffies; - if (ifp->flags & ADDR_INVALID) - event = RTM_NEWADDR; - ifp->flags &= ~(ADDR_DEPRECATED|ADDR_INVALID); - ipv6_ifa_notify(event, ifp); + flags = ifp->flags; + ifp->flags &= ~IFA_F_DEPRECATED; + spin_unlock(&ifp->lock); + + if (!(flags&IFA_F_TENTATIVE)) + ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ? + 0 : RTM_NEWADDR, ifp); + in6_ifa_put(ifp); } } + in6_dev_put(in6_dev); } /* @@ -810,7 +935,7 @@ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; - dev = dev_get_by_index(ireq.ifr6_ifindex); + dev = __dev_get_by_index(ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) @@ -840,7 +965,7 @@ if (err == 0) { err = -ENOBUFS; - if ((dev = dev_get(p.name)) == NULL) + if ((dev = __dev_get_by_name(p.name)) == NULL) goto err_exit; err = dev_open(dev); } @@ -860,8 +985,10 @@ struct inet6_dev *idev; struct net_device *dev; int scope; + + ASSERT_RTNL(); - if ((dev = dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(ifindex)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) @@ -872,15 +999,11 @@ scope = ipv6_addr_scope(pfx); - addrconf_lock(); - if ((ifp = ipv6_add_addr(idev, pfx, scope)) != NULL) { - ifp->prefix_len = plen; - ifp->flags |= ADDR_PERMANENT; + if ((ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT)) != NULL) { addrconf_dad_start(ifp); - addrconf_unlock(); + in6_ifa_put(ifp); return 0; } - addrconf_unlock(); return -ENOBUFS; } @@ -890,22 +1013,21 @@ struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; - int scope; - if ((dev = dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(ifindex)) == NULL) return -ENODEV; - if ((idev = ipv6_get_idev(dev)) == NULL) + if ((idev = __in6_dev_get(dev)) == NULL) return -ENXIO; - scope = ipv6_addr_scope(pfx); - - start_bh_atomic(); + read_lock_bh(&idev->lock); for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->scope == scope && ifp->prefix_len == plen && + if (ifp->prefix_len == plen && (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) { + in6_ifa_hold(ifp); + read_unlock_bh(&idev->lock); + ipv6_del_addr(ifp); - end_bh_atomic(); /* If the last address is deleted administratively, disable IPv6 on this interface. @@ -915,7 +1037,7 @@ return 0; } } - end_bh_atomic(); + read_unlock_bh(&idev->lock); return -EADDRNOTAVAIL; } @@ -961,6 +1083,8 @@ struct net_device *dev; int scope; + ASSERT_RTNL(); + memset(&addr, 0, sizeof(struct in6_addr)); memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); @@ -972,28 +1096,29 @@ } if (addr.s6_addr32[3]) { - addrconf_lock(); - ifp = ipv6_add_addr(idev, &addr, scope); + ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT); if (ifp) { - ifp->flags |= ADDR_PERMANENT; - ifp->prefix_len = 128; + spin_lock_bh(&ifp->lock); + ifp->flags &= ~IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); + in6_ifa_put(ifp); } - addrconf_unlock(); return; } - read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev->ip_ptr && (dev->flags & IFF_UP)) { - struct in_device * in_dev = dev->ip_ptr; + struct in_device * in_dev = __in_dev_get(dev); + if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; int flag = scope; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + int plen; + addr.s6_addr32[3] = ifa->ifa_local; - + if (ifa->ifa_scope == RT_SCOPE_LINK) continue; if (ifa->ifa_scope >= RT_SCOPE_HOST) { @@ -1001,22 +1126,23 @@ continue; flag |= IFA_HOST; } + if (idev->dev->flags&IFF_POINTOPOINT) + plen = 10; + else + plen = 96; - addrconf_lock(); - ifp = ipv6_add_addr(idev, &addr, flag); + ifp = ipv6_add_addr(idev, &addr, plen, flag, + IFA_F_PERMANENT); if (ifp) { - if (idev->dev->flags&IFF_POINTOPOINT) - ifp->prefix_len = 10; - else - ifp->prefix_len = 96; - ifp->flags |= ADDR_PERMANENT; + spin_lock_bh(&ifp->lock); + ifp->flags &= ~IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); + in6_ifa_put(ifp); } - addrconf_unlock(); } } } - read_unlock(&dev_base_lock); } static void init_loopback(struct net_device *dev) @@ -1027,6 +1153,8 @@ /* ::1 */ + ASSERT_RTNL(); + memset(&addr, 0, sizeof(struct in6_addr)); addr.s6_addr[15] = 1; @@ -1035,29 +1163,25 @@ return; } - addrconf_lock(); - ifp = ipv6_add_addr(idev, &addr, IFA_HOST); - + ifp = ipv6_add_addr(idev, &addr, 128, IFA_HOST, IFA_F_PERMANENT); if (ifp) { - ifp->flags |= ADDR_PERMANENT; - ifp->prefix_len = 128; + spin_lock_bh(&ifp->lock); + ifp->flags &= ~IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); + in6_ifa_put(ifp); } - addrconf_unlock(); } static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) { struct inet6_ifaddr * ifp; - addrconf_lock(); - ifp = ipv6_add_addr(idev, addr, IFA_LINK); + ifp = ipv6_add_addr(idev, addr, 10, IFA_LINK, IFA_F_PERMANENT); if (ifp) { - ifp->flags = ADDR_PERMANENT; - ifp->prefix_len = 10; addrconf_dad_start(ifp); + in6_ifa_put(ifp); } - addrconf_unlock(); } static void addrconf_dev_config(struct net_device *dev) @@ -1065,6 +1189,8 @@ struct in6_addr addr; struct inet6_dev * idev; + ASSERT_RTNL(); + if (dev->type != ARPHRD_ETHER) { /* Alas, we support only Ethernet autoconfiguration. */ return; @@ -1100,6 +1226,8 @@ { struct inet6_dev *idev; + ASSERT_RTNL(); + /* * Configure the tunnel with one of our IPv4 * addresses... we should configure all of @@ -1143,17 +1271,13 @@ addrconf_dev_config(dev); break; }; - -#ifdef CONFIG_IPV6_NETLINK - rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0); -#endif break; case NETDEV_CHANGEMTU: if (dev->mtu >= IPV6_MIN_MTU) { struct inet6_dev *idev; - if ((idev = ipv6_get_idev(dev)) == NULL) + if ((idev = __in6_dev_get(dev)) == NULL) break; idev->cnf.mtu6 = dev->mtu; rt6_mtu_change(dev, dev->mtu); @@ -1167,12 +1291,7 @@ /* * Remove all addresses from this interface. */ - if (addrconf_ifdown(dev, event != NETDEV_DOWN) == 0) { -#ifdef CONFIG_IPV6_NETLINK - rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0); -#endif - } - + addrconf_ifdown(dev, event != NETDEV_DOWN); break; case NETDEV_CHANGE: break; @@ -1183,102 +1302,114 @@ static int addrconf_ifdown(struct net_device *dev, int how) { - struct inet6_dev *idev, **bidev; + struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; - int i, hash; + int i; + + ASSERT_RTNL(); rt6_ifdown(dev); neigh_ifdown(&nd_tbl, dev); - idev = ipv6_get_idev(dev); + idev = __in6_dev_get(dev); if (idev == NULL) return -ENODEV; - start_bh_atomic(); - - /* Discard address list */ - - idev->addr_list = NULL; - - /* - * Clean addresses hash table + /* Step 1: remove reference to ipv6 device from parent device. + Do not dev_put! */ + if (how == 1) { + write_lock_bh(&addrconf_lock); + dev->ip6_ptr = NULL; + idev->dead = 1; + write_unlock_bh(&addrconf_lock); + } - for (i=0; i<16; i++) { + /* Step 2: clear hash table */ + for (i=0; iidev == idev) { *bifa = ifa->lst_next; - del_timer(&ifa->timer); - ipv6_ifa_notify(RTM_DELADDR, ifa); - kfree(ifa); + ifa->lst_next = NULL; + addrconf_del_timer(ifa); + in6_ifa_put(ifa); continue; } bifa = &ifa->lst_next; } + write_unlock_bh(&addrconf_hash_lock); } - /* Discard multicast list */ + /* Step 3: clear address list */ + + write_lock_bh(&idev->lock); + while ((ifa = idev->addr_list) != NULL) { + idev->addr_list = ifa->if_next; + ifa->if_next = NULL; + ifa->dead = 1; + addrconf_del_timer(ifa); + write_unlock_bh(&idev->lock); + + ipv6_ifa_notify(RTM_DELADDR, ifa); + in6_ifa_put(ifa); + + write_lock_bh(&idev->lock); + } + write_unlock_bh(&idev->lock); + + /* Step 4: Discard multicast list */ if (how == 1) ipv6_mc_destroy_dev(idev); else ipv6_mc_down(idev); - /* Delete device from device hash table (if unregistered) */ + /* Shot the device (if unregistered) */ if (how == 1) { - hash = ipv6_devindex_hash(dev->ifindex); - - for (bidev = &inet6_dev_lst[hash]; (idev=*bidev) != NULL; bidev = &idev->next) { - if (idev->dev == dev) { - *bidev = idev->next; - neigh_parms_release(&nd_tbl, idev->nd_parms); + neigh_parms_release(&nd_tbl, idev->nd_parms); #ifdef CONFIG_SYSCTL - addrconf_sysctl_unregister(&idev->cnf); + addrconf_sysctl_unregister(&idev->cnf); #endif - kfree(idev); - break; - } - } + in6_dev_put(idev); } - end_bh_atomic(); return 0; } - static void addrconf_rs_timer(unsigned long data) { - struct inet6_ifaddr *ifp; - - ifp = (struct inet6_ifaddr *) data; + struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; if (ifp->idev->cnf.forwarding) - return; + goto out; if (ifp->idev->if_flags & IF_RA_RCVD) { /* * Announcement received after solicitation * was sent */ - return; + goto out; } + spin_lock(&ifp->lock); if (ifp->probes++ <= ifp->idev->cnf.rtr_solicits) { struct in6_addr all_routers; + addrconf_mod_timer(ifp, AC_RS, + ifp->idev->cnf.rtr_solicit_interval); + spin_unlock(&ifp->lock); + ipv6_addr_all_routers(&all_routers); ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); - - ifp->timer.function = addrconf_rs_timer; - ifp->timer.expires = (jiffies + - ifp->idev->cnf.rtr_solicit_interval); - add_timer(&ifp->timer); } else { struct in6_rtmsg rtmsg; + spin_unlock(&ifp->lock); + printk(KERN_DEBUG "%s: no IPv6 routers present\n", ifp->idev->dev->name); @@ -1292,6 +1423,9 @@ ip6_route_add(&rtmsg); } + +out: + in6_ifa_put(ifp); } /* @@ -1306,49 +1440,53 @@ addrconf_join_solict(dev, &ifp->addr); - if (ifp->prefix_len != 128 && (ifp->flags&ADDR_PERMANENT)) + if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF); - if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) { - start_bh_atomic(); - ifp->flags &= ~DAD_INCOMPLETE; + net_srandom(ifp->addr.s6_addr32[3]); + rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1); + + spin_lock_bh(&ifp->lock); + + if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || + !(ifp->flags&IFA_F_TENTATIVE)) { + ifp->flags &= ~IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); + addrconf_dad_completed(ifp); - end_bh_atomic(); return; } - net_srandom(ifp->addr.s6_addr32[3]); - ifp->probes = ifp->idev->cnf.dad_transmits; - ifp->flags |= DAD_INCOMPLETE; + addrconf_mod_timer(ifp, AC_DAD, rand_num); - rand_num = net_random() % ifp->idev->cnf.rtr_solicit_delay; - - ifp->timer.function = addrconf_dad_timer; - ifp->timer.expires = jiffies + rand_num; - - add_timer(&ifp->timer); + spin_unlock_bh(&ifp->lock); } static void addrconf_dad_timer(unsigned long data) { - struct inet6_ifaddr *ifp; + struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; struct in6_addr unspec; struct in6_addr mcaddr; - ifp = (struct inet6_ifaddr *) data; - + spin_lock_bh(&ifp->lock); if (ifp->probes == 0) { /* * DAD was successful */ - ifp->flags &= ~DAD_INCOMPLETE; + ifp->flags &= ~IFA_F_TENTATIVE; + spin_unlock_bh(&ifp->lock); + addrconf_dad_completed(ifp); + + in6_ifa_put(ifp); return; } ifp->probes--; + addrconf_mod_timer(ifp, AC_DAD, ifp->idev->cnf.rtr_solicit_interval); + spin_unlock_bh(&ifp->lock); /* send a neighbour solicitation for our addr */ memset(&unspec, 0, sizeof(unspec)); @@ -1361,8 +1499,7 @@ ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec); #endif - ifp->timer.expires = jiffies + ifp->idev->cnf.rtr_solicit_interval; - add_timer(&ifp->timer); + in6_ifa_put(ifp); } static void addrconf_dad_completed(struct inet6_ifaddr *ifp) @@ -1393,12 +1530,11 @@ */ ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); + spin_lock_bh(&ifp->lock); ifp->probes = 1; - ifp->timer.function = addrconf_rs_timer; - ifp->timer.expires = (jiffies + - ifp->idev->cnf.rtr_solicit_interval); ifp->idev->if_flags |= IF_RS_SENT; - add_timer(&ifp->timer); + addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval); + spin_unlock_bh(&ifp->lock); } } @@ -1412,9 +1548,8 @@ off_t pos=0; off_t begin=0; - addrconf_lock(); - for (i=0; i < IN6_ADDR_HSIZE; i++) { + read_lock_bh(&addrconf_hash_lock); for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { int j; @@ -1436,13 +1571,15 @@ len=0; begin=pos; } - if(pos>offset+length) + if(pos>offset+length) { + read_unlock_bh(&addrconf_hash_lock); goto done; + } } + read_unlock_bh(&addrconf_hash_lock); } done: - addrconf_unlock(); *start=buffer+(offset-begin); len-=(offset-begin); @@ -1472,44 +1609,47 @@ unsigned long now = jiffies; int i; - if (atomic_read(&addr_list_lock)) { - addr_chk_timer.expires = jiffies + 1*HZ; - add_timer(&addr_chk_timer); - return; - } - for (i=0; i < IN6_ADDR_HSIZE; i++) { - for (ifp=inet6_addr_lst[i]; ifp;) { - if (ifp->flags & ADDR_INVALID) { - struct inet6_ifaddr *bp = ifp; - ifp= ifp->lst_next; - ipv6_del_addr(bp); + +restart: + write_lock(&addrconf_hash_lock); + for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { + unsigned long age; + + if (ifp->flags & IFA_F_PERMANENT) continue; - } - if (!(ifp->flags & ADDR_PERMANENT)) { - struct inet6_ifaddr *bp; - unsigned long age; - - age = (now - ifp->tstamp) / HZ; - - bp = ifp; - ifp= ifp->lst_next; - - if (age > bp->valid_lft) - ipv6_del_addr(bp); - else if (age > bp->prefered_lft) { - bp->flags |= ADDR_DEPRECATED; - ipv6_ifa_notify(0, bp); + + age = (now - ifp->tstamp) / HZ; + + if (age > ifp->valid_lft) { + in6_ifa_hold(ifp); + write_unlock(&addrconf_hash_lock); + ipv6_del_addr(ifp); + goto restart; + } else if (age > ifp->prefered_lft) { + int deprecate = 0; + + spin_lock(&ifp->lock); + if (!(ifp->flags&IFA_F_DEPRECATED)) { + deprecate = 1; + ifp->flags |= IFA_F_DEPRECATED; } + spin_unlock(&ifp->lock); - continue; + if (deprecate) { + in6_ifa_hold(ifp); + write_unlock(&addrconf_hash_lock); + + ipv6_ifa_notify(0, ifp); + in6_ifa_put(ifp); + goto restart; + } } - ifp = ifp->lst_next; } + write_unlock(&addrconf_hash_lock); } - addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY; - add_timer(&addr_chk_timer); + mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY); } #ifdef CONFIG_RTNETLINK @@ -1532,6 +1672,8 @@ return -EINVAL; pfx = RTA_DATA(rta[IFA_LOCAL-1]); } + if (pfx == NULL) + return -EINVAL; return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); } @@ -1554,6 +1696,8 @@ return -EINVAL; pfx = RTA_DATA(rta[IFA_LOCAL-1]); } + if (pfx == NULL) + return -EINVAL; return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); } @@ -1570,7 +1714,7 @@ ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET6; ifm->ifa_prefixlen = ifa->prefix_len; - ifm->ifa_flags = ifa->flags & ~ADDR_INVALID; + ifm->ifa_flags = ifa->flags; ifm->ifa_scope = RT_SCOPE_UNIVERSE; if (ifa->scope&IFA_HOST) ifm->ifa_scope = RT_SCOPE_HOST; @@ -1614,18 +1758,18 @@ continue; if (idx > s_idx) s_ip_idx = 0; - start_bh_atomic(); + read_lock_bh(&addrconf_hash_lock); for (ifa=inet6_addr_lst[idx], ip_idx = 0; ifa; ifa = ifa->lst_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if (inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) { - end_bh_atomic(); + read_unlock_bh(&addrconf_hash_lock); goto done; } } - end_bh_atomic(); + read_unlock_bh(&addrconf_hash_lock); } done: cb->args[0] = idx; @@ -1682,11 +1826,9 @@ ip6_rt_addr_add(&ifp->addr, ifp->idev->dev); break; case RTM_DELADDR: - start_bh_atomic(); addrconf_leave_solict(ifp->idev->dev, &ifp->addr); - if (ipv6_chk_addr(&ifp->addr, ifp->idev->dev, 0) == NULL) + if (!ipv6_chk_addr(&ifp->addr, ifp->idev->dev)) ip6_rt_addr_del(&ifp->addr, ifp->idev->dev); - end_bh_atomic(); break; } } @@ -1708,8 +1850,10 @@ if (valp != &ipv6_devconf.forwarding) { struct net_device *dev = dev_get_by_index(ctl->ctl_name); - if (dev) - idev = ipv6_get_idev(dev); + if (dev) { + idev = in6_dev_get(dev); + dev_put(dev); + } if (idev == NULL) return ret; } else @@ -1717,11 +1861,10 @@ addrconf_forward_change(idev); - if (*valp) { - start_bh_atomic(); + if (*valp) rt6_purge_dflt_routers(0); - end_bh_atomic(); - } + if (idev) + in6_dev_put(idev); } return ret; @@ -1845,7 +1988,7 @@ struct net_device *dev; /* This takes sense only during module load. */ - read_lock(&dev_base_lock); + rtnl_lock(); for (dev = dev_base; dev; dev = dev->next) { if (!(dev->flags&IFF_UP)) continue; @@ -1861,9 +2004,9 @@ /* Ignore all other */ } } - read_unlock(&dev_base_lock); + rtnl_unlock(); #endif - + #ifdef CONFIG_PROC_FS proc_net_register(&iface_proc_entry); #endif @@ -1883,6 +2026,7 @@ #ifdef MODULE void addrconf_cleanup(void) { + struct net_device *dev; struct inet6_dev *idev; struct inet6_ifaddr *ifa; int i; @@ -1895,25 +2039,23 @@ addrconf_sysctl_unregister(&ipv6_devconf); #endif - del_timer(&addr_chk_timer); + rtnl_lock(); /* * clean dev list. */ - for (i=0; i < IN6_ADDR_HSIZE; i++) { - struct inet6_dev *next; - for (idev = inet6_dev_lst[i]; idev; idev = next) { - next = idev->next; - addrconf_ifdown(idev->dev, 1); - } + for (dev=dev_base; dev; dev=dev->next) { + if ((idev = __in6_dev_get(dev)) == NULL) + continue; + addrconf_ifdown(dev, 1); } - start_bh_atomic(); /* - * clean addr_list + * Check hash table. */ + write_lock_bh(&addrconf_hash_lock); for (i=0; i < IN6_ADDR_HSIZE; i++) { for (ifa=inet6_addr_lst[i]; ifa; ) { struct inet6_ifaddr *bifa; @@ -1926,7 +2068,11 @@ */ } } - end_bh_atomic(); + write_unlock_bh(&addrconf_hash_lock); + + del_timer(&addr_chk_timer); + + rtnl_unlock(); #ifdef CONFIG_PROC_FS proc_net_unregister(iface_proc_entry.low_ino); diff -u --recursive --new-file v2.3.14/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.3.14/linux/net/ipv6/af_inet6.c Sat Jul 3 17:57:23 1999 +++ linux/net/ipv6/af_inet6.c Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.45 1999/07/02 11:26:38 davem Exp $ + * $Id: af_inet6.c,v 1.46 1999/08/20 11:06:16 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,16 @@ extern void ipv6_sysctl_unregister(void); #endif +atomic_t inet6_sock_nr; + +static void inet6_sock_destruct(struct sock *sk) +{ + inet_sock_destruct(sk); + + atomic_dec(&inet6_sock_nr); + MOD_DEC_USE_COUNT; +} + static int inet6_create(struct socket *sock, int protocol) { struct sock *sk; @@ -121,7 +132,7 @@ sock_init_data(sock, sk); - sk->destruct = NULL; + sk->destruct = inet6_sock_destruct; sk->zapped = 0; sk->family = PF_INET6; sk->protocol = protocol; @@ -130,7 +141,7 @@ sk->backlog_rcv = prot->backlog_rcv; sk->timer.data = (unsigned long)sk; - sk->timer.function = &net_timer; + sk->timer.function = &tcp_keepalive_timer; sk->net_pinfo.af_inet6.hop_limit = -1; sk->net_pinfo.af_inet6.mcast_hops = -1; @@ -140,15 +151,19 @@ /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. */ - sk->ip_ttl = 64; + sk->protinfo.af_inet.ttl = 64; + + sk->protinfo.af_inet.mc_loop = 1; + sk->protinfo.af_inet.mc_ttl = 1; + sk->protinfo.af_inet.mc_index = 0; + sk->protinfo.af_inet.mc_list = NULL; - sk->ip_mc_loop = 1; - sk->ip_mc_ttl = 1; - sk->ip_mc_index = 0; - sk->ip_mc_list = NULL; + atomic_inc(&inet6_sock_nr); + atomic_inc(&inet_sock_nr); + MOD_INC_USE_COUNT; if (sk->type==SOCK_RAW && protocol==IPPROTO_RAW) - sk->ip_hdrincl=1; + sk->protinfo.af_inet.hdrincl=1; if (sk->num) { /* It assumes that any protocol which allows @@ -162,11 +177,11 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - destroy_sock(sk); + sk->dead = 1; + inet_sock_release(sk); return(err); } } - MOD_INC_USE_COUNT; return(0); free_and_badtype: @@ -195,13 +210,10 @@ /* If the socket has its own bind function then use it. */ if(sk->prot->bind) return sk->prot->bind(sk, uaddr, addr_len); - - /* Check these errors (active socket, bad address length, double bind). */ - if ((sk->state != TCP_CLOSE) || - (addr_len < sizeof(struct sockaddr_in6)) || - (sk->num != 0)) + + if (addr_len < sizeof(struct sockaddr_in6)) return -EINVAL; - + addr_type = ipv6_addr_type(&addr->sin6_addr); if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) return -EINVAL; @@ -218,39 +230,54 @@ */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL) + if (!ipv6_chk_addr(&addr->sin6_addr, NULL)) return -EADDRNOTAVAIL; } } } + snum = ntohs(addr->sin6_port); + if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + lock_sock(sk); + + /* Check these errors (active socket, double bind). */ + if ((sk->state != TCP_CLOSE) || + (sk->num != 0)) { + release_sock(sk); + return -EINVAL; + } + sk->rcv_saddr = v4addr; sk->saddr = v4addr; - - memcpy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr, - sizeof(struct in6_addr)); + + ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr); if (!(addr_type & IPV6_ADDR_MULTICAST)) - memcpy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr, - sizeof(struct in6_addr)); - - snum = ntohs(addr->sin6_port); - if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) - return -EACCES; + ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr); /* Make sure we are allowed to bind here. */ - if(sk->prot->get_port(sk, snum) != 0) + if (sk->prot->get_port(sk, snum) != 0) { + sk->rcv_saddr = 0; + sk->saddr = 0; + memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, sizeof(struct in6_addr)); + memset(&sk->net_pinfo.af_inet6.saddr, 0, sizeof(struct in6_addr)); + + release_sock(sk); return -EADDRINUSE; + } sk->sport = ntohs(sk->num); sk->dport = 0; sk->daddr = 0; sk->prot->hash(sk); + release_sock(sk); - return(0); + return 0; } -static int inet6_release(struct socket *sock, struct socket *peer) +static int inet6_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -260,15 +287,7 @@ /* Free mc lists */ ipv6_sock_mc_close(sk); - /* Huh! MOD_DEC_USE_COUNT was here :-( - It is impossible by two reasons: socket destroy - may be delayed and inet_release may sleep and - return to nowhere then. It should be moved to - inet6_destroy_sock(), but we have no explicit constructor :-( - --ANK (980802) - */ - MOD_DEC_USE_COUNT; - return inet_release(sock, peer); + return inet_release(sock); } int inet6_destroy_sock(struct sock *sk) @@ -280,7 +299,7 @@ * Release destination entry */ - dst_release(xchg(&sk->dst_cache,NULL)); + sk_dst_reset(sk); /* Release rx options */ @@ -306,13 +325,12 @@ int *uaddr_len, int peer) { struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr; - struct sock *sk; + struct sock *sk = sock->sk; sin->sin6_family = AF_INET6; sin->sin6_flowinfo = 0; - sk = sock->sk; if (peer) { - if (!tcp_connected(sk->state)) + if (!sk->dport) return -ENOTCONN; sin->sin6_port = sk->dport; memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.daddr, @@ -397,7 +415,6 @@ struct proto_ops inet6_stream_ops = { PF_INET6, - sock_no_dup, inet6_release, inet6_bind, inet_stream_connect, /* ok */ @@ -412,13 +429,13 @@ inet_getsockopt, /* ok */ sock_no_fcntl, /* ok */ inet_sendmsg, /* ok */ - inet_recvmsg /* ok */ + inet_recvmsg, /* ok */ + sock_no_mmap }; struct proto_ops inet6_dgram_ops = { PF_INET6, - sock_no_dup, inet6_release, inet6_bind, inet_dgram_connect, /* ok */ @@ -433,7 +450,8 @@ inet_getsockopt, /* ok */ sock_no_fcntl, /* ok */ inet_sendmsg, /* ok */ - inet_recvmsg /* ok */ + inet_recvmsg, /* ok */ + sock_no_mmap, }; struct net_proto_family inet6_family_ops = { diff -u --recursive --new-file v2.3.14/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c --- v2.3.14/linux/net/ipv6/datagram.c Thu Apr 22 19:45:20 1999 +++ linux/net/ipv6/datagram.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: datagram.c,v 1.17 1999/04/22 10:07:40 davem Exp $ + * $Id: datagram.c,v 1.18 1999/08/20 11:06:17 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -158,7 +158,7 @@ ipv6_addr_set(&sin->sin6_addr, 0, 0, __constant_htonl(0xffff), skb->nh.iph->saddr); - if (sk->ip_cmsg_flags) + if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); } } @@ -269,11 +269,7 @@ } if (!ipv6_addr_any(&src_info->ipi6_addr)) { - struct inet6_ifaddr *ifp; - - ifp = ipv6_chk_addr(&src_info->ipi6_addr, NULL, 0); - - if (ifp == NULL) { + if (!ipv6_chk_addr(&src_info->ipi6_addr, NULL)) { err = -EINVAL; goto exit_f; } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c --- v2.3.14/linux/net/ipv6/icmp.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/icmp.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: icmp.c,v 1.22 1999/05/19 22:06:39 davem Exp $ + * $Id: icmp.c,v 1.24 1999/08/20 11:06:18 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -88,6 +88,42 @@ }; +static int icmpv6_xmit_holder = -1; + +static int icmpv6_xmit_lock_bh(void) +{ + if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) { + if (icmpv6_xmit_holder == smp_processor_id()) + return -EAGAIN; + spin_lock(&icmpv6_socket->sk->lock.slock); + } + icmpv6_xmit_holder = smp_processor_id(); + return 0; +} + +static __inline__ int icmpv6_xmit_lock(void) +{ + int ret; + local_bh_disable(); + ret = icmpv6_xmit_lock_bh(); + if (ret) + local_bh_enable(); + return ret; +} + +static void icmpv6_xmit_unlock_bh(void) +{ + icmpv6_xmit_holder = -1; + spin_unlock(&icmpv6_socket->sk->lock.slock); +} + +static __inline__ void icmpv6_xmit_unlock(void) +{ + icmpv6_xmit_unlock_bh(); + local_bh_enable(); +} + + /* * getfrag callback @@ -267,7 +303,7 @@ addr_type = ipv6_addr_type(&hdr->daddr); - if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0)) + if (ipv6_chk_addr(&hdr->daddr, skb->dev)) saddr = &hdr->daddr; /* @@ -319,8 +355,11 @@ fl.uli_u.icmpt.type = type; fl.uli_u.icmpt.code = code; - if (!icmpv6_xrlim_allow(sk, type, &fl)) - return; + if (icmpv6_xmit_lock()) + return; + + if (!icmpv6_xrlim_allow(sk, type, &fl)) + goto out; /* * ok. kick it. checksum will be provided by the @@ -341,7 +380,7 @@ if (len < 0) { printk(KERN_DEBUG "icmp: len problem\n"); - return; + goto out; } msg.len = len; @@ -351,6 +390,8 @@ if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) (&icmpv6_statistics.Icmp6OutDestUnreachs)[type-1]++; icmpv6_statistics.Icmp6OutMsgs++; +out: + icmpv6_xmit_unlock(); } static void icmpv6_echo_reply(struct sk_buff *skb) @@ -393,10 +434,15 @@ fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY; fl.uli_u.icmpt.code = 0; + if (icmpv6_xmit_lock_bh()) + return; + ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); icmpv6_statistics.Icmp6OutEchoReplies++; icmpv6_statistics.Icmp6OutMsgs++; + + icmpv6_xmit_unlock_bh(); } static void icmpv6_notify(struct sk_buff *skb, @@ -431,6 +477,7 @@ hash = nexthdr & (MAX_INET_PROTOS - 1); + read_lock(&inet6_protocol_lock); for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; ipprot != NULL; ipprot=(struct inet6_protocol *)ipprot->next) { @@ -440,16 +487,16 @@ if (ipprot->err_handler) ipprot->err_handler(skb, hdr, NULL, type, code, pb, info); } + read_unlock(&inet6_protocol_lock); - sk = raw_v6_htable[hash]; - - if (sk == NULL) - return; - - while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) { - rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); - sk = sk->next; + read_lock(&raw_v6_lock); + if ((sk = raw_v6_htable[hash]) != NULL) { + while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { + rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); + sk = sk->next; + } } + read_unlock(&raw_v6_lock); } /* @@ -615,7 +662,7 @@ sk = icmpv6_socket->sk; sk->allocation = GFP_ATOMIC; - sk->num = 256; /* Don't receive any data */ + sk->prot->unhash(sk); inet6_add_protocol(&icmpv6_protocol); diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c --- v2.3.14/linux/net/ipv6/ip6_fib.c Thu Apr 22 19:45:20 1999 +++ linux/net/ipv6/ip6_fib.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.17 1999/04/22 10:07:41 davem Exp $ + * $Id: ip6_fib.c,v 1.18 1999/08/20 11:06:19 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef CONFIG_PROC_FS #include @@ -35,12 +36,6 @@ #define RT6_DEBUG 2 #undef CONFIG_IPV6_SUBTREES -#if RT6_DEBUG >= 1 -#define BUG_TRAP(x) ({ if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } }) -#else -#define BUG_TRAP(x) do { ; } while (0) -#endif - #if RT6_DEBUG >= 3 #define RT6_TRACE(x...) printk(KERN_DEBUG x) #else @@ -49,6 +44,8 @@ struct rt6_statistics rt6_stats; +static kmem_cache_t * fib6_node_kmem; + enum fib_walk_state_t { #ifdef CONFIG_IPV6_SUBTREES @@ -67,6 +64,9 @@ void *arg; }; +rwlock_t fib6_walker_lock = RW_LOCK_UNLOCKED; + + #ifdef CONFIG_IPV6_SUBTREES #define FWS_INIT FWS_S #define SUBTREE(fn) ((fn)->subtree) @@ -210,18 +210,15 @@ { struct fib6_node *fn; - if ((fn = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC)) != NULL) { + if ((fn = kmem_cache_alloc(fib6_node_kmem, SLAB_ATOMIC)) != NULL) memset(fn, 0, sizeof(struct fib6_node)); - rt6_stats.fib_nodes++; - } return fn; } static __inline__ void node_free(struct fib6_node * fn) { - rt6_stats.fib_nodes--; - kfree(fn); + kmem_cache_free(fib6_node_kmem, fn); } static __inline__ void rt6_release(struct rt6_info *rt) @@ -297,7 +294,7 @@ } while (fn); /* - * We wlaked to the bottom of tree. + * We walked to the bottom of tree. * Create new leaf node without children. */ @@ -490,11 +487,8 @@ static __inline__ void fib6_start_gc(struct rt6_info *rt) { if (ip6_fib_timer.expires == 0 && - (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) { - del_timer(&ip6_fib_timer); - ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval; - add_timer(&ip6_fib_timer); - } + (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) + mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); } /* @@ -512,7 +506,7 @@ rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt); if (fn == NULL) - return -ENOMEM; + goto out; #ifdef CONFIG_IPV6_SUBTREES if (rt->rt6i_src.plen) { @@ -584,6 +578,7 @@ fib6_prune_clones(fn, rt); } +out: if (err) dst_free(&rt->u.dst); return err; @@ -845,6 +840,7 @@ } #endif + read_lock(&fib6_walker_lock); FOR_WALKERS(w) { if (child == NULL) { if (w->root == fn) { @@ -872,6 +868,7 @@ } } } + read_unlock(&fib6_walker_lock); node_free(fn); if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) @@ -896,6 +893,7 @@ rt6_stats.fib_rt_entries--; /* Adjust walkers */ + read_lock(&fib6_walker_lock); FOR_WALKERS(w) { if (w->state == FWS_C && w->leaf == rt) { RT6_TRACE("walker %p adjusted by delroute\n", w); @@ -904,6 +902,7 @@ w->state = FWS_U; } } + read_unlock(&fib6_walker_lock); rt->u.next = NULL; @@ -927,7 +926,7 @@ #if RT6_DEBUG >= 2 if (rt->u.dst.obsolete>0) { - BUG_TRAP(rt->u.dst.obsolete>0); + BUG_TRAP(rt->u.dst.obsolete<=0); return -EFAULT; } #endif @@ -1112,9 +1111,7 @@ c.func = func; c.arg = arg; - start_bh_atomic(); fib6_walk(&c.w); - end_bh_atomic(); } static int fib6_prune_clone(struct rt6_info *rt, void *arg) @@ -1151,7 +1148,7 @@ */ if (rt->rt6i_flags & RTF_CACHE) { - if (atomic_read(&rt->u.dst.use) == 0 && + if (atomic_read(&rt->u.dst.__refcnt) == 0 && (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) { RT6_TRACE("aging clone %p\n", rt); return -1; @@ -1175,24 +1172,45 @@ return 0; } +static spinlock_t fib6_gc_lock = SPIN_LOCK_UNLOCKED; + void fib6_run_gc(unsigned long dummy) { - if (dummy != ~0UL) + if (dummy != ~0UL) { + spin_lock_bh(&fib6_gc_lock); gc_args.timeout = (int)dummy; - else + } else { + local_bh_disable(); + if (!spin_trylock(&fib6_gc_lock)) { + mod_timer(&ip6_fib_timer, jiffies + HZ); + local_bh_enable(); + return; + } gc_args.timeout = ip6_rt_gc_interval; - + } gc_args.more = 0; - fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); - del_timer(&ip6_fib_timer); + write_lock_bh(&rt6_lock); + fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); + write_unlock_bh(&rt6_lock); - ip6_fib_timer.expires = 0; - if (gc_args.more) { - ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval; - add_timer(&ip6_fib_timer); + if (gc_args.more) + mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); + else { + del_timer(&ip6_fib_timer); + ip6_fib_timer.expires = 0; } + spin_unlock_bh(&fib6_gc_lock); +} + +__initfunc(void fib6_init(void)) +{ + if (!fib6_node_kmem) + fib6_node_kmem = kmem_cache_create("fib6_nodes", + sizeof(struct fib6_node), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); } #ifdef MODULE diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ip6_flowlabel.c linux/net/ipv6/ip6_flowlabel.c --- v2.3.14/linux/net/ipv6/ip6_flowlabel.c Fri Apr 23 18:39:47 1999 +++ linux/net/ipv6/ip6_flowlabel.c Mon Aug 23 10:01:02 1999 @@ -52,34 +52,37 @@ /* FL hash table lock: it protects only of GC */ -static atomic_t ip6_fl_lock = ATOMIC_INIT(0); +static rwlock_t ip6_fl_lock = RW_LOCK_UNLOCKED; -static __inline__ void fl_lock(void) -{ - atomic_inc(&ip6_fl_lock); - synchronize_bh(); -} +/* Big socket sock */ + +static rwlock_t ip6_sk_fl_lock = RW_LOCK_UNLOCKED; -static __inline__ void fl_unlock(void) + +static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label) { - atomic_dec(&ip6_fl_lock); + struct ip6_flowlabel *fl; + + for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { + if (fl->label == label) + return fl; + } + return NULL; } static struct ip6_flowlabel * fl_lookup(u32 label) { struct ip6_flowlabel *fl; - fl_lock(); - for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { - if (fl->label == label) { - atomic_inc(&fl->users); - break; - } - } - fl_unlock(); + read_lock_bh(&ip6_fl_lock); + fl = __fl_lookup(label); + if (fl) + atomic_inc(&fl->users); + read_unlock_bh(&ip6_fl_lock); return fl; } + static void fl_free(struct ip6_flowlabel *fl) { if (fl->opt) @@ -89,7 +92,6 @@ static void fl_release(struct ip6_flowlabel *fl) { - fl_lock(); fl->lastuse = jiffies; if (atomic_dec_and_test(&fl->users)) { unsigned long ttd = fl->lastuse + fl->linger; @@ -106,7 +108,6 @@ ip6_fl_gc_timer.expires = ttd; add_timer(&ip6_fl_gc_timer); } - fl_unlock(); } static void ip6_fl_gc(unsigned long dummy) @@ -115,11 +116,7 @@ unsigned long now = jiffies; unsigned long sched = 0; - if (atomic_read(&ip6_fl_lock)) { - ip6_fl_gc_timer.expires = now + HZ/10; - add_timer(&ip6_fl_gc_timer); - return; - } + write_lock(&ip6_fl_lock); for (i=0; i<=FL_HASH_MASK; i++) { struct ip6_flowlabel *fl, **flp; @@ -148,22 +145,22 @@ ip6_fl_gc_timer.expires = sched; add_timer(&ip6_fl_gc_timer); } + write_unlock(&ip6_fl_lock); } static int fl_intern(struct ip6_flowlabel *fl, __u32 label) { fl->label = label & IPV6_FLOWLABEL_MASK; - fl_lock(); + write_lock_bh(&ip6_fl_lock); if (label == 0) { for (;;) { fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; if (fl->label) { struct ip6_flowlabel *lfl; - lfl = fl_lookup(fl->label); + lfl = __fl_lookup(fl->label); if (lfl == NULL) break; - fl_release(lfl); } } } @@ -172,7 +169,7 @@ fl->next = fl_ht[FL_HASH(fl->label)]; fl_ht[FL_HASH(fl->label)] = fl; atomic_inc(&fl_size); - fl_unlock(); + write_unlock_bh(&ip6_fl_lock); return 0; } @@ -421,24 +418,29 @@ switch (freq.flr_action) { case IPV6_FL_A_PUT: + write_lock_bh(&ip6_sk_fl_lock); for (sflp = &np->ipv6_fl_list; (sfl=*sflp)!=NULL; sflp = &sfl->next) { if (sfl->fl->label == freq.flr_label) { if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) np->flow_label &= ~IPV6_FLOWLABEL_MASK; *sflp = sfl->next; - synchronize_bh(); + write_unlock_bh(&ip6_sk_fl_lock); fl_release(sfl->fl); kfree(sfl); return 0; } } + write_unlock_bh(&ip6_sk_fl_lock); return -ESRCH; case IPV6_FL_A_RENEW: + read_lock_bh(&ip6_sk_fl_lock); for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { if (sfl->fl->label == freq.flr_label) return fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); } + read_unlock_bh(&ip6_sk_fl_lock); + if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) { fl = fl_lookup(freq.flr_label); if (fl) { @@ -462,15 +464,19 @@ struct ip6_flowlabel *fl1 = NULL; err = -EEXIST; + read_lock_bh(&ip6_sk_fl_lock); for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { if (sfl->fl->label == freq.flr_label) { - if (freq.flr_flags&IPV6_FL_F_EXCL) + if (freq.flr_flags&IPV6_FL_F_EXCL) { + read_unlock_bh(&ip6_sk_fl_lock); goto done; + } fl1 = sfl->fl; atomic_inc(&fl->users); break; } } + read_unlock_bh(&ip6_sk_fl_lock); if (fl1 == NULL) fl1 = fl_lookup(freq.flr_label); @@ -496,10 +502,11 @@ fl1->linger = fl->linger; if ((long)(fl->expires - fl1->expires) > 0) fl1->expires = fl->expires; + write_lock_bh(&ip6_sk_fl_lock); sfl1->fl = fl1; sfl1->next = np->ipv6_fl_list; np->ipv6_fl_list = sfl1; - synchronize_bh(); + write_unlock_bh(&ip6_sk_fl_lock); fl_free(fl); return 0; @@ -556,7 +563,7 @@ len+= sprintf(buffer,"Label S Owner Users Linger Expires " "Dst Opt\n"); - fl_lock(); + read_lock_bh(&ip6_fl_lock); for (i=0; i<=FL_HASH_MASK; i++) { for (fl = fl_ht[i]; fl; fl = fl->next) { len+=sprintf(buffer+len,"%05X %-1d %-6d %-6d %-6d %-8ld ", @@ -585,7 +592,7 @@ *eof = 1; done: - fl_unlock(); + read_unlock_bh(&ip6_fl_lock); *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c --- v2.3.14/linux/net/ipv6/ip6_fw.c Mon Jul 5 20:03:14 1999 +++ linux/net/ipv6/ip6_fw.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fw.c,v 1.12 1999/06/09 08:29:32 davem Exp $ + * $Id: ip6_fw.c,v 1.14 1999/08/20 11:06:20 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,31 +60,34 @@ 0, RTN_ROOT|RTN_TL_ROOT, 0 }; +rwlock_t ip6_fw_lock = RW_LOCK_UNLOCKED; + + static void ip6_rule_add(struct ip6_fw_rule *rl) { struct ip6_fw_rule *next; - start_bh_atomic(); + write_lock_bh(&ip6_fw_lock); ip6_fw_rule_cnt++; next = &ip6_fw_rule_list; rl->next = next; rl->prev = next->prev; rl->prev->next = rl; next->prev = rl; - end_bh_atomic(); + write_unlock_bh(&ip6_fw_lock); } static void ip6_rule_del(struct ip6_fw_rule *rl) { struct ip6_fw_rule *next, *prev; - start_bh_atomic(); + write_lock_bh(&ip6_fw_lock); ip6_fw_rule_cnt--; next = rl->next; prev = rl->prev; next->prev = prev; prev->next = next; - end_bh_atomic(); + write_unlock_bh(&ip6_fw_lock); } static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void) diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c --- v2.3.14/linux/net/ipv6/ip6_input.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/ip6_input.c Mon Aug 23 10:01:02 1999 @@ -6,7 +6,7 @@ * Pedro Roque * Ian P. Morris * - * $Id: ip6_input.c,v 1.11 1998/08/26 12:04:59 davem Exp $ + * $Id: ip6_input.c,v 1.13 1999/08/20 11:06:21 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -48,6 +48,9 @@ ipv6_statistics.Ip6InReceives++; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + goto out; + /* Store incoming device index. When the packet will be queued, we cannot refer to skb->dev anymore. */ @@ -86,76 +89,11 @@ ipv6_statistics.Ip6InHdrErrors++; drop: kfree_skb(skb); +out: return 0; } /* - * 0 - deliver - * 1 - block - */ -static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) -{ - struct icmp6hdr *icmph; - struct raw6_opt *opt; - - opt = &sk->tp_pinfo.tp_raw; - icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1); - return test_bit(icmph->icmp6_type, &opt->filter); -} - -/* - * demultiplex raw sockets. - * (should consider queueing the skb in the sock receive_queue - * without calling rawv6.c) - */ -static struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr, unsigned long len) -{ - struct in6_addr *saddr; - struct in6_addr *daddr; - struct sock *sk, *sk2; - __u8 hash; - - saddr = &skb->nh.ipv6h->saddr; - daddr = saddr + 1; - - hash = nexthdr & (MAX_INET_PROTOS - 1); - - sk = raw_v6_htable[hash]; - - /* - * The first socket found will be delivered after - * delivery to transport protocols. - */ - - if (sk == NULL) - return NULL; - - sk = raw_v6_lookup(sk, nexthdr, daddr, saddr); - - if (sk) { - sk2 = sk; - - while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) { - struct sk_buff *buff; - - if (nexthdr == IPPROTO_ICMPV6 && - icmpv6_filter(sk2, skb)) - continue; - - buff = skb_clone(skb, GFP_ATOMIC); - if (buff) - rawv6_rcv(sk2, buff, len); - } - } - - if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb)) - sk = NULL; - - return sk; -} - -/* * Deliver the packet to the host */ @@ -199,9 +137,17 @@ } len = skb->tail - skb->h.raw; - raw_sk = ipv6_raw_deliver(skb, nexthdr, len); + if (skb->rx_dev) { + dev_put(skb->rx_dev); + skb->rx_dev = NULL; + } + + raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)]; + if (raw_sk) + raw_sk = ipv6_raw_deliver(skb, nexthdr, len); hash = nexthdr & (MAX_INET_PROTOS - 1); + read_lock(&inet6_protocol_lock); for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; ipprot != NULL; ipprot = (struct inet6_protocol *) ipprot->next) { @@ -216,9 +162,11 @@ ipprot->handler(buff, len); found = 1; } + read_unlock(&inet6_protocol_lock); if (raw_sk) { rawv6_rcv(raw_sk, skb, len); + sock_put(raw_sk); found = 1; } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c --- v2.3.14/linux/net/ipv6/ip6_output.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/ip6_output.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_output.c,v 1.20 1999/06/09 10:11:12 davem Exp $ + * $Id: ip6_output.c,v 1.22 1999/08/20 11:06:21 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -149,14 +149,11 @@ if (skb->len <= dst->pmtu) { ipv6_statistics.Ip6OutRequests++; - dst->output(skb); - return 0; + return dst->output(skb); } printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); - start_bh_atomic(); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); - end_bh_atomic(); kfree_skb(skb); return -EMSGSIZE; } @@ -317,6 +314,9 @@ data_off = frag_off - opt->opt_flen; } + if (flags&MSG_PROBE) + return 0; + last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len + dst->dev->hard_header_len + 15, 0, flags & MSG_DONTWAIT, &err); @@ -352,7 +352,7 @@ kfree_skb(last_skb); return -ENOMEM; } - + frag_off -= frag_len; data_off -= frag_len; @@ -378,7 +378,11 @@ ipv6_statistics.Ip6FragCreates++; ipv6_statistics.Ip6OutRequests++; - dst->output(skb); + err = dst->output(skb); + if (err) { + kfree_skb(last_skb); + return err; + } } } @@ -400,9 +404,7 @@ ipv6_statistics.Ip6FragCreates++; ipv6_statistics.Ip6FragOKs++; ipv6_statistics.Ip6OutRequests++; - dst->output(last_skb); - - return 0; + return dst->output(last_skb); } int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, @@ -425,11 +427,9 @@ if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr)) fl->oif = np->mcast_oif; - dst = NULL; - if (sk->dst_cache) { - dst = dst_check(&sk->dst_cache, np->dst_cookie); - if (dst) { - struct rt6_info *rt = (struct rt6_info*)dst_clone(dst); + dst = __sk_dst_check(sk, np->dst_cookie); + if (dst) { + struct rt6_info *rt = (struct rt6_info*)dst; /* Yes, checking route validity in not connected case is not very simple. Take into account, @@ -448,15 +448,15 @@ sockets. 2. oif also should be the same. */ - if (((rt->rt6i_dst.plen != 128 || - ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr)) - && (np->daddr_cache == NULL || - ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache))) - || (fl->oif && fl->oif != dst->dev->ifindex)) { - dst_release(dst); - dst = NULL; - } - } + + if (((rt->rt6i_dst.plen != 128 || + ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr)) + && (np->daddr_cache == NULL || + ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache))) + || (fl->oif && fl->oif != dst->dev->ifindex)) { + dst = NULL; + } else + dst_clone(dst); } if (dst == NULL) @@ -493,14 +493,14 @@ jumbolen = 0; - if (!sk->ip_hdrincl) { + if (!sk->protinfo.af_inet.hdrincl) { pktlength += sizeof(struct ipv6hdr); if (opt) pktlength += opt->opt_flen + opt->opt_nflen; if (pktlength > 0xFFFF + sizeof(struct ipv6hdr)) { /* Jumbo datagram. - It is assumed, that in the case of sk->ip_hdrincl + It is assumed, that in the case of hdrincl jumbo option is supplied by user. */ pktlength += 8; @@ -525,11 +525,18 @@ goto out; } + if (flags&MSG_CONFIRM) + dst_confirm(dst); + if (pktlength <= mtu) { struct sk_buff *skb; struct ipv6hdr *hdr; struct net_device *dev = dst->dev; + err = 0; + if (flags&MSG_PROBE) + goto out; + skb = sock_alloc_send_skb(sk, pktlength + 15 + dev->hard_header_len, 0, flags & MSG_DONTWAIT, &err); @@ -546,7 +553,7 @@ hdr = (struct ipv6hdr *) skb->tail; skb->nh.ipv6h = hdr; - if (!sk->ip_hdrincl) { + if (!sk->protinfo.af_inet.hdrincl) { ip6_bld_1(sk, skb, fl, hlimit, jumbolen ? sizeof(struct ipv6hdr) : pktlength); @@ -565,13 +572,13 @@ if (!err) { ipv6_statistics.Ip6OutRequests++; - dst->output(skb); + err = dst->output(skb); } else { err = -EFAULT; kfree_skb(skb); } } else { - if (sk->ip_hdrincl || jumbolen || + if (sk->protinfo.af_inet.hdrincl || jumbolen || np->pmtudisc == IPV6_PMTUDISC_DO) { ipv6_local_error(sk, EMSGSIZE, fl, mtu); err = -EMSGSIZE; @@ -587,6 +594,8 @@ */ out: ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL); + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; return err; } @@ -595,6 +604,7 @@ struct ip6_ra_chain *ra; struct sock *last = NULL; + read_lock(&ip6_ra_lock); for (ra = ip6_ra_chain; ra; ra = ra->next) { struct sock *sk = ra->sk; if (sk && ra->sel == sel) { @@ -609,8 +619,10 @@ if (last) { rawv6_rcv(last, skb, skb->len); + read_unlock(&ip6_ra_lock); return 1; } + read_unlock(&ip6_ra_lock); return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.3.14/linux/net/ipv6/ipv6_sockglue.c Thu Apr 22 19:45:20 1999 +++ linux/net/ipv6/ipv6_sockglue.c Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.27 1999/04/22 10:07:43 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.28 1999/08/20 11:06:23 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,6 +21,8 @@ * o Return an optlen of the truncated length if need be */ +#define __NO_VERSION__ +#include #include #include #include @@ -54,7 +56,7 @@ __constant_htons(ETH_P_IPV6), NULL, /* All devices */ ipv6_rcv, - NULL, + (void*)1, NULL }; @@ -68,6 +70,7 @@ }; struct ip6_ra_chain *ip6_ra_chain; +rwlock_t ip6_ra_lock = RW_LOCK_UNLOCKED; int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) { @@ -79,32 +82,37 @@ new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; + write_lock_bh(&ip6_ra_lock); for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { if (ra->sk == sk) { if (sel>=0) { + write_unlock_bh(&ip6_ra_lock); if (new_ra) kfree(new_ra); return -EADDRINUSE; } *rap = ra->next; - synchronize_bh(); + write_unlock_bh(&ip6_ra_lock); if (ra->destructor) ra->destructor(sk); + sock_put(sk); kfree(ra); return 0; } } - if (new_ra == NULL) + if (new_ra == NULL) { + write_unlock_bh(&ip6_ra_lock); return -ENOBUFS; + } new_ra->sk = sk; new_ra->sel = sel; new_ra->destructor = destructor; - start_bh_atomic(); new_ra->next = ra; *rap = new_ra; - end_bh_atomic(); + sock_hold(sk); + write_unlock_bh(&ip6_ra_lock); return 0; } @@ -129,6 +137,8 @@ valbool = (val!=0); + lock_sock(sk); + switch (optname) { case IPV6_ADDRFORM: @@ -138,17 +148,16 @@ if (sk->protocol != IPPROTO_UDP && sk->protocol != IPPROTO_TCP) - goto out; + break; - lock_sock(sk); if (sk->state != TCP_ESTABLISHED) { - retv = ENOTCONN; - goto addrform_done; + retv = -ENOTCONN; + break; } if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) { retv = -EADDRNOTAVAIL; - goto addrform_done; + break; } fl6_free_socklist(sk); @@ -172,14 +181,14 @@ pktopt = xchg(&np->pktoptions, NULL); if (pktopt) kfree_skb(pktopt); - retv = 0; -addrform_done: - release_sock(sk); - } else { - retv = -EINVAL; + sk->destruct = inet_sock_destruct; + atomic_dec(&inet6_sock_nr); + MOD_DEC_USE_COUNT; + retv = 0; + break; } - break; + goto e_inval; case IPV6_PKTINFO: np->rxopt.bits.rxinfo = valbool; @@ -192,11 +201,10 @@ break; case IPV6_RTHDR: - retv = -EINVAL; - if (val >= 0 && val <= 2) { - np->rxopt.bits.srcrt = val; - retv = 0; - } + if (val < 0 || val > 2) + goto e_inval; + np->rxopt.bits.srcrt = val; + retv = 0; break; case IPV6_HOPOPTS: @@ -216,7 +224,8 @@ case IPV6_FLOWINFO: np->rxopt.bits.rxflow = valbool; - return 0; + retv = 0; + break; case IPV6_PKTOPTIONS: { @@ -250,18 +259,23 @@ goto done; update: retv = 0; - start_bh_atomic(); - if (opt && sk->type == SOCK_STREAM) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - if ((tcp_connected(sk->state) || sk->state == TCP_SYN_SENT) - && sk->daddr != LOOPBACK4_IPV6) { - tp->ext_header_len = opt->opt_flen + opt->opt_nflen; - tcp_sync_mss(sk, tp->pmtu_cookie); + if (sk->type == SOCK_STREAM) { + if (opt) { + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + if ((tcp_connected(sk->state) || sk->state == TCP_SYN_SENT) + && sk->daddr != LOOPBACK4_IPV6) { + tp->ext_header_len = opt->opt_flen + opt->opt_nflen; + tcp_sync_mss(sk, tp->pmtu_cookie); + } } + opt = xchg(&np->opt, opt); + sk_dst_reset(sk); + } else { + write_lock(&sk->dst_lock); + opt = xchg(&np->opt, opt); + write_unlock(&sk->dst_lock); + sk_dst_reset(sk); } - opt = xchg(&np->opt, opt); - dst_release(xchg(&sk->dst_cache, NULL)); - end_bh_atomic(); done: if (opt) @@ -270,20 +284,18 @@ } case IPV6_UNICAST_HOPS: if (val > 255 || val < -1) - retv = -EINVAL; - else { - np->hop_limit = val; - retv = 0; - } + goto e_inval; + np->hop_limit = val; + retv = 0; break; case IPV6_MULTICAST_HOPS: + if (sk->type == SOCK_STREAM) + goto e_inval; if (val > 255 || val < -1) - retv = -EINVAL; - else { - np->mcast_hops = val; - retv = 0; - } + goto e_inval; + np->mcast_hops = val; + retv = 0; break; case IPV6_MULTICAST_LOOP: @@ -292,11 +304,12 @@ break; case IPV6_MULTICAST_IF: - if (sk->bound_dev_if && sk->bound_dev_if != val) { - retv = -EINVAL; - break; - } - if (dev_get_by_index(val) == NULL) { + if (sk->type == SOCK_STREAM) + goto e_inval; + if (sk->bound_dev_if && sk->bound_dev_if != val) + goto e_inval; + + if (__dev_get_by_index(val) == NULL) { retv = -ENODEV; break; } @@ -308,8 +321,9 @@ { struct ipv6_mreq mreq; + retv = -EFAULT; if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) - return -EFAULT; + break; if (optname == IPV6_ADD_MEMBERSHIP) retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); @@ -322,28 +336,38 @@ break; case IPV6_MTU_DISCOVER: if (val<0 || val>2) - return -EINVAL; + goto e_inval; np->pmtudisc = val; - return 0; + retv = 0; + break; case IPV6_MTU: if (val && val < IPV6_MIN_MTU) - return -EINVAL; + goto e_inval; np->frag_size = val; - return 0; + retv = 0; + break; case IPV6_RECVERR: np->recverr = valbool; if (!val) skb_queue_purge(&sk->error_queue); - return 0; + retv = 0; + break; case IPV6_FLOWINFO_SEND: np->sndflow = valbool; - return 0; + retv = 0; + break; case IPV6_FLOWLABEL_MGR: - return ipv6_flowlabel_opt(sk, optval, optlen); - }; + retv = ipv6_flowlabel_opt(sk, optval, optlen); + break; + } + release_sock(sk); out: return retv; + +e_inval: + release_sock(sk); + return -EINVAL; } int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, @@ -365,36 +389,54 @@ struct msghdr msg; struct sk_buff *skb; - start_bh_atomic(); + if (sk->type != SOCK_STREAM) + return -ENOPROTOOPT; + + msg.msg_control = optval; + msg.msg_controllen = len; + msg.msg_flags = 0; + + lock_sock(sk); skb = np->pktoptions; if (skb) atomic_inc(&skb->users); - end_bh_atomic(); + release_sock(sk); if (skb) { - int err; - - msg.msg_control = optval; - msg.msg_controllen = len; - msg.msg_flags = 0; - err = datagram_recv_ctl(sk, &msg, skb); + int err = datagram_recv_ctl(sk, &msg, skb); kfree_skb(skb); if (err) return err; - len -= msg.msg_controllen; - } else - len = 0; + } else { + if (np->rxopt.bits.rxinfo) { + struct in6_pktinfo src_info; + src_info.ipi6_ifindex = np->mcast_oif; + ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); + put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); + } + if (np->rxopt.bits.rxhlim) { + int hlim = np->mcast_hops; + put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); + } + } + len -= msg.msg_controllen; return put_user(len, optlen); } case IP_MTU: + { + struct dst_entry *dst; val = 0; lock_sock(sk); - if (sk->dst_cache) - val = sk->dst_cache->pmtu; + dst = sk_dst_get(sk); + if (dst) { + val = dst->pmtu; + dst_release(dst); + } release_sock(sk); if (!val) return -ENOTCONN; break; + } default: return -EINVAL; } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.3.14/linux/net/ipv6/mcast.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/mcast.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: mcast.c,v 1.23 1999/06/09 10:11:14 davem Exp $ + * $Id: mcast.c,v 1.25 1999/08/20 11:06:24 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -53,8 +53,6 @@ #define MDBG(x) #endif -/* Big mc list lock for all the devices */ -static rwlock_t ipv6_mc_lock = RW_LOCK_UNLOCKED; /* Big mc list lock for all the sockets */ static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED; @@ -67,11 +65,6 @@ #define IGMP6_UNSOLICITED_IVAL (10*HZ) /* - * Hash list of configured multicast addresses - */ -static struct ifmcaddr6 *inet6_mcast_lst[IN6_ADDR_HSIZE]; - -/* * socket join on multicast group */ @@ -99,6 +92,7 @@ rt = rt6_lookup(addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; + dev_hold(dev); dst_release(&rt->u.dst); } } else @@ -117,6 +111,7 @@ if (err) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); + dev_put(dev); return err; } @@ -125,6 +120,8 @@ np->ipv6_mc_list = mc_lst; write_unlock_bh(&ipv6_sk_mc_lock); + dev_put(dev); + return 0; } @@ -145,8 +142,10 @@ *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - if ((dev = dev_get_by_index(ifindex)) != NULL) + if ((dev = dev_get_by_index(ifindex)) != NULL) { ipv6_dev_mc_dec(dev, &mc_lst->addr); + dev_put(dev); + } sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); return 0; } @@ -169,8 +168,10 @@ write_unlock_bh(&ipv6_sk_mc_lock); dev = dev_get_by_index(mc_lst->ifindex); - if (dev) + if (dev) { ipv6_dev_mc_dec(dev, &mc_lst->addr); + dev_put(dev); + } sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); @@ -197,30 +198,32 @@ static int igmp6_group_added(struct ifmcaddr6 *mc) { + struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; if (!(mc->mca_flags&MAF_LOADED)) { mc->mca_flags |= MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, mc->dev, 0) == 0) - dev_mc_add(mc->dev, buf, mc->dev->addr_len, 0); + if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) + dev_mc_add(dev, buf, dev->addr_len, 0); } - if (mc->dev->flags&IFF_UP) + if (dev->flags&IFF_UP) igmp6_join_group(mc); return 0; } static int igmp6_group_dropped(struct ifmcaddr6 *mc) { + struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; if (mc->mca_flags&MAF_LOADED) { mc->mca_flags &= ~MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, mc->dev, 0) == 0) - dev_mc_delete(mc->dev, buf, mc->dev->addr_len, 0); + if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) + dev_mc_delete(dev, buf, dev->addr_len, 0); } - if (mc->dev->flags&IFF_UP) + if (dev->flags&IFF_UP) igmp6_leave_group(mc); return 0; } @@ -232,21 +235,25 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) { struct ifmcaddr6 *mc; - struct inet6_dev *idev; - int hash; + struct inet6_dev *idev; - idev = ipv6_get_idev(dev); + idev = in6_dev_get(dev); if (idev == NULL) return -EINVAL; - hash = ipv6_addr_hash(addr); + write_lock_bh(&idev->lock); + if (idev->dead) { + write_unlock_bh(&idev->lock); + in6_dev_put(idev); + return -ENODEV; + } - write_lock_bh(&ipv6_mc_lock); - for (mc = inet6_mcast_lst[hash]; mc; mc = mc->next) { - if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0 && mc->dev == dev) { + for (mc = idev->mc_list; mc; mc = mc->next) { + if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) { atomic_inc(&mc->mca_users); - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); + in6_dev_put(idev); return 0; } } @@ -258,7 +265,8 @@ mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); if (mc == NULL) { - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); + in6_dev_put(idev); return -ENOMEM; } @@ -267,66 +275,54 @@ mc->mca_timer.data = (unsigned long) mc; memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr)); - mc->dev = dev; + mc->idev = idev; atomic_set(&mc->mca_users, 1); - mc->next = inet6_mcast_lst[hash]; - inet6_mcast_lst[hash] = mc; - - mc->if_next = idev->mc_list; + mc->next = idev->mc_list; idev->mc_list = mc; igmp6_group_added(mc); - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); return 0; } -static void ipv6_mca_remove(struct net_device *dev, struct ifmcaddr6 *ma) -{ - struct inet6_dev *idev; - - idev = ipv6_get_idev(dev); - - if (idev) { - struct ifmcaddr6 *iter, **lnk; - - for (lnk = &idev->mc_list; (iter = *lnk) != NULL; lnk = &iter->if_next) { - if (iter == ma) { - *lnk = iter->if_next; - return; - } - } - } -} - /* * device multicast group del */ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) { - struct ifmcaddr6 *ma, **lnk; - int hash; + struct inet6_dev *idev; + struct ifmcaddr6 *ma, **map; - hash = ipv6_addr_hash(addr); + idev = in6_dev_get(dev); + if (idev == NULL) + return -ENODEV; - write_lock_bh(&ipv6_mc_lock); - for (lnk = &inet6_mcast_lst[hash]; (ma=*lnk) != NULL; lnk = &ma->next) { - if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0 && ma->dev == dev) { + write_lock_bh(&idev->lock); + for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) { + if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) { if (atomic_dec_and_test(&ma->mca_users)) { + *map = ma->next; + write_unlock_bh(&idev->lock); + igmp6_group_dropped(ma); - *lnk = ma->next; + if (ma->idev) + __in6_dev_put(ma->idev); - ipv6_mca_remove(dev, ma); kfree(ma); + in6_dev_put(idev); + return 0; } - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); + in6_dev_put(idev); return 0; } } - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); + in6_dev_put(idev); return -ENOENT; } @@ -336,20 +332,22 @@ */ int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr) { + struct inet6_dev *idev; struct ifmcaddr6 *mc; - int hash; - - hash = ipv6_addr_hash(addr); - read_lock_bh(&ipv6_mc_lock); - for (mc = inet6_mcast_lst[hash]; mc; mc=mc->next) { - if (mc->dev == dev && ipv6_addr_cmp(&mc->mca_addr, addr) == 0) { - read_unlock_bh(&ipv6_mc_lock); - return 1; + idev = in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (mc = idev->mc_list; mc; mc=mc->next) { + if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) { + read_unlock_bh(&idev->lock); + in6_dev_put(idev); + return 1; + } } + read_unlock_bh(&idev->lock); } - read_unlock_bh(&ipv6_mc_lock); - + in6_dev_put(idev); return 0; } @@ -385,6 +383,8 @@ struct ifmcaddr6 *ma; struct in6_addr *addrp; unsigned long resptime; + struct inet6_dev *idev; + if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr)) return -EINVAL; @@ -399,31 +399,25 @@ addrp = (struct in6_addr *) (hdr + 1); - if (ipv6_addr_any(addrp)) { - struct inet6_dev *idev; + idev = in6_dev_get(skb->dev); - idev = ipv6_get_idev(skb->dev); - - if (idev == NULL) - return 0; + if (idev == NULL) + return 0; - read_lock(&ipv6_mc_lock); - for (ma = idev->mc_list; ma; ma=ma->if_next) + read_lock(&idev->lock); + if (ipv6_addr_any(addrp)) { + for (ma = idev->mc_list; ma; ma=ma->next) igmp6_group_queried(ma, resptime); - read_unlock(&ipv6_mc_lock); } else { - int hash = ipv6_addr_hash(addrp); - - read_lock(&ipv6_mc_lock); - for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) { - if (ma->dev == skb->dev && - ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) { + for (ma = idev->mc_list; ma; ma=ma->next) { + if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) { igmp6_group_queried(ma, resptime); break; } } - read_unlock(&ipv6_mc_lock); } + read_unlock(&idev->lock); + in6_dev_put(idev); return 0; } @@ -433,8 +427,7 @@ { struct ifmcaddr6 *ma; struct in6_addr *addrp; - struct net_device *dev; - int hash; + struct inet6_dev *idev; /* Our own report looped back. Ignore it. */ if (skb->pkt_type == PACKET_LOOPBACK) @@ -449,17 +442,17 @@ addrp = (struct in6_addr *) (hdr + 1); - dev = skb->dev; + idev = in6_dev_get(skb->dev); + if (idev == NULL) + return -ENODEV; /* * Cancel the timer for this group */ - hash = ipv6_addr_hash(addrp); - - read_lock(&ipv6_mc_lock); - for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) { - if ((ma->dev == dev) && ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) { + read_lock(&idev->lock); + for (ma = idev->mc_list; ma; ma=ma->next) { + if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) { if (ma->mca_flags & MAF_TIMER_RUNNING) { del_timer(&ma->mca_timer); ma->mca_flags &= ~MAF_TIMER_RUNNING; @@ -469,8 +462,8 @@ break; } } - read_unlock(&ipv6_mc_lock); - + read_unlock(&idev->lock); + in6_dev_put(idev); return 0; } @@ -551,7 +544,7 @@ if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))) return; - igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT); + igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); delay = net_random() % IGMP6_UNSOLICITED_IVAL; if (del_timer(&ma->mca_timer)) @@ -573,7 +566,7 @@ return; if (ma->mca_flags & MAF_LAST_REPORTER) - igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REDUCTION); + igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION); if (ma->mca_flags & MAF_TIMER_RUNNING) del_timer(&ma->mca_timer); @@ -583,11 +576,9 @@ { struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data; - read_lock(&ipv6_mc_lock); ma->mca_flags |= MAF_LAST_REPORTER; - igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT); + igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); ma->mca_flags &= ~MAF_TIMER_RUNNING; - read_unlock(&ipv6_mc_lock); } /* Device going down */ @@ -599,10 +590,10 @@ /* Withdraw multicast list */ - read_lock_bh(&ipv6_mc_lock); - for (i = idev->mc_list; i; i=i->if_next) + read_lock_bh(&idev->lock); + for (i = idev->mc_list; i; i=i->next) igmp6_group_dropped(i); - read_unlock_bh(&ipv6_mc_lock); + read_unlock_bh(&idev->lock); /* Delete all-nodes address. */ @@ -624,10 +615,10 @@ /* Install multicast list, except for all-nodes (already installed) */ - read_lock(&ipv6_mc_lock); - for (i = idev->mc_list; i; i=i->if_next) + read_lock_bh(&idev->lock); + for (i = idev->mc_list; i; i=i->next) igmp6_group_added(i); - read_unlock(&ipv6_mc_lock); + read_unlock_bh(&idev->lock); } /* @@ -636,25 +627,22 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) { - int hash; - struct ifmcaddr6 *i, **lnk; + struct ifmcaddr6 *i; - write_lock_bh(&ipv6_mc_lock); + write_lock_bh(&idev->lock); while ((i = idev->mc_list) != NULL) { - idev->mc_list = i->if_next; + idev->mc_list = i->next; + write_unlock_bh(&idev->lock); - hash = ipv6_addr_hash(&i->mca_addr); - - for (lnk = &inet6_mcast_lst[hash]; *lnk; lnk = &(*lnk)->next) { - if (*lnk == i) { - *lnk = i->next; - break; - } - } igmp6_group_dropped(i); + + if (i->idev) + in6_dev_put(i->idev); kfree(i); + + write_lock_bh(&idev->lock); } - write_unlock_bh(&ipv6_mc_lock); + write_unlock_bh(&idev->lock); } #ifdef CONFIG_PROC_FS @@ -670,11 +658,11 @@ for (dev = dev_base; dev; dev = dev->next) { struct inet6_dev *idev; - if ((idev = ipv6_get_idev(dev)) == NULL) + if ((idev = in6_dev_get(dev)) == NULL) continue; - read_lock_bh(&ipv6_mc_lock); - for (im = idev->mc_list; im; im = im->if_next) { + read_lock_bh(&idev->lock); + for (im = idev->mc_list; im; im = im->next) { int i; len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name); @@ -694,11 +682,13 @@ begin=pos; } if (pos > offset+length) { - read_unlock_bh(&ipv6_mc_lock); + read_unlock_bh(&idev->lock); + in6_dev_put(idev); goto done; } } - read_unlock_bh(&ipv6_mc_lock); + read_unlock_bh(&idev->lock); + in6_dev_put(idev); } *eof = 1; @@ -744,7 +734,7 @@ sk = igmp6_socket->sk; sk->allocation = GFP_ATOMIC; - sk->num = 256; /* Don't receive any data */ + sk->prot->unhash(sk); sk->net_pinfo.af_inet6.hop_limit = 1; #ifdef CONFIG_PROC_FS diff -u --recursive --new-file v2.3.14/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.3.14/linux/net/ipv6/ndisc.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/ndisc.c Mon Aug 23 10:01:02 1999 @@ -75,6 +75,7 @@ static struct socket *ndisc_socket; +static u32 ndisc_hash(const void *pkey, const struct net_device *dev); static int ndisc_constructor(struct neighbour *neigh); static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); @@ -125,10 +126,12 @@ AF_INET6, sizeof(struct neighbour) + sizeof(struct in6_addr), sizeof(struct in6_addr), + ndisc_hash, ndisc_constructor, pndisc_constructor, pndisc_destructor, pndisc_redo, + "ndisc_cache", { NULL, NULL, &nd_tbl, 0, NULL, NULL, 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 0 }, 30*HZ, 128, 512, 1024, @@ -167,11 +170,24 @@ return -EINVAL; } +static u32 ndisc_hash(const void *pkey, const struct net_device *dev) +{ + u32 hash_val; + + hash_val = *(u32*)(pkey + sizeof(struct in6_addr) - 4); + hash_val ^= (hash_val>>16); + hash_val ^= hash_val>>8; + hash_val ^= hash_val>>3; + hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; + + return hash_val; +} + static int ndisc_constructor(struct neighbour *neigh) { struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key; struct net_device *dev = neigh->dev; - struct inet6_dev *in6_dev = ipv6_get_idev(dev); + struct inet6_dev *in6_dev = in6_dev_get(dev); int addr_type; if (in6_dev == NULL) @@ -211,7 +227,7 @@ else neigh->output = neigh->ops->output; } - + in6_dev_put(in6_dev); return 0; } @@ -221,7 +237,7 @@ struct in6_addr maddr; struct net_device *dev = n->dev; - if (dev == NULL || ipv6_get_idev(dev) == NULL) + if (dev == NULL || __in6_dev_get(dev) == NULL) return -EINVAL; #ifndef CONFIG_IPV6_NO_PB addrconf_addr_solict_mult_old(addr, &maddr); @@ -240,7 +256,7 @@ struct in6_addr maddr; struct net_device *dev = n->dev; - if (dev == NULL || ipv6_get_idev(dev) == NULL) + if (dev == NULL || __in6_dev_get(dev) == NULL) return; #ifndef CONFIG_IPV6_NO_PB addrconf_addr_solict_mult_old(addr, &maddr); @@ -385,8 +401,11 @@ } if (saddr == NULL) { - if (!ipv6_get_lladdr(dev, &addr_buf)) - saddr = &addr_buf; + if (ipv6_get_lladdr(dev, &addr_buf)) { + kfree_skb(skb); + return; + } + saddr = &addr_buf; } if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) { @@ -514,7 +533,7 @@ struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 0)) + if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev)) saddr = &skb->nh.ipv6h->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -567,13 +586,15 @@ * set the RA_RECV flag in the interface */ - in6_dev = ipv6_get_idev(skb->dev); + in6_dev = in6_dev_get(skb->dev); if (in6_dev == NULL) { ND_PRINTK1("RA: can't find in6 device\n"); return; } - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) { + in6_dev_put(in6_dev); return; + } if (in6_dev->if_flags & IF_RS_SENT) { /* @@ -589,7 +610,6 @@ if (rt && lifetime == 0) { ip6_del_rt(rt); - dst_release(&rt->u.dst); rt = NULL; } @@ -599,6 +619,7 @@ rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); if (rt == NULL) { ND_PRINTK1("route_add failed\n"); + in6_dev_put(in6_dev); return; } @@ -606,6 +627,7 @@ if (neigh == NULL) { ND_PRINTK1("nd: add default router: null neighbour\n"); dst_release(&rt->u.dst); + in6_dev_put(in6_dev); return; } neigh->flags |= NTF_ROUTER; @@ -706,6 +728,7 @@ } if (rt) dst_release(&rt->u.dst); + in6_dev_put(in6_dev); } static void ndisc_redirect_rcv(struct sk_buff *skb) @@ -752,9 +775,13 @@ return; } - in6_dev = ipv6_get_idev(skb->dev); - if (!in6_dev || in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) + in6_dev = in6_dev_get(skb->dev); + if (!in6_dev) return; + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) { + in6_dev_put(in6_dev); + return; + } /* passed validation tests */ @@ -771,6 +798,7 @@ __neigh_event_send(neigh, NULL); neigh_release(neigh); } + in6_dev_put(in6_dev); } void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, @@ -931,12 +959,10 @@ switch (msg->icmph.icmp6_type) { case NDISC_NEIGHBOUR_SOLICITATION: - if ((ifp = ipv6_chk_addr(&msg->target, dev, 1)) != NULL) { + if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) { int addr_type = ipv6_addr_type(saddr); - if (ifp->flags & ADDR_INVALID) - return 0; - if (ifp->flags & DAD_INCOMPLETE) { + if (ifp->flags & IFA_F_TENTATIVE) { /* Address is tentative. If the source is unspecified address, it is someone does DAD, otherwise we ignore solicitations @@ -944,6 +970,8 @@ */ if (addr_type == IPV6_ADDR_ANY) addrconf_dad_failure(ifp); + else + in6_ifa_put(ifp); return 0; } @@ -953,6 +981,7 @@ ipv6_addr_all_nodes(&maddr); ndisc_send_na(dev, NULL, &maddr, &ifp->addr, ifp->idev->cnf.forwarding, 0, 1, 1); + in6_ifa_put(ifp); return 0; } @@ -977,8 +1006,9 @@ neigh_release(neigh); } } + in6_ifa_put(ifp); } else { - struct inet6_dev *in6_dev = ipv6_get_idev(dev); + struct inet6_dev *in6_dev = in6_dev_get(dev); int addr_type = ipv6_addr_type(saddr); if (in6_dev && in6_dev->cnf.forwarding && @@ -1008,9 +1038,13 @@ */ atomic_inc(&skb->users); pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, skb); + in6_dev_put(in6_dev); return 0; } } + if (in6_dev) + in6_dev_put(in6_dev); + } return 0; @@ -1020,11 +1054,8 @@ ND_PRINTK0("NDISC: solicited NA is multicasted\n"); return 0; } - /* BUG! Target can be link-local on ANOTHER interface. Fixed. */ - if ((ifp = ipv6_chk_addr(&msg->target, dev, 1))) { - if (ifp->flags & ADDR_INVALID) - return 0; - if (ifp->flags & DAD_INCOMPLETE) { + if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) { + if (ifp->flags & IFA_F_TENTATIVE) { addrconf_dad_failure(ifp); return 0; } @@ -1035,6 +1066,7 @@ */ ND_PRINTK0("%s: someone avertise our address!\n", ifp->idev->dev->name); + in6_ifa_put(ifp); return 0; } neigh = neigh_lookup(&nd_tbl, &msg->target, skb->dev); @@ -1109,7 +1141,7 @@ now - neigh->confirmed, neigh->parms->reachable_time, neigh->parms->gc_staletime, - atomic_read(&neigh->refcnt), + atomic_read(&neigh->refcnt) - 1, neigh->flags | (!neigh->hh ? 0 : (neigh->hh->hh_output==dev_queue_xmit ? 4 : 2)), neigh->dev->name); @@ -1188,7 +1220,7 @@ sk->net_pinfo.af_inet6.hop_limit = 255; /* Do not loopback ndisc messages */ sk->net_pinfo.af_inet6.mc_loop = 0; - sk->num = 256; + sk->prot->unhash(sk); /* * Initialize the neighbour table diff -u --recursive --new-file v2.3.14/linux/net/ipv6/protocol.c linux/net/ipv6/protocol.c --- v2.3.14/linux/net/ipv6/protocol.c Fri May 8 00:08:02 1998 +++ linux/net/ipv6/protocol.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * PF_INET6 protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.6 1998/05/03 14:31:09 alan Exp $ + * Version: $Id: protocol.c,v 1.7 1999/08/20 11:06:26 davem Exp $ * * Authors: Pedro Roque * @@ -37,19 +37,7 @@ NULL }; - -struct inet6_protocol *inet6_get_protocol(unsigned char prot) -{ - unsigned char hash; - struct inet6_protocol *p; - - hash = prot & (MAX_INET_PROTOS - 1); - for (p = inet6_protos[hash] ; p != NULL; p=p->next) { - if (p->protocol == prot) - return((struct inet6_protocol *) p); - } - return(NULL); -} +rwlock_t inet6_protocol_lock = RW_LOCK_UNLOCKED; void inet6_add_protocol(struct inet6_protocol *prot) { @@ -57,6 +45,7 @@ struct inet6_protocol *p2; hash = prot->protocol & (MAX_INET_PROTOS - 1); + write_lock_bh(&inet6_protocol_lock); prot->next = inet6_protos[hash]; inet6_protos[hash] = prot; prot->copy = 0; @@ -73,6 +62,7 @@ } p2 = (struct inet6_protocol *) p2->next; } + write_unlock_bh(&inet6_protocol_lock); } /* @@ -86,8 +76,10 @@ unsigned char hash; hash = prot->protocol & (MAX_INET_PROTOS - 1); + write_lock_bh(&inet6_protocol_lock); if (prot == inet6_protos[hash]) { inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next; + write_unlock_bh(&inet6_protocol_lock); return(0); } @@ -106,6 +98,7 @@ if (p->copy == 0 && lp != NULL) lp->copy = 0; p->next = prot->next; + write_unlock_bh(&inet6_protocol_lock); return(0); } if (p->next != NULL && p->next->protocol == prot->protocol) @@ -113,5 +106,6 @@ p = (struct inet6_protocol *) p->next; } + write_unlock_bh(&inet6_protocol_lock); return(-1); } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.3.14/linux/net/ipv6/raw.c Mon Jul 5 20:35:18 1999 +++ linux/net/ipv6/raw.c Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.27 1999/07/02 11:26:40 davem Exp $ + * $Id: raw.c,v 1.29 1999/08/20 11:06:26 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -36,16 +36,19 @@ #include #include #include +#include +#include #include struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; +rwlock_t raw_v6_lock = RW_LOCK_UNLOCKED; static void raw_v6_hash(struct sock *sk) { struct sock **skp = &raw_v6_htable[sk->num & (RAWV6_HTABLE_SIZE - 1)]; - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&raw_v6_lock); if ((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -53,33 +56,34 @@ sk->prot->inuse++; if(sk->prot->highestinuse < sk->prot->inuse) sk->prot->highestinuse = sk->prot->inuse; - SOCKHASH_UNLOCK_WRITE(); + sock_hold(sk); + write_unlock_bh(&raw_v6_lock); } static void raw_v6_unhash(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&raw_v6_lock); if (sk->pprev) { if (sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->prot->inuse--; + __sock_put(sk); } - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&raw_v6_lock); } /* Grumble... icmp and ip_input want to get at this... */ -struct sock *raw_v6_lookup(struct sock *sk, unsigned short num, - struct in6_addr *loc_addr, struct in6_addr *rmt_addr) +struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, + struct in6_addr *loc_addr, struct in6_addr *rmt_addr) { struct sock *s = sk; int addr_type = ipv6_addr_type(loc_addr); for(s = sk; s; s = s->next) { - if((s->num == num) && - !(s->dead && (s->state == TCP_CLOSE))) { + if(s->num == num) { struct ipv6_pinfo *np = &s->net_pinfo.af_inet6; if (!ipv6_addr_any(&np->daddr) && @@ -88,56 +92,136 @@ if (!ipv6_addr_any(&np->rcv_saddr)) { if (ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0) - return(s); + break; if ((addr_type & IPV6_ADDR_MULTICAST) && inet6_mc_check(s, loc_addr)) - return (s); + break; continue; } - return(s); + break; + } + } + return s; +} + +/* + * 0 - deliver + * 1 - block + */ +static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) +{ + struct icmp6hdr *icmph; + struct raw6_opt *opt; + + opt = &sk->tp_pinfo.tp_raw; + icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1); + return test_bit(icmph->icmp6_type, &opt->filter); +} + +/* + * demultiplex raw sockets. + * (should consider queueing the skb in the sock receive_queue + * without calling rawv6.c) + */ +struct sock * ipv6_raw_deliver(struct sk_buff *skb, + int nexthdr, unsigned long len) +{ + struct in6_addr *saddr; + struct in6_addr *daddr; + struct sock *sk, *sk2; + __u8 hash; + + saddr = &skb->nh.ipv6h->saddr; + daddr = saddr + 1; + + hash = nexthdr & (MAX_INET_PROTOS - 1); + + read_lock(&raw_v6_lock); + sk = raw_v6_htable[hash]; + + /* + * The first socket found will be delivered after + * delivery to transport protocols. + */ + + if (sk == NULL) + goto out; + + sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr); + + if (sk) { + sk2 = sk; + + while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) { + struct sk_buff *buff; + + if (nexthdr == IPPROTO_ICMPV6 && + icmpv6_filter(sk2, skb)) + continue; + + buff = skb_clone(skb, GFP_ATOMIC); + if (buff) + rawv6_rcv(sk2, buff, len); } } - return NULL; + + if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb)) + sk = NULL; + +out: + if (sk) + sock_hold(sk); + read_unlock(&raw_v6_lock); + return sk; } + + /* This cleans up af_inet6 a bit. -DaveM */ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr; __u32 v4addr = 0; int addr_type; + int err; - /* Check these errors. */ - if (sk->state != TCP_CLOSE || (addr_len < sizeof(struct sockaddr_in6))) + if (addr_len < sizeof(struct sockaddr_in6)) return -EINVAL; addr_type = ipv6_addr_type(&addr->sin6_addr); - /* Check if the address belongs to the host. */ - if (addr_type == IPV6_ADDR_MAPPED) { - /* Raw sockets are IPv6 only */ + /* Raw sockets are IPv6 only */ + if (addr_type == IPV6_ADDR_MAPPED) return(-EADDRNOTAVAIL); - } else { - if (addr_type != IPV6_ADDR_ANY) { - /* ipv4 addr of the socket is invalid. Only the - * unpecified and mapped address have a v4 equivalent. - */ - v4addr = LOOPBACK4_IPV6; - if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL) - return(-EADDRNOTAVAIL); - } + + lock_sock(sk); + + err = -EINVAL; + if (sk->state != TCP_CLOSE) + goto out; + + /* Check if the address belongs to the host. */ + if (addr_type != IPV6_ADDR_ANY) { + /* ipv4 addr of the socket is invalid. Only the + * unpecified and mapped address have a v4 equivalent. + */ + v4addr = LOOPBACK4_IPV6; + if (!(addr_type & IPV6_ADDR_MULTICAST)) { + err = -EADDRNOTAVAIL; + if (!ipv6_chk_addr(&addr->sin6_addr, NULL)) + goto out; } } sk->rcv_saddr = v4addr; sk->saddr = v4addr; - memcpy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr, - sizeof(struct in6_addr)); + ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr); if (!(addr_type & IPV6_ADDR_MULTICAST)) - memcpy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr, - sizeof(struct in6_addr)); - return 0; + ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr); + err = 0; +out: + release_sock(sk); + return err; } void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr, @@ -193,7 +277,7 @@ */ int rawv6_rcv(struct sock *sk, struct sk_buff *skb, unsigned long len) { - if (sk->ip_hdrincl) + if (sk->protinfo.af_inet.hdrincl) skb->h.raw = skb->nh.raw; rawv6_rcv_skb(sk, skb); @@ -341,9 +425,7 @@ /* Mirror BSD error message compatibility */ if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - - if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT)) - return(-EINVAL); + /* * Get and verify the address. */ @@ -590,15 +672,10 @@ static void rawv6_close(struct sock *sk, long timeout) { - bh_lock_sock(sk); - - /* See for explanation: raw_close in ipv4/raw.c */ - sk->state = TCP_CLOSE; - raw_v6_unhash(sk); if (sk->num == IPPROTO_RAW) ip6_ra_control(sk, -1, NULL); - sk->dead = 1; - destroy_sock(sk); + + inet_sock_release(sk); } static int rawv6_init_sk(struct sock *sk) @@ -606,6 +683,9 @@ return(0); } +#define LINE_LEN 190 +#define LINE_FMT "%-190s\n" + static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i) { struct in6_addr *dest, *src; @@ -615,13 +695,13 @@ dest = &sp->net_pinfo.af_inet6.daddr; src = &sp->net_pinfo.af_inet6.rcv_saddr; - destp = ntohs(sp->dport); - srcp = ntohs(sp->sport); + destp = 0; + srcp = sp->num; timer_active = (sp->timer.prev != NULL) ? 2 : 0; timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies); sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -630,8 +710,9 @@ sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + sp->socket->inode->i_uid, 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } int raw6_get_info(char *buffer, char **start, off_t offset, int length, int dummy) @@ -639,10 +720,10 @@ int len = 0, num = 0, i; off_t pos = 0; off_t begin; - char tmpbuf[150]; + char tmpbuf[LINE_LEN+2]; - if (offset < 149) - len += sprintf(buffer, "%-148s\n", + if (offset < LINE_LEN+1) + len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ "remote_address " /* 38 */ @@ -650,25 +731,25 @@ " uid timeout inode"); /* 21 */ /*----*/ /*144 */ - pos = 149; - SOCKHASH_LOCK_READ(); + pos = LINE_LEN+1; + read_lock(&raw_v6_lock); for (i = 0; i < RAWV6_HTABLE_SIZE; i++) { struct sock *sk; for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) { if (sk->family != PF_INET6) continue; - pos += 149; + pos += LINE_LEN+1; if (pos < offset) continue; get_raw6_sock(sk, tmpbuf, i); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); + len += sprintf(buffer+len, LINE_FMT, tmpbuf); if(len >= length) goto out; } } out: - SOCKHASH_UNLOCK_READ(); + read_unlock(&raw_v6_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; @@ -682,6 +763,7 @@ struct proto rawv6_prot = { rawv6_close, /* close */ udpv6_connect, /* connect */ + udp_disconnect, /* disconnect */ NULL, /* accept */ NULL, /* retransmit */ NULL, /* write_wakeup */ diff -u --recursive --new-file v2.3.14/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c --- v2.3.14/linux/net/ipv6/reassembly.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/reassembly.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: reassembly.c,v 1.13 1999/06/09 08:29:40 davem Exp $ + * $Id: reassembly.c,v 1.15 1999/08/20 11:06:27 davem Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -50,6 +50,8 @@ atomic_t ip6_frag_mem = ATOMIC_INIT(0); +static spinlock_t ip6_frag_lock = SPIN_LOCK_UNLOCKED; + struct ipv6_frag { __u16 offset; __u16 len; @@ -131,15 +133,19 @@ { struct frag_queue *fq; + spin_lock(&ip6_frag_lock); while ((fq = ipv6_frag_queue.next) != &ipv6_frag_queue) { ipv6_statistics.Ip6ReasmFails++; fq_free(fq); - if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) + if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) { + spin_unlock(&ip6_frag_lock); return; + } } if (atomic_read(&ip6_frag_mem)) printk(KERN_DEBUG "IPv6 frag_prune: memleak\n"); atomic_set(&ip6_frag_mem, 0); + spin_unlock(&ip6_frag_lock); } @@ -166,21 +172,25 @@ if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) frag_prune(); + spin_lock(&ip6_frag_lock); for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) { if (fq->id == fhdr->identification && !ipv6_addr_cmp(&hdr->saddr, &fq->saddr) && !ipv6_addr_cmp(&hdr->daddr, &fq->daddr)) { + u8 *ret = NULL; reasm_queue(fq, skb, fhdr, nhptr); if (fq->last_in == (FIRST_IN|LAST_IN)) - return reasm_frag(fq, skbp); + ret = reasm_frag(fq, skbp); - return NULL; + spin_unlock(&ip6_frag_lock); + return ret; } } create_frag_entry(skb, nhptr, fhdr); + spin_unlock(&ip6_frag_lock); return NULL; } @@ -214,12 +224,15 @@ fq = (struct frag_queue *) data; + spin_lock(&ip6_frag_lock); + frag = fq->fragments; ipv6_statistics.Ip6ReasmTimeout++; ipv6_statistics.Ip6ReasmFails++; if (frag == NULL) { + spin_unlock(&ip6_frag_lock); printk(KERN_DEBUG "invalid fragment queue\n"); return; } @@ -239,10 +252,12 @@ frag->skb->dev = dev; icmpv6_send(frag->skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); + dev_put(dev); } } fq_free(fq); + spin_unlock(&ip6_frag_lock); } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.3.14/linux/net/ipv6/route.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/route.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.36 1999/06/09 10:11:21 davem Exp $ + * $Id: route.c,v 1.39 1999/08/20 11:06:28 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -58,12 +58,6 @@ #define RT6_TRACE(x...) do { ; } while (0) #endif -#if RT6_DEBUG >= 1 -#define BUG_TRAP(x) ({ if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } }) -#else -#define BUG_TRAP(x) do { ; } while (0) -#endif - int ip6_rt_max_size = 4096; int ip6_rt_gc_min_interval = 5*HZ; @@ -71,6 +65,7 @@ int ip6_rt_gc_interval = 30*HZ; int ip6_rt_gc_elasticity = 9; int ip6_rt_mtu_expires = 10*60*HZ; +int ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); @@ -93,11 +88,12 @@ NULL, ip6_negative_advice, ip6_link_failure, + sizeof(struct rt6_info), }; struct rt6_info ip6_null_entry = { - {{NULL, ATOMIC_INIT(1), ATOMIC_INIT(1), &loopback_dev, - -1, 0, 0, 0, 0, 0, 0, 0, 0, + {{NULL, ATOMIC_INIT(1), 1, &loopback_dev, + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL, ip6_pkt_discard, ip6_pkt_discard, #ifdef CONFIG_NET_CLS_ROUTE @@ -132,8 +128,13 @@ #define ip6_rt_policy (0) #endif +/* Protects all the ip6 fib */ + +rwlock_t rt6_lock = RW_LOCK_UNLOCKED; + + /* - * Route lookup + * Route lookup. Any rt6_lock is implied. */ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, @@ -162,9 +163,10 @@ } /* - * pointer to the last default router chosen + * pointer to the last default router chosen. BH is disabled locally. */ static struct rt6_info *rt6_dflt_pointer = NULL; +static spinlock_t rt6_dflt_lock = SPIN_LOCK_UNLOCKED; static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) { @@ -175,31 +177,23 @@ for (sprt = rt; sprt; sprt = sprt->u.next) { struct neighbour *neigh; - RDBG(("sprt(%p): ", sprt)); - if ((neigh = sprt->rt6i_nexthop)) { + if ((neigh = sprt->rt6i_nexthop) != NULL) { int m = -1; - RDBG(("nxthop(%p,%d) ", neigh, neigh->nud_state)); switch (neigh->nud_state) { case NUD_REACHABLE: - RDBG(("NUD_REACHABLE ")); if (sprt != rt6_dflt_pointer) { rt = sprt; - RDBG(("sprt!=dflt_ptr -> %p\n", - sprt)); goto out; } - RDBG(("m=2, ")); m = 2; break; case NUD_DELAY: - RDBG(("NUD_DELAY, m=1, ")); m = 1; break; case NUD_STALE: - RDBG(("NUD_STALE, m=1, ")); m = 1; break; }; @@ -209,7 +203,6 @@ } if (m >= mpri) { - RDBG(("m>=mpri setmatch, ")); mpri = m; match = sprt; } @@ -217,26 +210,28 @@ } if (match) { - RDBG(("match, set rt, ")); rt = match; } else { /* * No default routers are known to be reachable. * SHOULD round robin */ - RDBG(("!match, trying rt6_dflt_pointer, ")); + spin_lock(&rt6_dflt_lock); if (rt6_dflt_pointer) { struct rt6_info *next; - if ((next = rt6_dflt_pointer->u.next) && + if ((next = rt6_dflt_pointer->u.next) != NULL && + next->u.dst.obsolete <= 0 && next->u.dst.error == 0) rt = next; } + spin_unlock(&rt6_dflt_lock); } out: + spin_lock(&rt6_dflt_lock); rt6_dflt_pointer = rt; - RDBG(("returning %p, dflt_ptr set\n", rt)); + spin_unlock(&rt6_dflt_lock); return rt; } @@ -246,12 +241,12 @@ struct fib6_node *fn; struct rt6_info *rt; - start_bh_atomic(); + read_lock_bh(&rt6_lock); fn = fib6_lookup(&ip6_routing_table, daddr, saddr); rt = rt6_device_match(fn->leaf, oif, strict); - atomic_inc(&rt->u.dst.use); - atomic_inc(&rt->u.dst.refcnt); - end_bh_atomic(); + dst_hold(&rt->u.dst); + rt->u.dst.__use++; + read_unlock_bh(&rt6_lock); rt->u.dst.lastuse = jiffies; if (rt->u.dst.error == 0) @@ -260,17 +255,27 @@ return NULL; } +/* rt6_ins is called with FREE rt6_lock. + It takes new route entry, the addition fails by any reason the + route is freed. In any case, if caller does not hold it, it may + be destroyed. + */ + static int rt6_ins(struct rt6_info *rt) { int err; - start_bh_atomic(); + write_lock_bh(&rt6_lock); err = fib6_add(&ip6_routing_table, rt); - end_bh_atomic(); + write_unlock_bh(&rt6_lock); return err; } +/* No rt6_lock! If COW faild, the function returns dead route entry + with dst->error set to errno value. + */ + static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, struct in6_addr *saddr) { @@ -302,10 +307,13 @@ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); dst_clone(&rt->u.dst); + err = rt6_ins(rt); if (err == 0) return rt; + rt->u.dst.error = err; + return rt; } dst_clone(&ip6_null_entry.u.dst); @@ -362,9 +370,13 @@ struct fib6_node *fn; struct rt6_info *rt; int strict; + int attempts = 3; strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); +relookup: + read_lock_bh(&rt6_lock); + fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); @@ -399,9 +411,17 @@ if (ip6_rt_policy == 0) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { + read_unlock_bh(&rt6_lock); + rt = rt6_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); - goto out; + + if (rt->u.dst.error != -EEXIST || --attempts <= 0) + goto out2; + /* Race condition! In the gap, when rt6_lock was + released someone could insert this route. Relookup. + */ + goto relookup; } dst_clone(&rt->u.dst); } else { @@ -413,8 +433,10 @@ } out: + read_unlock_bh(&rt6_lock); +out2: rt->u.dst.lastuse = jiffies; - atomic_inc(&rt->u.dst.refcnt); + rt->u.dst.__use++; skb->dst = (struct dst_entry *) rt; } @@ -423,10 +445,13 @@ struct fib6_node *fn; struct rt6_info *rt; int strict; + int attempts = 3; strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); - start_bh_atomic(); +relookup: + read_lock_bh(&rt6_lock); + fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr); @@ -465,9 +490,18 @@ if (ip6_rt_policy == 0) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { + read_unlock_bh(&rt6_lock); + rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr); - goto out; + + if (rt->u.dst.error != -EEXIST || --attempts <= 0) + goto out2; + + /* Race condition! In the gap, when rt6_lock was + released someone could insert this route. Relookup. + */ + goto relookup; } dst_clone(&rt->u.dst); } else { @@ -479,9 +513,10 @@ } out: + read_unlock_bh(&rt6_lock); +out2: rt->u.dst.lastuse = jiffies; - atomic_inc(&rt->u.dst.refcnt); - end_bh_atomic(); + rt->u.dst.__use++; return &rt->u.dst; } @@ -520,7 +555,8 @@ if (rt) { if (rt->rt6i_flags & RTF_CACHE) ip6_del_rt(rt); - dst_release(dst); + else + dst_release(dst); } return NULL; } @@ -547,8 +583,8 @@ static unsigned long last_gc; unsigned long now = jiffies; - start_bh_atomic(); - if ((long)(now - last_gc) < ip6_rt_gc_min_interval) + if ((long)(now - last_gc) < ip6_rt_gc_min_interval && + atomic_read(&ip6_dst_ops.entries) <= ip6_rt_max_size) goto out; expire++; @@ -559,7 +595,6 @@ out: expire -= expire>>ip6_rt_gc_elasticity; - end_bh_atomic(); return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size); } @@ -582,24 +617,28 @@ static int ipv6_get_mtu(struct net_device *dev) { + int mtu = IPV6_MIN_MTU; struct inet6_dev *idev; - idev = ipv6_get_idev(dev); - if (idev) - return idev->cnf.mtu6; - else - return IPV6_MIN_MTU; + idev = in6_dev_get(dev); + if (idev) { + mtu = idev->cnf.mtu6; + in6_dev_put(idev); + } + return mtu; } static int ipv6_get_hoplimit(struct net_device *dev) { + int hoplimit = ipv6_devconf.hop_limit; struct inet6_dev *idev; - idev = ipv6_get_idev(dev); - if (idev) - return idev->cnf.hop_limit; - else - return ipv6_devconf.hop_limit; + idev = in6_dev_get(dev); + if (idev) { + hoplimit = idev->cnf.hop_limit; + in6_dev_put(idev); + } + return hoplimit; } /* @@ -622,7 +661,7 @@ if (rtmsg->rtmsg_metric == 0) rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; - rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops); + rt = dst_alloc(&ip6_dst_ops); if (rt == NULL) return -ENOMEM; @@ -663,7 +702,10 @@ */ if ((rtmsg->rtmsg_flags&RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { + if (dev) + dev_put(dev); dev = &loopback_dev; + dev_hold(dev); rt->u.dst.output = ip6_pkt_discard; rt->u.dst.input = ip6_pkt_discard; rt->u.dst.error = -ENETUNREACH; @@ -698,9 +740,17 @@ err = -EHOSTUNREACH; if (grt == NULL) goto out; + if (dev) { + if (dev != grt->rt6i_dev) { + dst_release(&grt->u.dst); + goto out; + } + } else { + dev = grt->rt6i_dev; + dev_hold(dev); + } if (!(grt->rt6i_flags&RTF_GATEWAY)) err = 0; - dev = grt->rt6i_dev; dst_release(&grt->u.dst); if (err) @@ -730,11 +780,19 @@ install_route: rt->u.dst.pmtu = ipv6_get_mtu(dev); - rt->u.dst.rtt = TCP_TIMEOUT_INIT; - rt->rt6i_dev = dev; + rt->u.dst.advmss = max(rt->u.dst.pmtu - 60, ip6_rt_min_advmss); + /* Maximal non-jumbo IPv6 payload is 65535 and corresponding + MSS is 65535 - tcp_header_size. 65535 is also valid and + means: "any MSS, rely only on pmtu discovery" + */ + if (rt->u.dst.advmss > 65535-20) + rt->u.dst.advmss = 65535; + rt->u.dst.dev = dev; return rt6_ins(rt); out: + if (dev) + dev_put(dev); dst_free((struct dst_entry *) rt); return err; } @@ -743,10 +801,16 @@ { int err; - start_bh_atomic(); + write_lock_bh(&rt6_lock); + + spin_lock_bh(&rt6_dflt_lock); rt6_dflt_pointer = NULL; + spin_unlock_bh(&rt6_dflt_lock); + + dst_release(&rt->u.dst); + err = fib6_del(rt); - end_bh_atomic(); + write_unlock_bh(&rt6_lock); return err; } @@ -757,7 +821,7 @@ struct rt6_info *rt; int err = -ESRCH; - start_bh_atomic(); + read_lock_bh(&rt6_lock); fn = fib6_locate(&ip6_routing_table, &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, @@ -775,112 +839,16 @@ if (rtmsg->rtmsg_metric && rtmsg->rtmsg_metric != rt->rt6i_metric) continue; - err = ip6_del_rt(rt); - break; - } - } - end_bh_atomic(); - - return err; -} - -#ifdef CONFIG_IPV6_NETLINK -/* - * NETLINK interface - * routing socket moral equivalent - */ - -static int rt6_msgrcv(int unit, struct sk_buff *skb) -{ - int count = 0; - struct in6_rtmsg *rtmsg; - int err; + dst_clone(&rt->u.dst); + read_unlock_bh(&rt6_lock); - rtnl_lock(); - while (skb->len) { - if (skb->len < sizeof(struct in6_rtmsg)) { - count = -EINVAL; - goto out; + return ip6_del_rt(rt); } - - rtmsg = (struct in6_rtmsg *) skb->data; - skb_pull(skb, sizeof(struct in6_rtmsg)); - count += sizeof(struct in6_rtmsg); - - switch (rtmsg->rtmsg_type) { - case RTMSG_NEWROUTE: - err = ip6_route_add(rtmsg); - break; - case RTMSG_DELROUTE: - err = ip6_route_del(rtmsg); - break; - default: - count = -EINVAL; - goto out; - }; - } - -out: - rtnl_unlock(); - kfree_skb(skb); - return count; -} - -static void rt6_sndrtmsg(struct in6_rtmsg *rtmsg) -{ - struct sk_buff *skb; - - skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC); - if (skb == NULL) - return; - - memcpy(skb_put(skb, sizeof(struct in6_rtmsg)), &rtmsg, - sizeof(struct in6_rtmsg)); - - if (netlink_post(NETLINK_ROUTE6, skb)) - kfree_skb(skb); -} - -void rt6_sndmsg(int type, struct in6_addr *dst, struct in6_addr *src, - struct in6_addr *gw, struct net_device *dev, - int dstlen, int srclen, int metric, __u32 flags) -{ - struct sk_buff *skb; - struct in6_rtmsg *msg; - - skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC); - if (skb == NULL) - return; - - msg = (struct in6_rtmsg *) skb_put(skb, sizeof(struct in6_rtmsg)); - - memset(msg, 0, sizeof(struct in6_rtmsg)); - - msg->rtmsg_type = type; - - if (dst) - ipv6_addr_copy(&msg->rtmsg_dst, dst); - - if (src) { - ipv6_addr_copy(&msg->rtmsg_src, src); - msg->rtmsg_src_len = srclen; } + read_unlock_bh(&rt6_lock); - if (gw) - ipv6_addr_copy(&msg->rtmsg_gateway, gw); - - msg->rtmsg_dst_len = dstlen; - msg->rtmsg_metric = metric; - - if (dev) - msg->rtmsg_ifindex = dev->ifindex; - - msg->rtmsg_flags = flags; - - if (netlink_post(NETLINK_ROUTE6, skb)) - kfree_skb(skb); + return err; } -#endif /* CONFIG_IPV6_NETLINK */ /* * Handle redirects @@ -923,7 +891,7 @@ /* * During transition gateways have more than * one link local address. Certainly, it is violation - * of basic principles, but it is temparary. + * of basic principles, but it is temporary. */ /* * RFC 1970 specifies that redirects should only be @@ -937,14 +905,17 @@ if (rt->rt6i_flags & RTF_DEFAULT) { struct rt6_info *rt1; + read_lock(&rt6_lock); for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) { dst_clone(&rt1->u.dst); dst_release(&rt->u.dst); + read_unlock(&rt6_lock); rt = rt1; goto source_ok; } } + read_unlock(&rt6_lock); } if (net_ratelimit()) printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " @@ -974,16 +945,18 @@ nrt->rt6i_nexthop = neigh_clone(neigh); /* Reset pmtu, it may be better */ nrt->u.dst.pmtu = ipv6_get_mtu(neigh->dev); + nrt->u.dst.advmss = max(nrt->u.dst.pmtu - 60, ip6_rt_min_advmss); + if (rt->u.dst.advmss > 65535-20) + rt->u.dst.advmss = 65535; nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev); if (rt6_ins(nrt)) goto out; - /* Sic! rt6_redirect is called by bh, so that it is allowed */ - dst_release(&rt->u.dst); - if (rt->rt6i_flags&RTF_CACHE) + if (rt->rt6i_flags&RTF_CACHE) { ip6_del_rt(rt); - return; + return; + } out: dst_release(&rt->u.dst); @@ -1071,17 +1044,16 @@ { struct rt6_info *rt; - rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops); + rt = dst_alloc(&ip6_dst_ops); if (rt) { rt->u.dst.input = ort->u.dst.input; rt->u.dst.output = ort->u.dst.output; - rt->u.dst.pmtu = ort->u.dst.pmtu; - rt->u.dst.rtt = ort->u.dst.rtt; - rt->u.dst.window = ort->u.dst.window; - rt->u.dst.mxlock = ort->u.dst.mxlock; + memcpy(&rt->u.dst.mxlock, &ort->u.dst.mxlock, RTAX_MAX*sizeof(unsigned)); rt->u.dst.dev = ort->u.dst.dev; + if (rt->u.dst.dev) + dev_hold(rt->u.dst.dev); rt->u.dst.lastuse = jiffies; rt->rt6i_hoplimit = ort->rt6i_hoplimit; rt->rt6i_expires = 0; @@ -1105,7 +1077,7 @@ fn = &ip6_routing_table; - start_bh_atomic(); + write_lock_bh(&rt6_lock); for (rt = fn->leaf; rt; rt=rt->u.next) { if (dev == rt->rt6i_dev && ipv6_addr_cmp(&rt->rt6i_gateway, addr) == 0) @@ -1113,7 +1085,7 @@ } if (rt) dst_clone(&rt->u.dst); - end_bh_atomic(); + write_unlock_bh(&rt6_lock); return rt; } @@ -1145,14 +1117,23 @@ flags = RTF_DEFAULT | RTF_ADDRCONF; restart: - rt6_dflt_pointer = NULL; - + read_lock_bh(&rt6_lock); for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { if (rt->rt6i_flags & flags) { + dst_hold(&rt->u.dst); + + spin_lock_bh(&rt6_dflt_lock); + rt6_dflt_pointer = NULL; + spin_unlock_bh(&rt6_dflt_lock); + + read_unlock_bh(&rt6_lock); + ip6_del_rt(rt); + goto restart; } } + read_unlock_bh(&rt6_lock); } int ipv6_route_ioctl(unsigned int cmd, void *arg) @@ -1160,7 +1141,6 @@ struct in6_rtmsg rtmsg; int err; - RDBG(("ipv6_route_ioctl(%d,%p)\n", cmd, arg)); switch(cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ @@ -1181,13 +1161,9 @@ break; default: err = -EINVAL; - }; + } rtnl_unlock(); -#ifdef CONFIG_IPV6_NETLINK - if (err == 0) - rt6_sndrtmsg(&rtmsg); -#endif return err; }; @@ -1214,15 +1190,17 @@ { struct rt6_info *rt; - rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops); + rt = dst_alloc(&ip6_dst_ops); if (rt == NULL) return -ENOMEM; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = dev_get("lo"); - rt->u.dst.rtt = TCP_TIMEOUT_INIT; + rt->rt6i_dev = dev_get_by_name("lo"); rt->u.dst.pmtu = ipv6_get_mtu(rt->rt6i_dev); + rt->u.dst.advmss = max(rt->u.dst.pmtu - 60, ip6_rt_min_advmss); + if (rt->u.dst.advmss > 65535-20) + rt->u.dst.advmss = 65535; rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev); rt->u.dst.obsolete = -1; @@ -1252,8 +1230,9 @@ rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1); if (rt) { if (rt->rt6i_dst.plen == 128) - err= ip6_del_rt(rt); - dst_release(&rt->u.dst); + err = ip6_del_rt(rt); + else + dst_release(&rt->u.dst); } return err; @@ -1386,7 +1365,9 @@ void rt6_ifdown(struct net_device *dev) { + write_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); + write_unlock_bh(&rt6_lock); } struct rt6_mtu_change_arg @@ -1400,13 +1381,16 @@ struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; /* In IPv6 pmtu discovery is not optional, - so that RTAX_MTU lock cannot dissable it. + so that RTAX_MTU lock cannot disable it. We still use this lock to block changes caused by addrconf/ndisc. - */ + */ if (rt->rt6i_dev == arg->dev && !(rt->u.dst.mxlock&(1<u.dst.pmtu = arg->mtu; + rt->u.dst.advmss = max(arg->mtu - 60, ip6_rt_min_advmss); + if (rt->u.dst.advmss > 65535-20) + rt->u.dst.advmss = 65535; return 0; } @@ -1416,7 +1400,9 @@ arg.dev = dev; arg.mtu = mtu; + read_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg); + read_unlock_bh(&rt6_lock); } #ifdef CONFIG_RTNETLINK @@ -1496,7 +1482,6 @@ struct rtmsg *rtm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; - struct rtattr *mx; struct rta_cacheinfo ci; nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm)); @@ -1541,22 +1526,11 @@ RTA_PUT(skb, RTA_IIF, 4, &iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf)) + if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } - mx = (struct rtattr*)skb->tail; - RTA_PUT(skb, RTA_METRICS, 0, NULL); - if (rt->u.dst.mxlock) - RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock); - if (rt->u.dst.pmtu) - RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu); - if (rt->u.dst.window) - RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window); - if (rt->u.dst.rtt) - RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt); - mx->rta_len = skb->tail - (u8*)mx; - if (mx->rta_len == RTA_LENGTH(0)) - skb_trim(skb, (u8*)mx - skb->data); + if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) + goto rtattr_failure; if (rt->u.dst.neighbour) RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); if (rt->u.dst.dev) @@ -1567,8 +1541,8 @@ ci.rta_expires = rt->rt6i_expires - jiffies; else ci.rta_expires = 0; - ci.rta_used = atomic_read(&rt->u.dst.refcnt); - ci.rta_clntref = atomic_read(&rt->u.dst.use); + ci.rta_used = rt->u.dst.__use; + ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); ci.rta_error = rt->u.dst.error; RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; @@ -1612,9 +1586,7 @@ if (w) { cb->args[0] = 0; - start_bh_atomic(); fib6_walker_unlink(w); - end_bh_atomic(); kfree(w); } if (cb->args[1]) { @@ -1650,7 +1622,7 @@ /* * 2. allocate and initialize walker. */ - w = kmalloc(sizeof(*w), GFP_KERNEL); + w = kmalloc(sizeof(*w), GFP_ATOMIC); if (w == NULL) return -ENOMEM; RT6_TRACE("dump<%p", w); @@ -1659,14 +1631,14 @@ w->func = fib6_dump_node; w->args = &arg; cb->args[0] = (long)w; - start_bh_atomic(); + read_lock_bh(&rt6_lock); res = fib6_walk(w); - end_bh_atomic(); + read_unlock_bh(&rt6_lock); } else { w->args = &arg; - start_bh_atomic(); + read_lock_bh(&rt6_lock); res = fib6_walk_continue(w); - end_bh_atomic(); + read_unlock_bh(&rt6_lock); } #if RT6_DEBUG >= 3 if (res <= 0 && skb->len == 0) @@ -1717,7 +1689,7 @@ if (iif) { struct net_device *dev; - dev = dev_get_by_index(iif); + dev = __dev_get_by_index(iif); if (!dev) return -ENODEV; } @@ -1831,8 +1803,8 @@ } arg->len += sprintf(arg->buffer + arg->len, " %08x %08x %08x %08x %8s\n", - rt->rt6i_metric, atomic_read(&rt->u.dst.use), - atomic_read(&rt->u.dst.refcnt), rt->rt6i_flags, + rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt), + rt->u.dst.__use, rt->rt6i_flags, rt->rt6i_dev ? rt->rt6i_dev->name : ""); return 0; } @@ -1847,7 +1819,9 @@ arg.skip = 0; arg.len = 0; + read_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg); + read_unlock_bh(&rt6_lock); *start = buffer; if (offset) @@ -1914,9 +1888,7 @@ proc_dointvec(ctl, write, filp, buffer, lenp); if (flush_delay < 0) flush_delay = 0; - start_bh_atomic(); fib6_run_gc((unsigned long)flush_delay); - end_bh_atomic(); return 0; } else return -EINVAL; @@ -1947,6 +1919,9 @@ {NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires", &ip6_rt_mtu_expires, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss", + &ip6_rt_min_advmss, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, {0} }; @@ -1955,13 +1930,15 @@ __initfunc(void ip6_route_init(void)) { + ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", + sizeof(struct rt6_info), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + fib6_init(); #ifdef CONFIG_PROC_FS proc_net_register(&proc_rt6_info); proc_net_register(&proc_rt6_stats); #endif -#ifdef CONFIG_IPV6_NETLINK - netlink_attach(NETLINK_ROUTE6, rt6_msgrcv); -#endif } #ifdef MODULE @@ -1971,9 +1948,7 @@ proc_net_unregister(PROC_NET_RT6); proc_net_unregister(PROC_NET_RT6_STATS); #endif -#ifdef CONFIG_IPV6_NETLINK - netlink_detach(NETLINK_ROUTE6); -#endif + rt6_ifdown(NULL); fib6_gc_cleanup(); } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/sit.c linux/net/ipv6/sit.c --- v2.3.14/linux/net/ipv6/sit.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/sit.c Mon Aug 23 10:01:02 1999 @@ -6,7 +6,7 @@ * Pedro Roque * Alexey Kuznetsov * - * $Id: sit.c,v 1.31 1999/03/25 10:04:55 davem Exp $ + * $Id: sit.c,v 1.33 1999/08/20 11:06:29 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -70,6 +70,8 @@ static struct ip_tunnel *tunnels_wc[1]; static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; +static rwlock_t ipip6_lock = RW_LOCK_UNLOCKED; + static struct ip_tunnel * ipip6_tunnel_lookup(u32 remote, u32 local) { unsigned h0 = HASH(remote); @@ -118,8 +120,9 @@ for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) { if (t == *tp) { + write_lock_bh(&ipip6_lock); *tp = t->next; - synchronize_bh(); + write_unlock_bh(&ipip6_lock); break; } } @@ -129,8 +132,9 @@ { struct ip_tunnel **tp = ipip6_bucket(t); + write_lock_bh(&ipip6_lock); t->next = *tp; - wmb(); + write_unlock_bh(&ipip6_lock); *tp = t; } @@ -170,12 +174,13 @@ nt->dev = dev; dev->name = nt->parms.name; dev->init = ipip6_tunnel_init; + dev->new_style = 1; memcpy(&nt->parms, parms, sizeof(*parms)); if (dev->name[0] == 0) { int i; for (i=1; i<100; i++) { sprintf(dev->name, "sit%d", i); - if (dev_get(dev->name) == NULL) + if (__dev_get_by_name(dev->name) == NULL) break; } if (i==100) @@ -185,6 +190,7 @@ if (register_netdevice(dev) < 0) goto failed; + dev_hold(dev); ipip6_tunnel_link(nt); /* Do not decrement MOD_USE_COUNT here. */ return nt; @@ -195,19 +201,27 @@ return NULL; } -static void ipip6_tunnel_destroy(struct net_device *dev) +static void ipip6_tunnel_destructor(struct net_device *dev) +{ + if (dev != &ipip6_fb_tunnel_dev) { + MOD_DEC_USE_COUNT; + } +} + +static void ipip6_tunnel_uninit(struct net_device *dev) { if (dev == &ipip6_fb_tunnel_dev) { + write_lock_bh(&ipip6_lock); tunnels_wc[0] = NULL; - synchronize_bh(); - return; + write_unlock_bh(&ipip6_lock); + dev_put(dev); } else { ipip6_tunnel_unlink((struct ip_tunnel*)dev->priv); - kfree(dev); - MOD_DEC_USE_COUNT; + dev_put(dev); } } + void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -252,17 +266,20 @@ break; } + read_lock(&ipip6_lock); t = ipip6_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) - return; + goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) - return; + goto out; if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO) t->err_count++; else t->err_count = 1; t->err_time = jiffies; +out: + read_unlock(&ipip6_lock); return; #else struct iphdr *iph = (struct iphdr*)dp; @@ -358,6 +375,7 @@ iph = skb->nh.iph; + read_lock(&ipip6_lock); if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { skb->mac.raw = skb->nh.raw; skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data); @@ -371,11 +389,13 @@ dst_release(skb->dst); skb->dst = NULL; netif_rx(skb); + read_unlock(&ipip6_lock); return 0; } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); kfree_skb(skb); + read_unlock(&ipip6_lock); return 0; } @@ -602,14 +622,12 @@ break; } t = (struct ip_tunnel*)dev->priv; - start_bh_atomic(); ipip6_tunnel_unlink(t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); ipip6_tunnel_link(t); - end_bh_atomic(); netdev_state_change(dev); } } @@ -671,7 +689,8 @@ { struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; - dev->destructor = ipip6_tunnel_destroy; + dev->destructor = ipip6_tunnel_destructor; + dev->uninit = ipip6_tunnel_uninit; dev->hard_start_xmit = ipip6_tunnel_xmit; dev->get_stats = ipip6_tunnel_get_stats; dev->do_ioctl = ipip6_tunnel_ioctl; @@ -710,7 +729,7 @@ } if (!tdev && tunnel->parms.link) - tdev = dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); @@ -753,6 +772,7 @@ iph->ihl = 5; iph->ttl = 64; + dev_hold(dev); tunnels_wc[0] = &ipip6_fb_tunnel; return 0; } diff -u --recursive --new-file v2.3.14/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.3.14/linux/net/ipv6/tcp_ipv6.c Sat Jul 3 17:57:23 1999 +++ linux/net/ipv6/tcp_ipv6.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.109 1999/07/02 11:26:41 davem Exp $ + * $Id: tcp_ipv6.c,v 1.111 1999/08/21 21:46:35 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -18,6 +18,8 @@ * 2 of the License, or (at your option) any later version. */ +#define __NO_VERSION__ +#include #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include #include @@ -44,13 +47,17 @@ #include extern int sysctl_max_syn_backlog; +extern int sysctl_tcp_tw_recycle; +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; static void tcp_v6_send_reset(struct sk_buff *skb); +static void tcp_v6_or_send_ack(struct sk_buff *skb, struct open_request *req); static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, struct sk_buff *skb); static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); -static void tcp_v6_xmit(struct sk_buff *skb); +static int tcp_v6_xmit(struct sk_buff *skb); static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, struct ipv6hdr *ip6h, struct tcphdr *th, @@ -67,7 +74,9 @@ int hashent = (lport ^ fport); hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); - return (hashent & ((tcp_ehash_size >> 1) - 1)); + hashent ^= hashent>>16; + hashent ^= hashent>>8; + return (hashent & (tcp_ehash_size - 1)); } static __inline__ int tcp_v6_sk_hashfn(struct sock *sk) @@ -86,28 +95,36 @@ */ static int tcp_v6_get_port(struct sock *sk, unsigned short snum) { + struct tcp_bind_hashbucket *head; struct tcp_bind_bucket *tb; + int ret; - SOCKHASH_LOCK_WRITE(); + local_bh_disable(); if (snum == 0) { - int rover = tcp_port_rover; int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; + int rover; + spin_lock(&tcp_portalloc_lock); + rover = tcp_port_rover; do { rover++; if ((rover < low) || (rover > high)) rover = low; - tb = tcp_bhash[tcp_bhashfn(rover)]; - for ( ; tb; tb = tb->next) + head = &tcp_bhash[tcp_bhashfn(rover)]; + spin_lock(&head->lock); + for (tb = head->chain; tb; tb = tb->next) if (tb->port == rover) goto next; break; next: + spin_unlock(&head->lock); } while (--remaining > 0); tcp_port_rover = rover; + spin_unlock(&tcp_portalloc_lock); /* Exhausted local port range during search? */ + ret = 1; if (remaining <= 0) goto fail; @@ -115,9 +132,9 @@ snum = rover; tb = NULL; } else { - for (tb = tcp_bhash[tcp_bhashfn(snum)]; - tb != NULL; - tb = tb->next) + head = &tcp_bhash[tcp_bhashfn(snum)]; + spin_lock(&head->lock); + for (tb = head->chain; tb != NULL; tb = tb->next) if (tb->port == snum) break; } @@ -135,22 +152,27 @@ if (!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) { + /* NOTE: IPv6 tw bucket have different format */ if (!sk2->rcv_saddr || - !addr_type == IPV6_ADDR_ANY || + addr_type == IPV6_ADDR_ANY || !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, - &sk2->net_pinfo.af_inet6.rcv_saddr)) + sk2->state != TCP_TIME_WAIT ? + &sk2->net_pinfo.af_inet6.rcv_saddr : + &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr)) break; } } } /* If we found a conflict, fail. */ + ret = 1; if (sk2 != NULL) - goto fail; + goto fail_unlock; } } + ret = 1; if (tb == NULL && - (tb = tcp_bucket_create(snum)) == NULL) - goto fail; + (tb = tcp_bucket_create(head, snum)) == NULL) + goto fail_unlock; if (tb->owners == NULL) { if (sk->reuse && sk->state != TCP_LISTEN) tb->fastreuse = 1; @@ -167,58 +189,54 @@ tb->owners = sk; sk->bind_pprev = &tb->owners; sk->prev = (struct sock *) tb; + ret = 0; - SOCKHASH_UNLOCK_WRITE(); - return 0; - +fail_unlock: + spin_unlock(&head->lock); fail: - SOCKHASH_UNLOCK_WRITE(); - return 1; + local_bh_enable(); + return ret; +} + +static __inline__ void __tcp_v6_hash(struct sock *sk) +{ + struct sock **skp; + rwlock_t *lock; + + BUG_TRAP(sk->pprev==NULL); + + if(sk->state == TCP_LISTEN) { + skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; + lock = &tcp_lhash_lock; + tcp_listen_wlock(); + } else { + skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))].chain; + lock = &tcp_ehash[sk->hashent].lock; + write_lock(lock); + } + + if((sk->next = *skp) != NULL) + (*skp)->pprev = &sk->next; + *skp = sk; + sk->pprev = skp; + sk->prot->inuse++; + if(sk->prot->highestinuse < sk->prot->inuse) + sk->prot->highestinuse = sk->prot->inuse; + write_unlock(lock); } + static void tcp_v6_hash(struct sock *sk) { if(sk->state != TCP_CLOSE) { - struct sock **skp; - - /* Well, I know that it is ugly... - * All this ->prot, ->af_specific etc. need LARGE cleanup --ANK - */ if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) { tcp_prot.hash(sk); return; } - - if(sk->state == TCP_LISTEN) - skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; - else - skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))]; - - SOCKHASH_LOCK_WRITE(); - if((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; - *skp = sk; - sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; - SOCKHASH_UNLOCK_WRITE(); - } -} - -static void tcp_v6_unhash(struct sock *sk) -{ - SOCKHASH_LOCK_WRITE(); - if(sk->pprev) { - if(sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sk->prot->inuse--; - tcp_reg_zap(sk); - __tcp_put_port(sk); + local_bh_disable(); + __tcp_v6_hash(sk); + local_bh_enable(); } - SOCKHASH_UNLOCK_WRITE(); } static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif) @@ -228,6 +246,7 @@ int score, hiscore; hiscore=0; + read_lock(&tcp_lhash_lock); sk = tcp_listening_hash[tcp_lhashfn(hnum)]; for(; sk; sk = sk->next) { if((sk->num == hnum) && (sk->family == PF_INET6)) { @@ -244,14 +263,19 @@ continue; score++; } - if (score == 3) - return sk; + if (score == 3) { + result = sk; + break; + } if (score > hiscore) { hiscore = score; result = sk; } } } + if (sk) + sock_hold(sk); + read_unlock(&tcp_lhash_lock); return result; } @@ -261,33 +285,27 @@ * The sockhash lock must be held as a reader here. */ static inline struct sock *__tcp_v6_lookup(struct in6_addr *saddr, u16 sport, - struct in6_addr *daddr, u16 dport, + struct in6_addr *daddr, u16 hnum, int dif) { + struct tcp_ehash_bucket *head; struct sock *sk; - __u16 hnum = ntohs(dport); __u32 ports = TCP_COMBINED_PORTS(sport, hnum); int hash; - /* Check TCP register quick cache first. */ - sk = TCP_RHASH(sport); - if(sk && TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) - goto hit; - /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ hash = tcp_v6_hashfn(daddr, hnum, saddr, sport); - for(sk = tcp_ehash[hash]; sk; sk = sk->next) { + head = &tcp_ehash[hash]; + read_lock(&head->lock); + for(sk = head->chain; sk; sk = sk->next) { /* For IPV6 do the cheaper port and family tests first. */ - if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) { - if (sk->state == TCP_ESTABLISHED) - TCP_RHASH(sport) = sk; + if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) goto hit; /* You sunk my battleship! */ - } } /* Must check for a TIME_WAIT'er before going to listener hash. */ - for(sk = tcp_ehash[hash+(tcp_ehash_size >> 1)]; sk; sk = sk->next) { + for(sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) { if(*((__u32 *)&(sk->dport)) == ports && sk->family == PF_INET6) { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; @@ -297,16 +315,21 @@ goto hit; } } - sk = tcp_v6_lookup_listener(daddr, hnum, dif); + read_unlock(&head->lock); + + return tcp_v6_lookup_listener(daddr, hnum, dif); + hit: + sock_hold(sk); + read_unlock(&head->lock); return sk; } #define tcp_v6_lookup(sa, sp, da, dp, dif) \ ({ struct sock *___sk; \ - SOCKHASH_LOCK_READ(); \ - ___sk = __tcp_v6_lookup((sa),(sp),(da),(dp),(dif)); \ - SOCKHASH_UNLOCK_READ(); \ + local_bh_disable(); \ + ___sk = __tcp_v6_lookup((sa),(sp),(da),ntohs(dp),(dif)); \ + local_bh_enable(); \ ___sk; \ }) @@ -336,34 +359,99 @@ skb->h.th->source); } -static int tcp_v6_unique_address(struct sock *sk) +static int tcp_v6_check_established(struct sock *sk) { - struct tcp_bind_bucket *tb; - unsigned short snum = sk->num; - int retval = 1; + struct in6_addr *daddr = &sk->net_pinfo.af_inet6.rcv_saddr; + struct in6_addr *saddr = &sk->net_pinfo.af_inet6.daddr; + int dif = sk->bound_dev_if; + u32 ports = TCP_COMBINED_PORTS(sk->dport, sk->num); + int hash = tcp_v6_hashfn(daddr, sk->num, saddr, sk->dport); + struct tcp_ehash_bucket *head = &tcp_ehash[hash]; + struct sock *sk2, **skp; + struct tcp_tw_bucket *tw; + + write_lock(&head->lock); + + for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { + tw = (struct tcp_tw_bucket*)sk2; + + if(*((__u32 *)&(sk2->dport)) == ports && + sk2->family == PF_INET6 && + !ipv6_addr_cmp(&tw->v6_daddr, saddr) && + !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) && + sk2->bound_dev_if == sk->bound_dev_if) { +#ifdef CONFIG_TCP_TW_RECYCLE + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - /* Freeze the hash while we snoop around. */ - SOCKHASH_LOCK_READ(); - tb = tcp_bhash[tcp_bhashfn(snum)]; - for(; tb; tb = tb->next) { - if(tb->port == snum && tb->owners != NULL) { - /* Almost certainly the re-use port case, search the real hashes - * so it actually scales. (we hope that all ipv6 ftp servers will - * use passive ftp, I just cover this case for completeness) - */ - sk = __tcp_v6_lookup(&sk->net_pinfo.af_inet6.daddr, - sk->dport, - &sk->net_pinfo.af_inet6.rcv_saddr, snum, - sk->bound_dev_if); - SOCKHASH_UNLOCK_READ(); - - if((sk != NULL) && (sk->state != TCP_LISTEN)) - retval = 0; - return retval; + if (sysctl_tcp_tw_recycle && tw->ts_recent_stamp) { + /* See comment in tcp_ipv4.c */ + if ((tp->write_seq = tw->snd_nxt + 2) == 0) + tp->write_seq = 1; + tp->ts_recent = tw->ts_recent; + tp->ts_recent_stamp = tw->ts_recent_stamp; + sock_hold(sk2); + skp = &head->chain; + goto unique; + } else +#endif + goto not_unique; } } - SOCKHASH_UNLOCK_READ(); - return retval; + tw = NULL; + + for(skp = &head->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { + if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) + goto not_unique; + } + +#ifdef CONFIG_TCP_TW_RECYCLE +unique: +#endif + BUG_TRAP(sk->pprev==NULL); + if ((sk->next = *skp) != NULL) + (*skp)->pprev = &sk->next; + + *skp = sk; + sk->pprev = skp; + sk->prot->inuse++; + if(sk->prot->highestinuse < sk->prot->inuse) + sk->prot->highestinuse = sk->prot->inuse; + write_unlock_bh(&head->lock); + +#ifdef CONFIG_TCP_TW_RECYCLE + if (tw) { + /* Silly. Should hash-dance instead... */ + local_bh_disable(); + tcp_tw_deschedule(tw); + tcp_timewait_kill(tw); + local_bh_enable(); + + tcp_tw_put(tw); + } +#endif + return 0; + +not_unique: + write_unlock_bh(&head->lock); + return -EADDRNOTAVAIL; +} + +static int tcp_v6_hash_connecting(struct sock *sk) +{ + unsigned short snum = sk->num; + struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)]; + struct tcp_bind_bucket *tb = head->chain; + + spin_lock_bh(&head->lock); + + if (tb->owners == sk && sk->bind_next == NULL) { + __tcp_v6_hash(sk); + spin_unlock_bh(&head->lock); + return 0; + } else { + spin_unlock_bh(&head->lock); + return tcp_v6_check_established(sk); + } } static __inline__ int tcp_v6_iif(struct sk_buff *skb) @@ -389,17 +477,10 @@ if (sk->state != TCP_CLOSE) return(-EISCONN); - /* - * Don't allow a double connect. - */ - - if(!ipv6_addr_any(&np->daddr)) - return -EINVAL; - if (addr_len < sizeof(struct sockaddr_in6)) return(-EINVAL); - if (usin->sin6_family && usin->sin6_family != AF_INET6) + if (usin->sin6_family != AF_INET6) return(-EAFNOSUPPORT); fl.fl6_flowlabel = 0; @@ -427,15 +508,20 @@ if(addr_type & IPV6_ADDR_MULTICAST) return -ENETUNREACH; - /* - * connect to self not allowed - */ - - if (ipv6_addr_cmp(&usin->sin6_addr, &np->saddr) == 0 && - usin->sin6_port == sk->sport) - return (-EINVAL); + /* We may need to bind the socket. */ + if (sk->num==0 && sk->prot->get_port(sk, 0)) + return -EAGAIN; + sk->sport = htons(sk->num); + +#ifdef CONFIG_TCP_TW_RECYCLE + if (tp->ts_recent_stamp && ipv6_addr_cmp(&np->daddr, &usin->sin6_addr)) { + tp->ts_recent = 0; + tp->ts_recent_stamp = 0; + tp->write_seq = 0; + } +#endif - memcpy(&np->daddr, &usin->sin6_addr, sizeof(struct in6_addr)); + ipv6_addr_copy(&np->daddr, &usin->sin6_addr); np->flow_label = fl.fl6_flowlabel; /* @@ -520,8 +606,7 @@ tp->ext_header_len = 0; if (np->opt) tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen; - /* Reset mss clamp */ - tp->mss_clamp = ~0; + tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); err = -ENOBUFS; buff = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header), @@ -532,28 +617,22 @@ sk->dport = usin->sin6_port; - if (!tcp_v6_unique_address(sk)) { - kfree_skb(buff); - err = -EADDRNOTAVAIL; - goto failure; - } - /* * Init variables */ - tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3], - np->daddr.s6_addr32[3], - sk->sport, sk->dport); + if (!tp->write_seq) + tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3], + np->daddr.s6_addr32[3], + sk->sport, sk->dport); - tcp_connect(sk, buff, dst->pmtu); - - return 0; + err = tcp_connect(sk, buff); + if (err == 0) + return 0; failure: - dst_release(xchg(&sk->dst_cache, NULL)); - memset(&np->daddr, 0, sizeof(struct in6_addr)); - sk->daddr = 0; + __sk_dst_reset(sk); + sk->dport = 0; return err; } @@ -562,6 +641,7 @@ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; int retval = -EINVAL; + lock_sock(sk); /* * Do sanity checking for sendmsg/sendto/send */ @@ -592,6 +672,7 @@ retval = tcp_do_sendmsg(sk, msg); out: + release_sock(sk); return retval; } @@ -606,41 +687,46 @@ struct sock *sk; int err; struct tcp_opt *tp; - __u32 seq; + __u32 seq; if (header + 8 > skb->tail) return; sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex); - if (sk == NULL || sk->state == TCP_TIME_WAIT) { - /* XXX: Update ICMP error count */ + if (sk == NULL) { + icmpv6_statistics.Icmp6InErrors++; + return; + } + + if (sk->state == TCP_TIME_WAIT) { + tcp_tw_put((struct tcp_tw_bucket*)sk); return; } + bh_lock_sock(sk); + if (sk->lock.users) + net_statistics.LockDroppedIcmps++; + tp = &sk->tp_pinfo.af_tcp; seq = ntohl(th->seq); if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { net_statistics.OutOfWindowIcmps++; - return; + goto out; } np = &sk->net_pinfo.af_inet6; + if (type == ICMPV6_PKT_TOOBIG) { struct dst_entry *dst = NULL; - if (sk->state == TCP_LISTEN) - return; - - bh_lock_sock(sk); - if(sk->lock.users) { - bh_unlock_sock(sk); - return; - } + if (sk->lock.users) + goto out; + if ((1<state)&(TCPF_LISTEN|TCPF_CLOSE)) + goto out; /* icmp should have updated the destination cache entry */ - if (sk->dst_cache) - dst = dst_check(&sk->dst_cache, np->dst_cookie); + dst = sk_dst_check(sk, np->dst_cookie); if (dst == NULL) { struct flowi fl; @@ -658,8 +744,7 @@ fl.uli_u.ports.sport = sk->sport; dst = ip6_route_output(sk, &fl); - } else - dst = dst_clone(dst); + } if (dst->error) { sk->err_soft = -dst->error; @@ -668,7 +753,7 @@ tcp_simple_retransmit(sk); } /* else let the usual retransmit timer handle it */ dst_release(dst); - bh_unlock_sock(sk); + goto out; } icmpv6_err_convert(type, code, &err); @@ -678,59 +763,71 @@ struct open_request *req, *prev; struct ipv6hdr hd; case TCP_LISTEN: - bh_lock_sock(sk); - if (sk->lock.users) { - net_statistics.LockDroppedIcmps++; - /* If too many ICMPs get dropped on busy - * servers this needs to be solved differently. - */ - bh_unlock_sock(sk); - return; - } + if (sk->lock.users) + goto out; /* Grrrr - fix this later. */ ipv6_addr_copy(&hd.saddr, saddr); ipv6_addr_copy(&hd.daddr, daddr); req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev); - if (!req || (seq != req->snt_isn)) { - net_statistics.OutOfWindowIcmps++; - bh_unlock_sock(sk); - return; - } + if (!req) + goto out; + if (req->sk) { + struct sock *nsk = req->sk; + + sock_hold(nsk); bh_unlock_sock(sk); - sk = req->sk; /* report error in accept */ + sock_put(sk); + sk = nsk; + + BUG_TRAP(sk->lock.users==0); + + tp = &sk->tp_pinfo.af_tcp; + if (!between(seq, tp->snd_una, tp->snd_nxt)) { + net_statistics.OutOfWindowIcmps++; + goto out; + } } else { + if (seq != req->snt_isn) { + net_statistics.OutOfWindowIcmps++; + goto out; + } + tp->syn_backlog--; tcp_synq_unlink(tp, req, prev); + tcp_dec_slow_timer(TCP_SLT_SYNACK); req->class->destructor(req); tcp_openreq_free(req); - bh_unlock_sock(sk); + goto out; } - - /* FALL THROUGH */ + break; case TCP_SYN_SENT: - case TCP_SYN_RECV: /* Cannot happen */ - tcp_statistics.TcpAttemptFails++; - sk->err = err; - sk->zapped = 1; - mb(); - sk->error_report(sk); - return; + case TCP_SYN_RECV: /* Cannot happen. + It can, it SYNs are crossed. --ANK */ + if (sk->lock.users == 0) { + tcp_statistics.TcpAttemptFails++; + sk->err = err; + sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + + tcp_set_state(sk, TCP_CLOSE); + tcp_done(sk); + } else { + sk->err_soft = err; + } + goto out; } - if (np->recverr) { - /* This code isn't serialized with the socket code */ - /* ANK (980927) ... which is harmless now, - sk->err's may be safely lost. - */ + if (sk->lock.users == 0 && np->recverr) { sk->err = err; - mb(); sk->error_report(sk); } else { sk->err_soft = err; - mb(); } + +out: + bh_unlock_sock(sk); + sock_put(sk); } @@ -740,7 +837,6 @@ struct dst_entry *dst; struct ipv6_txoptions *opt = NULL; struct flowi fl; - int mss; fl.proto = IPPROTO_TCP; fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr; @@ -769,9 +865,7 @@ if (dst->error) goto done; - mss = dst->pmtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr); - - skb = tcp_make_synack(sk, dst, req, mss); + skb = tcp_make_synack(sk, dst, req); if (skb) { struct tcphdr *th = skb->h.th; @@ -798,7 +892,9 @@ } static struct or_calltable or_ipv6 = { + AF_INET6, tcp_v6_send_synack, + tcp_v6_or_send_ack, tcp_v6_or_free, tcp_v6_send_reset }; @@ -825,20 +921,14 @@ /* FIXME: this is substantially similar to the ipv4 code. * Can some kind of merge be done? -- erics */ -static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn) +static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) { struct tcp_opt tp; struct open_request *req; - - /* If the socket is dead, don't accept the connection. */ - if (sk->dead) { - SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n", sk); - tcp_statistics.TcpAttemptFails++; - return -ENOTCONN; - } + __u32 isn = TCP_SKB_CB(skb)->when; if (skb->protocol == __constant_htons(ETH_P_IP)) - return tcp_v4_conn_request(sk, skb, isn); + return tcp_v4_conn_request(sk, skb); /* FIXME: do the same check for anycast */ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) @@ -869,17 +959,15 @@ req->rcv_isn = TCP_SKB_CB(skb)->seq; req->snt_isn = isn; tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0; - tp.mss_clamp = 65535; + + tp.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); + tp.user_mss = sk->tp_pinfo.af_tcp.user_mss; + tcp_parse_options(NULL, skb->h.th, &tp, 0); - if (tp.mss_clamp == 65535) - tp.mss_clamp = 576 - sizeof(struct ipv6hdr) - sizeof(struct iphdr); - if (sk->tp_pinfo.af_tcp.user_mss && sk->tp_pinfo.af_tcp.user_mss < tp.mss_clamp) - tp.mss_clamp = sk->tp_pinfo.af_tcp.user_mss; - - req->mss = tp.mss_clamp; - if (tp.saw_tstamp) - req->ts_recent = tp.rcv_tsval; - req->tstamp_ok = tp.tstamp_ok; + + req->mss = tp.mss_clamp; + req->ts_recent = tp.saw_tstamp ? tp.rcv_tsval : 0; + req->tstamp_ok = tp.tstamp_ok; req->sack_ok = tp.sack_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; @@ -887,7 +975,9 @@ ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr); ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr); req->af.v6_req.pktopts = NULL; - if (ipv6_opt_accepted(sk, skb)) { + if (ipv6_opt_accepted(sk, skb) || + sk->net_pinfo.af_inet6.rxopt.bits.rxinfo || + sk->net_pinfo.af_inet6.rxopt.bits.rxhlim) { atomic_inc(&skb->users); req->af.v6_req.pktopts = skb; } @@ -944,7 +1034,7 @@ if (newsk == NULL) return NULL; - + np = &newsk->net_pinfo.af_inet6; ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF), @@ -959,6 +1049,14 @@ newsk->backlog_rcv = tcp_v4_do_rcv; newsk->net_pinfo.af_inet6.pktoptions = NULL; newsk->net_pinfo.af_inet6.opt = NULL; + newsk->net_pinfo.af_inet6.mcast_oif = tcp_v6_iif(skb); + newsk->net_pinfo.af_inet6.mcast_hops = skb->nh.ipv6h->hop_limit; + + /* Charge newly allocated IPv6 socket. Though it is mapped, + * it is IPv6 yet. + */ + atomic_inc(&inet6_sock_nr); + MOD_INC_USE_COUNT; /* It is tricky place. Until this moment IPv4 tcp worked with IPv6 af_tcp.af_specific. @@ -1007,6 +1105,10 @@ if (newsk == NULL) goto out; + /* Charge newly allocated IPv6 socket */ + atomic_inc(&inet6_sock_nr); + MOD_INC_USE_COUNT; + ip6_dst_store(newsk, dst, NULL); newtp = &(newsk->tp_pinfo.af_tcp); @@ -1021,16 +1123,21 @@ First: no IPv4 options. */ - newsk->opt = NULL; + newsk->protinfo.af_inet.opt = NULL; /* Clone RX bits */ np->rxopt.all = sk->net_pinfo.af_inet6.rxopt.all; /* Clone pktoptions received with SYN */ - np->pktoptions = req->af.v6_req.pktopts; - if (np->pktoptions) - atomic_inc(&np->pktoptions->users); + np->pktoptions = NULL; + if (req->af.v6_req.pktopts) { + np->pktoptions = skb_clone(req->af.v6_req.pktopts, GFP_ATOMIC); + if (np->pktoptions) + skb_set_owner_r(np->pktoptions, newsk); + } np->opt = NULL; + np->mcast_oif = tcp_v6_iif(skb); + np->mcast_hops = skb->nh.ipv6h->hop_limit; /* Clone native IPv6 options from listening socket (if any) @@ -1049,15 +1156,21 @@ newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen; tcp_sync_mss(newsk, dst->pmtu); - newtp->rcv_mss = newtp->mss_clamp; + tcp_initialize_rcv_mss(newsk); + + if (newsk->rcvbuf < (3 * (dst->advmss+60+MAX_HEADER+15))) + newsk->rcvbuf = min ((3 * (dst->advmss+60+MAX_HEADER+15)), sysctl_rmem_max); + if (newsk->sndbuf < (3 * (newtp->mss_clamp+60+MAX_HEADER+15))) + newsk->sndbuf = min ((3 * (newtp->mss_clamp+60+MAX_HEADER+15)), sysctl_wmem_max); newsk->daddr = LOOPBACK4_IPV6; newsk->saddr = LOOPBACK4_IPV6; newsk->rcv_saddr= LOOPBACK4_IPV6; - newsk->prot->hash(newsk); + bh_lock_sock(newsk); + + __tcp_v6_hash(newsk); tcp_inherit_port(sk, newsk); - sk->data_ready(sk, 0); /* Deliver SIGIO */ return newsk; @@ -1104,10 +1217,8 @@ t1->seq = th->ack_seq; } else { t1->ack = 1; - if(!th->syn) - t1->ack_seq = th->seq; - else - t1->ack_seq = htonl(ntohl(th->seq)+1); + t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + + skb->len - (th->doff<<2)); } buff->csum = csum_partial((char *)t1, sizeof(*t1), 0); @@ -1139,6 +1250,85 @@ kfree_skb(buff); } +static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +{ + struct tcphdr *th = skb->h.th, *t1; + struct sk_buff *buff; + struct flowi fl; + int tot_len = sizeof(struct tcphdr); + + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC); + if (buff == NULL) + return; + + skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr)); + + if (ts) + tot_len += 3*4; + + t1 = (struct tcphdr *) skb_push(buff,tot_len); + + /* Swap the send and the receive. */ + memset(t1, 0, sizeof(*t1)); + t1->dest = th->source; + t1->source = th->dest; + t1->doff = tot_len/4; + t1->seq = htonl(seq); + t1->ack_seq = htonl(ack); + t1->ack = 1; + t1->window = htons(win); + + if (ts) { + u32 *ptr = (u32*)(t1 + 1); + *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + *ptr++ = htonl(tcp_time_stamp); + *ptr = htonl(ts); + } + + buff->csum = csum_partial((char *)t1, tot_len, 0); + + fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr; + fl.nl_u.ip6_u.saddr = &skb->nh.ipv6h->daddr; + fl.fl6_flowlabel = 0; + + t1->check = csum_ipv6_magic(fl.nl_u.ip6_u.saddr, + fl.nl_u.ip6_u.daddr, + tot_len, IPPROTO_TCP, + buff->csum); + + fl.proto = IPPROTO_TCP; + fl.oif = tcp_v6_iif(skb); + fl.uli_u.ports.dport = t1->dest; + fl.uli_u.ports.sport = t1->source; + + buff->dst = ip6_route_output(NULL, &fl); + + if (buff->dst->error == 0) { + ip6_xmit(NULL, buff, &fl, NULL); + tcp_statistics.TcpOutSegs++; + return; + } + + kfree_skb(buff); +} + +static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; + + tcp_v6_send_ack(skb, tw->snd_nxt, tw->rcv_nxt, 0, tw->ts_recent); + + tcp_tw_put(tw); +} + +static void tcp_v6_or_send_ack(struct sk_buff *skb, struct open_request *req) +{ + tcp_v6_send_ack(skb, req->snt_isn+1, req->rcv_isn+1, req->rcv_wnd, req->ts_recent); +} + static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, struct ipv6hdr *ip6h, struct tcphdr *th, @@ -1154,10 +1344,20 @@ */ prev = (struct open_request *) (&tp->syn_wait_queue); for (req = prev->dl_next; req; req = req->dl_next) { - if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) && + if (req->rmt_port == rport && + req->class->family == AF_INET6 && + !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) && !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) && - req->rmt_port == rport && (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) { + if (req->sk) { + bh_lock_sock(req->sk); + BUG_TRAP(req->sk->lock.users==0); + if (req->sk->state == TCP_CLOSE) { + bh_unlock_sock(req->sk); + prev = req; + continue; + } + } *prevp = prev; return req; } @@ -1166,57 +1366,44 @@ return NULL; } -static void tcp_v6_rst_req(struct sock *sk, struct sk_buff *skb) + +static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct open_request *req, *prev; + struct tcphdr *th = skb->h.th; + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,tcp_v6_iif(skb),&prev); - if (!req) - return; - /* Sequence number check required by RFC793 */ - if (before(TCP_SKB_CB(skb)->seq, req->rcv_isn) || - after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1)) - return; - if(req->sk) - sk->ack_backlog--; - else - tp->syn_backlog--; - tcp_synq_unlink(tp, req, prev); - req->class->destructor(req); - tcp_openreq_free(req); - net_statistics.EmbryonicRsts++; -} - -static inline struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) -{ - struct tcphdr *th = skb->h.th; - u32 flg = ((u32 *)th)[3]; - - /* Check for RST */ - if (flg & __constant_htonl(0x00040000)) { - tcp_v6_rst_req(sk, skb); - return NULL; - } - - /* Check SYN|ACK */ - if (flg & __constant_htonl(0x00120000)) { - struct open_request *req, *dummy; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - - req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &dummy); - if (req) { - sk = tcp_check_req(sk, skb, req); - } -#if 0 /*def CONFIG_SYN_COOKIES */ - else { - sk = cookie_v6_check(sk, skb); - } + /* Find possible connection requests. */ + req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &prev); + if (req) + return tcp_check_req(sk, skb, req, prev); + +#if 0 /*def CONFIG_SYN_COOKIES*/ + if (!th->rst && (th->syn || th->ack)) + sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt)); #endif - } return sk; } + +static int tcp_v6_csum_verify(struct sk_buff *skb) +{ + switch (skb->ip_summed) { + case CHECKSUM_NONE: + skb->csum = csum_partial((char *)skb->h.th, skb->len, 0); + case CHECKSUM_HW: + if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr,skb->csum)) { + printk(KERN_DEBUG "tcp v6 csum failed\n"); + return 1; + } + skb->ip_summed = CHECKSUM_UNNECESSARY; + default: + /* CHECKSUM_UNNECESSARY */ + }; + return 0; +} + /* The socket must have it's spinlock held when we get * here. * @@ -1230,7 +1417,7 @@ #ifdef CONFIG_FILTER struct sk_filter *filter; #endif - int users = 0, need_unlock = 0; + int users = 0; /* Imagine: socket is IPv6. IPv4 packet arrives, goes to IPv4 receive handler and backlogged. @@ -1282,6 +1469,9 @@ } if (sk->state == TCP_ESTABLISHED) { /* Fast path */ + /* Ready to move deeper ... */ + if (tcp_v6_csum_verify(skb)) + goto csum_err; if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) goto reset; if (users) @@ -1289,6 +1479,9 @@ return 0; } + if (tcp_v6_csum_verify(skb)) + goto csum_err; + if (sk->state == TCP_LISTEN) { struct sock *nsk; @@ -1302,15 +1495,24 @@ * the new socket.. */ if(nsk != sk) { - bh_lock_sock(nsk); - if (nsk->lock.users) { - skb_orphan(skb); - sk_add_backlog(nsk, skb); - bh_unlock_sock(nsk); - return 0; - } - need_unlock = 1; - sk = nsk; + int ret; + int state = nsk->state; + + skb_orphan(skb); + BUG_TRAP(nsk->lock.users == 0); + skb_set_owner_r(skb, nsk); + ret = tcp_rcv_state_process(nsk, skb, skb->h.th, skb->len); + + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && nsk->state != state) + sk->data_ready(sk, 0); + bh_unlock_sock(nsk); + + if (ret) + goto reset; + if (users) + kfree_skb(skb); + return 0; } } @@ -1318,7 +1520,7 @@ goto reset; if (users) goto ipv6_pktoptions; - goto out_maybe_unlock; + return 0; reset: tcp_v6_send_reset(skb); @@ -1326,7 +1528,11 @@ if (users) kfree_skb(skb); kfree_skb(skb); - goto out_maybe_unlock; + return 0; +csum_err: + tcp_statistics.TcpInErrs++; + goto discard; + ipv6_pktoptions: /* Do you ask, what is it? @@ -1339,6 +1545,10 @@ if (atomic_read(&skb->users) > users && TCP_SKB_CB(skb)->end_seq == sk->tp_pinfo.af_tcp.rcv_nxt && !((1<state)&(TCPF_CLOSE|TCPF_LISTEN))) { + if (sk->net_pinfo.af_inet6.rxopt.bits.rxinfo) + sk->net_pinfo.af_inet6.mcast_oif = tcp_v6_iif(skb); + if (sk->net_pinfo.af_inet6.rxopt.bits.rxhlim) + sk->net_pinfo.af_inet6.mcast_hops = skb->nh.ipv6h->hop_limit; if (ipv6_opt_accepted(sk, skb)) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); kfree_skb(skb); @@ -1355,9 +1565,6 @@ if (skb) kfree_skb(skb); -out_maybe_unlock: - if (need_unlock) - bh_unlock_sock(sk); return 0; } @@ -1389,36 +1596,21 @@ if (len < sizeof(struct tcphdr)) goto bad_packet; - /* - * Try to use the device checksum if provided. - */ - - switch (skb->ip_summed) { - case CHECKSUM_NONE: - skb->csum = csum_partial((char *)th, len, 0); - case CHECKSUM_HW: - if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) { - printk(KERN_DEBUG "tcp csum failed\n"); - bad_packet: - tcp_statistics.TcpInErrs++; - goto discard_it; - } - default: - /* CHECKSUM_UNNECESSARY */ - }; - - SOCKHASH_LOCK_READ_BH(); - sk = __tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb)); - SOCKHASH_UNLOCK_READ_BH(); - - if (!sk) - goto no_tcp_socket; - TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); + TCP_SKB_CB(skb)->when = 0; skb->used = 0; + + sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb)); + + if (!sk) + goto no_tcp_socket; + +process: + if(!ipsec_sk_policy(sk,skb)) + goto discard_and_relse; if(sk->state == TCP_TIME_WAIT) goto do_time_wait; @@ -1430,10 +1622,16 @@ sk_add_backlog(sk, skb); bh_unlock_sock(sk); + sock_put(sk); return ret; no_tcp_socket: - tcp_v6_send_reset(skb); + if (tcp_v6_csum_verify(skb)) { +bad_packet: + tcp_statistics.TcpInErrs++; + } else { + tcp_v6_send_reset(skb); + } discard_it: @@ -1444,20 +1642,50 @@ kfree_skb(skb); return 0; +discard_and_relse: + sock_put(sk); + goto discard_it; + do_time_wait: - if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, - skb, th, skb->len)) + if (tcp_v6_csum_verify(skb)) { + tcp_statistics.TcpInErrs++; + sock_put(sk); + goto discard_it; + } + + switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, + skb, th, skb->len)) { + case TCP_TW_SYN: + { + struct sock *sk2; + + sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); + if (sk2 != NULL) { + tcp_tw_deschedule((struct tcp_tw_bucket *)sk); + tcp_timewait_kill((struct tcp_tw_bucket *)sk); + tcp_tw_put((struct tcp_tw_bucket *)sk); + sk = sk2; + goto process; + } + /* Fall through to ACK */ + } + case TCP_TW_ACK: + tcp_v6_timewait_ack(sk, skb); + break; + case TCP_TW_RST: goto no_tcp_socket; + case TCP_TW_SUCCESS: + } goto discard_it; } static int tcp_v6_rebuild_header(struct sock *sk) { - struct dst_entry *dst = NULL; + int err; + struct dst_entry *dst; struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; - if (sk->dst_cache) - dst = dst_check(&sk->dst_cache, np->dst_cookie); + dst = sk_dst_check(sk, np->dst_cookie); if (dst == NULL) { struct flowi fl; @@ -1475,39 +1703,29 @@ fl.nl_u.ip6_u.daddr = rt0->addr; } - dst = ip6_route_output(sk, &fl); if (dst->error) { + err = dst->error; dst_release(dst); - return dst->error; + return err; } ip6_dst_store(sk, dst, NULL); + return 0; } - return dst->error; -} - -static struct sock * tcp_v6_get_sock(struct sk_buff *skb, struct tcphdr *th) -{ - struct in6_addr *saddr; - struct in6_addr *daddr; - - if (skb->protocol == __constant_htons(ETH_P_IP)) - return ipv4_specific.get_sock(skb, th); - - saddr = &skb->nh.ipv6h->saddr; - daddr = &skb->nh.ipv6h->daddr; - return tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb)); + err = dst->error; + dst_release(dst); + return err; } -static void tcp_v6_xmit(struct sk_buff *skb) +static int tcp_v6_xmit(struct sk_buff *skb) { struct sock *sk = skb->sk; struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6; struct flowi fl; - struct dst_entry *dst = sk->dst_cache; + struct dst_entry *dst; fl.proto = IPPROTO_TCP; fl.fl6_dst = &np->daddr; @@ -1522,8 +1740,7 @@ fl.nl_u.ip6_u.daddr = rt0->addr; } - if (sk->dst_cache) - dst = dst_check(&sk->dst_cache, np->dst_cookie); + dst = sk_dst_check(sk, np->dst_cookie); if (dst == NULL) { dst = ip6_route_output(sk, &fl); @@ -1531,18 +1748,19 @@ if (dst->error) { sk->err_soft = -dst->error; dst_release(dst); - return; + return -sk->err_soft; } + dst_clone(dst); ip6_dst_store(sk, dst, NULL); } - skb->dst = dst_clone(dst); + skb->dst = dst; /* Restore final destination back after routing done */ fl.nl_u.ip6_u.daddr = &np->daddr; - ip6_xmit(sk, skb, &fl, np->opt); + return ip6_xmit(sk, skb, &fl, np->opt); } static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) @@ -1563,7 +1781,7 @@ tcp_v6_rebuild_header, tcp_v6_conn_request, tcp_v6_syn_recv_sock, - tcp_v6_get_sock, + tcp_v6_hash_connecting, sizeof(struct ipv6hdr), ipv6_setsockopt, @@ -1582,7 +1800,7 @@ tcp_v4_rebuild_header, tcp_v6_conn_request, tcp_v6_syn_recv_sock, - tcp_v6_get_sock, + tcp_v4_hash_connecting, sizeof(struct iphdr), ipv6_setsockopt, @@ -1591,6 +1809,8 @@ sizeof(struct sockaddr_in6) }; + + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1601,9 +1821,8 @@ skb_queue_head_init(&tp->out_of_order_queue); tcp_init_xmit_timers(sk); - tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ + tp->rto = TCP_TIMEOUT_INIT; tp->mdev = TCP_TIMEOUT_INIT; - tp->mss_clamp = ~0; /* So many TCP implementations out there (incorrectly) count the * initial SYN frame in their delayed-ACK and congestion control @@ -1617,10 +1836,11 @@ */ tp->snd_cwnd_cnt = 0; tp->snd_ssthresh = 0x7fffffff; + tp->snd_cwnd_clamp = ~0; + tp->mss_cache = 536; sk->state = TCP_CLOSE; sk->max_ack_backlog = SOMAXCONN; - tp->rcv_mss = 536; /* Init SYN queue. */ tcp_synq_init(tp); @@ -1639,9 +1859,6 @@ tcp_clear_xmit_timers(sk); - if (sk->keepopen) - tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); - /* * Cleanup up the write buffer. */ @@ -1674,7 +1891,7 @@ dest = &req->af.v6_req.rmt_addr; sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], @@ -1689,8 +1906,8 @@ req->retrans, sk->socket ? sk->socket->inode->i_uid : 0, 0, /* non standard timer */ - 0 /* open_requests have no inode */ - ); + 0, /* open_requests have no inode */ + 0, req); } static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i) @@ -1722,7 +1939,7 @@ sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -1733,13 +1950,13 @@ timer_active, timer_expires-jiffies, tp->retransmits, sp->socket ? sp->socket->inode->i_uid : 0, - timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) { - extern int tcp_tw_death_row_slot; struct in6_addr *dest, *src; __u16 destp, srcp; int slot_dist; @@ -1757,24 +1974,28 @@ sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08X %08X %5d %8d %d", + "%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, TCP_TIME_WAIT, 0, 0, - 3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0); + 3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0, + atomic_read(&tw->refcnt), tw); } +#define LINE_LEN 190 +#define LINE_FMT "%-190s\n" + int tcp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { int len = 0, num = 0, i; off_t begin, pos = 0; - char tmpbuf[150]; + char tmpbuf[LINE_LEN+2]; - if(offset < 149) - len += sprintf(buffer, "%-148s\n", + if(offset < LINE_LEN+1) + len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ "remote_address " /* 38 */ @@ -1783,10 +2004,10 @@ /*----*/ /*144 */ - pos = 149; - SOCKHASH_LOCK_READ(); + pos = LINE_LEN+1; /* First, walk listening socket table. */ + tcp_listen_lock(); for(i = 0; i < TCP_LHTABLE_SIZE; i++) { struct sock *sk = tcp_listening_hash[i]; @@ -1796,64 +2017,81 @@ if (sk->family != PF_INET6) continue; - pos += 149; + pos += LINE_LEN+1; if (pos >= offset) { get_tcp6_sock(sk, tmpbuf, num); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); - if (len >= length) - goto out; + len += sprintf(buffer+len, LINE_FMT, tmpbuf); + if (len >= length) { + tcp_listen_unlock(); + goto out_no_bh; + } } + + lock_sock(sk); for (req = tp->syn_wait_queue; req; req = req->dl_next, num++) { if (req->sk) continue; - pos += 149; + if (req->class->family != PF_INET6) + continue; + pos += LINE_LEN+1; if (pos < offset) continue; get_openreq6(sk, req, tmpbuf, num); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); - if(len >= length) - goto out; + len += sprintf(buffer+len, LINE_FMT, tmpbuf); + if(len >= length) { + release_sock(sk); + tcp_listen_unlock(); + goto out_no_bh; + } } + release_sock(sk); } } + tcp_listen_unlock(); + + local_bh_disable(); /* Next, walk established hash chain. */ - for (i = 0; i < (tcp_ehash_size >> 1); i++) { + for (i = 0; i < tcp_ehash_size; i++) { + struct tcp_ehash_bucket *head = &tcp_ehash[i]; struct sock *sk; + struct tcp_tw_bucket *tw; - for(sk = tcp_ehash[i]; sk; sk = sk->next, num++) { + read_lock(&head->lock); + for(sk = head->chain; sk; sk = sk->next, num++) { if (sk->family != PF_INET6) continue; - pos += 149; + pos += LINE_LEN+1; if (pos < offset) continue; get_tcp6_sock(sk, tmpbuf, num); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); - if(len >= length) + len += sprintf(buffer+len, LINE_FMT, tmpbuf); + if(len >= length) { + read_unlock(&head->lock); goto out; + } } - } - - /* Finally, walk time wait buckets. */ - for (i = (tcp_ehash_size>>1); i < tcp_ehash_size; i++) { - struct tcp_tw_bucket *tw; - for (tw = (struct tcp_tw_bucket *)tcp_ehash[i]; + for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain; tw != NULL; tw = (struct tcp_tw_bucket *)tw->next, num++) { if (tw->family != PF_INET6) continue; - pos += 149; + pos += LINE_LEN+1; if (pos < offset) continue; get_timewait6_sock(tw, tmpbuf, num); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); - if(len >= length) + len += sprintf(buffer+len, LINE_FMT, tmpbuf); + if(len >= length) { + read_unlock(&head->lock); goto out; + } } + read_unlock(&head->lock); } out: - SOCKHASH_UNLOCK_READ(); + local_bh_enable(); +out_no_bh: begin = len - (pos - offset); *start = buffer + begin; @@ -1868,6 +2106,7 @@ struct proto tcpv6_prot = { tcp_close, /* close */ tcp_v6_connect, /* connect */ + tcp_disconnect, /* disconnect */ tcp_accept, /* accept */ NULL, /* retransmit */ tcp_write_wakeup, /* write_wakeup */ @@ -1884,7 +2123,7 @@ NULL, /* bind */ tcp_v6_do_rcv, /* backlog_rcv */ tcp_v6_hash, /* hash */ - tcp_v6_unhash, /* unhash */ + tcp_unhash, /* unhash */ tcp_v6_get_port, /* get_port */ 128, /* max_header */ 0, /* retransmits */ diff -u --recursive --new-file v2.3.14/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.3.14/linux/net/ipv6/udp.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipv6/udp.c Mon Aug 23 10:01:02 1999 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.43 1999/07/02 11:26:44 davem Exp $ + * $Id: udp.c,v 1.45 1999/08/20 11:06:32 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -51,7 +52,7 @@ */ static int udp_v6_get_port(struct sock *sk, unsigned short snum) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if (snum == 0) { int best_size_so_far, best, result, i; @@ -112,11 +113,11 @@ } sk->num = snum; - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); return 0; fail: - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); return 1; } @@ -124,7 +125,7 @@ { struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)]; - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if ((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; @@ -132,20 +133,22 @@ sk->prot->inuse++; if(sk->prot->highestinuse < sk->prot->inuse) sk->prot->highestinuse = sk->prot->inuse; - SOCKHASH_UNLOCK_WRITE(); + sock_hold(sk); + write_unlock_bh(&udp_hash_lock); } static void udp_v6_unhash(struct sock *sk) { - SOCKHASH_LOCK_WRITE(); + write_lock_bh(&udp_hash_lock); if (sk->pprev) { if (sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->prot->inuse--; + __sock_put(sk); } - SOCKHASH_UNLOCK_WRITE(); + write_unlock_bh(&udp_hash_lock); } static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, @@ -155,11 +158,10 @@ unsigned short hnum = ntohs(dport); int badness = -1; - SOCKHASH_LOCK_READ(); + read_lock(&udp_hash_lock); for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { if((sk->num == hnum) && - (sk->family == PF_INET6) && - !(sk->dead && (sk->state == TCP_CLOSE))) { + (sk->family == PF_INET6)) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; int score = 0; if(sk->dport) { @@ -191,7 +193,9 @@ } } } - SOCKHASH_UNLOCK_READ(); + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); return result; } @@ -219,7 +223,7 @@ if (addr_len < sizeof(*usin)) return -EINVAL; - if (usin->sin6_family && usin->sin6_family != AF_INET6) + if (usin->sin6_family != AF_INET6) return -EAFNOSUPPORT; fl.fl6_flowlabel = 0; @@ -334,13 +338,7 @@ static void udpv6_close(struct sock *sk, long timeout) { - bh_lock_sock(sk); - - /* See for explanation: raw_close in ipv4/raw.c */ - sk->state = TCP_CLOSE; - udp_v6_unhash(sk); - sk->dead = 1; - destroy_sock(sk); + inet_sock_release(sk); } #ifndef HAVE_CSUM_COPY_USER @@ -383,6 +381,19 @@ copied); } else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) { if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) { + /* Clear queue. */ + if (flags&MSG_PEEK) { + int clear = 0; + spin_lock_irq(&sk->receive_queue.lock); + if (skb == skb_peek(&sk->receive_queue)) { + __skb_unlink(skb, &sk->receive_queue); + clear = 1; + } + spin_unlock_irq(&sk->receive_queue.lock); + if (clear) + kfree_skb(skb); + } + /* Error for blocking case is chosen to masquerade as some normal condition. */ @@ -426,7 +437,7 @@ if (skb->protocol == __constant_htons(ETH_P_IP)) { ipv6_addr_set(&sin6->sin6_addr, 0, 0, __constant_htonl(0xffff), skb->nh.iph->saddr); - if (sk->ip_cmsg_flags) + if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); } else { memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, @@ -467,16 +478,19 @@ if (!icmpv6_err_convert(type, code, &err) && !sk->net_pinfo.af_inet6.recverr) - return; + goto out; - if (sk->bsdism && sk->state!=TCP_ESTABLISHED) - return; + if (sk->bsdism && sk->state!=TCP_ESTABLISHED && + !sk->net_pinfo.af_inet6.recverr) + goto out; if (sk->net_pinfo.af_inet6.recverr) ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); sk->err = err; sk->error_report(sk); +out: + sock_put(sk); } static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) @@ -511,8 +525,7 @@ struct sock *s = sk; unsigned short num = ntohs(loc_port); for(; s; s = s->next) { - if((s->num == num) && - !(s->dead && (s->state == TCP_CLOSE))) { + if(s->num == num) { struct ipv6_pinfo *np = &s->net_pinfo.af_inet6; if(s->dport) { if(s->dport != rmt_port) @@ -549,6 +562,7 @@ struct sk_buff *buff; int dif; + read_lock(&udp_hash_lock); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; dif = skb->dev->ifindex; sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); @@ -573,6 +587,7 @@ free_skb: kfree_skb(skb); } + read_unlock(&udp_hash_lock); } int udpv6_rcv(struct sk_buff *skb, unsigned long len) @@ -663,11 +678,17 @@ kfree_skb(skb); return(0); } + if (0/*sk->user_callback && + sk->user_callback(sk->user_data, skb) == 0*/) { + udp_stats_in6.UdpInDatagrams++; + sock_put(sk); + return(0); + } /* deliver */ udpv6_queue_rcv_skb(sk, skb); - + sock_put(sk); return(0); discard: @@ -764,9 +785,6 @@ if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr)) return -EMSGSIZE; - if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT)) - return -EINVAL; - fl.fl6_flowlabel = 0; if (sin6) { @@ -886,6 +904,9 @@ "UDPv6" /* name */ }; +#define LINE_LEN 190 +#define LINE_FMT "%-190s\n" + static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i) { struct in6_addr *dest, *src; @@ -901,7 +922,7 @@ timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies); sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -910,8 +931,9 @@ sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, timer_active ? sp->timeout : 0, - sp->socket ? sp->socket->inode->i_ino : 0); + sp->socket->inode->i_uid, 0, + sp->socket ? sp->socket->inode->i_ino : 0, + atomic_read(&sp->refcnt), sp); } int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy) @@ -919,10 +941,10 @@ int len = 0, num = 0, i; off_t pos = 0; off_t begin; - char tmpbuf[150]; + char tmpbuf[LINE_LEN+2]; - if (offset < 149) - len += sprintf(buffer, "%-148s\n", + if (offset < LINE_LEN+1) + len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ "remote_address " /* 38 */ @@ -930,25 +952,25 @@ " uid timeout inode"); /* 21 */ /*----*/ /*144 */ - pos = 149; - SOCKHASH_LOCK_READ(); + pos = LINE_LEN+1; + read_lock(&udp_hash_lock); for (i = 0; i < UDP_HTABLE_SIZE; i++) { struct sock *sk; for (sk = udp_hash[i]; sk; sk = sk->next, num++) { if (sk->family != PF_INET6) continue; - pos += 149; + pos += LINE_LEN+1; if (pos < offset) continue; get_udp6_sock(sk, tmpbuf, i); - len += sprintf(buffer+len, "%-148s\n", tmpbuf); + len += sprintf(buffer+len, LINE_FMT, tmpbuf); if(len >= length) goto out; } } out: - SOCKHASH_UNLOCK_READ(); + read_unlock(&udp_hash_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; @@ -962,6 +984,7 @@ struct proto udpv6_prot = { udpv6_close, /* close */ udpv6_connect, /* connect */ + udp_disconnect, /* disconnect */ NULL, /* accept */ NULL, /* retransmit */ NULL, /* write_wakeup */ diff -u --recursive --new-file v2.3.14/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.3.14/linux/net/ipx/af_ipx.c Wed Aug 18 11:38:49 1999 +++ linux/net/ipx/af_ipx.c Mon Aug 23 10:01:02 1999 @@ -96,7 +96,6 @@ #include #include #include -#include #include #include @@ -718,13 +717,6 @@ struct ipxhdr *ipx = skb->nh.ipxh; ipx_interface *i; - /* We firewall first, ask questions later. */ - if (call_in_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)!=FW_ACCEPT) - { - kfree_skb(skb); - return (0); - } - /* See if we should update our network number */ if(!intrfc->if_netnum /* net number of intrfc not known yet (== 0) */ && (ipx->ipx_source.net == ipx->ipx_dest.net) /* intra packet */ @@ -790,13 +782,8 @@ if(i - 1 == ipx->ipx_tctrl) { ipx->ipx_dest.net = ifcs->if_netnum; - /* See if we are allowed to firewall forward */ - if(call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb) == FW_ACCEPT) - { - skb2=skb_clone(skb, GFP_ATOMIC); - if(skb2) - ipxrtr_route_skb(skb2); - } + skb2=skb_clone(skb, GFP_ATOMIC); + ipxrtr_route_skb(skb2); } } @@ -812,13 +799,6 @@ if(intrfc->if_netnum != ipx->ipx_dest.net) { - /* See if we are allowed to firewall forward */ - if(call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb) != FW_ACCEPT) - { - kfree_skb(skb); - return (0); - } - /* We only route point-to-point packets. */ if(skb->pkt_type == PACKET_HOST) { @@ -937,7 +917,7 @@ && (ipxitf_find_using_net(idef->ipx_network) != NULL)) return (-EADDRINUSE); - dev = dev_get(idef->ipx_device); + dev = __dev_get_by_name(idef->ipx_device); if(dev == NULL) return (-ENODEV); @@ -1043,7 +1023,7 @@ if(dlink_type == 0) return (-EPROTONOSUPPORT); - dev = dev_get(idef->ipx_device); + dev = __dev_get_by_name(idef->ipx_device); if(dev == NULL) return (-ENODEV); @@ -1154,7 +1134,7 @@ return (-EFAULT); sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; - dev = dev_get(ifr.ifr_name); + dev = __dev_get_by_name(ifr.ifr_name); if(!dev) return (-ENODEV); @@ -1424,12 +1404,6 @@ else ipx->ipx_checksum = ipx_set_checksum(ipx, len + sizeof(struct ipxhdr)); - if(call_out_firewall(PF_IPX, skb->dev, ipx, NULL, &skb) != FW_ACCEPT) - { - kfree_skb(skb); - return (-EPERM); - } - return (ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? rt->ir_router_node : ipx->ipx_dest.node)); } @@ -1813,7 +1787,7 @@ return (0); } -static int ipx_release(struct socket *sock, struct socket *peer) +static int ipx_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -2010,12 +1984,6 @@ static int ipx_accept(struct socket *sock, struct socket *newsock, int flags) { - if(newsock->sk) - { - sk_free(newsock->sk); - MOD_DEC_USE_COUNT; - } - return (-EOPNOTSUPP); } @@ -2367,9 +2335,8 @@ ipx_create }; -static struct proto_ops ipx_dgram_ops = { +static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = { PF_IPX, - sock_no_dup, ipx_release, ipx_bind, ipx_connect, @@ -2384,8 +2351,13 @@ ipx_getsockopt, sock_no_fcntl, ipx_sendmsg, - ipx_recvmsg + ipx_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(ipx_dgram, PF_IPX); + /* Called by protocol.c on kernel start up */ diff -u --recursive --new-file v2.3.14/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c --- v2.3.14/linux/net/ipx/af_spx.c Mon Jan 4 15:31:35 1999 +++ linux/net/ipx/af_spx.c Mon Aug 23 10:01:02 1999 @@ -36,10 +36,9 @@ #include #include #include -#include static struct proto_ops *ipx_operations; -static struct proto_ops spx_operations; +static struct proto_ops spx_ops; static __u16 connids; /* Functions needed for SPX connection start up */ @@ -96,7 +95,7 @@ switch(sock->type) { case SOCK_SEQPACKET: - sock->ops = &spx_operations; + sock->ops = &spx_ops; break; default: sk_free(sk); @@ -149,7 +148,7 @@ } /* Release an SPX socket */ -static int spx_release(struct socket *sock, struct socket *peer) +static int spx_release(struct socket *sock) { struct sock *sk = sock->sk; struct spx_opt *pdata = &sk->tp_pinfo.af_spx; @@ -208,10 +207,6 @@ struct sk_buff *skb; int err; - if(newsock->sk != NULL) - spx_destroy_socket(newsock->sk); - newsock->sk = NULL; - if(sock->sk == NULL) return (-EINVAL); sk = sock->sk; @@ -847,9 +842,8 @@ return (err); } -static struct proto_ops spx_operations = { +static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = { PF_IPX, - sock_no_dup, spx_release, spx_bind, spx_connect, @@ -864,8 +858,13 @@ spx_getsockopt, sock_no_fcntl, spx_sendmsg, - spx_recvmsg + spx_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(spx, PF_IPX); + static struct net_proto_family spx_family_ops= { diff -u --recursive --new-file v2.3.14/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.3.14/linux/net/irda/af_irda.c Wed Aug 18 11:38:49 1999 +++ linux/net/irda/af_irda.c Mon Aug 23 10:01:02 1999 @@ -498,10 +498,15 @@ struct sock *sk = sock->sk; struct sock *newsk; struct sk_buff *skb; + int err; self = sk->protinfo.irda; ASSERT(self != NULL, return -1;); + err = irda_create(newsock, sk->protocol); + if (err) + return err; + if (sock->state != SS_UNCONNECTED) return -EINVAL; @@ -763,7 +768,7 @@ * * */ -static int irda_release(struct socket *sock, struct socket *peer) +static int irda_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -1332,10 +1337,9 @@ irda_create }; -static struct proto_ops irda_stream_ops = { +static struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = { PF_IRDA, - sock_no_dup, irda_release, irda_bind, irda_connect, @@ -1350,13 +1354,13 @@ irda_getsockopt, sock_no_fcntl, irda_sendmsg, - irda_recvmsg_stream + irda_recvmsg_stream, + sock_no_mmap }; -static struct proto_ops irda_dgram_ops = { +static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { PF_IRDA, - sock_no_dup, irda_release, irda_bind, irda_connect, @@ -1371,8 +1375,13 @@ irda_getsockopt, sock_no_fcntl, irda_sendmsg, - irda_recvmsg_dgram + irda_recvmsg_dgram, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(irda_dgram, PF_IRDA); +SOCKOPS_WRAP(irda_stream, PF_IRDA); /* * Function irda_device_event (this, event, ptr) diff -u --recursive --new-file v2.3.14/linux/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c --- v2.3.14/linux/net/irda/irlan/irlan_eth.c Wed Aug 18 11:38:49 1999 +++ linux/net/irda/irlan/irlan_eth.c Mon Aug 23 10:01:02 1999 @@ -346,12 +346,18 @@ * subnet. */ DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); - in_dev = dev->ip_ptr; + in_dev = in_dev_get(dev); + if (in_dev == NULL) + return; + read_lock(&in_dev->lock); + if (in_dev->ifa_list) arp_send(ARPOP_REQUEST, ETH_P_ARP, in_dev->ifa_list->ifa_address, dev, in_dev->ifa_list->ifa_address, NULL, dev->dev_addr, NULL); + read_unlock(&in_dev->lock); + in_dev_put(in_dev); } /* diff -u --recursive --new-file v2.3.14/linux/net/khttpd/accept.c linux/net/khttpd/accept.c --- v2.3.14/linux/net/khttpd/accept.c Wed Aug 18 09:45:10 1999 +++ linux/net/khttpd/accept.c Mon Aug 23 10:01:02 1999 @@ -63,13 +63,10 @@ the allocation of a new socket. (Which doesn't seem to be used anyway) */ - lock_sock(Socket->sk); if (Socket->sk->tp_pinfo.af_tcp.syn_wait_queue==NULL) { - release_sock(Socket->sk); return 0; } - release_sock(Socket->sk); error = 0; while (error>=0) @@ -78,31 +75,25 @@ if (NewSock==NULL) break; - lock_kernel(); /* Required for the TCPIP-stack in 2.3.13 */ - /* This is actually bogus, since accept() releases - it immediatly again. This will be fixed - eventually though. */ - NewSock->type = Socket->type; - (void)Socket->ops->dup(NewSock,Socket); + NewSock->ops = Socket->ops; error = Socket->ops->accept(Socket,NewSock,O_NONBLOCK); - unlock_kernel(); - if ((error<0)&&(NewSock!=NULL)) + if (error<0) { sock_release(NewSock); break; } - - - if (NewSock==NULL) - break; - - + + if (NewSock->sk->state==TCP_CLOSE) + { + sock_release(NewSock); + continue; + } /* Allocate a request-entry for the connection */ NewRequest = kmalloc(sizeof(struct http_request),(int)GFP_KERNEL); @@ -111,7 +102,6 @@ { Send50x(NewSock); /* Service not available. Try again later */ sock_release(NewSock); - error = -1; break; } memset(NewRequest,0,sizeof(struct http_request)); diff -u --recursive --new-file v2.3.14/linux/net/khttpd/datasending.c linux/net/khttpd/datasending.c --- v2.3.14/linux/net/khttpd/datasending.c Wed Aug 18 09:49:42 1999 +++ linux/net/khttpd/datasending.c Mon Aug 23 13:44:03 1999 @@ -34,6 +34,7 @@ The number of requests that changed status (ie: made some progress) */ +#include #include #include @@ -69,11 +70,9 @@ Space=4096; - if (CurrentRequest->sock->sk!=NULL) + if (CurrentRequest->sock->sk!=NULL) /* It's impossible */ { - lock_sock(CurrentRequest->sock->sk); Space = sock_wspace(CurrentRequest->sock->sk); - release_sock(CurrentRequest->sock->sk); } ReadSize = min(4096,CurrentRequest->FileLength - CurrentRequest->BytesSent); @@ -84,6 +83,8 @@ /* This part does a redundant data-copy. To bad for now. In the future, we might want to nick the data right out of the page-cache + + WHY DO YOU NOT USE SENDFILE? */ CurrentRequest->filp->f_pos = CurrentRequest->BytesSent; @@ -104,30 +105,27 @@ } } - lock_sock(CurrentRequest->sock->sk); /* If end-of-file or closed connection: Finish this request by moving it to the "logging" queue. */ if ((CurrentRequest->BytesSent>=CurrentRequest->FileLength)|| - (CurrentRequest->sock->sk->state !=TCP_ESTABLISHED)) + (CurrentRequest->sock->sk->state!=TCP_ESTABLISHED + && CurrentRequest->sock->sk->state!=TCP_CLOSE_WAIT)) { struct http_request *Next; Next = CurrentRequest->Next; - - if (CurrentRequest->sock->sk->state ==TCP_ESTABLISHED) + + lock_sock(CurrentRequest->sock->sk); + if (CurrentRequest->sock->sk->state == TCP_ESTABLISHED || + CurrentRequest->sock->sk->state == TCP_CLOSE_WAIT) { - CurrentRequest->sock->sk->nonagle = 0; - CurrentRequest->sock->sk->linger = 0; tcp_push_pending_frames(CurrentRequest->sock->sk,&(CurrentRequest->sock->sk->tp_pinfo.af_tcp)); } - release_sock(CurrentRequest->sock->sk); - - (*Prev) = CurrentRequest->Next; CurrentRequest->Next = threadinfo[CPUNR].LoggingQueue; @@ -137,7 +135,6 @@ continue; } - release_sock(CurrentRequest->sock->sk); Prev = &(CurrentRequest->Next); diff -u --recursive --new-file v2.3.14/linux/net/khttpd/main.c linux/net/khttpd/main.c --- v2.3.14/linux/net/khttpd/main.c Wed Aug 18 09:50:01 1999 +++ linux/net/khttpd/main.c Mon Aug 23 13:44:03 1999 @@ -50,6 +50,7 @@ * ****************************************************************/ +#include #include #include #include diff -u --recursive --new-file v2.3.14/linux/net/khttpd/misc.c linux/net/khttpd/misc.c --- v2.3.14/linux/net/khttpd/misc.c Wed Aug 18 09:45:10 1999 +++ linux/net/khttpd/misc.c Mon Aug 23 10:01:02 1999 @@ -71,8 +71,6 @@ if (sock->sk==NULL) return; - if (sock->sk->state!=TCP_ESTABLISHED) - return; len = 1; @@ -115,12 +113,8 @@ if ((Req->sock!=NULL)&&(Req->sock->sk!=NULL)) { ReadRest(Req->sock); - lock_kernel(); /* 2.3.11 quirk - needed for 2.3.13 ?? */ - lock_sock(Req->sock->sk); remove_wait_queue(Req->sock->sk->sleep,&(Req->sleep)); - release_sock(Req->sock->sk); sock_release(Req->sock); - unlock_kernel(); /* 2.3.13 quirk */ } /* ... and the file-pointer ... */ @@ -170,16 +164,11 @@ len = 0; - if (sock->sk->state==TCP_ESTABLISHED) - { - oldfs = get_fs(); set_fs(KERNEL_DS); - len = sock_sendmsg(sock,&msg,(size_t)(Length-len)); - set_fs(oldfs); - LeaveFunction("SendBuffer"); - return len; - } - else - return -ECONNRESET; + oldfs = get_fs(); set_fs(KERNEL_DS); + len = sock_sendmsg(sock,&msg,(size_t)(Length-len)); + set_fs(oldfs); + LeaveFunction("SendBuffer"); + return len; } int SendBuffer_async(struct socket *sock, const char *Buffer,const size_t Length) diff -u --recursive --new-file v2.3.14/linux/net/khttpd/rfc.c linux/net/khttpd/rfc.c --- v2.3.14/linux/net/khttpd/rfc.c Wed Aug 18 09:50:16 1999 +++ linux/net/khttpd/rfc.c Mon Aug 23 10:41:25 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #include "prototypes.h" @@ -90,7 +89,7 @@ MimeTypes[atomic_read(&MimeCount)].identifier=*I; - strcpy(MimeTypes[atomic_read(&MimeCount)].type,Type); + strncpy(MimeTypes[atomic_read(&MimeCount)].type,Type,(64-sizeof(__u32)-sizeof(__kernel_size_t))); MimeTypes[atomic_read(&MimeCount)].len = strlen(Type); atomic_inc(&MimeCount); @@ -325,7 +324,7 @@ if (tmp>Endval) continue; - strcpy(Head->FileName,sysctl_khttpd_docroot); + strncpy(Head->FileName,sysctl_khttpd_docroot,sizeof(Head->FileName)); PrefixLen = strlen(sysctl_khttpd_docroot); Head->FileNameLength = min(255,tmp-Buffer+PrefixLen); diff -u --recursive --new-file v2.3.14/linux/net/khttpd/security.c linux/net/khttpd/security.c --- v2.3.14/linux/net/khttpd/security.c Wed Aug 18 09:45:10 1999 +++ linux/net/khttpd/security.c Mon Aug 23 10:41:25 1999 @@ -156,7 +156,7 @@ while (List!=NULL) { - if (strstr(List->value,Filename)!=NULL) + if (strstr(Filename,List->value)!=NULL) { if (filp!=NULL) fput(filp); @@ -257,13 +257,14 @@ memset(String,0,255); - strcat(String,"Dynamic strings are : -"); + strncpy(String,"Dynamic strings are : -",255); Temp = DynamicList; while (Temp!=NULL) { max=253 - strlen(String) - strlen(Temp->value); strncat(String,Temp->value,max); - strcat(String,"- -"); + max=253 - strlen(String) - 3; + strncat(String,"- -",max); Temp = Temp->Next; } diff -u --recursive --new-file v2.3.14/linux/net/khttpd/structure.h linux/net/khttpd/structure.h --- v2.3.14/linux/net/khttpd/structure.h Wed Aug 18 09:45:10 1999 +++ linux/net/khttpd/structure.h Mon Aug 23 10:01:02 1999 @@ -64,21 +64,5 @@ }; -/* - -struct khttpd_delayed_release is used to build a list of all struct sockets -that were passed to userspace. It seems to be required that they are not destroyed -immediatly, so they have a timeout-counter. - -*/ -struct khttpd_delayed_release; - -struct khttpd_delayed_release -{ - struct socket *sock; - unsigned long timeout; - - struct khttpd_delayed_release *Next; -}; #endif diff -u --recursive --new-file v2.3.14/linux/net/khttpd/sysctl.c linux/net/khttpd/sysctl.c --- v2.3.14/linux/net/khttpd/sysctl.c Wed Aug 18 09:45:10 1999 +++ linux/net/khttpd/sysctl.c Mon Aug 23 13:44:03 1999 @@ -24,7 +24,6 @@ #include -#include #include #include #include diff -u --recursive --new-file v2.3.14/linux/net/khttpd/userspace.c linux/net/khttpd/userspace.c --- v2.3.14/linux/net/khttpd/userspace.c Wed Aug 18 09:50:44 1999 +++ linux/net/khttpd/userspace.c Wed Aug 25 14:50:35 1999 @@ -62,9 +62,6 @@ /* prototypes of local, static functions */ static int AddSocketToAcceptQueue(struct socket *sock,const int Port); -static void purge_delayed_release(int CPUNR, int All); - -static struct khttpd_delayed_release *delayed_release[CONFIG_KHTTPD_NUMCPU]; int Userspace(const int CPUNR) @@ -74,7 +71,6 @@ EnterFunction("Userspace"); - purge_delayed_release(CPUNR,0); CurrentRequest = threadinfo[CPUNR].UserspaceQueue; @@ -87,42 +83,21 @@ this is forgotten. */ if (CurrentRequest->sock!=NULL) { - lock_kernel(); /* Just to be sure (2.3.11) -- Check this for 2.3.13 */ if ((CurrentRequest->sock!=NULL)&&(CurrentRequest->sock->sk!=NULL)) { - /* Some TCP/IP functions call waitqueue-operations without - holding the sock-lock. I am not that brave. - */ - lock_sock(CurrentRequest->sock->sk); remove_wait_queue(CurrentRequest->sock->sk->sleep,&(CurrentRequest->sleep)); - release_sock(CurrentRequest->sock->sk); } - unlock_kernel(); } if (AddSocketToAcceptQueue(CurrentRequest->sock,sysctl_khttpd_clientport)>=0) { - struct khttpd_delayed_release *delayed; (*Prev) = CurrentRequest->Next; Next = CurrentRequest->Next; - delayed = kmalloc(sizeof(struct khttpd_delayed_release),GFP_KERNEL); - if (delayed==NULL) - { - sock_release(CurrentRequest->sock); - } else - { - /* Schedule socket-deletion 120 seconds from now */ - delayed->Next = delayed_release[CPUNR]; - delayed->timeout = jiffies+120*HZ; - delayed->sock = CurrentRequest->sock; - delayed_release[CPUNR]=delayed; - } - - + sock_release(CurrentRequest->sock); CurrentRequest->sock = NULL; /* We no longer own it */ CleanUpRequest(CurrentRequest); @@ -168,25 +143,26 @@ CurrentRequest=Next; } threadinfo[CPUNR].UserspaceQueue = NULL; - purge_delayed_release(CPUNR,1); LeaveFunction("StopUserspace"); } -extern struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif); - /* "FindUserspace" returns the struct sock of the userspace-daemon, so that we can "drop" our request in the accept-queue */ + static struct sock *FindUserspace(const unsigned short Port) { + struct sock *sk; + EnterFunction("FindUserspace"); - - return tcp_v4_lookup_listener(INADDR_ANY,Port,0); - - return NULL; + + local_bh_disable(); + sk = tcp_v4_lookup_listener(INADDR_ANY,Port,0); + local_bh_enable(); + return sk; } static void dummy_destructor(struct open_request *req) @@ -195,13 +171,13 @@ static struct or_calltable Dummy = { + 0, + NULL, NULL, &dummy_destructor, NULL }; -#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */ - static int AddSocketToAcceptQueue(struct socket *sock,const int Port) { struct open_request *req; @@ -219,42 +195,44 @@ } lock_sock(sk); - - if (BACKLOG(sk)>128) /* To many pending requests */ + + if (sk->state != TCP_LISTEN || + sk->ack_backlog > sk->max_ack_backlog) /* To many pending requests */ { + release_sock(sk); + sock_put(sk); return -1; } + req = tcp_openreq_alloc(); if (req==NULL) { release_sock(sk); - return -1; + sock_put(sk); + return -1; } req->sk = sock->sk; sock->sk = NULL; sock->state = SS_UNCONNECTED; - - - if (req->sk==NULL) - (void)printk(KERN_CRIT "kHTTPd: Woops, the socket-buffer is NULL \n"); - + req->class = &Dummy; + write_lock_irq(&req->sk->callback_lock); req->sk->socket = NULL; - req->expires = jiffies + TCP_TIMEOUT_INIT; - + req->sk->sleep = NULL; + write_unlock_irq(&req->sk->callback_lock); + tp =&(sk->tp_pinfo.af_tcp); sk->ack_backlog++; - tcp_inc_slow_timer(TCP_SLT_SYNACK); tcp_synq_queue(tp,req); - if (!sk->dead) - wake_up_interruptible(sk->sleep); - + sk->data_ready(sk, 0); + release_sock(sk); - + sock_put(sk); + LeaveFunction("AddSocketToAcceptQueue"); return +1; @@ -265,44 +243,6 @@ void InitUserspace(const int CPUNR) { - int I; - - I=0; - while (Itimeout<=jiffies)||(All)) - { - Next = Current->Next; - - *Prev = Next; - - sock_release(Current->sock); - kfree(Current); - - Current = Next; - continue; - } - - Prev = &Current->Next; - Current=Current->Next; - } -} diff -u --recursive --new-file v2.3.14/linux/net/khttpd/waitheaders.c linux/net/khttpd/waitheaders.c --- v2.3.14/linux/net/khttpd/waitheaders.c Wed Aug 18 09:51:00 1999 +++ linux/net/khttpd/waitheaders.c Mon Aug 23 13:44:03 1999 @@ -34,6 +34,7 @@ The number of requests that changed status */ +#include #include #include #include @@ -67,8 +68,8 @@ /* If the connection is lost, remove from queue */ - lock_sock(CurrentRequest->sock->sk); - if (CurrentRequest->sock->sk->state!=TCP_ESTABLISHED) + if (CurrentRequest->sock->sk->state != TCP_ESTABLISHED + && CurrentRequest->sock->sk->state != TCP_CLOSE_WAIT) { struct http_request *Next; @@ -76,7 +77,6 @@ *Prev = CurrentRequest->Next; CurrentRequest->Next = NULL; - release_sock(CurrentRequest->sock->sk); CleanUpRequest(CurrentRequest); @@ -90,12 +90,11 @@ sk = CurrentRequest->sock->sk; - if (atomic_read(&(sk->rmem_alloc))>0) /* Do we have data ? */ + if (!skb_queue_empty(&(sk->receive_queue))) /* Do we have data ? */ { struct http_request *Next; - release_sock(CurrentRequest->sock->sk); /* Decode header */ @@ -129,8 +128,6 @@ continue; } - else - release_sock(CurrentRequest->sock->sk); Prev = &(CurrentRequest->Next); @@ -200,6 +197,12 @@ len = sock_recvmsg(Request->sock,&msg,4095,MSG_PEEK); set_fs(oldfs); + + if (len<0) { + /* WONDERFUL. NO COMMENTS. --ANK */ + Request->IsForUserspace = 1; + return 0; + } if (len>=4094) /* BIG header, we cannot decode it so leave it to userspace */ { diff -u --recursive --new-file v2.3.14/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.3.14/linux/net/netlink/af_netlink.c Wed Jun 2 11:29:13 1999 +++ linux/net/netlink/af_netlink.c Mon Aug 23 10:01:02 1999 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -43,8 +44,23 @@ #define NL_EMULATE_DEV #endif +#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } + +struct netlink_opt +{ + pid_t pid; + unsigned groups; + pid_t dst_pid; + unsigned dst_groups; + unsigned long state; + int (*handler)(int unit, struct sk_buff *skb); + wait_queue_head_t wait; + struct netlink_callback *cb; + spinlock_t cb_lock; + void (*data_ready)(struct sock *sk, int bytes); +}; + static struct sock *nl_table[MAX_LINKS]; -static atomic_t nl_table_lock[MAX_LINKS]; static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); #ifdef NL_EMULATE_DEV @@ -54,89 +70,131 @@ static int netlink_dump(struct sock *sk); static void netlink_destroy_callback(struct netlink_callback *cb); -/* Netlink table lock. It protects against sk list changes - during uninterruptible sleeps in netlink_broadcast. +atomic_t netlink_sock_nr; - These lock MUST NOT be used from bh/irq on SMP kernels, because - It would result in race in netlink_wait_on_table. - */ +static rwlock_t nl_table_lock = RW_LOCK_UNLOCKED; +static atomic_t nl_table_users = ATOMIC_INIT(0); -extern __inline__ void -netlink_wait_on_table(int protocol) +static void netlink_sock_destruct(struct sock *sk) { - while (atomic_read(&nl_table_lock[protocol])) - sleep_on(&nl_table_wait); -} + skb_queue_purge(&sk->receive_queue); -extern __inline__ void -netlink_lock_table(int protocol) -{ - atomic_inc(&nl_table_lock[protocol]); + if (!sk->dead) { + printk("Freeing alive netlink socket %p\n", sk); + return; + } + BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); + BUG_TRAP(atomic_read(&sk->wmem_alloc)==0); + BUG_TRAP(sk->protinfo.af_netlink->cb==NULL); + + kfree(sk->protinfo.af_netlink); + + atomic_dec(&netlink_sock_nr); +#ifdef NETLINK_REFCNT_DEBUG + printk(KERN_DEBUG "NETLINK %p released, %d are still alive\n", sk, atomic_read(&netlink_sock_nr)); +#endif } -extern __inline__ void -netlink_unlock_table(int protocol) +static void netlink_table_grab(void) { -#if 0 - /* F...g gcc does not eat it! */ + write_lock_bh(&nl_table_lock); - if (atomic_dec_and_test(&nl_table_lock[protocol])) - wake_up(&nl_table_wait); -#else - atomic_dec(&nl_table_lock[protocol]); - if (!atomic_read(&nl_table_lock[protocol])) - wake_up(&nl_table_wait); -#endif + if (atomic_read(&nl_table_users)) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&nl_table_wait, &wait); + do { + current->state = TASK_UNINTERRUPTIBLE; + if (atomic_read(&nl_table_users) == 0) + break; + write_unlock_bh(&nl_table_lock); + schedule(); + write_lock_bh(&nl_table_lock); + } while (atomic_read(&nl_table_users)); + + current->state = TASK_RUNNING; + remove_wait_queue(&nl_table_wait, &wait); + } } -static __inline__ void netlink_lock(struct sock *sk) +static __inline__ void netlink_table_ungrab(void) { - atomic_inc(&sk->protinfo.af_netlink.locks); + write_unlock_bh(&nl_table_lock); } -static __inline__ void netlink_unlock(struct sock *sk) +static __inline__ void +netlink_lock_table(void) { - atomic_dec(&sk->protinfo.af_netlink.locks); + /* read_lock() synchronizes us to netlink_table_grab */ + + read_lock(&nl_table_lock); + atomic_inc(&nl_table_users); + read_unlock(&nl_table_lock); } -static __inline__ int netlink_locked(struct sock *sk) +static __inline__ void +netlink_unlock_table(void) { - return atomic_read(&sk->protinfo.af_netlink.locks); + if (atomic_dec_and_test(&nl_table_users)) + wake_up(&nl_table_wait); } static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) { struct sock *sk; + read_lock(&nl_table_lock); for (sk=nl_table[protocol]; sk; sk=sk->next) { - if (sk->protinfo.af_netlink.pid == pid) { - netlink_lock(sk); + if (sk->protinfo.af_netlink->pid == pid) { + sock_hold(sk); + read_unlock(&nl_table_lock); return sk; } } + read_unlock(&nl_table_lock); return NULL; } extern struct proto_ops netlink_ops; -static void netlink_insert(struct sock *sk) +static int netlink_insert(struct sock *sk, u32 pid) { - sk->next = nl_table[sk->protocol]; - nl_table[sk->protocol] = sk; + int err = -EADDRINUSE; + struct sock *osk; + + netlink_table_grab(); + for (osk=nl_table[sk->protocol]; osk; osk=osk->next) { + if (osk->protinfo.af_netlink->pid == pid) + break; + } + if (osk == NULL) { + err = -EBUSY; + if (sk->protinfo.af_netlink->pid == 0) { + sk->protinfo.af_netlink->pid = pid; + sk->next = nl_table[sk->protocol]; + nl_table[sk->protocol] = sk; + sock_hold(sk); + err = 0; + } + } + netlink_table_ungrab(); + return err; } static void netlink_remove(struct sock *sk) { struct sock **skp; + + netlink_table_grab(); for (skp = &nl_table[sk->protocol]; *skp; skp = &((*skp)->next)) { if (*skp == sk) { - start_bh_atomic(); *skp = sk->next; - end_bh_atomic(); - return; + __sock_put(sk); + break; } } + netlink_table_ungrab(); } static int netlink_create(struct socket *sock, int protocol) @@ -158,66 +216,56 @@ return -ENOMEM; sock_init_data(sock,sk); - sk->destruct = NULL; - + + sk->protinfo.af_netlink = kmalloc(sizeof(struct netlink_opt), GFP_KERNEL); + if (sk->protinfo.af_netlink == NULL) { + sk_free(sk); + return -ENOMEM; + } + memset(sk->protinfo.af_netlink, 0, sizeof(struct netlink_opt)); + + spin_lock_init(&sk->protinfo.af_netlink->cb_lock); + init_waitqueue_head(&sk->protinfo.af_netlink->wait); + sk->destruct = netlink_sock_destruct; + atomic_inc(&netlink_sock_nr); + sk->protocol=protocol; return 0; } -static int netlink_release(struct socket *sock, struct socket *peer) +static int netlink_release(struct socket *sock) { struct sock *sk = sock->sk; if (!sk) return 0; - /* Wait on table before removing socket */ - netlink_wait_on_table(sk->protocol); netlink_remove(sk); - if (sk->protinfo.af_netlink.cb) { - netlink_unlock(sk); - sk->protinfo.af_netlink.cb->done(sk->protinfo.af_netlink.cb); - netlink_destroy_callback(sk->protinfo.af_netlink.cb); - sk->protinfo.af_netlink.cb = NULL; + spin_lock(&sk->protinfo.af_netlink->cb_lock); + if (sk->protinfo.af_netlink->cb) { + sk->protinfo.af_netlink->cb->done(sk->protinfo.af_netlink->cb); + netlink_destroy_callback(sk->protinfo.af_netlink->cb); + sk->protinfo.af_netlink->cb = NULL; + __sock_put(sk); } + spin_unlock(&sk->protinfo.af_netlink->cb_lock); /* OK. Socket is unlinked, and, therefore, no new packets will arrive */ - sk->state_change(sk); + + write_lock_irq(&sk->callback_lock); sk->dead = 1; + sk->socket = NULL; + sock->sk = NULL; + wake_up_interruptible(sk->sleep); + sk->sleep = NULL; + wake_up_interruptible(&sk->protinfo.af_netlink->wait); + write_unlock_irq(&sk->callback_lock); - skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->write_queue); - /* IMPORTANT! It is the major unpleasant feature of this - transport (and AF_UNIX datagram, when it will be repaired). - - Someone could wait on our sock->wait now. - We cannot release socket until waiter will remove itself - from wait queue. I choose the most conservetive way of solving - the problem. - - We waked up this queue above, so that we need only to wait - when the readers release us. - */ - - while (netlink_locked(sk)) { - current->policy |= SCHED_YIELD; - schedule(); - } - - if (sk->socket) { - sk->socket = NULL; - sock->sk = NULL; - } - - if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { - printk(KERN_DEBUG "netlink_release: impossible event. Please, report.\n"); - return 0; - } - - sk_free(sk); + sock_put(sk); return 0; } @@ -225,29 +273,34 @@ { struct sock *sk = sock->sk; struct sock *osk; - - sk->protinfo.af_netlink.groups = 0; - sk->protinfo.af_netlink.pid = current->pid; + s32 pid = current->pid; + int err; retry: + netlink_table_grab(); for (osk=nl_table[sk->protocol]; osk; osk=osk->next) { - if (osk->protinfo.af_netlink.pid == sk->protinfo.af_netlink.pid) { + if (osk->protinfo.af_netlink->pid == pid) { /* Bind collision, search negative pid values. */ - if (sk->protinfo.af_netlink.pid > 0) - sk->protinfo.af_netlink.pid = -4096; - sk->protinfo.af_netlink.pid--; + if (pid > 0) + pid = -4096; + pid--; + netlink_table_ungrab(); goto retry; } } + netlink_table_ungrab(); - netlink_insert(sk); + err = netlink_insert(sk, pid); + if (err == -EADDRINUSE) + goto retry; + sk->protinfo.af_netlink->groups = 0; return 0; } static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; - struct sock *osk; + int err; struct sockaddr_nl *nladdr=(struct sockaddr_nl *)addr; if (nladdr->nl_family != AF_NETLINK) @@ -257,40 +310,36 @@ if (nladdr->nl_groups && !capable(CAP_NET_ADMIN)) return -EPERM; - if (sk->protinfo.af_netlink.pid) { - if (nladdr->nl_pid != sk->protinfo.af_netlink.pid) + if (sk->protinfo.af_netlink->pid) { + if (nladdr->nl_pid != sk->protinfo.af_netlink->pid) return -EINVAL; - sk->protinfo.af_netlink.groups = nladdr->nl_groups; + sk->protinfo.af_netlink->groups = nladdr->nl_groups; return 0; } if (nladdr->nl_pid == 0) { - netlink_autobind(sock); - sk->protinfo.af_netlink.groups = nladdr->nl_groups; - return 0; + err = netlink_autobind(sock); + if (err == 0) + sk->protinfo.af_netlink->groups = nladdr->nl_groups; + return err; } - for (osk=nl_table[sk->protocol]; osk; osk=osk->next) { - if (osk->protinfo.af_netlink.pid == nladdr->nl_pid) - return -EADDRINUSE; - } - - sk->protinfo.af_netlink.pid = nladdr->nl_pid; - sk->protinfo.af_netlink.groups = nladdr->nl_groups; - netlink_insert(sk); - return 0; + err = netlink_insert(sk, nladdr->nl_pid); + if (err == 0) + sk->protinfo.af_netlink->groups = nladdr->nl_groups; + return err; } static int netlink_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { + int err = 0; struct sock *sk = sock->sk; struct sockaddr_nl *nladdr=(struct sockaddr_nl*)addr; - if (addr->sa_family == AF_UNSPEC) - { - sk->protinfo.af_netlink.dst_pid = 0; - sk->protinfo.af_netlink.dst_groups = 0; + if (addr->sa_family == AF_UNSPEC) { + sk->protinfo.af_netlink->dst_pid = 0; + sk->protinfo.af_netlink->dst_groups = 0; return 0; } if (addr->sa_family != AF_NETLINK) @@ -300,11 +349,14 @@ if (nladdr->nl_groups && !capable(CAP_NET_ADMIN)) return -EPERM; - sk->protinfo.af_netlink.dst_pid = nladdr->nl_pid; - sk->protinfo.af_netlink.dst_groups = nladdr->nl_groups; + if (!sk->protinfo.af_netlink->pid) + err = netlink_autobind(sock); + + if (err == 0) { + sk->protinfo.af_netlink->dst_pid = nladdr->nl_pid; + sk->protinfo.af_netlink->dst_groups = nladdr->nl_groups; + } - if (!sk->protinfo.af_netlink.pid) - netlink_autobind(sock); return 0; } @@ -317,15 +369,23 @@ *addr_len = sizeof(*nladdr); if (peer) { - nladdr->nl_pid = sk->protinfo.af_netlink.dst_pid; - nladdr->nl_groups = sk->protinfo.af_netlink.dst_groups; + nladdr->nl_pid = sk->protinfo.af_netlink->dst_pid; + nladdr->nl_groups = sk->protinfo.af_netlink->dst_groups; } else { - nladdr->nl_pid = sk->protinfo.af_netlink.pid; - nladdr->nl_groups = sk->protinfo.af_netlink.groups; + nladdr->nl_pid = sk->protinfo.af_netlink->pid; + nladdr->nl_groups = sk->protinfo.af_netlink->groups; } return 0; } +static void netlink_overrun(struct sock *sk) +{ + if (!test_and_set_bit(0, &sk->protinfo.af_netlink->state)) { + sk->err = ENOBUFS; + sk->error_report(sk); + } +} + int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) { struct sock *sk; @@ -334,58 +394,59 @@ DECLARE_WAITQUEUE(wait, current); retry: - for (sk = nl_table[protocol]; sk; sk = sk->next) { - if (sk->protinfo.af_netlink.pid != pid) - continue; - - netlink_lock(sk); + sk = netlink_lookup(protocol, pid); + if (sk == NULL) + goto no_dst; #ifdef NL_EMULATE_DEV - if (sk->protinfo.af_netlink.handler) { - skb_orphan(skb); - len = sk->protinfo.af_netlink.handler(protocol, skb); - netlink_unlock(sk); - return len; - } + if (sk->protinfo.af_netlink->handler) { + skb_orphan(skb); + len = sk->protinfo.af_netlink->handler(protocol, skb); + sock_put(sk); + return len; + } #endif - if (!nonblock) { - add_wait_queue(sk->sleep, &wait); - current->state = TASK_INTERRUPTIBLE; + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + test_bit(0, &sk->protinfo.af_netlink->state)) { + if (nonblock) { + if (ssk->protinfo.af_netlink->pid == 0) + netlink_overrun(sk); + sock_put(sk); + kfree_skb(skb); + return -EAGAIN; } - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { - if (nonblock) { - netlink_unlock(sk); - kfree_skb(skb); - return -EAGAIN; - } + add_wait_queue(&sk->protinfo.af_netlink->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + barrier(); + + if ((atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + test_bit(0, &sk->protinfo.af_netlink->state)) && + !signal_pending(current) && + !sk->dead) schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); - netlink_unlock(sk); - - if (signal_pending(current)) { - kfree_skb(skb); - return -ERESTARTSYS; - } - goto retry; + current->state = TASK_RUNNING; + remove_wait_queue(&sk->protinfo.af_netlink->wait, &wait); + sock_put(sk); + + if (signal_pending(current)) { + kfree_skb(skb); + return -ERESTARTSYS; } + goto retry; + } - if (!nonblock) { - current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); - } + skb_orphan(skb); + skb_set_owner_r(skb, sk); + skb_queue_tail(&sk->receive_queue, skb); + sk->data_ready(sk, len); + sock_put(sk); + return len; - skb_orphan(skb); - skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, len); - netlink_unlock(sk); - return len; - } +no_dst: kfree_skb(skb); return -ECONNREFUSED; } @@ -393,14 +454,14 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) { #ifdef NL_EMULATE_DEV - if (sk->protinfo.af_netlink.handler) { + if (sk->protinfo.af_netlink->handler) { skb_orphan(skb); - sk->protinfo.af_netlink.handler(sk->protocol, skb); + sk->protinfo.af_netlink->handler(sk->protocol, skb); return 0; } else #endif - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { -Nprintk("broadcast_deliver %d\n", skb->len); + if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf && + !test_bit(0, &sk->protinfo.af_netlink->state)) { skb_orphan(skb); skb_set_owner_r(skb, sk); skb_queue_tail(&sk->receive_queue, skb); @@ -420,24 +481,22 @@ /* While we sleep in clone, do not allow to change socket list */ - if (allocation == GFP_KERNEL) - netlink_lock_table(protocol); + netlink_lock_table(); for (sk = nl_table[protocol]; sk; sk = sk->next) { if (ssk == sk) continue; - if (sk->protinfo.af_netlink.pid == pid || - !(sk->protinfo.af_netlink.groups&group)) + if (sk->protinfo.af_netlink->pid == pid || + !(sk->protinfo.af_netlink->groups&group)) continue; if (failure) { - sk->err = ENOBUFS; - sk->state_change(sk); + netlink_overrun(sk); continue; } - netlink_lock(sk); + sock_hold(sk); if (skb2 == NULL) { if (atomic_read(&skb->users) != 1) { skb2 = skb_clone(skb, allocation); @@ -447,20 +506,17 @@ } } if (skb2 == NULL) { - sk->err = ENOBUFS; - sk->state_change(sk); + netlink_overrun(sk); /* Clone failed. Notify ALL listeners. */ failure = 1; } else if (netlink_broadcast_deliver(sk, skb2)) { - sk->err = ENOBUFS; - sk->state_change(sk); + netlink_overrun(sk); } else skb2 = NULL; - netlink_unlock(sk); + sock_put(sk); } - if (allocation == GFP_KERNEL) - netlink_unlock_table(protocol); + netlink_unlock_table(); if (skb2) kfree_skb(skb2); @@ -472,18 +528,19 @@ struct sock *sk; int protocol = ssk->protocol; -Nprintk("seterr"); + read_lock(&nl_table_lock); for (sk = nl_table[protocol]; sk; sk = sk->next) { if (ssk == sk) continue; - if (sk->protinfo.af_netlink.pid == pid || - !(sk->protinfo.af_netlink.groups&group)) + if (sk->protinfo.af_netlink->pid == pid || + !(sk->protinfo.af_netlink->groups&group)) continue; sk->err = code; - sk->state_change(sk); + sk->error_report(sk); } + read_unlock(&nl_table_lock); } static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, int len, @@ -494,6 +551,7 @@ u32 dst_pid; u32 dst_groups; struct sk_buff *skb; + int err; if (msg->msg_flags&MSG_OOB) return -EOPNOTSUPP; @@ -509,19 +567,23 @@ if (dst_groups && !capable(CAP_NET_ADMIN)) return -EPERM; } else { - dst_pid = sk->protinfo.af_netlink.dst_pid; - dst_groups = sk->protinfo.af_netlink.dst_groups; + dst_pid = sk->protinfo.af_netlink->dst_pid; + dst_groups = sk->protinfo.af_netlink->dst_groups; } - if (!sk->protinfo.af_netlink.pid) - netlink_autobind(sock); + if (!sk->protinfo.af_netlink->pid) { + err = netlink_autobind(sock); + if (err) + goto out; + } - skb = sock_wmalloc(sk, len, 0, GFP_KERNEL); + err = -ENOBUFS; + skb = alloc_skb(len, GFP_KERNEL); if (skb==NULL) - return -ENOBUFS; + goto out; - NETLINK_CB(skb).pid = sk->protinfo.af_netlink.pid; - NETLINK_CB(skb).groups = sk->protinfo.af_netlink.groups; + NETLINK_CB(skb).pid = sk->protinfo.af_netlink->pid; + NETLINK_CB(skb).groups = sk->protinfo.af_netlink->groups; NETLINK_CB(skb).dst_pid = dst_pid; NETLINK_CB(skb).dst_groups = dst_groups; memcpy(NETLINK_CREDS(skb), &scm->creds, sizeof(struct ucred)); @@ -533,16 +595,20 @@ */ NETLINK_CB(skb).eff_cap = current->cap_effective; + err = -EFAULT; if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) { kfree_skb(skb); - return -EFAULT; + goto out; } if (dst_groups) { atomic_inc(&skb->users); netlink_broadcast(sk, skb, dst_pid, dst_groups, GFP_KERNEL); } - return netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); + err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); + +out: + return err; } static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, int len, @@ -554,12 +620,14 @@ struct sk_buff *skb; int err; - if (flags&(MSG_OOB|MSG_PEEK)) + if (flags&MSG_OOB) return -EOPNOTSUPP; + copied = 0; + skb = skb_recv_datagram(sk,flags,noblock,&err); if (skb==NULL) - return err; + goto out; msg->msg_namelen = 0; @@ -583,12 +651,33 @@ scm->creds = *NETLINK_CREDS(skb); skb_free_datagram(sk, skb); - if (sk->protinfo.af_netlink.cb + if (sk->protinfo.af_netlink->cb && atomic_read(&sk->rmem_alloc) <= sk->rcvbuf/2) netlink_dump(sk); + +out: + if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) { + if (skb_queue_len(&sk->receive_queue) == 0) + clear_bit(0, &sk->protinfo.af_netlink->state); + if (!test_bit(0, &sk->protinfo.af_netlink->state)) + wake_up_interruptible(&sk->protinfo.af_netlink->wait); + } return err ? : copied; } +void netlink_data_ready(struct sock *sk, int len) +{ + if (sk->protinfo.af_netlink->data_ready) + sk->protinfo.af_netlink->data_ready(sk, len); + + if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) { + if (skb_queue_len(&sk->receive_queue) == 0) + clear_bit(0, &sk->protinfo.af_netlink->state); + if (!test_bit(0, &sk->protinfo.af_netlink->state)) + wake_up_interruptible(&sk->protinfo.af_netlink->wait); + } +} + /* * We export these functions to other modules. They provide a * complete set of kernel non-blocking support for message @@ -614,10 +703,11 @@ return NULL; } sk = sock->sk; + sk->data_ready = netlink_data_ready; if (input) - sk->data_ready = input; + sk->protinfo.af_netlink->data_ready = input; - netlink_insert(sk); + netlink_insert(sk, 0); return sk; } @@ -644,11 +734,19 @@ if (!skb) return -ENOBUFS; - cb = sk->protinfo.af_netlink.cb; + spin_lock(&sk->protinfo.af_netlink->cb_lock); + + cb = sk->protinfo.af_netlink->cb; + if (cb == NULL) { + spin_unlock(&sk->protinfo.af_netlink->cb_lock); + kfree_skb(skb); + return -EINVAL; + } len = cb->dump(skb, cb); if (len > 0) { + spin_unlock(&sk->protinfo.af_netlink->cb_lock); skb_queue_tail(&sk->receive_queue, skb); sk->data_ready(sk, len); return 0; @@ -661,9 +759,11 @@ sk->data_ready(sk, skb->len); cb->done(cb); - sk->protinfo.af_netlink.cb = NULL; + sk->protinfo.af_netlink->cb = NULL; + spin_unlock(&sk->protinfo.af_netlink->cb_lock); + netlink_destroy_callback(cb); - netlink_unlock(sk); + sock_put(sk); return 0; } @@ -692,12 +792,16 @@ return -ECONNREFUSED; } /* A dump is in progress... */ - if (sk->protinfo.af_netlink.cb) { + spin_lock(&sk->protinfo.af_netlink->cb_lock); + if (sk->protinfo.af_netlink->cb) { + spin_unlock(&sk->protinfo.af_netlink->cb_lock); netlink_destroy_callback(cb); - netlink_unlock(sk); + sock_put(sk); return -EBUSY; } - sk->protinfo.af_netlink.cb = cb; + sk->protinfo.af_netlink->cb = cb; + spin_unlock(&sk->protinfo.af_netlink->cb_lock); + netlink_dump(sk); return 0; } @@ -717,7 +821,7 @@ skb = alloc_skb(size, GFP_KERNEL); if (!skb) return; - + rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, NLMSG_ERROR, sizeof(struct nlmsgerr)); errmsg = NLMSG_DATA(rep); @@ -728,6 +832,9 @@ #ifdef NL_EMULATE_DEV + +static rwlock_t nl_emu_lock = RW_LOCK_UNLOCKED; + /* * Backward compatibility. */ @@ -737,31 +844,44 @@ struct sock *sk = netlink_kernel_create(unit, NULL); if (sk == NULL) return -ENOBUFS; - sk->protinfo.af_netlink.handler = function; + sk->protinfo.af_netlink->handler = function; + write_lock_bh(&nl_emu_lock); netlink_kernel[unit] = sk->socket; + write_unlock_bh(&nl_emu_lock); return 0; } void netlink_detach(int unit) { - struct socket *sock = netlink_kernel[unit]; + struct socket *sock; + write_lock_bh(&nl_emu_lock); + sock = netlink_kernel[unit]; netlink_kernel[unit] = NULL; - synchronize_bh(); + write_unlock_bh(&nl_emu_lock); sock_release(sock); } int netlink_post(int unit, struct sk_buff *skb) { - struct socket *sock = netlink_kernel[unit]; - barrier(); + struct socket *sock; + + read_lock(&nl_emu_lock); + sock = netlink_kernel[unit]; if (sock) { + struct sock *sk = sock->sk; memset(skb->cb, 0, sizeof(skb->cb)); - netlink_broadcast(sock->sk, skb, 0, ~0, GFP_ATOMIC); + sock_hold(sk); + read_unlock(&nl_emu_lock); + + netlink_broadcast(sk, skb, 0, ~0, GFP_ATOMIC); + + sock_put(sk); return 0; } - return -EUNATCH;; + read_unlock(&nl_emu_lock); + return -EUNATCH; } #endif @@ -781,16 +901,17 @@ "Rmem Wmem Dump Locks\n"); for (i=0; inext) { len+=sprintf(buffer+len,"%p %-3d %-6d %08x %-8d %-8d %p %d", s, s->protocol, - s->protinfo.af_netlink.pid, - s->protinfo.af_netlink.groups, + s->protinfo.af_netlink->pid, + s->protinfo.af_netlink->groups, atomic_read(&s->rmem_alloc), atomic_read(&s->wmem_alloc), - s->protinfo.af_netlink.cb, - atomic_read(&s->protinfo.af_netlink.locks) + s->protinfo.af_netlink->cb, + atomic_read(&s->refcnt) ); buffer[len++]='\n'; @@ -800,9 +921,12 @@ len=0; begin=pos; } - if(pos>offset+length) + if(pos>offset+length) { + read_unlock(&nl_table_lock); goto done; + } } + read_unlock(&nl_table_lock); } *eof = 1; @@ -820,7 +944,6 @@ struct proto_ops netlink_ops = { PF_NETLINK, - sock_no_dup, netlink_release, netlink_bind, netlink_connect, @@ -835,7 +958,8 @@ sock_no_getsockopt, sock_no_fcntl, netlink_sendmsg, - netlink_recvmsg + netlink_recvmsg, + sock_no_mmap }; struct net_proto_family netlink_family_ops = { diff -u --recursive --new-file v2.3.14/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c --- v2.3.14/linux/net/netlink/netlink_dev.c Wed Jun 2 11:29:13 1999 +++ linux/net/netlink/netlink_dev.c Mon Aug 23 10:01:02 1999 @@ -106,7 +106,7 @@ struct socket *sock; struct sockaddr_nl nladdr; int err; - + if (minor>=MAX_LINKS) return -ENODEV; if (open_map&(1<type = SOCK_RAW; - if ((err = net_families[PF_NETLINK]->create(sock, minor)) < 0) - { - sock_release(sock); + err = sock_create(PF_NETLINK, SOCK_RAW, minor, &sock); + if (err < 0) goto out; - } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; diff -u --recursive --new-file v2.3.14/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.3.14/linux/net/netrom/af_netrom.c Wed Aug 18 11:38:49 1999 +++ linux/net/netrom/af_netrom.c Mon Aug 23 10:01:02 1999 @@ -545,7 +545,7 @@ return sk; } -static int nr_release(struct socket *sock, struct socket *peer) +static int nr_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -747,11 +747,6 @@ struct sock *newsk; struct sk_buff *skb; - if (newsock->sk != NULL) - nr_destroy_socket(newsock->sk); - - newsock->sk = NULL; - if ((sk = sock->sk) == NULL) return -EINVAL; @@ -1248,10 +1243,9 @@ nr_create }; -static struct proto_ops nr_proto_ops = { +static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = { PF_NETROM, - sock_no_dup, nr_release, nr_bind, nr_connect, @@ -1266,8 +1260,12 @@ nr_getsockopt, sock_no_fcntl, nr_sendmsg, - nr_recvmsg + nr_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(nr_proto, PF_NETROM); static struct notifier_block nr_dev_notifier = { nr_device_event, diff -u --recursive --new-file v2.3.14/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v2.3.14/linux/net/netrom/nr_route.c Wed Aug 18 11:38:49 1999 +++ linux/net/netrom/nr_route.c Mon Aug 23 10:01:02 1999 @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include static unsigned int nr_neigh_no = 1; @@ -548,12 +548,13 @@ { struct net_device *dev; - if ((dev = dev_get(devname)) == NULL) + if ((dev = dev_get_by_name(devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; + dev_put(dev); return NULL; } @@ -584,8 +585,10 @@ read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) { + dev_hold(dev); goto out; + } } out: read_unlock(&dev_base_lock); @@ -706,11 +709,6 @@ struct net_device *dev; unsigned char *dptr; - if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) - return 0; - - if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) - return 0; nr_src = (ax25_address *)(skb->data + 0); nr_dest = (ax25_address *)(skb->data + 7); @@ -743,9 +741,6 @@ nr_neigh = nr_node->routes[nr_node->which].neighbour; if ((dev = nr_dev_first()) == NULL) - return 0; - - if (ax25 != NULL && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) return 0; dptr = skb_push(skb, 1); diff -u --recursive --new-file v2.3.14/linux/net/netsyms.c linux/net/netsyms.c --- v2.3.14/linux/net/netsyms.c Wed Aug 18 09:45:10 1999 +++ linux/net/netsyms.c Mon Aug 23 13:44:03 1999 @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef CONFIG_HIPPI #include #endif @@ -39,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -77,8 +77,6 @@ #include "../drivers/net/8390.h" #endif -extern int (*rarp_ioctl_hook)(int,void*); - #ifdef CONFIG_IPX_MODULE extern struct datalink_proto *make_EII_client(void); extern struct datalink_proto *make_8023_client(void); @@ -94,22 +92,17 @@ extern int sysctl_max_syn_backlog; #endif -EXPORT_SYMBOL(dev_lockct); - /* Skbuff symbols. */ EXPORT_SYMBOL(skb_over_panic); EXPORT_SYMBOL(skb_under_panic); -/* Socket layer global data */ -EXPORT_SYMBOL(sockhash_lock); - /* Socket layer registration */ EXPORT_SYMBOL(sock_register); EXPORT_SYMBOL(sock_unregister); /* Socket locking */ -EXPORT_SYMBOL(lock_sock); -EXPORT_SYMBOL(release_sock); +EXPORT_SYMBOL(__lock_sock); +EXPORT_SYMBOL(__release_sock); /* Socket layer support routines */ EXPORT_SYMBOL(memcpy_fromiovec); @@ -126,7 +119,6 @@ EXPORT_SYMBOL(sock_wake_async); EXPORT_SYMBOL(sock_alloc_send_skb); EXPORT_SYMBOL(sock_init_data); -EXPORT_SYMBOL(sock_no_dup); EXPORT_SYMBOL(sock_no_release); EXPORT_SYMBOL(sock_no_bind); EXPORT_SYMBOL(sock_no_connect); @@ -142,6 +134,7 @@ EXPORT_SYMBOL(sock_no_fcntl); EXPORT_SYMBOL(sock_no_sendmsg); EXPORT_SYMBOL(sock_no_recvmsg); +EXPORT_SYMBOL(sock_no_mmap); EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); @@ -154,7 +147,6 @@ EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(put_cmsg); -EXPORT_SYMBOL(net_families); EXPORT_SYMBOL(sock_kmalloc); EXPORT_SYMBOL(sock_kfree_s); @@ -167,6 +159,8 @@ EXPORT_SYMBOL(neigh_resolve_output); EXPORT_SYMBOL(neigh_connected_output); EXPORT_SYMBOL(neigh_update); +EXPORT_SYMBOL(neigh_create); +EXPORT_SYMBOL(neigh_lookup); EXPORT_SYMBOL(__neigh_event_send); EXPORT_SYMBOL(neigh_event_ns); EXPORT_SYMBOL(neigh_ifdown); @@ -178,12 +172,11 @@ #endif EXPORT_SYMBOL(pneigh_lookup); EXPORT_SYMBOL(pneigh_enqueue); -EXPORT_SYMBOL(neigh_create); EXPORT_SYMBOL(neigh_destroy); -EXPORT_SYMBOL(neigh_lookup); EXPORT_SYMBOL(neigh_parms_alloc); EXPORT_SYMBOL(neigh_parms_release); EXPORT_SYMBOL(neigh_rand_reach_time); +EXPORT_SYMBOL(neigh_compat_output); /* dst_entry */ EXPORT_SYMBOL(dst_alloc); @@ -220,17 +213,20 @@ #ifdef CONFIG_BRIDGE EXPORT_SYMBOL(br_ioctl); +EXPORT_SYMBOL(port_info); +EXPORT_SYMBOL(br_avl_find_addr); #endif #ifdef CONFIG_INET /* Internet layer registration */ EXPORT_SYMBOL(inet_add_protocol); EXPORT_SYMBOL(inet_del_protocol); -EXPORT_SYMBOL(rarp_ioctl_hook); EXPORT_SYMBOL(init_etherdev); EXPORT_SYMBOL(ip_route_output); +EXPORT_SYMBOL(ip_route_input); EXPORT_SYMBOL(icmp_send); EXPORT_SYMBOL(ip_options_compile); +EXPORT_SYMBOL(ip_options_undo); EXPORT_SYMBOL(arp_send); EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(ip_id_count); @@ -240,9 +236,15 @@ EXPORT_SYMBOL(in_aton); EXPORT_SYMBOL(ip_mc_inc_group); EXPORT_SYMBOL(ip_mc_dec_group); -EXPORT_SYMBOL(__ip_finish_output); +EXPORT_SYMBOL(ip_finish_output); EXPORT_SYMBOL(inet_dgram_ops); EXPORT_SYMBOL(ip_cmsg_recv); +EXPORT_SYMBOL(inet_addr_type); +EXPORT_SYMBOL(inet_select_addr); +EXPORT_SYMBOL(ip_dev_find); +EXPORT_SYMBOL(inetdev_by_index); +EXPORT_SYMBOL(in_dev_finish_destroy); +EXPORT_SYMBOL(ip_defrag); /* Route manipulation */ EXPORT_SYMBOL(ip_rt_ioctl); @@ -275,20 +277,28 @@ EXPORT_SYMBOL(inet_getsockopt); EXPORT_SYMBOL(inet_sendmsg); EXPORT_SYMBOL(inet_recvmsg); +EXPORT_SYMBOL(inet_sock_nr); +EXPORT_SYMBOL(inet_sock_destruct); /* Socket demultiplexing. */ EXPORT_SYMBOL(tcp_ehash); EXPORT_SYMBOL(tcp_ehash_size); EXPORT_SYMBOL(tcp_listening_hash); +EXPORT_SYMBOL(tcp_lhash_lock); +EXPORT_SYMBOL(tcp_lhash_users); +EXPORT_SYMBOL(tcp_lhash_wait); +EXPORT_SYMBOL(tcp_listen_wlock); EXPORT_SYMBOL(tcp_bhash); EXPORT_SYMBOL(tcp_bhash_size); +EXPORT_SYMBOL(tcp_portalloc_lock); EXPORT_SYMBOL(udp_hash); +EXPORT_SYMBOL(udp_hash_lock); -EXPORT_SYMBOL(destroy_sock); +EXPORT_SYMBOL(tcp_destroy_sock); EXPORT_SYMBOL(ip_queue_xmit); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(csum_partial_copy_fromiovecend); -EXPORT_SYMBOL(net_timer); +EXPORT_SYMBOL(tcp_keepalive_timer); EXPORT_SYMBOL(tcp_v4_lookup_listener); /* UDP/TCP exported functions for TCPv6 */ EXPORT_SYMBOL(udp_ioctl); @@ -329,9 +339,8 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock); EXPORT_SYMBOL(tcp_v4_do_rcv); EXPORT_SYMBOL(tcp_v4_connect); -EXPORT_SYMBOL(inet_addr_type); -EXPORT_SYMBOL(net_reset_timer); -EXPORT_SYMBOL(net_delete_timer); +EXPORT_SYMBOL(tcp_v4_hash_connecting); +EXPORT_SYMBOL(tcp_unhash); EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(tcp_prot); EXPORT_SYMBOL(tcp_openreq_cachep); @@ -351,7 +360,6 @@ EXPORT_SYMBOL(tcp_write_xmit); EXPORT_SYMBOL(dev_loopback_xmit); -EXPORT_SYMBOL(tcp_regs); #ifdef CONFIG_SYSCTL EXPORT_SYMBOL(sysctl_max_syn_backlog); @@ -445,6 +453,10 @@ EXPORT_SYMBOL(ether_setup); EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_get_by_index); +EXPORT_SYMBOL(__dev_get_by_index); +EXPORT_SYMBOL(dev_get_by_name); +EXPORT_SYMBOL(__dev_get_by_name); +EXPORT_SYMBOL(netdev_finish_unregister); EXPORT_SYMBOL(eth_type_trans); #ifdef CONFIG_FDDI EXPORT_SYMBOL(fddi_type_trans); @@ -461,6 +473,9 @@ EXPORT_SYMBOL(dev_get); EXPORT_SYMBOL(dev_alloc); EXPORT_SYMBOL(dev_alloc_name); +#ifdef CONFIG_KMOD +EXPORT_SYMBOL(dev_load); +#endif EXPORT_SYMBOL(dev_ioctl); EXPORT_SYMBOL(dev_queue_xmit); EXPORT_SYMBOL(netdev_dropping); @@ -513,6 +528,7 @@ EXPORT_SYMBOL(unregister_qdisc); EXPORT_SYMBOL(qdisc_get_rtab); EXPORT_SYMBOL(qdisc_put_rtab); +EXPORT_SYMBOL(qdisc_copy_stats); #ifdef CONFIG_NET_ESTIMATOR EXPORT_SYMBOL(qdisc_new_estimator); EXPORT_SYMBOL(qdisc_kill_estimator); @@ -529,6 +545,18 @@ #ifdef CONFIG_NET_CLS EXPORT_SYMBOL(register_tcf_proto_ops); EXPORT_SYMBOL(unregister_tcf_proto_ops); +#endif +#ifdef CONFIG_NETFILTER +#include +EXPORT_SYMBOL(nf_register_hook); +EXPORT_SYMBOL(nf_unregister_hook); +EXPORT_SYMBOL(nf_register_sockopt); +EXPORT_SYMBOL(nf_unregister_sockopt); +EXPORT_SYMBOL(nf_getinfo); +EXPORT_SYMBOL(nf_reinject); +EXPORT_SYMBOL(nf_register_interest); +EXPORT_SYMBOL(nf_unregister_interest); +EXPORT_SYMBOL(nf_hook_slow); #endif EXPORT_SYMBOL(register_gifconf); diff -u --recursive --new-file v2.3.14/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.3.14/linux/net/packet/af_packet.c Wed Aug 18 11:38:49 1999 +++ linux/net/packet/af_packet.c Mon Aug 23 10:01:02 1999 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.20 1999/06/09 10:11:32 davem Exp $ + * Version: $Id: af_packet.c,v 1.23 1999/08/23 06:30:40 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include @@ -69,6 +71,7 @@ #endif #ifdef CONFIG_BRIDGE +#include #include #endif @@ -161,7 +164,11 @@ */ /* List of all packet sockets. */ -struct sock * packet_sklist = NULL; +static struct sock * packet_sklist = NULL; +static rwlock_t packet_sklist_lock = RW_LOCK_UNLOCKED; + +atomic_t packet_socks_nr; + /* Private packet socket structures. */ @@ -176,19 +183,56 @@ unsigned char addr[8]; }; #endif +#ifdef CONFIG_PACKET_MMAP +static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing); +#endif static void packet_flush_mclist(struct sock *sk); struct packet_opt { struct packet_type prot_hook; + spinlock_t bind_lock; char running; /* prot_hook is attached*/ int ifindex; /* bound device */ + struct tpacket_stats stats; #ifdef CONFIG_PACKET_MULTICAST struct packet_mclist *mclist; #endif +#ifdef CONFIG_PACKET_MMAP + atomic_t mapped; + unsigned long *pg_vec; + unsigned int pg_vec_order; + unsigned int pg_vec_pages; + unsigned int pg_vec_len; + + struct tpacket_hdr **iovec; + unsigned int frame_size; + unsigned int iovmax; + unsigned int head; +#endif }; +void packet_sock_destruct(struct sock *sk) +{ + BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); + BUG_TRAP(atomic_read(&sk->wmem_alloc)==0); + + if (!sk->dead) { + printk("Attempt to release alive packet socket: %p\n", sk); + return; + } + + if (sk->protinfo.destruct_hook) + kfree(sk->protinfo.destruct_hook); + atomic_dec(&packet_socks_nr); +#ifdef PACKET_REFCNT_DEBUG + printk(KERN_DEBUG "PACKET socket %p is free, %d are alive\n", sk, atomic_read(&packet_socks_nr)); +#endif + MOD_DEC_USE_COUNT; +} + + extern struct proto_ops packet_ops; #ifdef CONFIG_SOCK_PACKET @@ -217,10 +261,11 @@ * so that this procedure is noop. */ - if (skb->pkt_type == PACKET_LOOPBACK) { - kfree_skb(skb); - return 0; - } + if (skb->pkt_type == PACKET_LOOPBACK) + goto out; + + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + goto oom; skb_push(skb, skb->data-skb->mac.raw); @@ -229,24 +274,26 @@ */ spkt->spkt_family = dev->type; - strncpy(spkt->spkt_device, dev->name, 15); + strncpy(spkt->spkt_device, dev->name, sizeof(spkt->spkt_device)); spkt->spkt_protocol = skb->protocol; + if (skb->rx_dev) { + dev_put(skb->rx_dev); + skb->rx_dev = NULL; + } + /* * Charge the memory to the socket. This is done specifically * to prevent sockets using all the memory up. */ - if (sock_queue_rcv_skb(sk,skb)<0) - { - kfree_skb(skb); + if (sock_queue_rcv_skb(sk,skb) == 0) return 0; - } - /* - * Processing complete. - */ - return(0); +out: + kfree_skb(skb); +oom: + return 0; } @@ -266,13 +313,6 @@ int err; /* - * Check the flags. - */ - - if (msg->msg_flags&~MSG_DONTWAIT) - return(-EINVAL); - - /* * Get and verify the address. */ @@ -286,14 +326,12 @@ else return(-ENOTCONN); /* SOCK_PACKET must be sent giving an address */ - dev_lock_list(); - /* * Find the device first to size check it */ saddr->spkt_device[13] = 0; - dev = dev_get(saddr->spkt_device); + dev = dev_get_by_name(saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -318,7 +356,7 @@ if (skb == NULL) goto out_unlock; - + /* * Fill it in */ @@ -353,36 +391,100 @@ */ dev_queue_xmit(skb); - dev_unlock_list(); + dev_put(dev); return(len); out_free: kfree_skb(skb); out_unlock: - dev_unlock_list(); + if (dev) + dev_put(dev); return err; } #endif +/* + This function makes lazy skb cloning in hope that most of packets + are discarded by BPF. + + Note tricky part: we DO mangle shared skb! skb->data, skb->len + and skb->cb are mangled. It works because (and until) packets + falling here are owned by current CPU. Output packets are cloned + by dev_queue_xmit_nit(), input packets are processed by net_bh + sequencially, so that if we return skb to original state on exit, + we will not harm anyone. + */ + static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) { struct sock *sk; - struct sockaddr_ll *sll = (struct sockaddr_ll*)skb->cb; - - /* - * When we registered the protocol we saved the socket in the data - * field for just this event. - */ + struct sockaddr_ll *sll; + struct packet_opt *po; + u8 * skb_head = skb->data; +#ifdef CONFIG_FILTER + unsigned snaplen; +#endif + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; sk = (struct sock *) pt->data; + po = sk->protinfo.af_packet; - if (skb->pkt_type == PACKET_LOOPBACK) { - kfree_skb(skb); - return 0; + skb->dev = dev; + + if (dev->hard_header) { + /* The device has an explicit notion of ll header, + exported to higher levels. + + Otherwise, the device hides datails of it frame + structure, so that corresponding packet head + never delivered to user. + */ + if (sk->type != SOCK_DGRAM) + skb_push(skb, skb->data - skb->mac.raw); + else if (skb->pkt_type == PACKET_OUTGOING) { + /* Special case: outgoing packets have ll header at head */ + skb_pull(skb, skb->nh.raw - skb->data); + } } - skb->dev = dev; +#ifdef CONFIG_FILTER + snaplen = skb->len; + + if (sk->filter) { + unsigned res = snaplen; + struct sk_filter *filter; + + bh_lock_sock(sk); + if ((filter = sk->filter) != NULL) + res = sk_run_filter(skb, sk->filter->insns, sk->filter->len); + bh_unlock_sock(sk); + + if (res == 0) + goto drop_n_restore; + if (snaplen > res) + snaplen = res; + } +#endif /* CONFIG_FILTER */ + + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + goto drop_n_acct; + + if (skb_shared(skb)) { + struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb == NULL) + goto drop_n_acct; + + if (skb_head != skb->data) { + skb->data = skb_head; + skb->len = skb->tail - skb->data; + } + kfree_skb(skb); + skb = nskb; + } + sll = (struct sockaddr_ll*)skb->cb; sll->sll_family = AF_PACKET; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; @@ -393,14 +495,59 @@ if (dev->hard_header_parse) sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); - if (dev->hard_header) { - /* The device has an explicit notion of ll header, - exported to higher levels. + if (skb->rx_dev) { + dev_put(skb->rx_dev); + skb->rx_dev = NULL; + } + +#ifdef CONFIG_FILTER + if (skb->len > snaplen) + __skb_trim(skb, snaplen); +#endif + + skb_set_owner_r(skb, sk); + spin_lock(&sk->receive_queue.lock); + po->stats.tp_packets++; + __skb_queue_tail(&sk->receive_queue, skb); + spin_unlock(&sk->receive_queue.lock); + sk->data_ready(sk,skb->len); + return 0; - Otherwise, the device hides datails of it frame - structure, so that corresponding packet head - never delivered to user. - */ +drop_n_acct: + spin_lock(&sk->receive_queue.lock); + po->stats.tp_drops++; + spin_unlock(&sk->receive_queue.lock); + +#ifdef CONFIG_FILTER +drop_n_restore: +#endif + if (skb_head != skb->data && skb_shared(skb)) { + skb->data = skb_head; + skb->len = skb->tail - skb->data; + } +drop: + kfree_skb(skb); + return 0; +} + +#ifdef CONFIG_PACKET_MMAP +static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +{ + struct sock *sk; + struct packet_opt *po; + struct sockaddr_ll *sll; + struct tpacket_hdr *h; + u8 * skb_head = skb->data; + unsigned snaplen; + unsigned long losing; + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; + + sk = (struct sock *) pt->data; + po = sk->protinfo.af_packet; + + if (dev->hard_header) { if (sk->type != SOCK_DGRAM) skb_push(skb, skb->data - skb->mac.raw); else if (skb->pkt_type == PACKET_OUTGOING) { @@ -409,19 +556,92 @@ } } - /* - * Charge the memory to the socket. This is done specifically - * to prevent sockets using all the memory up. - */ + snaplen = skb->len; - if (sock_queue_rcv_skb(sk,skb)<0) - { - kfree_skb(skb); - return 0; +#ifdef CONFIG_FILTER + if (sk->filter) { + unsigned res = snaplen; + struct sk_filter *filter; + + bh_lock_sock(sk); + if ((filter = sk->filter) != NULL) + res = sk_run_filter(skb, sk->filter->insns, sk->filter->len); + bh_unlock_sock(sk); + + if (res == 0) + goto drop_n_restore; + if (snaplen > res) + snaplen = res; + } +#endif + spin_lock(&sk->receive_queue.lock); + h = po->iovec[po->head]; + + if (h->tp_status) + goto ring_is_full; + po->head = po->head != po->iovmax ? po->head+1 : 0; + po->stats.tp_packets++; + losing = TP_STATUS_LOSING; + if (!po->stats.tp_drops) + losing = 0; + spin_unlock(&sk->receive_queue.lock); + + if (sk->type == SOCK_DGRAM) { + h->tp_mac = h->tp_net = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + } else { + unsigned maclen = skb->nh.raw - skb->data; + h->tp_net = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); + h->tp_mac = h->tp_net - maclen; } - return(0); + + if (h->tp_mac + snaplen > po->frame_size) { + snaplen = po->frame_size - h->tp_mac; + if ((int)snaplen < 0) + snaplen = 0; + } + + memcpy((u8*)h + h->tp_mac, skb->data, snaplen); + + h->tp_sec = skb->stamp.tv_sec; + h->tp_usec = skb->stamp.tv_usec; + h->tp_len = skb->len; + h->tp_snaplen = snaplen; + + sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); + sll->sll_halen = 0; + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + sll->sll_family = AF_PACKET; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + + h->tp_status = losing|TP_STATUS_USER; + mb(); + + sk->data_ready(sk, 0); + +drop_n_restore: + if (skb_head != skb->data && skb_shared(skb)) { + skb->data = skb_head; + skb->len = skb->tail - skb->data; + } +drop: + kfree_skb(skb); + return 0; + +ring_is_full: + po->stats.tp_drops++; + spin_unlock(&sk->receive_queue.lock); + + sk->data_ready(sk, 0); + goto drop_n_restore; } +#endif + + static int packet_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { @@ -432,13 +652,6 @@ unsigned short proto; unsigned char *addr; int ifindex, err, reserve = 0; - - /* - * Check the flags. - */ - - if (msg->msg_flags&~MSG_DONTWAIT) - return(-EINVAL); /* * Get and verify the address. @@ -449,14 +662,15 @@ proto = sk->num; addr = NULL; } else { - if (msg->msg_namelen < sizeof(struct sockaddr_ll)) - return -EINVAL; + err = -EINVAL; + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) + goto out; ifindex = saddr->sll_ifindex; proto = saddr->sll_protocol; addr = saddr->sll_addr; } - dev_lock_list(); + dev = dev_get_by_index(ifindex); err = -ENXIO; if (dev == NULL) @@ -468,7 +682,6 @@ if (len > dev->mtu+reserve) goto out_unlock; - skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) @@ -490,11 +703,12 @@ /* Returns -EFAULT on error */ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + if (err) + goto out_free; + skb->protocol = proto; skb->dev = dev; skb->priority = sk->priority; - if (err) - goto out_free; err = -ENETDOWN; if (!(dev->flags & IFF_UP)) @@ -504,90 +718,88 @@ * Now send it */ - dev_queue_xmit(skb); - dev_unlock_list(); + err = dev_queue_xmit(skb); + if (err > 0 && (err = net_xmit_errno(err)) != 0) + goto out_unlock; + + dev_put(dev); + return(len); out_free: kfree_skb(skb); out_unlock: - dev_unlock_list(); + if (dev) + dev_put(dev); +out: return err; } -static void packet_destroy_timer(unsigned long data) -{ - struct sock *sk=(struct sock *)data; - - if (!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) { - sk_free(sk); - MOD_DEC_USE_COUNT; - return; - } - - sk->timer.expires=jiffies+10*HZ; - add_timer(&sk->timer); - printk(KERN_DEBUG "packet sk destroy delayed\n"); -} - /* * Close a PACKET socket. This is fairly simple. We immediately go * to 'closed' state and remove our protocol entry in the device list. */ -static int packet_release(struct socket *sock, struct socket *peersock) +static int packet_release(struct socket *sock) { - struct sk_buff *skb; struct sock *sk = sock->sk; + struct sock **skp; if (!sk) return 0; - sklist_remove_socket(&packet_sklist, sk); + write_lock_bh(&packet_sklist_lock); + for (skp = &packet_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock_bh(&packet_sklist_lock); /* * Unhook packet receive handler. */ - if (sk->protinfo.af_packet->running) - { + if (sk->protinfo.af_packet->running) { /* * Remove the protocol hook */ - dev_remove_pack(&sk->protinfo.af_packet->prot_hook); sk->protinfo.af_packet->running = 0; + __sock_put(sk); } #ifdef CONFIG_PACKET_MULTICAST packet_flush_mclist(sk); #endif +#ifdef CONFIG_PACKET_MMAP + if (sk->protinfo.af_packet->pg_vec) { + struct tpacket_req req; + memset(&req, 0, sizeof(req)); + packet_set_ring(sk, &req, 1); + } +#endif + /* * Now the socket is dead. No more input will appear. */ - sk->state_change(sk); /* It is useless. Just for sanity. */ - + write_lock_irq(&sk->callback_lock); sock->sk = NULL; sk->socket = NULL; sk->dead = 1; + sk->sleep = NULL; + write_unlock_irq(&sk->callback_lock); - /* Purge queues */ - while ((skb=skb_dequeue(&sk->receive_queue))!=NULL) - kfree_skb(skb); + /* Purge queues */ - if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { - sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+HZ; - sk->timer.function=packet_destroy_timer; - add_timer(&sk->timer); - return 0; - } + skb_queue_purge(&sk->receive_queue); - sk_free(sk); - MOD_DEC_USE_COUNT; + sock_put(sk); return 0; } @@ -601,8 +813,12 @@ * Detach an existing hook if present. */ + lock_sock(sk); + + spin_lock(&sk->protinfo.af_packet->bind_lock); if (sk->protinfo.af_packet->running) { dev_remove_pack(&sk->protinfo.af_packet->prot_hook); + __sock_put(sk); sk->protinfo.af_packet->running = 0; } @@ -610,23 +826,30 @@ sk->protinfo.af_packet->prot_hook.type = protocol; sk->protinfo.af_packet->prot_hook.dev = dev; + sk->protinfo.af_packet->ifindex = dev ? dev->ifindex : 0; + if (protocol == 0) - return 0; + goto out_unlock; if (dev) { - sk->protinfo.af_packet->ifindex = dev->ifindex; if (dev->flags&IFF_UP) { dev_add_pack(&sk->protinfo.af_packet->prot_hook); + sock_hold(sk); sk->protinfo.af_packet->running = 1; } else { sk->err = ENETDOWN; - sk->error_report(sk); + if (!sk->dead) + sk->error_report(sk); } } else { - sk->protinfo.af_packet->ifindex = 0; dev_add_pack(&sk->protinfo.af_packet->prot_hook); + sock_hold(sk); sk->protinfo.af_packet->running = 1; } + +out_unlock: + spin_unlock(&sk->protinfo.af_packet->bind_lock); + release_sock(sk); return 0; } @@ -641,6 +864,7 @@ struct sock *sk=sock->sk; char name[15]; struct net_device *dev; + int err = -ENODEV; /* * Check legality @@ -651,10 +875,12 @@ strncpy(name,uaddr->sa_data,14); name[14]=0; - dev = dev_get(name); - if (dev) - return packet_do_bind(sk, dev, sk->num); - return -ENODEV; + dev = dev_get_by_name(name); + if (dev) { + err = packet_do_bind(sk, dev, sk->num); + dev_put(dev); + } + return err; } #endif @@ -663,7 +889,9 @@ struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; struct sock *sk=sock->sk; struct net_device *dev = NULL; - + int err; + + /* * Check legality */ @@ -674,11 +902,17 @@ return -EINVAL; if (sll->sll_ifindex) { + err = -ENODEV; dev = dev_get_by_index(sll->sll_ifindex); if (dev == NULL) - return -ENODEV; + goto out; } - return packet_do_bind(sk, dev, sll->sll_protocol ? : sk->num); + err = packet_do_bind(sk, dev, sll->sll_protocol ? : sk->num); + if (dev) + dev_put(dev); + +out: + return err; } @@ -708,7 +942,6 @@ if (sk == NULL) goto out; - sk->reuse = 1; sock->ops = &packet_ops; #ifdef CONFIG_SOCK_PACKET if (sock->type == SOCK_PACKET) @@ -720,14 +953,17 @@ if (sk->protinfo.af_packet == NULL) goto out_free; memset(sk->protinfo.af_packet, 0, sizeof(struct packet_opt)); - sk->zapped=0; sk->family = PF_PACKET; sk->num = protocol; + sk->destruct = packet_sock_destruct; + atomic_inc(&packet_socks_nr); + /* * Attach a protocol block */ + spin_lock_init(&sk->protinfo.af_packet->bind_lock); sk->protinfo.af_packet->prot_hook.func = packet_rcv; #ifdef CONFIG_SOCK_PACKET if (sock->type == SOCK_PACKET) @@ -738,10 +974,15 @@ if (protocol) { sk->protinfo.af_packet->prot_hook.type = protocol; dev_add_pack(&sk->protinfo.af_packet->prot_hook); + sock_hold(sk); sk->protinfo.af_packet->running = 1; } - sklist_insert_socket(&packet_sklist, sk); + write_lock_bh(&packet_sklist_lock); + sk->next = packet_sklist; + packet_sklist = sk; + sock_hold(sk); + write_unlock_bh(&packet_sklist_lock); return(0); out_free: @@ -756,16 +997,6 @@ * If necessary we block. */ -/* - * NOTE about lock_* & release_* primitives. - * I do not understand why skb_recv_datagram locks socket. - * My analysis shows that it is useless for datagram services: - * i.e. here, udp, raw and netlink. FIX ME if I am wrong, - * but lock&release are necessary only for SOCK_STREAM - * and, maybe, SOCK_SEQPACKET. - * --ANK - */ - static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) { @@ -854,9 +1085,10 @@ uaddr->sa_family = AF_PACKET; dev = dev_get_by_index(sk->protinfo.af_packet->ifindex); - if (dev) + if (dev) { strncpy(uaddr->sa_data, dev->name, 15); - else + dev_put(dev); + } else memset(uaddr->sa_data, 0, 14); *uaddr_len = sizeof(*uaddr); @@ -882,6 +1114,7 @@ sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); + dev_put(dev); } else { sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; @@ -925,10 +1158,10 @@ struct net_device *dev; int err; - rtnl_shlock(); + rtnl_lock(); err = -ENODEV; - dev = dev_get_by_index(mreq->mr_ifindex); + dev = __dev_get_by_index(mreq->mr_ifindex); if (!dev) goto done; @@ -964,7 +1197,7 @@ packet_dev_mc(dev, i, +1); done: - rtnl_shunlock(); + rtnl_unlock(); return err; } @@ -972,6 +1205,8 @@ { struct packet_mclist *ml, **mlp; + rtnl_lock(); + for (mlp=&sk->protinfo.af_packet->mclist; (ml=*mlp)!=NULL; mlp=&ml->next) { if (ml->ifindex == mreq->mr_ifindex && ml->type == mreq->mr_type && @@ -981,13 +1216,17 @@ struct net_device *dev; *mlp = ml->next; dev = dev_get_by_index(ml->ifindex); - if (dev) + if (dev) { packet_dev_mc(dev, ml, -1); + dev_put(dev); + } kfree_s(ml, sizeof(*ml)); } + rtnl_unlock(); return 0; } } + rtnl_unlock(); return -EADDRNOTAVAIL; } @@ -995,41 +1234,104 @@ { struct packet_mclist *ml; + if (sk->protinfo.af_packet->mclist == NULL) + return; + + rtnl_lock(); while ((ml=sk->protinfo.af_packet->mclist) != NULL) { struct net_device *dev; sk->protinfo.af_packet->mclist = ml->next; - if ((dev = dev_get_by_index(ml->ifindex)) != NULL) + if ((dev = dev_get_by_index(ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); + dev_put(dev); + } kfree_s(ml, sizeof(*ml)); } + rtnl_unlock(); } +#endif static int packet_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { struct sock *sk = sock->sk; - struct packet_mreq mreq; + int ret; if (level != SOL_PACKET) return -ENOPROTOOPT; - + switch(optname) { +#ifdef CONFIG_PACKET_MULTICAST case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: - + { + struct packet_mreq mreq; if (optlensk; + + if (level != SOL_PACKET) + return -ENOPROTOOPT; + + if (get_user(len,optlen)) + return -EFAULT; + + switch(optname) { + case PACKET_STATISTICS: + { + struct tpacket_stats st; + + if (len > sizeof(struct tpacket_stats)) + len = sizeof(struct tpacket_stats); + spin_lock_bh(&sk->receive_queue.lock); + st = sk->protinfo.af_packet->stats; + memset(&sk->protinfo.af_packet->stats, 0, sizeof(st)); + spin_unlock_bh(&sk->receive_queue.lock); + st.tp_packets += st.tp_drops; + + if (copy_to_user(optval, &st, len)) + return -EFAULT; + break; + } + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; + return 0; +} + static int packet_notifier(struct notifier_block *this, unsigned long msg, void *data) { @@ -1037,6 +1339,7 @@ struct packet_opt *po; struct net_device *dev = (struct net_device*)data; + read_lock(&packet_sklist_lock); for (sk = packet_sklist; sk; sk = sk->next) { po = sk->protinfo.af_packet; @@ -1044,16 +1347,20 @@ case NETDEV_DOWN: case NETDEV_UNREGISTER: if (dev->ifindex == po->ifindex) { + spin_lock(&po->bind_lock); if (po->running) { dev_remove_pack(&po->prot_hook); + __sock_put(sk); po->running = 0; sk->err = ENETDOWN; - sk->error_report(sk); + if (!sk->dead) + sk->error_report(sk); } if (msg == NETDEV_UNREGISTER) { po->ifindex = -1; po->prot_hook.dev = NULL; } + spin_unlock(&po->bind_lock); } #ifdef CONFIG_PACKET_MULTICAST if (po->mclist) @@ -1061,10 +1368,13 @@ #endif break; case NETDEV_UP: + spin_lock(&po->bind_lock); if (dev->ifindex == po->ifindex && sk->num && po->running==0) { dev_add_pack(&po->prot_hook); + sock_hold(sk); po->running = 1; } + spin_unlock(&po->bind_lock); #ifdef CONFIG_PACKET_MULTICAST if (po->mclist) packet_dev_mclist(dev, po->mclist, +1); @@ -1072,6 +1382,7 @@ break; } } + read_unlock(&packet_sklist_lock); return NOTIFY_DONE; } @@ -1130,8 +1441,11 @@ case SIOCGIFBR: case SIOCSIFBR: -#ifdef CONFIG_BRIDGE - return(br_ioctl(cmd,(void *) arg)); +#ifdef CONFIG_BRIDGE + lock_kernel(); + err = br_ioctl(cmd,(void *) arg); + unlock_kernel(); + return err; #else return -ENOPKG; #endif @@ -1142,9 +1456,6 @@ case SIOCDARP: case SIOCGARP: case SIOCSARP: - case SIOCDRARP: - case SIOCGRARP: - case SIOCSRARP: case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: @@ -1174,11 +1485,252 @@ return(0); } +#ifndef CONFIG_PACKET_MMAP +#define packet_mmap sock_no_mmap +#define packet_poll datagram_poll +#else + +unsigned int packet_poll(struct file * file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + struct packet_opt *po = sk->protinfo.af_packet; + unsigned int mask = datagram_poll(file, sock, wait); + + spin_lock_bh(&sk->receive_queue.lock); + if (po->iovec) { + unsigned last = po->head ? po->head-1 : po->iovmax; + + if (po->iovec[last]->tp_status) + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_bh(&sk->receive_queue.lock); + return mask; +} + + +/* Dirty? Well, I still did not learn better way to account + * for user mmaps. + */ + +static void packet_mm_open(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct inode *inode = file->f_dentry->d_inode; + struct socket * sock = &inode->u.socket_i; + struct sock *sk = sock->sk; + + if (sk) + atomic_inc(&sk->protinfo.af_packet->mapped); +} + +static void packet_mm_close(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct inode *inode = file->f_dentry->d_inode; + struct socket * sock = &inode->u.socket_i; + struct sock *sk = sock->sk; + + if (sk) + atomic_dec(&sk->protinfo.af_packet->mapped); +} + +static struct vm_operations_struct packet_mmap_ops = { + packet_mm_open, /* open */ + packet_mm_close, /* close */ + NULL, /* unmap */ + NULL, /* no special protect */ + NULL, /* sync */ + NULL, /* advise */ + NULL, /* nopage */ + NULL, /* wppage */ + NULL /* swapout */ +}; + +static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) +{ + int i; + + for (i=0; iprotinfo.af_packet; + int order = 0; + int err = 0; + + if (req->tp_block_nr) { + int i, l; + int frames_per_block; + + /* Sanity tests and some calculations */ + if ((int)req->tp_block_size <= 0) + return -EINVAL; + if (req->tp_block_size&(PAGE_SIZE-1)) + return -EINVAL; + if (req->tp_frame_size < TPACKET_HDRLEN) + return -EINVAL; + if (req->tp_frame_size&(TPACKET_ALIGNMENT-1)) + return -EINVAL; + frames_per_block = req->tp_block_size/req->tp_frame_size; + if (frames_per_block <= 0) + return -EINVAL; + if (frames_per_block*req->tp_block_nr != req->tp_frame_nr) + return -EINVAL; + /* OK! */ + + /* Allocate page vector */ + while ((PAGE_SIZE<tp_block_size) + order++; + + err = -ENOMEM; + + pg_vec = kmalloc(req->tp_block_nr*sizeof(unsigned long*), GFP_KERNEL); + if (pg_vec == NULL) + goto out; + memset(pg_vec, 0, req->tp_block_nr*sizeof(unsigned long*)); + + for (i=0; itp_block_nr; i++) { + unsigned long map, mapend; + pg_vec[i] = __get_free_pages(GFP_KERNEL, order); + if (!pg_vec[i]) + goto out_free_pgvec; + + mapend = MAP_NR(pg_vec[i] + (PAGE_SIZE << order) - 1); + for (map = MAP_NR(pg_vec[i]); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + } + /* Page vector is allocated */ + + /* Draw frames */ + io_vec = kmalloc(req->tp_frame_nr*sizeof(struct tpacket_hdr*), GFP_KERNEL); + if (io_vec == NULL) + goto out_free_pgvec; + memset(io_vec, 0, req->tp_frame_nr*sizeof(struct tpacket_hdr*)); + + l = 0; + for (i=0; itp_block_nr; i++) { + unsigned long ptr = pg_vec[i]; + int k; + + for (k=0; ktp_status = TP_STATUS_KERNEL; + ptr += req->tp_frame_size; + } + } + /* Done */ + } else { + if (req->tp_frame_nr) + return -EINVAL; + } + + lock_sock(sk); + + /* Detach socket from network */ + spin_lock(&po->bind_lock); + if (po->running) + dev_remove_pack(&po->prot_hook); + spin_unlock(&po->bind_lock); + + err = -EBUSY; + if (closing || atomic_read(&po->mapped) == 0) { + err = 0; +#define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) + + spin_lock_bh(&sk->receive_queue.lock); + pg_vec = XC(po->pg_vec, pg_vec); + io_vec = XC(po->iovec, io_vec); + po->iovmax = req->tp_frame_nr-1; + po->head = 0; + po->frame_size = req->tp_frame_size; + spin_unlock_bh(&sk->receive_queue.lock); + + order = XC(po->pg_vec_order, order); + req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr); + + po->pg_vec_pages = req->tp_block_size/PAGE_SIZE; + po->prot_hook.func = po->iovec ? tpacket_rcv : packet_rcv; + skb_queue_purge(&sk->receive_queue); +#undef XC + if (atomic_read(&po->mapped)) + printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); + } + + spin_lock(&po->bind_lock); + if (po->running) + dev_add_pack(&po->prot_hook); + spin_unlock(&po->bind_lock); + + release_sock(sk); + + if (io_vec) + kfree(io_vec); + +out_free_pgvec: + if (pg_vec) + free_pg_vec(pg_vec, order, req->tp_block_nr); +out: + return err; +} + +static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) +{ + struct sock *sk = sock->sk; + struct packet_opt *po = sk->protinfo.af_packet; + unsigned long size; + unsigned long start; + int err = -EINVAL; + int i; + + if (vma->vm_offset) + return -EINVAL; + + size = vma->vm_end - vma->vm_start; + + lock_sock(sk); + if (po->pg_vec == NULL) + goto out; + if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) + goto out; + + atomic_inc(&po->mapped); + start = vma->vm_start; + err = -EAGAIN; + for (i=0; ipg_vec_len; i++) { + if (remap_page_range(start, __pa(po->pg_vec[i]), + po->pg_vec_pages*PAGE_SIZE, + vma->vm_page_prot)) + goto out; + start += po->pg_vec_pages*PAGE_SIZE; + } + vma->vm_ops = &packet_mmap_ops; + err = 0; + +out: + release_sock(sk); + return err; +} +#endif + + #ifdef CONFIG_SOCK_PACKET struct proto_ops packet_ops_spkt = { PF_PACKET, - sock_no_dup, packet_release, packet_bind_spkt, sock_no_connect, @@ -1193,33 +1745,30 @@ sock_no_getsockopt, sock_no_fcntl, packet_sendmsg_spkt, - packet_recvmsg + packet_recvmsg, + sock_no_mmap }; #endif struct proto_ops packet_ops = { PF_PACKET, - sock_no_dup, packet_release, packet_bind, sock_no_connect, sock_no_socketpair, sock_no_accept, packet_getname, - datagram_poll, + packet_poll, packet_ioctl, sock_no_listen, sock_no_shutdown, -#ifdef CONFIG_PACKET_MULTICAST packet_setsockopt, -#else - sock_no_setsockopt, -#endif - sock_no_getsockopt, + packet_getsockopt, sock_no_fcntl, packet_sendmsg, - packet_recvmsg + packet_recvmsg, + packet_mmap, }; static struct net_proto_family packet_family_ops = { @@ -1233,10 +1782,63 @@ 0 }; +#ifdef CONFIG_PROC_FS +static int packet_read_proc(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + off_t pos=0; + off_t begin=0; + int len=0; + struct sock *s; + + len+= sprintf(buffer,"sk RefCnt Type Proto Iface R Rmem User Inode\n"); + + read_lock(&packet_sklist_lock); + + for (s = packet_sklist; s; s = s->next) { + len+=sprintf(buffer+len,"%p %-6d %-4d %04x %-5d %1d %-6u %-6u %-6lu", + s, + atomic_read(&s->refcnt), + s->type, + ntohs(s->num), + s->protinfo.af_packet->ifindex, + s->protinfo.af_packet->running, + atomic_read(&s->rmem_alloc), + s->socket->inode->i_uid, + s->socket->inode->i_ino + ); + + buffer[len++]='\n'; + + pos=begin+len; + if(posoffset+length) + goto done; + } + *eof = 1; + +done: + read_unlock(&packet_sklist_lock); + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + if(len<0) + len=0; + return len; +} +#endif + #ifdef MODULE void cleanup_module(void) { +#ifdef CONFIG_PROC_FS + remove_proc_entry("net/packet", 0); +#endif unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); return; @@ -1248,8 +1850,15 @@ void __init packet_proto_init(struct net_proto *pro) #endif { +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *ent; +#endif sock_register(&packet_family_ops); register_netdevice_notifier(&packet_netdev_notifier); +#ifdef CONFIG_PROC_FS + ent = create_proc_entry("net/packet", 0, 0); + ent->read_proc = packet_read_proc; +#endif #ifdef MODULE return 0; #endif diff -u --recursive --new-file v2.3.14/linux/net/protocols.c linux/net/protocols.c --- v2.3.14/linux/net/protocols.c Thu Dec 17 09:03:57 1998 +++ linux/net/protocols.c Mon Aug 23 09:56:32 1999 @@ -87,6 +87,10 @@ extern void rif_init(struct net_proto *); #endif +#ifdef CONFIG_ATM +#include +#endif + #ifdef NEED_LLC #define NEED_802 #include @@ -121,6 +125,11 @@ #ifdef CONFIG_TR { "RIF", rif_init }, /* RIF for Token ring */ #endif + +#ifdef CONFIG_ATM + { "ATMPVC", atmpvc_proto_init }, /* ATM PVCs */ + { "ATMSVC", atmsvc_proto_init }, /* ATM SVCs */ +#endif #ifdef NEED_LLC { "802.2LLC", llc_init }, /* 802.2 LLC */ diff -u --recursive --new-file v2.3.14/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.3.14/linux/net/rose/af_rose.c Wed Aug 18 11:38:49 1999 +++ linux/net/rose/af_rose.c Mon Aug 23 10:01:02 1999 @@ -618,7 +618,7 @@ return sk; } -static int rose_release(struct socket *sock, struct socket *peer) +static int rose_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -847,11 +847,6 @@ struct sock *newsk; struct sk_buff *skb; - if (newsock->sk != NULL) - rose_destroy_socket(newsock->sk); - - newsock->sk = NULL; - if ((sk = sock->sk) == NULL) return -EINVAL; @@ -1438,10 +1433,9 @@ rose_create }; -static struct proto_ops rose_proto_ops = { +static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = { PF_ROSE, - sock_no_dup, rose_release, rose_bind, rose_connect, @@ -1456,8 +1450,12 @@ rose_getsockopt, sock_no_fcntl, rose_sendmsg, - rose_recvmsg + rose_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(rose_proto, PF_ROSE); static struct notifier_block rose_dev_notifier = { rose_device_event, diff -u --recursive --new-file v2.3.14/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.3.14/linux/net/rose/rose_link.c Sat Apr 11 17:18:16 1998 +++ linux/net/rose/rose_link.c Mon Aug 23 10:01:02 1999 @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include static void rose_ftimer_expiry(unsigned long); @@ -291,10 +291,12 @@ { unsigned char *dptr; +#if 0 if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb); return; } +#endif if (neigh->loopback) { rose_loopback_queue(skb, neigh); diff -u --recursive --new-file v2.3.14/linux/net/rose/rose_route.c linux/net/rose/rose_route.c --- v2.3.14/linux/net/rose/rose_route.c Wed Aug 18 11:38:49 1999 +++ linux/net/rose/rose_route.c Mon Aug 23 10:01:02 1999 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include static unsigned int rose_neigh_no = 1; @@ -527,12 +527,13 @@ { struct net_device *dev; - if ((dev = dev_get(devname)) == NULL) + if ((dev = dev_get_by_name(devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; + dev_put(dev); return NULL; } @@ -563,14 +564,33 @@ read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) { + dev_hold(dev); goto out; + } } out: read_unlock(&dev_base_lock); return dev; } +static int rose_dev_exists(rose_address *addr) +{ + struct net_device *dev; + + read_lock(&dev_base_lock); + for (dev = dev_base; dev != NULL; dev = dev->next) { + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) + goto out; + } +out: + read_unlock(&dev_base_lock); + return dev != NULL; +} + + + + struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh) { struct rose_route *rose_route; @@ -622,6 +642,7 @@ { struct rose_route_struct rose_route; struct net_device *dev; + int err; switch (cmd) { @@ -630,19 +651,26 @@ return -EFAULT; if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; - if (rose_dev_get(&rose_route.address) != NULL) /* Can't add routes to ourself */ + if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ + dev_put(dev); return -EINVAL; + } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; - return rose_add_node(&rose_route, dev); + err = rose_add_node(&rose_route, dev); + dev_put(dev); + return err; case SIOCDELRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; - return rose_del_node(&rose_route, dev); + err = rose_del_node(&rose_route, dev); + dev_put(dev); + return err; + case SIOCRSCLRRT: return rose_clear_routes(); @@ -749,8 +777,10 @@ unsigned long flags; int len; +#if 0 if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) return 0; +#endif frametype = skb->data[2]; lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); @@ -810,8 +840,11 @@ * Is is a Call Request and is it for us ? */ if (frametype == ROSE_CALL_REQUEST) - if ((dev = rose_dev_get(dest_addr)) != NULL) - return rose_rx_call_request(skb, dev, rose_neigh, lci); + if ((dev = rose_dev_get(dest_addr)) != NULL) { + int err = rose_rx_call_request(skb, dev, rose_neigh, lci); + dev_put(dev); + return err; + } if (!sysctl_rose_routing_control) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); diff -u --recursive --new-file v2.3.14/linux/net/sched/Config.in linux/net/sched/Config.in --- v2.3.14/linux/net/sched/Config.in Sun Mar 21 07:22:00 1999 +++ linux/net/sched/Config.in Mon Aug 23 09:56:32 1999 @@ -7,6 +7,9 @@ tristate 'CSZ packet scheduler' CONFIG_NET_SCH_CSZ #tristate 'H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ #tristate 'H-FSC packet scheduler' CONFIG_NET_SCH_HFCS +if [ "$CONFIG_ATM" = "y" ]; then + bool 'ATM pseudo-scheduler' CONFIG_NET_SCH_ATM +fi tristate 'The simplest PRIO pseudoscheduler' CONFIG_NET_SCH_PRIO tristate 'RED queue' CONFIG_NET_SCH_RED tristate 'SFQ queue' CONFIG_NET_SCH_SFQ diff -u --recursive --new-file v2.3.14/linux/net/sched/Makefile linux/net/sched/Makefile --- v2.3.14/linux/net/sched/Makefile Sun Mar 21 07:22:00 1999 +++ linux/net/sched/Makefile Mon Aug 23 09:56:32 1999 @@ -101,6 +101,10 @@ endif endif +ifeq ($(CONFIG_NET_SCH_ATM), y) +O_OBJS += sch_atm.o +endif + ifeq ($(CONFIG_NET_CLS_U32), y) O_OBJS += cls_u32.o else diff -u --recursive --new-file v2.3.14/linux/net/sched/cls_api.c linux/net/sched/cls_api.c --- v2.3.14/linux/net/sched/cls_api.c Wed Aug 18 11:38:49 1999 +++ linux/net/sched/cls_api.c Mon Aug 23 10:01:02 1999 @@ -145,7 +145,7 @@ /* Find head of filter chain. */ /* Find link */ - if ((dev = dev_get_by_index(t->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(t->tcm_ifindex)) == NULL) return -ENODEV; /* Find qdisc */ @@ -372,6 +372,7 @@ q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); if (q == NULL) { read_unlock(&qdisc_tree_lock); + dev_put(dev); return skb->len; } if ((cops = q->ops->cl_ops) == NULL) @@ -425,6 +426,7 @@ cops->put(q, cl); read_unlock(&qdisc_tree_lock); + dev_put(dev); return skb->len; } diff -u --recursive --new-file v2.3.14/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c --- v2.3.14/linux/net/sched/cls_fw.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/cls_fw.c Mon Aug 23 10:01:02 1999 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -64,8 +65,8 @@ { struct fw_head *head = (struct fw_head*)tp->root; struct fw_filter *f; -#ifdef CONFIG_IP_FIREWALL - u32 id = skb->fwmark; +#ifdef CONFIG_NETFILTER + u32 id = (skb->nfreason == NF_REASON_FOR_CLS_FW ? skb->nfmark : 0); #else u32 id = 0; #endif diff -u --recursive --new-file v2.3.14/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c --- v2.3.14/linux/net/sched/cls_u32.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/cls_u32.c Mon Aug 23 10:01:02 1999 @@ -52,8 +52,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - struct tc_u_knode { @@ -488,7 +486,7 @@ sch_tree_lock(q); police = xchg(&n->police, police); - sch_tree_lock(q); + sch_tree_unlock(q); tcf_police_release(police); } diff -u --recursive --new-file v2.3.14/linux/net/sched/police.c linux/net/sched/police.c --- v2.3.14/linux/net/sched/police.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/police.c Mon Aug 23 10:01:02 1999 @@ -31,8 +31,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_api.c linux/net/sched/sch_api.c --- v2.3.14/linux/net/sched/sch_api.c Wed Aug 18 11:38:49 1999 +++ linux/net/sched/sch_api.c Mon Aug 23 10:01:02 1999 @@ -40,8 +40,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - #ifdef CONFIG_RTNETLINK static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new); @@ -95,9 +93,15 @@ ---enqueue - enqueue returns number of enqueued packets i.e. this number is 1, - if packet was enqueued successfully and <1 if something (not - necessary THIS packet) was dropped. + enqueue returns 0, if packet was enqueued successfully. + If packet (this one or another one) was dropped, it returns + not zero error code. + NET_XMIT_DROP - this packet dropped + Expected action: do not backoff, but wait until queue will clear. + NET_XMIT_CN - probably this packet enqueued, but another one dropped. + Expected action: backoff or ignore + NET_XMIT_POLICED - dropped by police. + Expected action: backoff or error to real-time apps. Auxiliary routines: @@ -509,7 +513,7 @@ struct Qdisc *p = NULL; int err; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -566,7 +570,7 @@ struct Qdisc *p = NULL; int err; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -807,7 +811,7 @@ u32 qid = TC_H_MAJ(clid); int err; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) return -ENODEV; /* @@ -1006,6 +1010,7 @@ cb->args[0] = t; + dev_put(dev); return skb->len; } #endif @@ -1019,8 +1024,9 @@ { int len; - len = sprintf(buffer, "%08x %08x\n", - psched_tick_per_us, psched_us_per_tick); + len = sprintf(buffer, "%08x %08x %08x %08x\n", + psched_tick_per_us, psched_us_per_tick, + 1000000, HZ); len -= offset; @@ -1201,6 +1207,9 @@ #endif #ifdef CONFIG_NET_SCH_PRIO INIT_QDISC(prio); +#endif +#ifdef CONFIG_NET_SCH_ATM + INIT_QDISC(atm); #endif #ifdef CONFIG_NET_CLS tc_filter_init(); diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c --- v2.3.14/linux/net/sched/sch_atm.c Wed Dec 31 16:00:00 1969 +++ linux/net/sched/sch_atm.c Mon Aug 23 09:56:32 1999 @@ -0,0 +1,644 @@ +/* net/sched/sch_atm.c - ATM VC selection "queueing discipline" */ + +/* Written 1998,1999 by Werner Almesberger, EPFL ICA */ + + +#include +#include +#include +#include +#include +#include +#include +#include /* for fput */ +#include +#include + + +extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */ +#define sockfd_put(sock) fput((sock)->file) /* @@@ copied because it's + __inline__ in socket.c */ + + +#if 1 /* control */ +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + +#if 0 /* data */ +#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define D2PRINTK(format,args...) +#endif + + +/* + * The ATM queuing discipline provides a framework for invoking classifiers + * (aka "filters"), which in turn select classes of this queuing discipline. + * Each class maps the flow(s) it is handling to a given VC. Multiple classes + * may share the same VC. + * + * When creating a class, VCs are specified by passing the number of the open + * socket descriptor by which the calling process references the VC. The kernel + * keeps the VC open at least until all classes using it are removed. + * + * In this file, most functions are named atm_tc_* to avoid confusion with all + * the atm_* in net/atm. This naming convention differs from what's used in the + * rest of net/sched. + * + * Known bugs: + * - sometimes messes up the IP stack + * - any manipulations besides the few operations described in the README, are + * untested and likely to crash the system + * - should lock the flow while there is data in the queue (?) + */ + + +#define PRIV(sch) ((struct atm_qdisc_data *) (sch)->data) + + +struct atm_flow_data { + struct Qdisc *q; /* FIFO, TBF, etc. */ + struct tcf_proto *filter_list; + struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */ + struct socket *sock; /* for closing */ + u32 classid; /* x:y type ID */ + int ref; /* reference count */ + struct tc_stats stats; + struct atm_flow_data *next; + struct atm_flow_data *excess; /* flow for excess traffic; + NULL to set CLP instead */ + int hdr_len; + unsigned char hdr[0]; /* header data; MUST BE LAST */ +}; + +struct atm_qdisc_data { + struct atm_flow_data link; /* unclassified skbs go here */ + struct atm_flow_data *flows; /* NB: "link" is also on this + list */ +}; + + +/* ------------------------- Class/flow operations ------------------------- */ + + +static int find_flow(struct atm_qdisc_data *qdisc,struct atm_flow_data *flow) +{ + struct atm_flow_data *walk; + + DPRINTK("find_flow(qdisc %p,flow %p)\n",qdisc,flow); + for (walk = qdisc->flows; walk; walk = walk->next) + if (walk == flow) return 1; + DPRINTK("find_flow: not found\n"); + return 0; +} + + +static __inline__ struct atm_flow_data *lookup_flow(struct Qdisc *sch, + u32 classid) +{ + struct atm_flow_data *flow; + + for (flow = PRIV(sch)->flows; flow; flow = flow->next) + if (flow->classid == classid) break; + return flow; +} + + +static int atm_tc_graft(struct Qdisc *sch,unsigned long arg, + struct Qdisc *new,struct Qdisc **old) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) arg; + + DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",sch, + p,flow,new,old); + if (!find_flow(p,flow)) return -EINVAL; + if (!new) new = &noop_qdisc; + *old = xchg(&flow->q,new); + if (*old) qdisc_reset(*old); + return 0; +} + + +static struct Qdisc *atm_tc_leaf(struct Qdisc *sch,unsigned long cl) +{ + struct atm_flow_data *flow = (struct atm_flow_data *) cl; + + DPRINTK("atm_tc_leaf(sch %p,flow %p)\n",sch,flow); + return flow ? flow->q : NULL; +} + + +static unsigned long atm_tc_get(struct Qdisc *sch,u32 classid) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + + DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid); + flow = lookup_flow(sch,classid); + if (flow) flow->ref++; + DPRINTK("atm_tc_get: flow %p\n",flow); + return (unsigned long) flow; +} + + +static unsigned long atm_tc_bind_filter(struct Qdisc *sch, + unsigned long parent, u32 classid) +{ + return atm_tc_get(sch,classid); +} + + +/* + * atm_tc_put handles all destructions, including the ones that are explicitly + * requested (atm_tc_destroy, etc.). The assumption here is that we never drop + * anything that still seems to be in use. + */ + +static void atm_tc_put(struct Qdisc *sch, unsigned long cl) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) cl; + struct atm_flow_data **prev; + struct tcf_proto *filter; + + DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n",sch,p,flow); + if (--flow->ref) return; + DPRINTK("atm_tc_put: destroying\n"); + for (prev = &p->flows; *prev; prev = &(*prev)->next) + if (*prev == flow) break; + if (!*prev) { + printk(KERN_CRIT "atm_tc_put: class %p not found\n",flow); + return; + } + *prev = flow->next; + DPRINTK("atm_tc_put: qdisc %p\n",flow->q); + qdisc_destroy(flow->q); + while ((filter = flow->filter_list)) { + DPRINTK("atm_tc_put: destroying filter %p\n",filter); + flow->filter_list = filter->next; + DPRINTK("atm_tc_put: filter %p\n",filter); + filter->ops->destroy(filter); + } + if (flow->sock) { + DPRINTK("atm_tc_put: f_count %d\n",file_count(flow->sock->file)); + sockfd_put(flow->sock); + } + if (flow->excess) atm_tc_put(sch,(unsigned long) flow->excess); + if (flow != &p->link) kfree(flow); + /* + * If flow == &p->link, the qdisc no longer works at this point and + * needs to be removed. (By the caller of atm_tc_put.) + */ +} + + +static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, + struct rtattr **tca, unsigned long *arg) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) *arg; + struct atm_flow_data *excess = NULL; + struct rtattr *opt = tca[TCA_OPTIONS-1]; + struct rtattr *tb[TCA_ATM_MAX]; + struct socket *sock; + int fd,error,hdr_len; + void *hdr; + + DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x," + "flow %p,opt %p)\n",sch,p,classid,parent,flow,opt); + /* + * The concept of parents doesn't apply for this qdisc. + */ + if (parent && parent != TC_H_ROOT && parent != sch->handle) + return -EINVAL; + /* + * ATM classes cannot be changed. In order to change properties of the + * ATM connection, that socket needs to be modified directly (via the + * native ATM API. In order to send a flow to a different VC, the old + * class needs to be removed and a new one added. (This may be changed + * later.) + */ + if (flow) return -EBUSY; + if (opt == NULL || rtattr_parse(tb,TCA_ATM_MAX,RTA_DATA(opt), + RTA_PAYLOAD(opt))) return -EINVAL; + if (!tb[TCA_ATM_FD-1] || RTA_PAYLOAD(tb[TCA_ATM_FD-1]) < sizeof(fd)) + return -EINVAL; + fd = *(int *) RTA_DATA(tb[TCA_ATM_FD-1]); + DPRINTK("atm_tc_change: fd %d\n",fd); + if (tb[TCA_ATM_HDR-1]) { + hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR-1]); + hdr = RTA_DATA(tb[TCA_ATM_HDR-1]); + } + else { + hdr_len = RFC1483LLC_LEN; + hdr = NULL; /* default LLC/SNAP for IP */ + } + if (!tb[TCA_ATM_EXCESS-1]) excess = NULL; + else { + if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS-1]) != sizeof(u32)) + return -EINVAL; + excess = (struct atm_flow_data *) atm_tc_get(sch, + *(u32 *) RTA_DATA(tb[TCA_ATM_EXCESS-1])); + if (!excess) return -ENOENT; + } + DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n", + opt->rta_type,RTA_PAYLOAD(opt),hdr_len); + if (!(sock = sockfd_lookup(fd,&error))) return error; /* f_count++ */ + DPRINTK("atm_tc_change: f_count %d\n",file_count(sock->file)); + if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) { + error = -EPROTOTYPE; + goto err_out; + } + /* @@@ should check if the socket is really operational or we'll crash + on vcc->dev->ops->send */ + if (classid) { + if (TC_H_MAJ(classid ^ sch->handle)) { + DPRINTK("atm_tc_change: classid mismatch\n"); + error = -EINVAL; + goto err_out; + } + if (find_flow(p,flow)) { + error = -EEXIST; + goto err_out; + } + } + else { + int i; + unsigned long cl; + + for (i = 1; i < 0x8000; i++) { + classid = TC_H_MAKE(sch->handle,0x8000 | i); + if (!(cl = atm_tc_get(sch,classid))) break; + atm_tc_put(sch,cl); + } + } + DPRINTK("atm_tc_change: new id %x\n",classid); + flow = kmalloc(sizeof(struct atm_flow_data)+hdr_len,GFP_KERNEL); + DPRINTK("atm_tc_change: flow %p\n",flow); + if (!flow) { + error = -ENOBUFS; + goto err_out; + } + memset(flow,0,sizeof(*flow)); + flow->filter_list = NULL; + if (!(flow->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops))) + flow->q = &noop_qdisc; + DPRINTK("atm_tc_change: qdisc %p\n",flow->q); + flow->sock = sock; + flow->vcc = ATM_SD(sock); /* speedup */ + DPRINTK("atm_tc_change: vcc %p\n",flow->vcc); + flow->classid = classid; + flow->ref = 1; + flow->excess = excess; + flow->next = p->link.next; + p->link.next = flow; + flow->hdr_len = hdr_len; + if (hdr) memcpy(flow->hdr,hdr,hdr_len); + else { + memcpy(flow->hdr,llc_oui,sizeof(llc_oui)); + ((u16 *) flow->hdr)[3] = htons(ETH_P_IP); + } + *arg = (unsigned long) flow; + return 0; +err_out: + if (excess) atm_tc_put(sch,(unsigned long) excess); + sockfd_put(sock); + return error; +} + + +static int atm_tc_delete(struct Qdisc *sch,unsigned long arg) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) arg; + + DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n",sch,p,flow); + if (!find_flow(PRIV(sch),flow)) return -EINVAL; + if (flow->filter_list || flow == &p->link) return -EBUSY; + /* + * Reference count must be 2: one for "keepalive" (set at class + * creation), and one for the reference held when calling delete. + */ + if (flow->ref < 2) { + printk(KERN_ERR "atm_tc_delete: flow->ref == %d\n",flow->ref); + return -EINVAL; + } + if (flow->ref > 2) return -EBUSY; /* catch references via excess, etc.*/ + atm_tc_put(sch,arg); + return 0; +} + + +static void atm_tc_walk(struct Qdisc *sch,struct qdisc_walker *walker) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + + DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker); + if (walker->stop) return; + for (flow = p->flows; flow; flow = flow->next) { + if (walker->count >= walker->skip) + if (walker->fn(sch,(unsigned long) flow,walker) < 0) { + walker->stop = 1; + break; + } + walker->count++; + } +} + + +static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch,unsigned long cl) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) cl; + + DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n",sch,p,flow); + return flow ? &flow->filter_list : &p->link.filter_list; +} + + +/* --------------------------- Qdisc operations ---------------------------- */ + + +static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = NULL ; /* @@@ */ + struct tcf_result res; + int result; + int ret = NET_XMIT_POLICED; + + D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); + result = TC_POLICE_OK; /* be nice to gcc */ + if (TC_H_MAJ(skb->priority) != sch->handle || + !(flow = (struct atm_flow_data *) atm_tc_get(sch,skb->priority))) + for (flow = p->link.next; flow; flow = flow->next) + if (flow->filter_list) { + result = tc_classify(skb,flow->filter_list, + &res); + if (result < 0) continue; + flow = (struct atm_flow_data *) res.class; + if (!flow) flow = lookup_flow(sch,res.classid); + break; + } + if (!flow) flow = &p->link; + else { + if (flow->vcc) + ATM_SKB(skb)->atm_options = flow->vcc->atm_options; + /*@@@ looks good ... but it's not supposed to work :-)*/ +#ifdef CONFIG_NET_CLS_POLICE + switch (result) { + case TC_POLICE_SHOT: + kfree_skb(skb); + break; + case TC_POLICE_RECLASSIFY: + if (flow->excess) flow = flow->excess; + else { + ATM_SKB(skb)->atm_options |= + ATM_ATMOPT_CLP; + break; + } + /* fall through */ + case TC_POLICE_OK: + /* fall through */ + default: + break; + } +#endif + } + if ( +#ifdef CONFIG_NET_CLS_POLICE + result == TC_POLICE_SHOT || +#endif + (ret = flow->q->enqueue(skb,flow->q)) != 0) { + sch->stats.drops++; + if (flow) flow->stats.drops++; + return ret; + } + sch->stats.bytes += skb->len; + sch->stats.packets++; + flow->stats.bytes += skb->len; + flow->stats.packets++; + sch->q.qlen++; + return 0; +} + + +static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + struct sk_buff *skb; + + D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p); + for (flow = p->link.next; flow; flow = flow->next) + /* + * If traffic is properly shaped, this won't generate nasty + * little bursts. Otherwise, it may ... @@@ + */ + while ((skb = flow->q->dequeue(flow->q))) { + sch->q.qlen--; + D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow); + /* remove any LL header somebody else has attached */ + skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data); + if (skb_headroom(skb) < flow->hdr_len) { + struct sk_buff *new; + + new = skb_realloc_headroom(skb,flow->hdr_len); + dev_kfree_skb(skb); + if (!new) continue; + skb = new; + } + D2PRINTK("atm_tc_dequeue: ip %p, data %p\n", + skb->nh.iph,skb->data); + ATM_SKB(skb)->vcc = flow->vcc; + memcpy(skb_push(skb,flow->hdr_len),flow->hdr, + flow->hdr_len); + atomic_add(skb->truesize,&flow->vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + /* atm.atm_options are already set by atm_tc_enqueue */ + (void) flow->vcc->dev->ops->send(flow->vcc,skb); + } + skb = p->link.q->dequeue(p->link.q); + if (skb) sch->q.qlen--; + return skb; +} + + +static int atm_tc_drop(struct Qdisc *sch) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + + DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n",sch,p); + for (flow = p->flows; flow; flow = flow->next) + if (flow->q->ops->drop && flow->q->ops->drop(flow->q)) + return 1; + return 0; +} + + +static int atm_tc_init(struct Qdisc *sch,struct rtattr *opt) +{ + struct atm_qdisc_data *p = PRIV(sch); + + DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); + memset(p,0,sizeof(*p)); + p->flows = &p->link; + if(!(p->link.q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops))) + p->link.q = &noop_qdisc; + DPRINTK("atm_tc_init: link (%p) qdisc %p\n",&p->link,p->link.q); + p->link.filter_list = NULL; + p->link.vcc = NULL; + p->link.sock = NULL; + p->link.classid = sch->handle; + p->link.ref = 1; + p->link.next = NULL; + MOD_INC_USE_COUNT; + return 0; +} + + +static void atm_tc_reset(struct Qdisc *sch) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + + DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n",sch,p); + for (flow = p->flows; flow; flow = flow->next) qdisc_reset(flow->q); + sch->q.qlen = 0; +} + + +static void atm_tc_destroy(struct Qdisc *sch) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow; + + DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p); + /* races ? */ + while ((flow = p->flows)) { + if (flow->ref > 1) + printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow, + flow->ref); + atm_tc_put(sch,(unsigned long) flow); + if (p->flows == flow) { + printk(KERN_ERR "atm_destroy: putting flow %p didn't " + "kill it\n",flow); + p->flows = flow->next; /* brute force */ + break; + } + } + MOD_DEC_USE_COUNT; +} + + +#ifdef CONFIG_RTNETLINK + +static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct atm_qdisc_data *p = PRIV(sch); + struct atm_flow_data *flow = (struct atm_flow_data *) cl; + unsigned char *b = skb->tail; + struct rtattr *rta; + + DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", + sch,p,flow,skb,tcm); + if (!find_flow(p,flow)) return -EINVAL; + tcm->tcm_handle = flow->classid; + rta = (struct rtattr *) b; + RTA_PUT(skb,TCA_OPTIONS,0,NULL); + RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr); + if (flow->vcc) { + struct sockaddr_atmpvc pvc; + int state; + + pvc.sap_family = AF_ATMPVC; + pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1; + pvc.sap_addr.vpi = flow->vcc->vpi; + pvc.sap_addr.vci = flow->vcc->vci; + RTA_PUT(skb,TCA_ATM_ADDR,sizeof(pvc),&pvc); + state = ATM_VF2VS(flow->vcc->flags); + RTA_PUT(skb,TCA_ATM_STATE,sizeof(state),&state); + } + if (flow->excess) + RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(u32),&flow->classid); + else { + static u32 zero = 0; + + RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(zero),&zero); + } + rta->rta_len = skb->tail-b; + return skb->len; + +rtattr_failure: + skb_trim(skb,b-skb->data); + return -1; +} + +static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + return 0; +} + +#endif + + +static struct Qdisc_class_ops atm_class_ops = +{ + atm_tc_graft, /* graft */ + atm_tc_leaf, /* leaf */ + atm_tc_get, /* get */ + atm_tc_put, /* put */ + atm_tc_change, /* change */ + atm_tc_delete, /* delete */ + atm_tc_walk, /* walk */ + + atm_tc_find_tcf, /* tcf_chain */ + atm_tc_bind_filter, /* bind_tcf */ + atm_tc_put, /* unbind_tcf */ + +#ifdef CONFIG_RTNETLINK + atm_tc_dump_class, /* dump */ +#endif +}; + +struct Qdisc_ops atm_qdisc_ops = +{ + NULL, /* next */ + &atm_class_ops, /* cl_ops */ + "atm", + sizeof(struct atm_qdisc_data), + + atm_tc_enqueue, /* enqueue */ + atm_tc_dequeue, /* dequeue */ + atm_tc_enqueue, /* requeue; we're cheating a little */ + atm_tc_drop, /* drop */ + + atm_tc_init, /* init */ + atm_tc_reset, /* reset */ + atm_tc_destroy, /* destroy */ + NULL, /* change */ + +#ifdef CONFIG_RTNETLINK + atm_tc_dump /* dump */ +#endif +}; + + +#ifdef MODULE +int init_module(void) +{ + return register_qdisc(&atm_qdisc_ops); +} + + +void cleanup_module(void) +{ + unregister_qdisc(&atm_qdisc_ops); +} +#endif diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c --- v2.3.14/linux/net/sched/sch_cbq.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/sch_cbq.c Mon Aug 23 10:01:02 1999 @@ -176,6 +176,7 @@ struct cbq_class *tx_borrowed; int tx_len; psched_time_t now; /* Cached timestamp */ + psched_time_t now_rt; /* Cached real time */ unsigned pmask; struct timer_list delay_timer; @@ -191,8 +192,6 @@ #define L2T(cl,len) ((cl)->R_tab->data[(len)>>(cl)->R_tab->rate.cell_log]) -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - static __inline__ unsigned cbq_hash(u32 h) { @@ -375,9 +374,11 @@ if (toplevel > cl->level && !(cl->q->flags&TCQ_F_THROTTLED)) { psched_time_t now; + psched_tdiff_t incr; + PSCHED_GET_TIME(now); - if (PSCHED_TLESS(now, q->now)) - now = q->now; + incr = PSCHED_TDIFF(now, q->now_rt); + PSCHED_TADD2(q->now, incr, now); do { if (PSCHED_TLESS(cl->undertime, now)) { @@ -394,6 +395,7 @@ struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl = cbq_classify(skb, sch); int len = skb->len; + int ret = NET_XMIT_POLICED; #ifdef CONFIG_NET_CLS_POLICE q->rx_class = cl; @@ -402,14 +404,14 @@ #ifdef CONFIG_NET_CLS_POLICE cl->q->__parent = sch; #endif - if (cl->q->enqueue(skb, cl->q) == 1) { + if ((ret = cl->q->enqueue(skb, cl->q)) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; cbq_mark_toplevel(q, cl); if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } } @@ -420,7 +422,7 @@ cbq_mark_toplevel(q, cl); cl->stats.drops++; } - return 0; + return ret; } static int @@ -428,11 +430,12 @@ { struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl; + int ret; if ((cl = q->tx_class) == NULL) { kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_CN; } q->tx_class = NULL; @@ -442,15 +445,15 @@ q->rx_class = cl; cl->q->__parent = sch; #endif - if (cl->q->ops->requeue(skb, cl->q) == 1) { + if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) { sch->q.qlen++; if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } sch->stats.drops++; cl->stats.drops++; - return 0; + return ret; } /* Overlimit actions */ @@ -685,7 +688,7 @@ q->rx_class = cl; cl->q->__parent = sch; - if (cl->q->enqueue(skb, cl->q) == 1) { + if (cl->q->enqueue(skb, cl->q) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; @@ -756,14 +759,19 @@ idle = (now - last) - last_pktlen/rate */ - idle = PSCHED_TDIFF(q->now, cl->last) - L2T(cl, len); + idle = PSCHED_TDIFF(q->now, cl->last); + if ((unsigned long)idle > 128*1024*1024) { + avgidle = cl->maxidle; + } else { + idle -= L2T(cl, len); /* true_avgidle := (1-W)*true_avgidle + W*idle, where W=2^{-ewma_log}. But cl->avgidle is scaled: cl->avgidle == true_avgidle/W, hence: */ - avgidle += idle - (avgidle>>cl->ewma_log); + avgidle += idle - (avgidle>>cl->ewma_log); + } if (avgidle <= 0) { /* Overlimit or at-limit */ @@ -980,10 +988,13 @@ struct sk_buff *skb; struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; psched_time_t now; + psched_tdiff_t incr; PSCHED_GET_TIME(now); + incr = PSCHED_TDIFF(now, q->now_rt); if (q->tx_class) { + psched_tdiff_t incr2; /* Time integrator. We calculate EOS time by adding expected packet transmittion time. If real time is greater, we warp artificial clock, @@ -991,12 +1002,14 @@ cbq_time = max(real_time, work); */ - PSCHED_TADD(q->now, L2T(&q->link, q->tx_len)); - if (PSCHED_TLESS(q->now, now)) - q->now = now; + incr2 = L2T(&q->link, q->tx_len); + PSCHED_TADD(q->now, incr2); cbq_update(q); - } else if (PSCHED_TLESS(q->now, now)) - q->now = now; + if ((incr -= incr2) < 0) + incr = 0; + } + PSCHED_TADD(q->now, incr); + q->now_rt = now; for (;;) { q->wd_expires = 0; @@ -1224,7 +1237,7 @@ struct cbq_class *cl, *cl_head; int prio; - for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio++) { + for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio--) { if ((cl_head = q->active[prio]) == NULL) continue; @@ -1252,6 +1265,8 @@ del_timer(&q->wd_timer); del_timer(&q->delay_timer); q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++) q->active[prio] = NULL; @@ -1426,6 +1441,8 @@ q->delay_timer.data = (unsigned long)sch; q->delay_timer.function = cbq_undelay; q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; cbq_link_class(&q->link); @@ -1561,7 +1578,7 @@ int cbq_copy_xstats(struct sk_buff *skb, struct tc_cbq_xstats *st) { - RTA_PUT(skb, TCA_STATS, sizeof(*st), st); + RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st); return 0; rtattr_failure: @@ -1838,7 +1855,7 @@ if (cl->q->q.qlen) cbq_activate_class(cl); - sch_tree_lock(sch); + sch_tree_unlock(sch); #ifdef CONFIG_NET_ESTIMATOR if (tca[TCA_RATE-1]) { diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c --- v2.3.14/linux/net/sched/sch_csz.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/sch_csz.c Mon Aug 23 10:01:02 1999 @@ -477,7 +477,7 @@ if (this->q.qlen >= this->limit || this->L_tab == NULL) { sch->stats.drops++; kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } R = csz_update(sch); @@ -505,7 +505,7 @@ sch->q.qlen++; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } static __inline__ struct sk_buff * diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_fifo.c linux/net/sched/sch_fifo.c --- v2.3.14/linux/net/sched/sch_fifo.c Sun Mar 21 07:22:00 1999 +++ linux/net/sched/sch_fifo.c Mon Aug 23 10:01:02 1999 @@ -51,14 +51,14 @@ sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sch->stats.drops++; #ifdef CONFIG_NET_CLS_POLICE if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int @@ -66,7 +66,7 @@ { __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static struct sk_buff * @@ -110,21 +110,21 @@ __skb_queue_tail(&sch->q, skb); sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sch->stats.drops++; #ifdef CONFIG_NET_CLS_POLICE if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch) { __skb_queue_head(&sch->q, skb); - return 1; + return 0; } diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c --- v2.3.14/linux/net/sched/sch_generic.c Wed Aug 18 11:38:49 1999 +++ linux/net/sched/sch_generic.c Mon Aug 23 10:01:02 1999 @@ -30,8 +30,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - /* Main transmission queue. */ struct Qdisc_head qdisc_head = { &qdisc_head, &qdisc_head }; @@ -90,16 +88,18 @@ struct Qdisc *q = dev->qdisc; struct sk_buff *skb; + /* Dequeue packet */ if ((skb = q->dequeue(q)) != NULL) { - /* Dequeue packet and release queue */ - spin_unlock(&dev->queue_lock); - - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); - if (spin_trylock(&dev->xmit_lock)) { /* Remember that the driver is grabbed by us. */ dev->xmit_lock_owner = smp_processor_id(); + + /* And release queue */ + spin_unlock(&dev->queue_lock); + + if (netdev_nit) + dev_queue_xmit_nit(skb, dev); + if (dev->hard_start_xmit(skb, dev) == 0) { dev->xmit_lock_owner = -1; spin_unlock(&dev->xmit_lock); @@ -111,6 +111,8 @@ /* Release the driver */ dev->xmit_lock_owner = -1; spin_unlock(&dev->xmit_lock); + spin_lock(&dev->queue_lock); + q = dev->qdisc; } else { /* So, someone grabbed the driver. */ @@ -123,7 +125,6 @@ kfree_skb(skb); if (net_ratelimit()) printk(KERN_DEBUG "Dead loop on virtual %s, fix it urgently!\n", dev->name); - spin_lock(&dev->queue_lock); return -1; } @@ -143,12 +144,10 @@ 3. device is buggy (ppp) */ - spin_lock(&dev->queue_lock); - q = dev->qdisc; q->ops->requeue(skb, q); return -1; } - return dev->qdisc->q.qlen; + return q->q.qlen; } static __inline__ void @@ -212,19 +211,19 @@ qdisc_stop_run(q); dev = q->dev; - spin_unlock(&qdisc_runqueue_lock); res = -1; if (spin_trylock(&dev->queue_lock)) { + spin_unlock(&qdisc_runqueue_lock); while (!dev->tbusy && (res = qdisc_restart(dev)) < 0) /* NOTHING */; + spin_lock(&qdisc_runqueue_lock); spin_unlock(&dev->queue_lock); } - spin_lock(&qdisc_runqueue_lock); /* If qdisc is not empty add it to the tail of list */ if (res) - qdisc_continue_run(q); + qdisc_continue_run(dev->qdisc); } out: spin_unlock(&qdisc_runqueue_lock); @@ -259,17 +258,16 @@ qdisc_stop_run(q); dev = q->dev; - spin_unlock(&qdisc_runqueue_lock); if (spin_trylock(&dev->queue_lock)) { + spin_unlock(&qdisc_runqueue_lock); q = dev->qdisc; if (dev->tbusy && jiffies - q->tx_last > q->tx_timeo) qdisc_restart(dev); + spin_lock(&qdisc_runqueue_lock); spin_unlock(&dev->queue_lock); } - spin_lock(&qdisc_runqueue_lock); - qdisc_continue_run(dev->qdisc); } @@ -289,7 +287,7 @@ noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc) { kfree_skb(skb); - return 0; + return NET_XMIT_CN; } static struct sk_buff * @@ -304,7 +302,7 @@ if (net_ratelimit()) printk(KERN_DEBUG "%s deferred output. It is buggy.\n", skb->dev->name); kfree_skb(skb); - return 0; + return NET_XMIT_CN; } struct Qdisc_ops noop_qdisc_ops = @@ -370,11 +368,11 @@ if (list->qlen <= skb->dev->tx_queue_len) { __skb_queue_tail(list, skb); qdisc->q.qlen++; - return 1; + return 0; } qdisc->stats.drops++; kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static struct sk_buff * @@ -404,7 +402,7 @@ __skb_queue_head(list, skb); qdisc->q.qlen++; - return 1; + return 0; } static void @@ -557,16 +555,18 @@ struct Qdisc *qdisc; spin_lock_bh(&dev->queue_lock); + spin_lock(&qdisc_runqueue_lock); qdisc = dev->qdisc; dev->qdisc = &noop_qdisc; qdisc_reset(qdisc); - spin_lock(&qdisc_runqueue_lock); if (qdisc_on_runqueue(qdisc)) qdisc_stop_run(qdisc); spin_unlock(&qdisc_runqueue_lock); spin_unlock_bh(&dev->queue_lock); + + spin_unlock_wait(&dev->xmit_lock); } void dev_init_scheduler(struct net_device *dev) diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c --- v2.3.14/linux/net/sched/sch_prio.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/sch_prio.c Mon Aug 23 10:01:02 1999 @@ -69,17 +69,18 @@ { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; + int ret; qdisc = q->queues[prio_classify(skb, sch)]; - if (qdisc->enqueue(skb, qdisc) == 1) { + if ((ret = qdisc->enqueue(skb, qdisc)) == 0) { sch->stats.bytes += skb->len; sch->stats.packets++; sch->q.qlen++; - return 1; + return 0; } sch->stats.drops++; - return 0; + return ret; } @@ -88,15 +89,16 @@ { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; + int ret; qdisc = q->queues[prio_classify(skb, sch)]; - if (qdisc->ops->requeue(skb, qdisc) == 1) { + if ((ret = qdisc->ops->requeue(skb, qdisc)) == 0) { sch->q.qlen++; - return 1; + return 0; } sch->stats.drops++; - return 0; + return ret; } diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_red.c linux/net/sched/sch_red.c --- v2.3.14/linux/net/sched/sch_red.c Sun Mar 21 07:22:00 1999 +++ linux/net/sched/sch_red.c Mon Aug 23 10:01:02 1999 @@ -10,6 +10,7 @@ * * Changes: * J Hadi Salim 980914: computation fixes + * Alexey Makarenko 990814: qave on idle link was calculated incorrectly. */ #include @@ -159,6 +160,8 @@ if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) { long us_idle; + int shift; + PSCHED_GET_TIME(now); us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0); PSCHED_SET_PASTPERFECT(q->qidlestart); @@ -179,7 +182,25 @@ I believe that a simpler model may be used here, but it is field for experiments. */ - q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF]; + shift = q->Stab[us_idle>>q->Scell_log]; + + if (shift) { + q->qave >>= shift; + } else { + /* Approximate initial part of exponent + with linear function: + (1-W)^m ~= 1-mW + ... + + Seems, it is the best solution to + problem of too coarce exponent tabulation. + */ + + us_idle = (q->qave * us_idle)>>q->Scell_log; + if (us_idle < q->qave/2) + q->qave -= us_idle; + else + q->qave >>= 1; + } } else { q->qave += sch->stats.backlog - (q->qave >> q->Wlog); /* NOTE: @@ -200,17 +221,19 @@ sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } -drop: kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_DROP; } if (q->qave >= q->qth_max) { q->qcount = -1; sch->stats.overlimits++; - goto drop; +mark: + kfree_skb(skb); + sch->stats.drops++; + return NET_XMIT_CN; } if (++q->qcount) { /* The formula used below causes questions. @@ -231,11 +254,10 @@ */ if (((q->qave - q->qth_min)>>q->Wlog)*q->qcount < q->qR) goto enqueue; -printk(KERN_DEBUG "Drop %d\n", q->qcount); q->qcount = 0; q->qR = net_random()&q->Rmask; sch->stats.overlimits++; - goto drop; + goto mark; } q->qR = net_random()&q->Rmask; goto enqueue; @@ -250,7 +272,7 @@ __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static struct sk_buff * @@ -298,7 +320,7 @@ q->qcount = -1; } -static int red_init(struct Qdisc *sch, struct rtattr *opt) +static int red_change(struct Qdisc *sch, struct rtattr *opt) { struct red_sched_data *q = (struct red_sched_data *)sch->data; struct rtattr *tb[TCA_RED_STAB]; @@ -313,6 +335,7 @@ ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); + sch_tree_lock(sch); q->Wlog = ctl->Wlog; q->Plog = ctl->Plog; q->Rmask = ctl->Plog < 32 ? ((1<Plog) - 1) : ~0UL; @@ -324,11 +347,25 @@ memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256); q->qcount = -1; - PSCHED_SET_PASTPERFECT(q->qidlestart); - MOD_INC_USE_COUNT; + if (skb_queue_len(&sch->q) == 0) + PSCHED_SET_PASTPERFECT(q->qidlestart); + sch_tree_unlock(sch); return 0; } +static int red_init(struct Qdisc* sch, struct rtattr *opt) +{ + int err; + + MOD_INC_USE_COUNT; + + if ((err = red_change(sch, opt)) != 0) { + MOD_DEC_USE_COUNT; + } + return err; +} + + #ifdef CONFIG_RTNETLINK static int red_dump(struct Qdisc *sch, struct sk_buff *skb) { @@ -376,7 +413,7 @@ red_init, red_reset, red_destroy, - NULL /* red_change */, + red_change, #ifdef CONFIG_RTNETLINK red_dump, diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c --- v2.3.14/linux/net/sched/sch_sfq.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/sch_sfq.c Mon Aug 23 10:01:02 1999 @@ -278,11 +278,11 @@ if (++sch->q.qlen < SFQ_DEPTH-1) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sfq_drop(sch); - return 0; + return NET_XMIT_CN; } static int @@ -311,11 +311,11 @@ } } if (++sch->q.qlen < SFQ_DEPTH-1) - return 1; + return 0; sch->stats.drops++; sfq_drop(sch); - return 0; + return NET_XMIT_CN; } diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c --- v2.3.14/linux/net/sched/sch_tbf.c Wed Jun 9 14:45:37 1999 +++ linux/net/sched/sch_tbf.c Mon Aug 23 10:01:02 1999 @@ -139,7 +139,7 @@ if ((sch->stats.backlog += skb->len) <= q->limit) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } /* Drop action: undo the things that we just did, @@ -155,7 +155,7 @@ if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int @@ -163,7 +163,7 @@ { __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static int diff -u --recursive --new-file v2.3.14/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c --- v2.3.14/linux/net/sched/sch_teql.c Wed Aug 18 11:38:49 1999 +++ linux/net/sched/sch_teql.c Mon Aug 23 10:01:02 1999 @@ -97,13 +97,13 @@ if (q->q.qlen <= dev->tx_queue_len) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } __skb_unlink(skb, &q->q); kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_DROP; } static int @@ -112,7 +112,7 @@ struct teql_sched_data *q = (struct teql_sched_data *)sch->data; __skb_queue_head(&q->q, skb); - return 1; + return 0; } static struct sk_buff * diff -u --recursive --new-file v2.3.14/linux/net/socket.c linux/net/socket.c --- v2.3.14/linux/net/socket.c Thu Jul 1 10:48:17 1999 +++ linux/net/socket.c Mon Aug 23 11:15:53 1999 @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include @@ -78,10 +77,10 @@ #include #include #include -#include #include #include #include +#include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static long long sock_lseek(struct file *file, long long offset, int whence); @@ -89,6 +88,7 @@ size_t size, loff_t *ppos); static ssize_t sock_write(struct file *file, const char *buf, size_t size, loff_t *ppos); +static int sock_mmap(struct file *file, struct vm_area_struct * vma); static int sock_close(struct inode *inode, struct file *file); static unsigned int sock_poll(struct file *file, @@ -110,7 +110,7 @@ NULL, /* readdir */ sock_poll, sock_ioctl, - NULL, /* mmap */ + sock_mmap, sock_no_open, /* special open code to disallow open via /proc */ NULL, /* flush */ sock_close, @@ -122,18 +122,59 @@ * The protocol list. Each protocol is registered in here. */ -struct net_proto_family *net_families[NPROTO]; +static struct net_proto_family *net_families[NPROTO]; -/* - * Statistics counters of the socket lists +#ifdef __SMP__ +static atomic_t net_family_lockct = ATOMIC_INIT(0); +static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED; + +/* The strategy is: modifications net_family vector are short, do not + sleep and veeery rare, but read access should be free of any exclusive + locks. */ -static int sockets_in_use = 0; +static void net_family_write_lock(void) +{ + spin_lock(&net_family_lock); + while (atomic_read(&net_family_lockct) != 0) { + spin_unlock(&net_family_lock); + + current->policy |= SCHED_YIELD; + schedule(); + + spin_lock(&net_family_lock); + } +} + +static __inline__ void net_family_write_unlock(void) +{ + spin_unlock(&net_family_lock); +} + +static __inline__ void net_family_read_lock(void) +{ + atomic_inc(&net_family_lockct); + spin_unlock_wait(&net_family_lock); +} + +static __inline__ void net_family_read_unlock(void) +{ + atomic_dec(&net_family_lockct); +} + +#else +#define net_family_write_lock() do { } while(0) +#define net_family_write_unlock() do { } while(0) +#define net_family_read_lock() do { } while(0) +#define net_family_read_unlock() do { } while(0) +#endif + /* - * Socket hashing lock. + * Statistics counters of the socket lists */ -rwlock_t sockhash_lock = RW_LOCK_UNLOCKED; + +static int sockets_in_use = 0; /* * Support routines. Move socket addresses back and forth across the kernel/user @@ -184,10 +225,23 @@ } /* - * Obtains the first available file descriptor and sets it up for use. + * Obtains the first available file descriptor and sets it up for use. + * + * This functions creates file structure and maps it to fd space + * of current process. On success it returns file descriptor + * and file struct implicitly stored in sock->file. + * Note that another thread may close file descriptor before we return + * from this function. We use the fact that now we do not refer + * to socket after mapping. If one day we will need it, this + * function will inincrement ref. count on file by 1. + * + * In any case returned fd MAY BE not valid! + * This race condition is inavoidable + * with shared fd spaces, we cannot solve is inside kernel, + * but we take care of internal coherence yet. */ -static int get_fd(struct inode *inode) +static int sock_map_fd(struct socket *sock) { int fd; @@ -201,28 +255,36 @@ if (!file) { put_unused_fd(fd); - return -ENFILE; + fd = -ENFILE; + goto out; } - file->f_dentry = d_alloc_root(inode); + lock_kernel(); + file->f_dentry = d_alloc_root(sock->inode); if (!file->f_dentry) { + unlock_kernel(); put_filp(file); put_unused_fd(fd); - return -ENOMEM; + fd = -ENOMEM; + goto out; } /* * The socket maintains a reference to the inode, so we * have to increment the count. */ - inode->i_count++; + sock->inode->i_count++; + unlock_kernel(); - fd_install(fd, file); file->f_op = &socket_file_ops; file->f_mode = 3; file->f_flags = O_RDWR; file->f_pos = 0; + fd_install(fd, file); + sock->file = file; } + +out: return fd; } @@ -276,9 +338,18 @@ struct inode * inode; struct socket * sock; + lock_kernel(); + /* Damn! get_empty_inode is not SMP safe. + I ask, why does it have decorative spinlock + at the very beginning? Probably, dcache ops should + be lock_kernel'ed inside inode.c + */ inode = get_empty_inode(); - if (!inode) + if (!inode) { + unlock_kernel(); return NULL; + } + unlock_kernel(); sock = socki_lookup(inode); @@ -313,11 +384,8 @@ void sock_release(struct socket *sock) { - if (sock->state != SS_UNCONNECTED) - sock->state = SS_DISCONNECTING; - if (sock->ops) - sock->ops->release(sock, NULL); + sock->ops->release(sock); if (sock->fasync_list) printk(KERN_ERR "sock_release: fasync list not empty!\n"); @@ -374,6 +442,7 @@ struct socket *sock; struct iovec iov; struct msghdr msg; + int flags; if (ppos != &file->f_pos) return -ESPIPE; @@ -390,9 +459,9 @@ msg.msg_controllen=0; iov.iov_base=ubuf; iov.iov_len=size; + flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; - return sock_recvmsg(sock, &msg, size, - !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT); + return sock_recvmsg(sock, &msg, size, flags); } @@ -422,6 +491,8 @@ msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_flags=!(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; + if (sock->type == SOCK_SEQPACKET) + msg.msg_flags |= MSG_EOR; iov.iov_base=(void *)ubuf; iov.iov_len=size; @@ -447,6 +518,10 @@ /* read() does a VERIFY_WRITE */ if (type == VERIFY_WRITE) return sock_recvmsg(sock, &msg, size, msg.msg_flags); + + if (sock->type == SOCK_SEQPACKET) + msg.msg_flags |= MSG_EOR; + return sock_sendmsg(sock, &msg, size); } @@ -459,24 +534,41 @@ int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct socket *sock = socki_lookup(inode); - return sock->ops->ioctl(sock, cmd, arg); + struct socket *sock; + int err; + + unlock_kernel(); + sock = socki_lookup(inode); + err = sock->ops->ioctl(sock, cmd, arg); + lock_kernel(); + + return err; } static unsigned int sock_poll(struct file *file, poll_table * wait) { struct socket *sock; + int err; + unlock_kernel(); sock = socki_lookup(file->f_dentry->d_inode); /* * We can't return errors to poll, so it's either yes or no. */ - return sock->ops->poll(file, sock, wait); + err = sock->ops->poll(file, sock, wait); + lock_kernel(); + return err; } +static int sock_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct socket *sock = socki_lookup(file->f_dentry->d_inode); + + return sock->ops->mmap(file, sock, vma); +} int sock_close(struct inode *inode, struct file *filp) { @@ -490,20 +582,34 @@ printk(KERN_DEBUG "sock_close: NULL inode\n"); return 0; } + unlock_kernel(); sock_fasync(-1, filp, 0); sock_release(socki_lookup(inode)); + lock_kernel(); return 0; } /* * Update the socket async list + * + * Fasync_list locking strategy. + * + * 1. fasync_list is modified only under process context socket lock + * i.e. under semaphore. + * 2. fasync_list is used under read_lock(&sk->callback_lock) + * or under socket lock. + * 3. fasync_list is used from any context including IRQ, so that + * modification under socket lock have to be enhanced with + * write_lock_irq(&sk->callback_lock). + * --ANK (990710) */ static int sock_fasync(int fd, struct file *filp, int on) { struct fasync_struct *fa, *fna=NULL, **prev; struct socket *sock; - + struct sock *sk; + if (on) { fna=(struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); @@ -511,44 +617,57 @@ return -ENOMEM; } + sock = socki_lookup(filp->f_dentry->d_inode); + if ((sk=sock->sk) == NULL) + return -EINVAL; + + lock_sock(sk); + prev=&(sock->fasync_list); - lock_sock(sock->sk); - for (fa=*prev; fa!=NULL; prev=&fa->fa_next,fa=*prev) if (fa->fa_file==filp) break; - + if(on) { if(fa!=NULL) { + write_lock_irq(&sk->callback_lock); fa->fa_fd=fd; + write_unlock_irq(&sk->callback_lock); + kfree_s(fna,sizeof(struct fasync_struct)); - release_sock(sock->sk); - return 0; + goto out; } fna->fa_file=filp; fna->fa_fd=fd; fna->magic=FASYNC_MAGIC; fna->fa_next=sock->fasync_list; + write_lock_irq(&sk->callback_lock); sock->fasync_list=fna; + write_unlock_irq(&sk->callback_lock); } else { if (fa!=NULL) { + write_lock_irq(&sk->callback_lock); *prev=fa->fa_next; + write_unlock_irq(&sk->callback_lock); kfree_s(fa,sizeof(struct fasync_struct)); } } - release_sock(sock->sk); +out: + release_sock(sock->sk); return 0; } +/* This function may be called only under socket lock or callback_lock */ + int sock_wake_async(struct socket *sock, int how) { if (!sock || !sock->fasync_list) @@ -566,8 +685,10 @@ /* fall through */ case 0: call_kill: + /* read_lock(&sock->sk->callback_lock); */ if(sock->fasync_list != NULL) kill_fasync(sock->fasync_list, SIGIO); + /* read_unlock(&sock->sk->callback_lock); */ break; } return 0; @@ -582,8 +703,22 @@ /* * Check protocol is in range */ - if(family<0||family>=NPROTO) + if(family<0 || family>=NPROTO) return -EINVAL; + + /* Compatibility. + + This uglymoron is moved from INET layer to here to avoid + deadlock in module load. + */ + if (family == PF_INET && type == SOCK_PACKET) { + static int warned; + if (!warned) { + warned = 1; + printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); + } + family = PF_PACKET; + } #if defined(CONFIG_KMOD) && defined(CONFIG_NET) /* Attempt to load a protocol module if the find failed. @@ -600,22 +735,11 @@ } #endif - if (net_families[family]==NULL) - return -EINVAL; - -/* - * Check that this is a type that we know how to manipulate and - * the protocol makes sense here. The family can still reject the - * protocol later. - */ - - if ((type != SOCK_STREAM && type != SOCK_DGRAM && - type != SOCK_SEQPACKET && type != SOCK_RAW && type != SOCK_RDM && -#ifdef CONFIG_XTP - type != SOCK_WEB && -#endif - type != SOCK_PACKET) || protocol < 0) - return -EINVAL; + net_family_read_lock(); + if (net_families[family] == NULL) { + i = -EINVAL; + goto out; + } /* * Allocate the socket and allow the family to set things up. if @@ -626,109 +750,110 @@ if (!(sock = sock_alloc())) { printk(KERN_WARNING "socket: no more sockets\n"); - return -ENFILE; /* Not exactly a match, but its the + i = -ENFILE; /* Not exactly a match, but its the closest posix thing */ + goto out; } - sock->type = type; + sock->type = type; if ((i = net_families[family]->create(sock, protocol)) < 0) { sock_release(sock); - return i; + goto out; } *res = sock; - return 0; + +out: + net_family_read_unlock(); + return i; } -asmlinkage int sys_socket(int family, int type, int protocol) +asmlinkage long sys_socket(int family, int type, int protocol) { int retval; struct socket *sock; - lock_kernel(); - retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out; - retval = get_fd(sock->inode); + retval = sock_map_fd(sock); if (retval < 0) goto out_release; - sock->file = fcheck(retval); out: - unlock_kernel(); + /* It may be already another descriptor 8) Not kernel problem. */ return retval; out_release: sock_release(sock); - goto out; + return retval; } /* * Create a pair of connected sockets. */ -asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]) +asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2]) { struct socket *sock1, *sock2; int fd1, fd2, err; - lock_kernel(); - /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. */ - err = sys_socket(family, type, protocol); + err = sock_create(family, type, protocol, &sock1); if (err < 0) goto out; - fd1 = err; - /* - * Now grab another socket - */ - err = -EINVAL; - fd2 = sys_socket(family, type, protocol); - if (fd2 < 0) - goto out_close1; - - /* - * Get the sockets for the two fd's - */ - sock1 = sockfd_lookup(fd1, &err); - if (!sock1) - goto out_close2; - sock2 = sockfd_lookup(fd2, &err); - if (!sock2) - goto out_put1; + err = sock_create(family, type, protocol, &sock2); + if (err < 0) + goto out_release_1; - /* try to connect the two sockets together */ err = sock1->ops->socketpair(sock1, sock2); if (err < 0) - goto out_put2; + goto out_release_both; + + fd1 = fd2 = -1; + + err = sock_map_fd(sock1); + if (err < 0) + goto out_release_both; + fd1 = err; + + err = sock_map_fd(sock2); + if (err < 0) + goto out_close_1; + fd2 = err; + + /* fd1 and fd2 may be already another descriptors. + * Not kernel problem. + */ err = put_user(fd1, &usockvec[0]); - if (err) - goto out_put2; - err = put_user(fd2, &usockvec[1]); - -out_put2: - sockfd_put(sock2); -out_put1: - sockfd_put(sock1); - - if (err) { - out_close2: - sys_close(fd2); - out_close1: - sys_close(fd1); - } + if (!err) + err = put_user(fd2, &usockvec[1]); + if (!err) + return 0; + + sys_close(fd2); + sys_close(fd1); + return err; + +out_close_1: + sock_release(sock2); + sys_close(fd1); + return err; + +out_release_both: + sock_release(sock2); +out_release_1: + sock_release(sock1); out: - unlock_kernel(); return err; } @@ -741,20 +866,18 @@ * the protocol layer (having also checked the address is ok). */ -asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) +asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) { struct socket *sock; char address[MAX_SOCK_ADDR]; int err; - lock_kernel(); if((sock = sockfd_lookup(fd,&err))!=NULL) { if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -765,18 +888,15 @@ * ready for listening. */ -asmlinkage int sys_listen(int fd, int backlog) +asmlinkage long sys_listen(int fd, int backlog) { struct socket *sock; int err; - lock_kernel(); - if((sock = sockfd_lookup(fd, &err))!=NULL) - { + if ((sock = sockfd_lookup(fd, &err)) != NULL) { err=sock->ops->listen(sock, backlog); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -793,56 +913,43 @@ * clean when we restucture accept also. */ -asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) +asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) { - struct inode *inode; struct socket *sock, *newsock; int err, len; char address[MAX_SOCK_ADDR]; - lock_kernel(); sock = sockfd_lookup(fd, &err); if (!sock) goto out; -restart: err = -EMFILE; if (!(newsock = sock_alloc())) goto out_put; - inode = newsock->inode; newsock->type = sock->type; + newsock->ops = sock->ops; - err = sock->ops->dup(newsock, sock); - if (err < 0) - goto out_release; - - err = newsock->ops->accept(sock, newsock, sock->file->f_flags); + err = sock->ops->accept(sock, newsock, sock->file->f_flags); if (err < 0) goto out_release; - newsock = socki_lookup(inode); - - if ((err = get_fd(inode)) < 0) - goto out_release; - newsock->file = fcheck(err); - if (upeer_sockaddr) - { - /* Handle the race where the accept works and we - then getname after it has closed again */ - if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1)<0) - { - sys_close(err); - goto restart; + if (upeer_sockaddr) { + if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1)<0) { + err = -ECONNABORTED; + goto out_release; } - /* N.B. Should check for errors here */ - move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); + err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); + if (err < 0) + goto out_release; } + if ((err = sock_map_fd(newsock)) < 0) + goto out_release; + out_put: sockfd_put(sock); out: - unlock_kernel(); return err; out_release: @@ -863,13 +970,12 @@ * include the -EINPROGRESS status for such sockets. */ -asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) +asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) { struct socket *sock; char address[MAX_SOCK_ADDR]; int err; - lock_kernel(); sock = sockfd_lookup(fd, &err); if (!sock) goto out; @@ -881,7 +987,6 @@ out_put: sockfd_put(sock); out: - unlock_kernel(); return err; } @@ -890,13 +995,12 @@ * name to user space. */ -asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; int len, err; - lock_kernel(); sock = sockfd_lookup(fd, &err); if (!sock) goto out; @@ -908,7 +1012,6 @@ out_put: sockfd_put(sock); out: - unlock_kernel(); return err; } @@ -917,13 +1020,12 @@ * name to user space. */ -asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; int len, err; - lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); @@ -931,7 +1033,6 @@ err=move_addr_to_user(address,len, usockaddr, usockaddr_len); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -941,8 +1042,8 @@ * the protocol. */ -asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, - struct sockaddr *addr, int addr_len) +asmlinkage long sys_sendto(int fd, void * buff, size_t len, unsigned flags, + struct sockaddr *addr, int addr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -983,7 +1084,7 @@ * Send a datagram down a socket. */ -asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags) +asmlinkage long sys_send(int fd, void * buff, size_t len, unsigned flags) { return sys_sendto(fd, buff, len, flags, NULL, 0); } @@ -994,8 +1095,8 @@ * sender address from kernel to user space. */ -asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, - struct sockaddr *addr, int *addr_len) +asmlinkage long sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, + struct sockaddr *addr, int *addr_len) { struct socket *sock; struct iovec iov; @@ -1034,7 +1135,7 @@ * Receive a datagram from a socket. */ -asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags) +asmlinkage long sys_recv(int fd, void * ubuf, size_t size, unsigned flags) { return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); } @@ -1044,12 +1145,11 @@ * to pass the user mode parameter for the protocols to sort out. */ -asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen) +asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int optlen) { int err; struct socket *sock; - lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (level == SOL_SOCKET) @@ -1058,7 +1158,6 @@ err=sock->ops->setsockopt(sock, level, optname, optval, optlen); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -1067,12 +1166,11 @@ * to pass a user mode parameter for the protocols to sort out. */ -asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen) +asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen) { int err; struct socket *sock; - lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (level == SOL_SOCKET) @@ -1081,7 +1179,6 @@ err=sock->ops->getsockopt(sock, level, optname, optval, optlen); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -1090,18 +1187,16 @@ * Shutdown a socket. */ -asmlinkage int sys_shutdown(int fd, int how) +asmlinkage long sys_shutdown(int fd, int how) { int err; struct socket *sock; - lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { err=sock->ops->shutdown(sock, how); sockfd_put(sock); } - unlock_kernel(); return err; } @@ -1109,7 +1204,7 @@ * BSD sendmsg interface */ -asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) +asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1149,7 +1244,6 @@ err = -ENOBUFS; - /* msg_controllen must fit to int */ if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; ctl_len = msg_sys.msg_controllen; @@ -1157,12 +1251,6 @@ { if (ctl_len > sizeof(ctl)) { - /* Suggested by the Advanced Sockets API for IPv6 draft: - * Limit the msg_controllen size by the SO_SNDBUF size. - */ - /* Note - when this code becomes multithreaded on - * SMP machines you have a race to fix here. - */ err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); if (ctl_buf == NULL) @@ -1195,7 +1283,7 @@ * BSD recvmsg interface */ -asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) +asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) { struct socket *sock; struct iovec iovstack[UIO_FASTIOV]; @@ -1310,7 +1398,7 @@ * it is set by the callees. */ -asmlinkage int sys_socketcall(int call, unsigned long *args) +asmlinkage long sys_socketcall(int call, unsigned long *args) { unsigned long a[6]; unsigned long a0,a1; @@ -1396,12 +1484,20 @@ int sock_register(struct net_proto_family *ops) { + int err; + if (ops->family >= NPROTO) { printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, NPROTO); return -ENOBUFS; } - net_families[ops->family]=ops; - return 0; + net_family_write_lock(); + err = -EEXIST; + if (net_families[ops->family] == NULL) { + net_families[ops->family]=ops; + err = 0; + } + net_family_write_unlock(); + return err; } /* @@ -1415,7 +1511,9 @@ if (family < 0 || family >= NPROTO) return -1; + net_family_write_lock(); net_families[family]=NULL; + net_family_write_unlock(); return 0; } @@ -1476,14 +1574,6 @@ #endif /* - * Attach the firewall module if configured - */ - -#ifdef CONFIG_FIREWALL - fwchain_init(); -#endif - - /* * Initialize the protocols module. */ @@ -1498,6 +1588,9 @@ #endif #ifdef CONFIG_NETLINK_DEV init_netlink(); +#endif +#ifdef CONFIG_NETFILTER + netfilter_init(); #endif } diff -u --recursive --new-file v2.3.14/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.3.14/linux/net/sunrpc/svcsock.c Tue May 11 14:37:40 1999 +++ linux/net/sunrpc/svcsock.c Mon Aug 23 10:01:02 1999 @@ -523,13 +523,8 @@ dprintk("svc: tcp_accept %p allocated\n", newsock); newsock->type = sock->type; - if ((err = sock->ops->dup(newsock, sock)) < 0) { - printk(KERN_WARNING "%s: socket dup failed (err %d)!\n", - serv->sv_name, -err); - goto failed; - } + newsock->ops = ops = sock->ops; - ops = newsock->ops; if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { printk(KERN_WARNING "%s: accept failed (err %d)!\n", serv->sv_name, -err); diff -u --recursive --new-file v2.3.14/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.3.14/linux/net/unix/af_unix.c Mon Jul 5 20:35:18 1999 +++ linux/net/unix/af_unix.c Wed Aug 25 14:46:05 1999 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.79 1999/06/29 12:36:07 davem Exp $ + * Version: $Id: af_unix.c,v 1.81 1999/08/20 11:06:56 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -43,6 +43,9 @@ * number of socks to 2*max_files and * the number of skb queueable in the * dgram receiver. + * Artur Skawina : Hash function optimizations + * Alexey Kuznetsov : Full scale SMP. Lot of bugs are introduced 8) + * * * Known differences from reference BSD that was tested: * @@ -108,28 +111,28 @@ #define min(a,b) (((a)<(b))?(a):(b)) -int sysctl_unix_delete_delay = HZ; -int sysctl_unix_destroy_delay = 10*HZ; int sysctl_unix_max_dgram_qlen = 10; unix_socket *unix_socket_table[UNIX_HASH_SIZE+1]; +rwlock_t unix_table_lock = RW_LOCK_UNLOCKED; static atomic_t unix_nr_socks = ATOMIC_INIT(0); -static DECLARE_WAIT_QUEUE_HEAD(unix_ack_wqueue); -static DECLARE_WAIT_QUEUE_HEAD(unix_dgram_wqueue); #define unix_sockets_unbound (unix_socket_table[UNIX_HASH_SIZE]) #define UNIX_ABSTRACT(sk) ((sk)->protinfo.af_unix.addr->hash!=UNIX_HASH_SIZE) -static void unix_destroy_socket(unix_socket *sk); -static void unix_stream_write_space(struct sock *sk); +/* + SMP locking strategy. + * hash table is protceted with rwlock unix_table_lock + * each socket state is protected by separate rwlock. + + */ extern __inline__ unsigned unix_hash_fold(unsigned hash) { hash ^= hash>>16; hash ^= hash>>8; - hash ^= hash>>4; - return hash; + return hash&(UNIX_HASH_SIZE-1); } #define unix_peer(sk) ((sk)->pair) @@ -144,37 +147,22 @@ return (unix_peer(osk) == NULL || unix_our_peer(sk, osk)); } -#define ulock(sk) (&(sk->protinfo.af_unix.user_count)) - -extern __inline__ void unix_lock(unix_socket *sk) +static __inline__ unix_socket * unix_peer_get(unix_socket *s) { - atomic_inc(ulock(sk)); -} - -extern __inline__ void unix_unlock(unix_socket *sk) -{ - atomic_dec(ulock(sk)); -} + unix_socket *peer; -extern __inline__ int unix_locked(unix_socket *sk) -{ - return (atomic_read(ulock(sk)) != 0); + unix_state_rlock(s); + peer = unix_peer(s); + if (peer) + sock_hold(peer); + unix_state_runlock(s); + return peer; } extern __inline__ void unix_release_addr(struct unix_address *addr) { - if (addr) - { - if (atomic_dec_and_test(&addr->refcnt)) - kfree(addr); - } -} - -static void unix_destruct_addr(struct sock *sk) -{ - struct unix_address *addr = sk->protinfo.af_unix.addr; - - unix_release_addr(addr); + if (atomic_dec_and_test(&addr->refcnt)) + kfree(addr); } /* @@ -211,127 +199,192 @@ return len; } -static void unix_remove_socket(unix_socket *sk) +static void __unix_remove_socket(unix_socket *sk) { unix_socket **list = sk->protinfo.af_unix.list; - if (sk->next) - sk->next->prev = sk->prev; - if (sk->prev) - sk->prev->next = sk->next; - if (*list == sk) - *list = sk->next; - sk->protinfo.af_unix.list = NULL; - sk->prev = NULL; - sk->next = NULL; + if (list) { + if (sk->next) + sk->next->prev = sk->prev; + if (sk->prev) + sk->prev->next = sk->next; + if (*list == sk) + *list = sk->next; + sk->protinfo.af_unix.list = NULL; + sk->prev = NULL; + sk->next = NULL; + __sock_put(sk); + } } -static void unix_insert_socket(unix_socket *sk) +static void __unix_insert_socket(unix_socket **list, unix_socket *sk) { - unix_socket **list = sk->protinfo.af_unix.list; + BUG_TRAP(sk->protinfo.af_unix.list==NULL); + + sk->protinfo.af_unix.list = list; sk->prev = NULL; sk->next = *list; if (*list) (*list)->prev = sk; *list=sk; + sock_hold(sk); } -static unix_socket *unix_find_socket_byname(struct sockaddr_un *sunname, - int len, int type, unsigned hash) +static __inline__ void unix_remove_socket(unix_socket *sk) +{ + write_lock(&unix_table_lock); + __unix_remove_socket(sk); + write_unlock(&unix_table_lock); +} + +static __inline__ void unix_insert_socket(unix_socket **list, unix_socket *sk) +{ + write_lock(&unix_table_lock); + __unix_insert_socket(list, sk); + write_unlock(&unix_table_lock); +} + +static unix_socket *__unix_find_socket_byname(struct sockaddr_un *sunname, + int len, int type, unsigned hash) { unix_socket *s; - for (s=unix_socket_table[(hash^type)&0xF]; s; s=s->next) - { + for (s=unix_socket_table[hash^type]; s; s=s->next) { if(s->protinfo.af_unix.addr->len==len && - memcmp(s->protinfo.af_unix.addr->name, sunname, len) == 0 && - s->type == type) - { - unix_lock(s); - return(s); - } + memcmp(s->protinfo.af_unix.addr->name, sunname, len) == 0) + return s; } - return(NULL); + return NULL; +} + +static __inline__ unix_socket * +unix_find_socket_byname(struct sockaddr_un *sunname, + int len, int type, unsigned hash) +{ + unix_socket *s; + + read_lock(&unix_table_lock); + s = __unix_find_socket_byname(sunname, len, type, hash); + if (s) + sock_hold(s); + read_unlock(&unix_table_lock); + return s; } static unix_socket *unix_find_socket_byinode(struct inode *i) { unix_socket *s; - for (s=unix_socket_table[i->i_ino & 0xF]; s; s=s->next) + read_lock(&unix_table_lock); + for (s=unix_socket_table[i->i_ino & (UNIX_HASH_SIZE-1)]; s; s=s->next) { struct dentry *dentry = s->protinfo.af_unix.dentry; if(dentry && dentry->d_inode == i) { - unix_lock(s); - return(s); + sock_hold(s); + break; } } - return(NULL); + read_unlock(&unix_table_lock); + return s; } -/* - * Delete a unix socket. We have to allow for deferring this on a timer. - */ - -static void unix_destroy_timer(unsigned long data) +static __inline__ int unix_writable(struct sock *sk) { - unix_socket *sk=(unix_socket *)data; - if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0) - { - atomic_dec(&unix_nr_socks); + return ((atomic_read(&sk->wmem_alloc)<<2) <= sk->sndbuf); +} - sk_free(sk); - - /* socket destroyed, decrement count */ - MOD_DEC_USE_COUNT; - return; +static void unix_write_space(struct sock *sk) +{ + read_lock(&sk->callback_lock); + if (!sk->dead && unix_writable(sk)) { + wake_up_interruptible(sk->sleep); + sock_wake_async(sk->socket, 2); } - - /* - * Retry; - */ - - sk->timer.expires=jiffies+sysctl_unix_destroy_delay; /* No real hurry try it every 10 seconds or so */ - add_timer(&sk->timer); + read_unlock(&sk->callback_lock); } - - -static void unix_delayed_delete(unix_socket *sk) + +static void unix_sock_destructor(struct sock *sk) { - sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+sysctl_unix_delete_delay; /* Normally 1 second after will clean up. After that we try every 10 */ - sk->timer.function=unix_destroy_timer; - add_timer(&sk->timer); + skb_queue_purge(&sk->receive_queue); + + BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0); + BUG_TRAP(sk->protinfo.af_unix.list==NULL); + BUG_TRAP(sk->socket==NULL); + if (sk->dead==0) { + printk("Attempt to release alive unix socket: %p\n", sk); + return; + } + + if (sk->protinfo.af_unix.addr) + unix_release_addr(sk->protinfo.af_unix.addr); + + atomic_dec(&unix_nr_socks); +#ifdef UNIX_REFCNT_DEBUG + printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk, atomic_read(&unix_nr_socks)); +#endif + MOD_DEC_USE_COUNT; } -static int unix_release_sock (unix_socket *sk) +static int unix_release_sock (unix_socket *sk, int embrion) { + struct dentry *dentry; unix_socket *skpair; + struct sk_buff *skb; + int state; + + unix_remove_socket(sk); - sk->state_change(sk); - sk->dead=1; + /* Clear state */ + unix_state_wlock(sk); + write_lock(&sk->callback_lock); + sk->dead = 1; sk->socket = NULL; + write_unlock(&sk->callback_lock); + sk->shutdown = SHUTDOWN_MASK; + dentry = sk->protinfo.af_unix.dentry; + sk->protinfo.af_unix.dentry=NULL; + state = sk->state; + sk->state = TCP_CLOSE; + unix_state_wunlock(sk); - if (sk->state == TCP_LISTEN) - wake_up_interruptible(&unix_ack_wqueue); - if (sk->type == SOCK_DGRAM) - wake_up_interruptible(&unix_dgram_wqueue); + wake_up_interruptible(sk->sleep); + wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); skpair=unix_peer(sk); - if (skpair!=NULL) - { - if (sk->type==SOCK_STREAM && unix_our_peer(sk, skpair)) - { - skpair->data_ready(skpair,0); + if (skpair!=NULL) { + if (sk->type==SOCK_STREAM) { + unix_state_wlock(skpair); skpair->shutdown=SHUTDOWN_MASK; /* No more writes*/ + if (!skb_queue_empty(&sk->receive_queue) || embrion) + skpair->err = ECONNRESET; + unix_state_wunlock(skpair); + sk->data_ready(skpair,0); } - unix_unlock(skpair); /* It may now die */ + sock_put(skpair); /* It may now die */ + unix_peer(sk) = NULL; } /* Try to flush out this socket. Throw out buffers at least */ - unix_destroy_socket(sk); + + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) + { + if (state==TCP_LISTEN) + unix_release_sock(skb->sk, 1); + /* passed fds are erased in the kfree_skb hook */ + kfree_skb(skb); + } + + if (dentry) { + lock_kernel(); + dput(dentry); + unlock_kernel(); + } + + sock_put(sk); + + /* ---- Socket is dead now and most probably destroyed ---- */ /* * Fixme: BSD difference: In BSD all sockets connected to use get @@ -344,60 +397,30 @@ * What the above comment does talk about? --ANK(980817) */ - unix_gc(); /* Garbage collect fds */ - return 0; -} - -static void unix_destroy_socket(unix_socket *sk) -{ - struct sk_buff *skb; - - unix_remove_socket(sk); - - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) - { - if(sk->state==TCP_LISTEN) - unix_release_sock(skb->sk); - /* passed fds are erased in the kfree_skb hook */ - kfree_skb(skb); - } - - if(sk->protinfo.af_unix.dentry!=NULL) - { - dput(sk->protinfo.af_unix.dentry); - sk->protinfo.af_unix.dentry=NULL; - } - - if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0) - { - atomic_dec(&unix_nr_socks); - - sk_free(sk); - - /* socket destroyed, decrement count */ - MOD_DEC_USE_COUNT; - } - else - { - sk->state=TCP_CLOSE; - sk->dead=1; - unix_delayed_delete(sk); /* Try every so often until buffers are all freed */ - } + if (atomic_read(&unix_tot_inflight)) + unix_gc(); /* Garbage collect fds */ + return 0; } static int unix_listen(struct socket *sock, int backlog) { + int err; struct sock *sk = sock->sk; - if (sock->state != SS_UNCONNECTED) - return(-EINVAL); + err = -EOPNOTSUPP; if (sock->type!=SOCK_STREAM) - return -EOPNOTSUPP; /* Only stream sockets accept */ + goto out; /* Only stream sockets accept */ + err = -EINVAL; if (!sk->protinfo.af_unix.addr) - return -EINVAL; /* No listens on an unbound socket */ + goto out; /* No listens on an unbound socket */ if ((unsigned) backlog > SOMAXCONN) backlog = SOMAXCONN; + unix_state_wlock(sk); + if (sk->state != TCP_CLOSE && sk->state != TCP_LISTEN) + goto out_unlock; + if (backlog > sk->max_ack_backlog) + wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); sk->max_ack_backlog=backlog; sk->state=TCP_LISTEN; sock->flags |= SO_ACCEPTCON; @@ -405,13 +428,18 @@ sk->peercred.pid = current->pid; sk->peercred.uid = current->euid; sk->peercred.gid = current->egid; - return 0; + err = 0; + +out_unlock: + unix_state_wunlock(sk); +out: + return err; } extern struct proto_ops unix_stream_ops; extern struct proto_ops unix_dgram_ops; -static struct sock * unix_create1(struct socket *sock, int stream) +static struct sock * unix_create1(struct socket *sock) { struct sock *sk; @@ -429,23 +457,23 @@ sock_init_data(sock,sk); - if (stream) - sk->write_space = unix_stream_write_space; + sk->write_space = unix_write_space; - sk->destruct = unix_destruct_addr; - sk->protinfo.af_unix.family=PF_UNIX; + sk->max_ack_backlog = sysctl_unix_max_dgram_qlen; + sk->destruct = unix_sock_destructor; sk->protinfo.af_unix.dentry=NULL; + sk->protinfo.af_unix.lock = RW_LOCK_UNLOCKED; + atomic_set(&sk->protinfo.af_unix.inflight, 0); init_MUTEX(&sk->protinfo.af_unix.readsem);/* single task reading lock */ - sk->protinfo.af_unix.list=&unix_sockets_unbound; - unix_insert_socket(sk); + init_waitqueue_head(&sk->protinfo.af_unix.peer_wait); + sk->protinfo.af_unix.list=NULL; + unix_insert_socket(&unix_sockets_unbound, sk); return sk; } static int unix_create(struct socket *sock, int protocol) { - int stream = 0; - if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; @@ -454,7 +482,6 @@ switch (sock->type) { case SOCK_STREAM: sock->ops = &unix_stream_ops; - stream = 1; break; /* * Believe it or not BSD has AF_UNIX, SOCK_RAW though @@ -469,21 +496,19 @@ return -ESOCKTNOSUPPORT; } - return unix_create1(sock, stream) ? 0 : -ENOMEM; + return unix_create1(sock) ? 0 : -ENOMEM; } -static int unix_release(struct socket *sock, struct socket *peer) +static int unix_release(struct socket *sock) { unix_socket *sk = sock->sk; if (!sk) return 0; - + sock->sk = NULL; - if (sock->state != SS_UNCONNECTED) - sock->state = SS_DISCONNECTING; - return unix_release_sock (sk); + return unix_release_sock (sk, 0); } static int unix_autobind(struct socket *sock) @@ -491,37 +516,51 @@ struct sock *sk = sock->sk; static u32 ordernum = 1; struct unix_address * addr; - unix_socket *osk; + int err; + + down(&sk->protinfo.af_unix.readsem); + + err = 0; + if (sk->protinfo.af_unix.addr) + goto out; + err = -ENOMEM; addr = kmalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL); if (!addr) - return -ENOMEM; - if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.dentry) - { - kfree(addr); - return -EINVAL; - } + goto out; + memset(addr, 0, sizeof(*addr) + sizeof(short) + 16); addr->name->sun_family = AF_UNIX; atomic_set(&addr->refcnt, 1); retry: - addr->len = sprintf(addr->name->sun_path+1, "%08x", ordernum) + 1 + sizeof(short); + addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short); addr->hash = unix_hash_fold(csum_partial((void*)addr->name, addr->len, 0)); - ordernum++; - if ((osk=unix_find_socket_byname(addr->name, addr->len, sock->type, - addr->hash)) != NULL) - { - unix_unlock(osk); + write_lock(&unix_table_lock); + ordernum = (ordernum+1)&0xFFFFF; + + if (__unix_find_socket_byname(addr->name, addr->len, sock->type, + addr->hash)) { + write_unlock(&unix_table_lock); + /* Sanity yield. It is unusual case, but yet... */ + if (!(ordernum&0xFF)) { + current->policy |= SCHED_YIELD; + schedule(); + } goto retry; } + addr->hash ^= sk->type; + __unix_remove_socket(sk); sk->protinfo.af_unix.addr = addr; - unix_remove_socket(sk); - sk->protinfo.af_unix.list = &unix_socket_table[(addr->hash ^ sk->type)&0xF]; - unix_insert_socket(sk); - return 0; + __unix_insert_socket(&unix_socket_table[addr->hash], sk); + write_unlock(&unix_table_lock); + err = 0; + +out: + up(&sk->protinfo.af_unix.readsem); + return err; } static unix_socket *unix_find_other(struct sockaddr_un *sunname, int len, @@ -532,17 +571,23 @@ if (sunname->sun_path[0]) { struct dentry *dentry; + + /* Do not believe to VFS, grab kernel lock */ + lock_kernel(); dentry = open_namei(sunname->sun_path, 2, S_IFSOCK); if (IS_ERR(dentry)) { *error = PTR_ERR(dentry); + unlock_kernel(); return NULL; } u=unix_find_socket_byinode(dentry->d_inode); dput(dentry); + unlock_kernel(); + if (u && u->type != type) { *error=-EPROTOTYPE; - unix_unlock(u); + sock_put(u); return NULL; } } @@ -562,77 +607,85 @@ { struct sock *sk = sock->sk; struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; - struct dentry * dentry; + struct dentry * dentry = NULL; int err; unsigned hash; struct unix_address *addr; - - if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.dentry || - sunaddr->sun_family != AF_UNIX) - return -EINVAL; + unix_socket **list; - if (addr_len==sizeof(short)) - return unix_autobind(sock); + err = -EINVAL; + if (sunaddr->sun_family != AF_UNIX) + goto out; - addr_len = unix_mkname(sunaddr, addr_len, &hash); - if (addr_len < 0) - return addr_len; + if (addr_len==sizeof(short)) { + err = unix_autobind(sock); + goto out; + } - addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); - if (!addr) - return -ENOMEM; + err = unix_mkname(sunaddr, addr_len, &hash); + if (err < 0) + goto out; + addr_len = err; - /* We slept; recheck ... */ + down(&sk->protinfo.af_unix.readsem); - if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.dentry) - { - kfree(addr); - return -EINVAL; /* Already bound */ - } + err = -EINVAL; + if (sk->protinfo.af_unix.addr) + goto out_up; + + err = -ENOMEM; + addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); + if (!addr) + goto out_up; memcpy(addr->name, sunaddr, addr_len); addr->len = addr_len; - addr->hash = hash; + addr->hash = hash^sk->type; atomic_set(&addr->refcnt, 1); - if (!sunaddr->sun_path[0]) - { - unix_socket *osk = unix_find_socket_byname(sunaddr, addr_len, - sk->type, hash); - if (osk) - { - unix_unlock(osk); - kfree(addr); - return -EADDRINUSE; + if (sunaddr->sun_path[0]) { + lock_kernel(); + dentry = do_mknod(sunaddr->sun_path, S_IFSOCK|sock->inode->i_mode, 0); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + unlock_kernel(); + if (err==-EEXIST) + err=-EADDRINUSE; + unix_release_addr(addr); + goto out_up; } - unix_remove_socket(sk); - sk->protinfo.af_unix.addr = addr; - sk->protinfo.af_unix.list = &unix_socket_table[(hash^sk->type)&0xF]; - unix_insert_socket(sk); - return 0; + unlock_kernel(); + + addr->hash = UNIX_HASH_SIZE; } - addr->hash = UNIX_HASH_SIZE; - sk->protinfo.af_unix.addr = addr; - + write_lock(&unix_table_lock); - dentry = do_mknod(sunaddr->sun_path, S_IFSOCK|sock->inode->i_mode, 0); - if (IS_ERR(dentry)) - { - err = PTR_ERR(dentry); - unix_release_addr(addr); - sk->protinfo.af_unix.addr = NULL; - if (err==-EEXIST) - return -EADDRINUSE; - else - return err; + if (!sunaddr->sun_path[0]) { + err = -EADDRINUSE; + if (__unix_find_socket_byname(sunaddr, addr_len, + sk->type, hash)) { + unix_release_addr(addr); + goto out_unlock; + } + + list = &unix_socket_table[addr->hash]; + } else { + list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; + sk->protinfo.af_unix.dentry = dentry; } - unix_remove_socket(sk); - sk->protinfo.af_unix.list = &unix_socket_table[dentry->d_inode->i_ino & 0xF]; - sk->protinfo.af_unix.dentry = dentry; - unix_insert_socket(sk); - return 0; + err = 0; + __unix_remove_socket(sk); + sk->protinfo.af_unix.addr = addr; + __unix_insert_socket(list, sk); + +out_unlock: + write_unlock(&unix_table_lock); +out_up: + up(&sk->protinfo.af_unix.readsem); +out: + return err; } static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, @@ -644,141 +697,192 @@ unsigned hash; int err; - /* - * 1003.1g breaking connected state with AF_UNSPEC - */ + if (addr->sa_family != AF_UNSPEC) { + err = unix_mkname(sunaddr, alen, &hash); + if (err < 0) + goto out; + alen = err; - if(addr->sa_family==AF_UNSPEC) - { - if(unix_peer(sk)) - { - unix_unlock(unix_peer(sk)); - unix_peer(sk) = NULL; - sock->state=SS_UNCONNECTED; - } - return 0; - } - - alen = unix_mkname(sunaddr, alen, &hash); - if (alen < 0) - return alen; + if (sock->passcred && !sk->protinfo.af_unix.addr && + (err = unix_autobind(sock)) != 0) + goto out; - other=unix_find_other(sunaddr, alen, sock->type, hash, &err); - if (!other) - return err; - if (!unix_may_send(sk, other)) - { - unix_unlock(other); - return -EINVAL; + other=unix_find_other(sunaddr, alen, sock->type, hash, &err); + if (!other) + goto out; + + unix_state_wlock(sk); + + err = -EPERM; + if (!unix_may_send(sk, other)) + goto out_unlock; + } else { + /* + * 1003.1g breaking connected state with AF_UNSPEC + */ + other = NULL; + unix_state_wlock(sk); } /* * If it was connected, reconnect. */ - if (unix_peer(sk)) - { - unix_unlock(unix_peer(sk)); + if (unix_peer(sk)) { + sock_put(unix_peer(sk)); unix_peer(sk)=NULL; } unix_peer(sk)=other; - if (sock->passcred && !sk->protinfo.af_unix.addr) - unix_autobind(sock); + unix_state_wunlock(sk); return 0; + +out_unlock: + unix_state_wunlock(sk); + sock_put(other); +out: + return err; +} + +static void unix_wait_for_peer(unix_socket *other) +{ + int sched; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&other->protinfo.af_unix.peer_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + barrier(); + + sched = (!other->dead && + !(other->shutdown&RCV_SHUTDOWN) && + !signal_pending(current) && + skb_queue_len(&other->receive_queue) >= other->max_ack_backlog); + + unix_state_runlock(other); + + if (sched) + schedule(); + + current->state = TASK_RUNNING; + remove_wait_queue(&other->protinfo.af_unix.peer_wait, &wait); } static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; - struct sock *sk = sock->sk, *newsk; - unix_socket *other; - struct sk_buff *skb; - int err; + struct sock *sk = sock->sk; + struct sock *newsk = NULL; + unix_socket *other = NULL; + struct sk_buff *skb = NULL; unsigned hash; + int st; + int err; - addr_len = unix_mkname(sunaddr, addr_len, &hash); - if (addr_len < 0) - return addr_len; + err = unix_mkname(sunaddr, addr_len, &hash); + if (err < 0) + goto out; + addr_len = err; + + if (sock->passcred && !sk->protinfo.af_unix.addr && + (err = unix_autobind(sock)) != 0) + goto out; /* First of all allocate resources. - If we will make it after state checks, + If we will make it after state is locked, we will have to recheck all again in any case. */ + err = -ENOMEM; + + /* create new sock for complete connection */ + newsk = unix_create1(NULL); + if (newsk == NULL) + goto out; + + /* Allocate skb for sending to listening sock */ + skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); + if (skb == NULL) + goto out; + restart: - /* Find listening sock */ + /* Find listening sock. */ other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err); - if (!other) - return -ECONNREFUSED; + goto out; - while (other->ack_backlog >= other->max_ack_backlog) { - unix_unlock(other); - if (other->dead || other->state != TCP_LISTEN) - return -ECONNREFUSED; - if (flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&unix_ack_wqueue); - if (signal_pending(current)) - return -ERESTARTSYS; + /* Latch state of peer */ + unix_state_rlock(other); + + /* Apparently VFS overslept socket death. Retry. */ + if (other->dead) { + unix_state_runlock(other); + sock_put(other); goto restart; - } + } - /* create new sock for complete connection */ - newsk = unix_create1(NULL, 1); + err = -ECONNREFUSED; + if (other->state != TCP_LISTEN) + goto out_unlock; - /* Allocate skb for sending to listening sock */ - skb = NULL; - if (newsk) - skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); + if (skb_queue_len(&other->receive_queue) >= other->max_ack_backlog) { + err = -EAGAIN; + if (flags & O_NONBLOCK) + goto out_unlock; - switch (sock->state) - { - case SS_UNCONNECTED: - /* This is ok... continue with connect */ - break; - case SS_CONNECTED: - /* Socket is already connected */ - err = -EISCONN; - goto out; - default: - err = -EINVAL; + unix_wait_for_peer(other); + + err = -ERESTARTSYS; + if (signal_pending(current)) goto out; - } + sock_put(other); + goto restart; + } - err = -EINVAL; - if (sk->state != TCP_CLOSE) - goto out; + /* Latch our state. - /* Check that listener is in valid state. */ - err = -ECONNREFUSED; - if (other->dead || other->state != TCP_LISTEN) - goto out; + It is tricky place. We need to grab write lock and cannot + drop lock on peer. It is dangerous because deadlock is + possible. Connect to self case and simultaneous + attempt to connect are eliminated by checking socket + state. other is TCP_LISTEN, if sk is TCP_LISTEN we + check this before attempt to grab lock. - err = -ENOMEM; - if (newsk == NULL || skb == NULL) - goto out; + Well, and we have to recheck the state after socket locked. + */ + st = sk->state; - UNIXCB(skb).attr = MSG_SYN; + switch (st) { + case TCP_CLOSE: + /* This is ok... continue with connect */ + break; + case TCP_ESTABLISHED: + /* Socket is already connected */ + err = -EISCONN; + goto out_unlock; + default: + err = -EINVAL; + goto out_unlock; + } - /* set up connecting socket */ - sock->state=SS_CONNECTED; - if (!sk->protinfo.af_unix.addr) - unix_autobind(sock); - unix_peer(sk)=newsk; - unix_lock(sk); - sk->state=TCP_ESTABLISHED; - /* Set credentials */ - sk->peercred = other->peercred; + unix_state_wlock(sk); - /* set up newly created sock */ + if (sk->state != st) { + unix_state_wunlock(sk); + unix_state_runlock(other); + sock_put(other); + goto restart; + } + + /* The way is open! Fastly set all the necessary fields... */ + + sock_hold(sk); unix_peer(newsk)=sk; - unix_lock(newsk); newsk->state=TCP_ESTABLISHED; newsk->type=SOCK_STREAM; newsk->peercred.pid = current->pid; newsk->peercred.uid = current->euid; newsk->peercred.gid = current->egid; + newsk->sleep = &newsk->protinfo.af_unix.peer_wait; /* copy address information from listening to new sock*/ if (other->protinfo.af_unix.addr) @@ -786,23 +890,41 @@ atomic_inc(&other->protinfo.af_unix.addr->refcnt); newsk->protinfo.af_unix.addr=other->protinfo.af_unix.addr; } - if (other->protinfo.af_unix.dentry) + if (other->protinfo.af_unix.dentry) { + /* Damn, even dget is not SMP safe. It becomes ridiculous... */ + lock_kernel(); newsk->protinfo.af_unix.dentry=dget(other->protinfo.af_unix.dentry); + unlock_kernel(); + } + + /* Set credentials */ + sk->peercred = other->peercred; - /* send info to listening sock */ - other->ack_backlog++; + sock_hold(newsk); + unix_peer(sk)=newsk; + sock->state=SS_CONNECTED; + sk->state=TCP_ESTABLISHED; + + unix_state_wunlock(sk); + + /* take ten and and send info to listening sock */ skb_queue_tail(&other->receive_queue,skb); - other->data_ready(other,0); /* Wake up ! */ - unix_unlock(other); + unix_state_runlock(other); + other->data_ready(other, 0); + sock_put(other); return 0; +out_unlock: + if (other) + unix_state_runlock(other); + out: if (skb) kfree_skb(skb); if (newsk) - unix_destroy_socket(newsk); + unix_release_sock(newsk, 0); if (other) - unix_unlock(other); + sock_put(other); return err; } @@ -811,8 +933,8 @@ struct sock *ska=socka->sk, *skb = sockb->sk; /* Join our sockets back to back */ - unix_lock(ska); - unix_lock(skb); + sock_hold(ska); + sock_hold(skb); unix_peer(ska)=skb; unix_peer(skb)=ska; @@ -829,58 +951,42 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags) { unix_socket *sk = sock->sk; - unix_socket *newsk = newsock->sk; unix_socket *tsk; struct sk_buff *skb; - - if (sock->state != SS_UNCONNECTED) - return(-EINVAL); - if (!(sock->flags & SO_ACCEPTCON)) - return(-EINVAL); + int err; + err = -EOPNOTSUPP; if (sock->type!=SOCK_STREAM) - return -EOPNOTSUPP; + goto out; + + err = -EINVAL; if (sk->state!=TCP_LISTEN) - return -EINVAL; - - for (;;) - { - skb=skb_dequeue(&sk->receive_queue); - if(skb==NULL) - { - if(flags&O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(sk->sleep); - if(signal_pending(current)) - return -ERESTARTSYS; - continue; - } - if (!(UNIXCB(skb).attr & MSG_SYN)) - { - tsk=skb->sk; - tsk->state_change(tsk); - kfree_skb(skb); - continue; - } - tsk = skb->sk; - if (sk->max_ack_backlog == sk->ack_backlog--) - wake_up_interruptible(&unix_ack_wqueue); - kfree_skb(skb); - break; - } + goto out; + /* If socket state is TCP_LISTEN it cannot change, + so that no locks are necessary. + */ - /* attach accepted sock to socket */ - newsock->state=SS_CONNECTED; - newsock->sk=tsk; - tsk->sleep=newsk->sleep; - tsk->socket=newsock; - - /* destroy handed sock */ - newsk->socket = NULL; - unix_destroy_socket(newsk); + skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); + if (!skb) + goto out; + tsk = skb->sk; + if (skb_queue_len(&sk->receive_queue) <= sk->max_ack_backlog/2) + wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); + skb_free_datagram(sk, skb); + + /* attach accepted sock to socket */ + unix_state_wlock(tsk); + newsock->state = SS_CONNECTED; + newsock->sk = tsk; + tsk->sleep = &newsock->wait; + tsk->socket = newsock; + unix_state_wunlock(tsk); return 0; + +out: + return err; } @@ -888,23 +994,34 @@ { struct sock *sk = sock->sk; struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; - - if (peer) - { - if (!unix_peer(sk)) - return -ENOTCONN; - sk=unix_peer(sk); + int err = 0; + + if (peer) { + sk = unix_peer_get(sk); + + err = -ENOTCONN; + if (!sk) + goto out; + err = 0; + } else { + sock_hold(sk); } - if (!sk->protinfo.af_unix.addr) - { + + unix_state_rlock(sk); + if (!sk->protinfo.af_unix.addr) { sunaddr->sun_family = AF_UNIX; sunaddr->sun_path[0] = 0; *uaddr_len = sizeof(short); - return 0; /* Not bound */ + } else { + struct unix_address *addr = sk->protinfo.af_unix.addr; + + *uaddr_len = addr->len; + memcpy(sunaddr, addr->name, *uaddr_len); } - *uaddr_len = sk->protinfo.af_unix.addr->len; - memcpy(sunaddr, sk->protinfo.af_unix.addr->name, *uaddr_len); - return 0; + unix_state_runlock(sk); + sock_put(sk); +out: + return err; } static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) @@ -924,7 +1041,11 @@ struct scm_cookie scm; memset(&scm, 0, sizeof(scm)); unix_detach_fds(&scm, skb); + + /* Alas, it calls VFS */ + lock_kernel(); scm_destroy(&scm); + unlock_kernel(); sock_wfree(skb); } @@ -938,47 +1059,51 @@ scm->fp = NULL; } - /* * Send AF_UNIX data. */ -static int do_unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len, +static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sockaddr_un *sunaddr=msg->msg_name; - unix_socket *other; + unix_socket *other = NULL; int namelen = 0; /* fake GCC */ int err; unsigned hash; struct sk_buff *skb; + err = -EOPNOTSUPP; if (msg->msg_flags&MSG_OOB) - return -EOPNOTSUPP; + goto out; + err = -EINVAL; if (msg->msg_flags&~(MSG_DONTWAIT|MSG_NOSIGNAL)) - return -EINVAL; + goto out; if (msg->msg_namelen) { - namelen = unix_mkname(sunaddr, msg->msg_namelen, &hash); - if (namelen < 0) - return namelen; + err = unix_mkname(sunaddr, msg->msg_namelen, &hash); + if (err < 0) + goto out; + namelen = err; } else { sunaddr = NULL; - if (!unix_peer(sk)) - return -ENOTCONN; + err = -ENOTCONN; + other = unix_peer_get(sk); + if (!other) + goto out; } - if (sock->passcred && !sk->protinfo.af_unix.addr) - unix_autobind(sock); + if (sock->passcred && !sk->protinfo.af_unix.addr && + (err = unix_autobind(sock)) != 0) + goto out; skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err); if (skb==NULL) goto out; memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred)); - UNIXCB(skb).attr = msg->msg_flags; if (scm->fp) unix_attach_fds(scm, skb); @@ -987,117 +1112,120 @@ if (err) goto out_free; - other = unix_peer(sk); - if (other && other->dead) - { +restart: + if (!other) { + err = -ECONNRESET; + if (sunaddr == NULL) + goto out_free; + + other = unix_find_other(sunaddr, namelen, sk->type, hash, &err); + if (other==NULL) + goto out_free; + } + + unix_state_rlock(other); + err = -EPERM; + if (!unix_may_send(sk, other)) + goto out_unlock; + + if (other->dead) { /* * Check with 1003.1g - what should * datagram error */ - dead: - unix_unlock(other); - unix_peer(sk)=NULL; + unix_state_runlock(other); + sock_put(other); + + err = 0; + unix_state_wlock(sk); + if (unix_peer(sk) == other) { + sock_put(other); + unix_peer(sk)=NULL; + err = -ECONNREFUSED; + } + unix_state_wunlock(sk); + other = NULL; - err = -ECONNRESET; - if (sunaddr == NULL) + if (err) goto out_free; + goto restart; } - if (!other) - { - other = unix_find_other(sunaddr, namelen, sk->type, hash, &err); - if (other==NULL) - goto out_free; - err = -EINVAL; - if (!unix_may_send(sk, other)) - goto out_unlock; + + err = -EPIPE; + if (other->shutdown&RCV_SHUTDOWN) + goto out_unlock; + + if (0/*other->user_callback && + other->user_callback(other->user_data, skb) == 0*/) { + unix_state_runlock(other); + sock_put(other); + return len; } - while (skb_queue_len(&other->receive_queue) >= - sysctl_unix_max_dgram_qlen) - { - if (sock->file->f_flags & O_NONBLOCK) - { + if (skb_queue_len(&other->receive_queue) >= other->max_ack_backlog) { + if (msg->msg_flags & MSG_DONTWAIT) { err = -EAGAIN; goto out_unlock; } - interruptible_sleep_on(&unix_dgram_wqueue); - if (other->dead) - goto dead; - if (sk->shutdown & SEND_SHUTDOWN) - { - err = -EPIPE; - goto out_unlock; - } + + unix_wait_for_peer(other); + + err = -ERESTARTSYS; if (signal_pending(current)) - { - err = -ERESTARTSYS; - goto out_unlock; - } + goto out_free; + + goto restart; } skb_queue_tail(&other->receive_queue, skb); - other->data_ready(other,len); - - if (!unix_peer(sk)) - unix_unlock(other); - + unix_state_runlock(other); + other->data_ready(other, len); + sock_put(other); return len; out_unlock: - unix_unlock(other); + unix_state_runlock(other); out_free: kfree_skb(skb); out: + if (other) + sock_put(other); return err; } -static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len, - struct scm_cookie *scm) -{ - int retval; - - lock_kernel(); - retval = do_unix_dgram_sendmsg(sock, msg, len, scm); - unlock_kernel(); - return retval; -} -static int do_unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len, +static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; - unix_socket *other; + unix_socket *other = NULL; struct sockaddr_un *sunaddr=msg->msg_name; int err,size; struct sk_buff *skb; int limit=0; int sent=0; - if (sock->flags & SO_ACCEPTCON) - return(-EINVAL); - + err = -EOPNOTSUPP; if (msg->msg_flags&MSG_OOB) - return -EOPNOTSUPP; + goto out_err; + err = -EINVAL; if (msg->msg_flags&~(MSG_DONTWAIT|MSG_NOSIGNAL)) - return -EINVAL; + goto out_err; if (msg->msg_namelen) { - if (sk->state==TCP_ESTABLISHED) - return -EISCONN; - else - return -EOPNOTSUPP; + err = (sk->state==TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP); + goto out_err; } else { sunaddr = NULL; - if (!unix_peer(sk)) - return -ENOTCONN; + err = -ENOTCONN; + other = unix_peer_get(sk); + if (!other) + goto out_err; } - if (sk->shutdown&SEND_SHUTDOWN) { - if (!(msg->msg_flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE,current,0); - return -EPIPE; - } + if (sk->shutdown&SEND_SHUTDOWN) + goto pipe_err; while(sent < len) { @@ -1105,7 +1233,7 @@ * Optimisation for the fact that under 0.01% of X messages typically * need breaking up. */ - + size=len-sent; /* Keep two messages in the pipe so it schedules better */ @@ -1128,13 +1256,9 @@ */ skb=sock_alloc_send_skb(sk,size,limit,msg->msg_flags&MSG_DONTWAIT, &err); - + if (skb==NULL) - { - if (!sent) - sent = err; - goto out; - } + goto out_err; /* * If you pass two values to the sock_alloc_send_skb @@ -1146,64 +1270,52 @@ size = min(size, skb_tailroom(skb)); memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred)); - UNIXCB(skb).attr = msg->msg_flags; if (scm->fp) unix_attach_fds(scm, skb); - if (memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) { + if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { kfree_skb(skb); - if (!sent) - sent = -EFAULT; - goto out; + goto out_err; } - other=unix_peer(sk); + unix_state_rlock(other); - if (other->dead || (sk->shutdown & SEND_SHUTDOWN)) - { - kfree_skb(skb); - if(sent) - goto out; - if (!(msg->msg_flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE,current,0); - sent = -EPIPE; - goto out; - } + if (other->dead || (other->shutdown & RCV_SHUTDOWN)) + goto pipe_err_free; skb_queue_tail(&other->receive_queue, skb); - other->data_ready(other,size); + unix_state_runlock(other); + other->data_ready(other, size); sent+=size; } -out: + sock_put(other); return sent; -} - -static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len, - struct scm_cookie *scm) -{ - int retval; - - lock_kernel(); - retval = do_unix_stream_sendmsg(sock, msg, len, scm); - unlock_kernel(); - return retval; -} -/* - * Sleep until data has arrive. But check for races.. - */ - -static void unix_data_wait(unix_socket * sk) -{ - if (!skb_peek(&sk->receive_queue)) - { - sk->socket->flags |= SO_WAITDATA; - interruptible_sleep_on(sk->sleep); - sk->socket->flags &= ~SO_WAITDATA; +pipe_err_free: + kfree_skb(skb); + unix_state_runlock(other); +pipe_err: + if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL)) + send_sig(SIGPIPE,current,0); + err = -EPIPE; +out_err: + if (other) + sock_put(other); + return sent ? : err; +} + +static void unix_copy_addr(struct msghdr *msg, struct sock *sk) +{ + msg->msg_namelen = sizeof(short); + if (sk->protinfo.af_unix.addr) { + msg->msg_namelen=sk->protinfo.af_unix.addr->len; + memcpy(msg->msg_name, + sk->protinfo.af_unix.addr->name, + sk->protinfo.af_unix.addr->len); } } -static int do_unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size, +static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; @@ -1211,8 +1323,9 @@ struct sk_buff *skb; int err; + err = -EOPNOTSUPP; if (flags&MSG_OOB) - return -EOPNOTSUPP; + goto out; msg->msg_namelen = 0; @@ -1220,24 +1333,11 @@ if (!skb) goto out; - /* - * sysctl_unix_max_dgram_qlen may change over the time we blocked - * in the waitqueue so we must wakeup every time we shrink the - * receiver queue. -arca - */ - wake_up_interruptible(&unix_dgram_wqueue); + if (skb_queue_len(&sk->receive_queue) <= sk->max_ack_backlog/2) + wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); if (msg->msg_name) - { - msg->msg_namelen = sizeof(short); - if (skb->sk->protinfo.af_unix.addr) - { - msg->msg_namelen=skb->sk->protinfo.af_unix.addr->len; - memcpy(msg->msg_name, - skb->sk->protinfo.af_unix.addr->name, - skb->sk->protinfo.af_unix.addr->len); - } - } + unix_copy_addr(msg, skb->sk); if (size > skb->len) size = skb->len; @@ -1280,18 +1380,44 @@ return err; } -static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size, - int flags, struct scm_cookie *scm) +/* + * Sleep until data has arrive. But check for races.. + */ + +static void unix_stream_data_wait(unix_socket * sk) { - int retval; + DECLARE_WAITQUEUE(wait, current); - lock_kernel(); - retval = do_unix_dgram_recvmsg(sock, msg, size, flags, scm); - unlock_kernel(); - return retval; + unix_state_rlock(sk); + + add_wait_queue(sk->sleep, &wait); + + for (;;) { + current->state = TASK_INTERRUPTIBLE; + + barrier(); + + if (skb_queue_len(&sk->receive_queue) || + sk->err || + (sk->shutdown & RCV_SHUTDOWN) || + signal_pending(current)) + break; + + sk->socket->flags |= SO_WAITDATA; + unix_state_runlock(sk); + schedule(); + unix_state_rlock(sk); + sk->socket->flags &= ~SO_WAITDATA; + } + + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); + unix_state_runlock(sk); } -static int do_unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size, + + +static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; @@ -1300,15 +1426,20 @@ int copied = 0; int check_creds = 0; int target = 1; + int err = 0; - if (sock->flags & SO_ACCEPTCON) - return(-EINVAL); + err = -EINVAL; + if (sk->state != TCP_ESTABLISHED) + goto out; + err = -EOPNOTSUPP; if (flags&MSG_OOB) - return -EOPNOTSUPP; + goto out; + if (flags&MSG_WAITALL) target = size; + msg->msg_namelen = 0; /* Lock the socket to prevent queue disordering @@ -1332,43 +1463,41 @@ * POSIX 1003.1g mandates this order. */ - if (sk->err) - { - up(&sk->protinfo.af_unix.readsem); - return sock_error(sk); - } - + if ((err = sock_error(sk)) != 0) + break; if (sk->shutdown & RCV_SHUTDOWN) break; - up(&sk->protinfo.af_unix.readsem); + err = -EAGAIN; if (noblock) - return -EAGAIN; - unix_data_wait(sk); - if (signal_pending(current)) - return -ERESTARTSYS; + break; + up(&sk->protinfo.af_unix.readsem); + + unix_stream_data_wait(sk); + + if (signal_pending(current)) { + err = -ERESTARTSYS; + goto out; + } down(&sk->protinfo.af_unix.readsem); continue; } - /* Never glue messages from different writers */ - if (check_creds && - memcmp(UNIXCREDS(skb), &scm->creds, sizeof(scm->creds)) != 0) - { - skb_queue_head(&sk->receive_queue, skb); - break; + if (check_creds) { + /* Never glue messages from different writers */ + if (memcmp(UNIXCREDS(skb), &scm->creds, sizeof(scm->creds)) != 0) { + skb_queue_head(&sk->receive_queue, skb); + break; + } + } else { + /* Copy credentials */ + scm->creds = *UNIXCREDS(skb); + check_creds = 1; } /* Copy address just once */ if (sunaddr) { - msg->msg_namelen = sizeof(short); - if (skb->sk->protinfo.af_unix.addr) - { - msg->msg_namelen=skb->sk->protinfo.af_unix.addr->len; - memcpy(sunaddr, - skb->sk->protinfo.af_unix.addr->name, - skb->sk->protinfo.af_unix.addr->len); - } + unix_copy_addr(msg, skb->sk); sunaddr = NULL; } @@ -1382,10 +1511,6 @@ copied += chunk; size -= chunk; - /* Copy credentials */ - scm->creds = *UNIXCREDS(skb); - check_creds = 1; - /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { @@ -1409,7 +1534,6 @@ else { /* It is questionable, see note in unix_dgram_recvmsg. - */ if (UNIXCB(skb).fp) scm->fp = scm_fp_dup(UNIXCB(skb).fp); @@ -1421,44 +1545,43 @@ } while (size); up(&sk->protinfo.af_unix.readsem); - return copied; -} - -static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size, - int flags, struct scm_cookie *scm) -{ - int retval; - - lock_kernel(); - retval = do_unix_stream_recvmsg(sock, msg, size, flags, scm); - unlock_kernel(); - return retval; +out: + return copied ? : err; } static int unix_shutdown(struct socket *sock, int mode) { struct sock *sk = sock->sk; - unix_socket *other=unix_peer(sk); - + unix_socket *other; + mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN); if (mode) { + unix_state_wlock(sk); sk->shutdown |= mode; + other=unix_peer(sk); + if (other) + sock_hold(other); + unix_state_wunlock(sk); sk->state_change(sk); - if (other && sk->type == SOCK_STREAM && - unix_our_peer(sk, other)) { + + if (other && sk->type == SOCK_STREAM) { int peer_mode = 0; if (mode&RCV_SHUTDOWN) peer_mode |= SEND_SHUTDOWN; if (mode&SEND_SHUTDOWN) peer_mode |= RCV_SHUTDOWN; + unix_state_wlock(other); other->shutdown |= peer_mode; + unix_state_wunlock(other); if (peer_mode&RCV_SHUTDOWN) other->data_ready(other,0); else other->state_change(other); } + if (other) + sock_put(other); } return 0; } @@ -1468,7 +1591,8 @@ { struct sock *sk = sock->sk; long amount=0; - + int err; + switch(cmd) { @@ -1476,26 +1600,29 @@ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount<0) amount=0; - return put_user(amount, (int *)arg); + err = put_user(amount, (int *)arg); + break; case TIOCINQ: { struct sk_buff *skb; - if(sk->state==TCP_LISTEN) - return -EINVAL; - /* - * These two are safe on current systems as - * only user tasks fiddle here - */ + if (sk->state==TCP_LISTEN) { + err = -EINVAL; + break; + } + + spin_lock(&sk->receive_queue.lock); if((skb=skb_peek(&sk->receive_queue))!=NULL) amount=skb->len; - return put_user(amount, (int *)arg); + spin_unlock(&sk->receive_queue.lock); + err = put_user(amount, (int *)arg); + break; } default: - return -EINVAL; + err = -EINVAL; + break; } - /*NOTREACHED*/ - return(0); + return err; } static unsigned int unix_poll(struct file * file, struct socket *sock, poll_table *wait) @@ -1524,20 +1651,12 @@ * we set writable also when the other side has shut down the * connection. This prevents stuck sockets. */ - if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE) - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + if (unix_writable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; return mask; } -static void unix_stream_write_space(struct sock *sk) -{ - if (sk->dead) - return; - wake_up_interruptible(sk->sleep); - if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE) - sock_wake_async(sk->socket, 2); -} #ifdef CONFIG_PROC_FS static int unix_read_proc(char *buffer, char **start, off_t offset, @@ -1551,18 +1670,21 @@ len+= sprintf(buffer,"Num RefCount Protocol Flags Type St " "Inode Path\n"); - + + read_lock(&unix_table_lock); forall_unix_sockets (i,s) { - len+=sprintf(buffer+len,"%p: %08X %08X %08lX %04X %02X %5ld", + unix_state_rlock(s); + + len+=sprintf(buffer+len,"%p: %08X %08X %08X %04X %02X %5ld", s, - atomic_read(ulock(s)), + atomic_read(&s->refcnt), 0, - s->socket ? s->socket->flags : 0, + s->state == TCP_LISTEN ? SO_ACCEPTCON : 0, s->type, - s->socket ? s->socket->state : - (s->state == TCP_ESTABLISHED ? - SS_CONNECTING : SS_DISCONNECTING), + s->socket ? + (s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : + (s->state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), s->socket ? s->socket->inode->i_ino : 0); if (s->protinfo.af_unix.addr) @@ -1576,6 +1698,8 @@ buffer[len] = '@'; len += s->protinfo.af_unix.addr->len - sizeof(short); } + unix_state_runlock(s); + buffer[len++]='\n'; pos = begin + len; @@ -1589,6 +1713,7 @@ } *eof = 1; done: + read_unlock(&unix_table_lock); *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) @@ -1602,7 +1727,6 @@ struct proto_ops unix_stream_ops = { PF_UNIX, - sock_no_dup, unix_release, unix_bind, unix_stream_connect, @@ -1617,13 +1741,13 @@ sock_no_getsockopt, sock_no_fcntl, unix_stream_sendmsg, - unix_stream_recvmsg + unix_stream_recvmsg, + sock_no_mmap }; struct proto_ops unix_dgram_ops = { PF_UNIX, - sock_no_dup, unix_release, unix_bind, unix_dgram_connect, @@ -1638,7 +1762,8 @@ sock_no_getsockopt, sock_no_fcntl, unix_dgram_sendmsg, - unix_dgram_recvmsg + unix_dgram_recvmsg, + sock_no_mmap }; struct net_proto_family unix_family_ops = { @@ -1654,13 +1779,13 @@ int init_module(void) #else -__initfunc(void unix_proto_init(struct net_proto *pro)) +void __init unix_proto_init(struct net_proto *pro) #endif { struct sk_buff *dummy_skb; struct proc_dir_entry *ent; - printk(KERN_INFO "NET4: Unix domain sockets 1.0 for Linux NET4.0.\n"); + printk(KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n"); if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) { printk(KERN_CRIT "unix_proto_init: panic\n"); diff -u --recursive --new-file v2.3.14/linux/net/unix/garbage.c linux/net/unix/garbage.c --- v2.3.14/linux/net/unix/garbage.c Tue Jul 6 10:11:40 1999 +++ linux/net/unix/garbage.c Mon Aug 23 10:01:02 1999 @@ -84,9 +84,14 @@ /* Internal data structures and random procedures: */ -#define GC_HEAD ((unix_socket *)(-1)) +#define GC_HEAD ((unix_socket *)(-1)) +#define GC_ORPHAN ((unix_socket *)(-3)) + static unix_socket *gc_current=GC_HEAD; /* stack of objects to mark */ +atomic_t unix_tot_inflight = ATOMIC_INIT(0); + + extern inline unix_socket *unix_get_socket(struct file *filp) { unix_socket * u_sock = NULL; @@ -116,15 +121,19 @@ void unix_inflight(struct file *fp) { unix_socket *s=unix_get_socket(fp); - if(s) - s->protinfo.af_unix.inflight++; + if(s) { + atomic_inc(&s->protinfo.af_unix.inflight); + atomic_inc(&unix_tot_inflight); + } } void unix_notinflight(struct file *fp) { unix_socket *s=unix_get_socket(fp); - if(s) - s->protinfo.af_unix.inflight--; + if(s) { + atomic_dec(&s->protinfo.af_unix.inflight); + atomic_dec(&unix_tot_inflight); + } } @@ -146,8 +155,9 @@ extern inline void maybe_unmark_and_push(unix_socket *x) { - if (x->protinfo.af_unix.gc_tree) + if (x->protinfo.af_unix.gc_tree != GC_ORPHAN) return; + sock_hold(x); x->protinfo.af_unix.gc_tree = gc_current; gc_current = x; } @@ -157,23 +167,24 @@ void unix_gc(void) { - static int in_unix_gc=0; + static DECLARE_MUTEX(unix_gc_sem); int i; unix_socket *s; struct sk_buff_head hitlist; struct sk_buff *skb; - + /* * Avoid a recursive GC. */ - if(in_unix_gc) + if(!down_trylock(&unix_gc_sem)) return; - in_unix_gc=1; - + + read_lock(&unix_table_lock); + forall_unix_sockets(i, s) { - s->protinfo.af_unix.gc_tree=NULL; + s->protinfo.af_unix.gc_tree=GC_ORPHAN; } /* * Everything is now marked @@ -199,7 +210,7 @@ * in flight we are in use. */ if(s->socket && s->socket->file && - file_count(s->socket->file) > s->protinfo.af_unix.inflight) + file_count(s->socket->file) > atomic_read(&s->protinfo.af_unix.inflight)) maybe_unmark_and_push(s); } @@ -210,8 +221,9 @@ while (!empty_stack()) { unix_socket *x = pop_stack(); - unix_socket *f=NULL,*sk; -tail: + unix_socket *sk; + + spin_lock(&x->receive_queue.lock); skb=skb_peek(&x->receive_queue); /* @@ -238,49 +250,28 @@ */ if((sk=unix_get_socket(*fp++))!=NULL) { - /* - * Remember the first, - * unmark the rest. - */ - if(f==NULL) - f=sk; - else - maybe_unmark_and_push(sk); + maybe_unmark_and_push(sk); } } } /* We have to scan not-yet-accepted ones too */ - if ((UNIXCB(skb).attr & MSG_SYN) && !skb->sk->dead) { - if (f==NULL) - f=skb->sk; - else - maybe_unmark_and_push(skb->sk); + if (x->state == TCP_LISTEN) { + maybe_unmark_and_push(skb->sk); } skb=skb->next; } - /* - * Handle first born specially - */ - - if (f) - { - if (!f->protinfo.af_unix.gc_tree) - { - f->protinfo.af_unix.gc_tree=GC_HEAD; - x=f; - f=NULL; - goto tail; - } - } + spin_unlock(&x->receive_queue.lock); + sock_put(x); } skb_queue_head_init(&hitlist); forall_unix_sockets(i, s) { - if (!s->protinfo.af_unix.gc_tree) + if (s->protinfo.af_unix.gc_tree == GC_ORPHAN) { struct sk_buff *nextsk; + spin_lock(&s->receive_queue.lock); skb=skb_peek(&s->receive_queue); while(skb && skb != (struct sk_buff *)&s->receive_queue) { @@ -290,21 +281,24 @@ */ if(UNIXCB(skb).fp) { - skb_unlink(skb); - skb_queue_tail(&hitlist,skb); + __skb_unlink(skb, skb->list); + __skb_queue_tail(&hitlist,skb); } skb=nextsk; } + spin_unlock(&s->receive_queue.lock); } + s->protinfo.af_unix.gc_tree = GC_ORPHAN; } + read_unlock(&unix_table_lock); /* * Here we are. Hitlist is filled. Die. */ - while ((skb=skb_dequeue(&hitlist))!=NULL) { + while ((skb=__skb_dequeue(&hitlist))!=NULL) { kfree_skb(skb); } - in_unix_gc=0; + up(&unix_gc_sem); } diff -u --recursive --new-file v2.3.14/linux/net/unix/sysctl_net_unix.c linux/net/unix/sysctl_net_unix.c --- v2.3.14/linux/net/unix/sysctl_net_unix.c Sun Mar 21 07:22:00 1999 +++ linux/net/unix/sysctl_net_unix.c Mon Aug 23 10:01:02 1999 @@ -17,17 +17,9 @@ #ifdef CONFIG_SYSCTL -extern int sysctl_unix_destroy_delay; -extern int sysctl_unix_delete_delay; extern int sysctl_unix_max_dgram_qlen; ctl_table unix_table[] = { - {NET_UNIX_DESTROY_DELAY, "destroy_delay", - &sysctl_unix_destroy_delay, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, - {NET_UNIX_DELETE_DELAY, "delete_delay", - &sysctl_unix_delete_delay, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies}, {NET_UNIX_MAX_DGRAM_QLEN, "max_dgram_qlen", &sysctl_unix_max_dgram_qlen, sizeof(int), 0600, NULL, &proc_dointvec_jiffies}, diff -u --recursive --new-file v2.3.14/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.3.14/linux/net/x25/af_x25.c Wed Aug 18 11:38:49 1999 +++ linux/net/x25/af_x25.c Mon Aug 23 10:01:02 1999 @@ -522,7 +522,7 @@ return sk; } -static int x25_release(struct socket *sock, struct socket *peer) +static int x25_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -680,11 +680,6 @@ struct sock *newsk; struct sk_buff *skb; - if (newsock->sk != NULL) - x25_destroy_socket(newsock->sk); - - newsock->sk = NULL; - if ((sk = sock->sk) == NULL) return -EINVAL; @@ -1239,10 +1234,9 @@ x25_create }; -static struct proto_ops x25_proto_ops = { +static struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { AF_X25, - sock_no_dup, x25_release, x25_bind, x25_connect, @@ -1257,8 +1251,13 @@ x25_getsockopt, sock_no_fcntl, x25_sendmsg, - x25_recvmsg + x25_recvmsg, + sock_no_mmap }; + +#include +SOCKOPS_WRAP(x25_proto, AF_X25); + static struct packet_type x25_packet_type = { diff -u --recursive --new-file v2.3.14/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c --- v2.3.14/linux/net/x25/x25_dev.c Wed Aug 18 11:38:49 1999 +++ linux/net/x25/x25_dev.c Mon Aug 23 10:01:02 1999 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,7 @@ #include #include #include -#include +#include #include static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) @@ -51,11 +50,6 @@ struct sock *sk; unsigned short frametype; unsigned int lci; - - if (call_in_firewall(PF_X25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { - kfree_skb(skb); - return 0; - } frametype = skb->data[2]; lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); diff -u --recursive --new-file v2.3.14/linux/net/x25/x25_link.c linux/net/x25/x25_link.c --- v2.3.14/linux/net/x25/x25_link.c Wed Aug 18 11:38:49 1999 +++ linux/net/x25/x25_link.c Mon Aug 23 10:01:02 1999 @@ -39,7 +39,6 @@ #include #include #include -#include #include static struct x25_neigh *x25_neigh_list = NULL; @@ -224,11 +223,6 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh) { - if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { - kfree_skb(skb); - return; - } - switch (neigh->state) { case X25_LINK_STATE_0: skb_queue_tail(&neigh->queue, skb); @@ -378,8 +372,11 @@ case SIOCX25GSUBSCRIP: if ((dev = x25_dev_get(x25_subscr.device)) == NULL) return -EINVAL; - if ((x25_neigh = x25_get_neigh(dev)) == NULL) + if ((x25_neigh = x25_get_neigh(dev)) == NULL) { + dev_put(dev); return -EINVAL; + } + dev_put(dev); x25_subscr.extended = x25_neigh->extended; if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct))) return -EFAULT; @@ -390,8 +387,11 @@ return -EFAULT; if ((dev = x25_dev_get(x25_subscr.device)) == NULL) return -EINVAL; - if ((x25_neigh = x25_get_neigh(dev)) == NULL) + if ((x25_neigh = x25_get_neigh(dev)) == NULL) { + dev_put(dev); return -EINVAL; + } + dev_put(dev); if (x25_subscr.extended != 0 && x25_subscr.extended != 1) return -EINVAL; x25_neigh->extended = x25_subscr.extended; diff -u --recursive --new-file v2.3.14/linux/net/x25/x25_route.c linux/net/x25/x25_route.c --- v2.3.14/linux/net/x25/x25_route.c Wed Aug 18 11:38:49 1999 +++ linux/net/x25/x25_route.c Mon Aug 23 10:01:02 1999 @@ -42,7 +42,6 @@ #include #include #include -#include #include static struct x25_route *x25_route_list = NULL; @@ -142,7 +141,7 @@ { struct net_device *dev; - if ((dev = dev_get(devname)) == NULL) + if ((dev = dev_get_by_name(devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25 @@ -152,6 +151,8 @@ )) return dev; + dev_put(dev); + return NULL; } @@ -183,6 +184,7 @@ { struct x25_route_struct x25_route; struct net_device *dev; + int err; switch (cmd) { @@ -193,7 +195,9 @@ return -EINVAL; if ((dev = x25_dev_get(x25_route.device)) == NULL) return -EINVAL; - return x25_add_route(&x25_route.address, x25_route.sigdigits, dev); + err = x25_add_route(&x25_route.address, x25_route.sigdigits, dev); + dev_put(dev); + return err; case SIOCDELRT: if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct))) @@ -202,7 +206,9 @@ return -EINVAL; if ((dev = x25_dev_get(x25_route.device)) == NULL) return -EINVAL; - return x25_del_route(&x25_route.address, x25_route.sigdigits, dev); + err = x25_del_route(&x25_route.address, x25_route.sigdigits, dev); + dev_put(dev); + return err; default: return -EINVAL; diff -u --recursive --new-file v2.3.14/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.3.14/linux/scripts/mkdep.c Thu Aug 5 14:43:32 1999 +++ linux/scripts/mkdep.c Mon Aug 23 11:15:53 1999 @@ -8,6 +8,16 @@ * I make simple dependency lines for #include <*.h> and #include "*.h". * I also find instances of CONFIG_FOO and generate dependencies * like include/config/foo.h. + * + * 1 August 1999, Michael Elizabeth Chastain, + * - Keith Owens reported a bug in smart config processing. There used + * to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO", + * so that the file would not depend on CONFIG_FOO because the file defines + * this symbol itself. But this optimization is bogus! Consider this code: + * "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO". Here + * the definition is inactivated, but I still used it. It turns out this + * actually happens a few times in the kernel source. The simple way to + * fix this problem is to remove this particular optimization. */ #include @@ -93,22 +103,11 @@ /* * Add a new value to the configuration string. */ -void define_config(int convert, const char * name, int len) +void define_config(const char * name, int len) { grow_config(len + 1); memcpy(str_config+len_config, name, len); - - if (convert) { - int i; - for (i = 0; i < len; i++) { - char c = str_config[len_config+i]; - if (isupper(c)) c = tolower(c); - if (c == '_') c = '/'; - str_config[len_config+i] = c; - } - } - len_config += len; str_config[len_config++] = '\n'; } @@ -121,7 +120,7 @@ void clear_config(void) { len_config = 0; - define_config(0, "", 0); + define_config("", 0); } @@ -186,7 +185,7 @@ return; if (len >= 7 && !memcmp(name, "config/", 7)) - define_config(0, name+7, len-7-2); + define_config(name+7, len-7-2); memcpy(path->buffer+path->len, name, len); path->buffer[path->len+len] = '\0'; @@ -225,7 +224,7 @@ if (is_defined_config(pc, len)) return; - define_config(0, pc, len); + define_config(pc, len); if (!hasdep) { hasdep = 1; @@ -242,7 +241,8 @@ * Thus, there is one memory access per sizeof(unsigned long) characters. */ -#if defined(__alpha__) || defined(__i386__) || defined(__MIPSEL__) || defined(__arm__) +#if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__MIPSEL__) \ + || defined(__arm__) #define LE_MACHINE #endif @@ -409,7 +409,13 @@ GETNEXT NOTCASE('f', __start); goto pound_define_undef; -/* #\s*(define|undef)\s*CONFIG_(\w*) */ +/* + * #\s*(define|undef)\s*CONFIG_(\w*) + * + * this does not define the word, because it could be inside another + * conditional (#if 0). But I do parse the word so that this instance + * does not count as a use. -- mec + */ pound_define_undef: GETNEXT CASE(' ', pound_define_undef); @@ -428,7 +434,6 @@ GETNEXT if (isalnum(current) || current == '_') goto pound_define_undef_CONFIG_word; - define_config(1, map_dot, next - map_dot - 1); goto __start; /* \