diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes --- linux.vanilla/Documentation/Changes Wed Mar 24 10:55:09 1999 +++ linux.ac/Documentation/Changes Wed Mar 24 11:00:08 1999 @@ -258,6 +258,11 @@ The ISDN code in the stock 2.2 kernel may not work for you. If it doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions. + In 2.0.x the kernel could be configured to drop source routed IP +packets via a compile time configuration option. In 2.2.x, this has +been replaced by a sysctl. See Documentation/networking/ip-sysctl.txt +for more information. + Memory ====== diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Wed Mar 24 10:55:09 1999 +++ linux.ac/Documentation/Configure.help Thu Mar 25 18:05:23 1999 @@ -85,13 +85,13 @@ a system with only one CPU, like most personal computers, say N. If you have a system with more than one CPU, say Y. - If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If + If you say N here, the kernel will run on single and multi-processor + machines, but will use only one CPU of a multi-processor machine. If you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel + single-processor machines. On a single-processor machine, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or + Note that if you say Y here and choose architectures "586" or "Pentium" under "Processor family", the kernel will not work on 486 architectures. Similarly, multiprocessor kernels for the "PPro" architecture may not work on all Pentium based boards. @@ -1747,6 +1747,18 @@ except that your Apollo won't be able to boot from it (because the code in the ROM will be for a PC). +Apollo support +CONFIG_APOLLO + Say Y here if you want to run Linux on an MC680x0-based Apollo + Domain workstation such as the DN3500. + +Apollo 3c505 support +CONFIG_APOLLO_ELPLUS + Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card. + If you don't have one made for Apollos, you can use one from a PC, + except that your Apollo won't be able to boot from it (because the + code in the ROM will be for a PC). + Atari native chipset support CONFIG_FB_ATARI This is the frame buffer device driver for the builtin graphics @@ -3689,34 +3701,49 @@ say M here and read Documentation/modules.txt. The module will be called aic7xxx.o. -Override driver defaults for commands per LUN -CONFIG_OVERRIDE_CMDS - Say Y here if you want to override the default maximum number of - commands that a single device on the aic7xxx controller is allowed - to have active at one time. This option only affects tagged queueing - capable devices. The driver uses a value of 24 by default. - If you say Y here, you can adjust the number of commands per LUN - with the following configuration option. - - If unsure, say N. - -Maximum number of commands per LUN -CONFIG_AIC7XXX_CMDS_PER_LUN - Specify the maximum number of commands you would like to allocate - per LUN (a LUN is a Logical Unit Number -- some physical SCSI - devices, e.g. CD jukeboxes, act logically as several separate units, - each of which gets its own number). +Enable or Disable Tagged Command Queueing by default +CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + This option causes the aic7xxx driver to attempt to use tagged command + queueing on any devices that claim to support it. If this is set to yes, + you can still turn off TCQ on troublesome devices with the use of the + tag_info boot parameter. See /usr/src/linux/drivers/scsi/README.aic7xxx + for more information on that and other aic7xxx setup commands. If this + option is turned off, you may still enable TCQ on known good devices by + use of the tag_info boot parameter. + + If you are unsure about your devices then it is safest to say N here. + + However, TCQ can increase performance on some hard drives by as much + as 50% or more, so I would recommend that if you say N here, that you + at least read the README.aic7xxx file so you will know how to enable + this option manually should your drives prove to be safe in regards + to TCQ. + + Conversely, certain drives are known to lock up or cause bus resets when + TCQ is enabled on them. If you have a Western Digital Enterprise SCSI + drive for instance, then don't even bother to enable TCQ on it as the + drive will become unreliable, and it will actually reduce performance. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. - Reasonable figures are in the range of 14 to 32 commands per device, + Reasonable figures are in the range of 8 to 24 commands per device, but depending on hardware could be increased or decreased from that figure. If the number is too high for any particular device, the driver will automatically compensate usually after only 10 minutes - of uptime and will issue a message to alert you to the fact that the - number of commands for that device has been reduced. It will not - hinder performance if some of your devices eventually have their - commands per LUN reduced, but is a waste of memory if all of your - devices end up reducing this number down to a more reasonable - figure. Default: 24 + of uptime. It will not hinder performance if some of your devices + eventually have their command depth reduced, but is a waste of memory + if all of your devices end up reducing this number down to a more + reasonable figure. + + NOTE: Certain very broken drives are known to lock up when given more + commands than they like to deal with. Quantum Fireball drives are the + most common in this category. For the Quantum Fireball drives I would + suggest no more than 8 commands per device. + + Default: 8 Collect statistics to report in /proc CONFIG_AIC7XXX_PROC_STATS @@ -5346,8 +5373,8 @@ are planning to use the box as a WAN ( = Wide Area Network) router ( = device used to interconnect local area networks over wide area communication links, such as leased lines or public data networks, - e.g. X.25 or frame relay) and you will be offered a list of drivers - for WAN cards currently available. For more information, read + e.g. X.25 or frame relay etc ) and you will be offered a list of + drivers for WAN cards currently available. For more information, read Documentation/networking/wan-router.txt. Note that the answer to this question won't directly affect the @@ -5361,11 +5388,12 @@ that has a program like lynx or netscape) is a family of intelligent multiprotocol WAN adapters with data transfer rates up to T1 (1.544 Mbps). They are also known as Synchronous Data Link Adapters (SDLA) - and designated S502E(A), S503 or S508. These cards support the X.25, - Frame Relay, and PPP protocols. If you have one or more of these - cards, say Y to this option; you may then also want to read the file - Documentation/networking/wanpipe.txt. The next questions will ask - you about the protocols you want the driver to support. + and designated S503 or S508. These cards support the X.25, + Frame Relay, PPP, Cisco HDLC protocols. It also offers API support for + protocols like HDLC (LAPB), HDLC Streaming and BiSync. If you have one + or more of these cards, say Y to this option; you may then also want to + read the file Documentation/networking/wanpipe.txt. The next questions + will ask you about the protocols you want the driver to support. The driver will be compiled as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -5383,26 +5411,46 @@ WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. If you say N, the X.25 support will not be included + in the driver. X.25 option is ONLY supported on S508 cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network. f you say N, the frame relay support will not + be included in the driver. Frame Relay option is ONLY supported on S508 + cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If + you say N, the PPP support will not be included in the driver. PPP option + is ONLY supported on S508 cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Cisco HDLC protocol. This now supports Dual Port + Cisco HDLC on the S508 card ONLY. This support also allows user to build + applications using the HDLC streaming API. If you say 'N', the Cisco HDLC + support and HDLC streaming API will not be included in the driver. + +WANPIPE BiSync Streaming API support +CONFIG_WANPIPE_BSTRM + Say Y to this option if you are planning to use a WANPIPE card to develope + user applications to send RAW BiSync data. This option provides an API + support for customers to build their own applications. This API ONLY supports + S503 cards. If you say N, then BiSync API support will not be included in + the driver. + +WANPIPE HDLC (LAPB) API support +CONFIG_WANPIPE_HDLC + Say Y to this option if you are planning to use a WANPIPE card to develope + user application to send HDLC (LAPB) data. This option provides an API + support for customers to build their own applications. This API ONLY supports + the S508 cards. If you say N, then HDLC (LAPB) API support will not be + included in the driver. Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET @@ -5617,7 +5665,7 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called yellowfin.o. -Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support. +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit Ethernet adapter. The driver allows for using the Jumbo Frame @@ -6513,9 +6561,6 @@ (PhotoCDs). There is a new driver (next question) which can do this. If you want that one, say N here. - If the driver doesn't work out of the box, you might want to have a - look at drivers/cdrom/mcd.h. - If you say Y here, you should also say Y or M to "ISO 9660 CDROM filesystem support" below, because that's the filesystem used on CDROMs. @@ -6525,6 +6570,20 @@ The module will be called mcd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IRQ channel for Mitsumi CD-ROM +CONFIG_MCD_IRQ + This allows you to specify default value of interrupt number used by + the driver. This setting can be overriden at boot time by passing "mcd=" + parameter to the kernel or module load time (if you compiled this as a + module). + +I/O base address for Mitsumi CD-ROM +CONFIG_MCD_BASE + This allows you to specify default value of I/O base address used by + the driver. This setting can be overriden at boot time by passing "mcd=" + parameter to the kernel or module load time (if you compiled this as a + module). + Mitsumi [XA/MultiSession] support CONFIG_MCDX Use this driver if you want to be able to read XA or MultiSession @@ -6998,9 +7057,9 @@ kernel based NFS server. The advantage of the kernel based solution is that it is faster; it might not be completely stable yet, though. You will need the support software from the linux-nfs package - available at ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/. + available from http://csua.berkeley.edu/~gam3/knfsd/ Please read the NFS-HOWTO, available via FTP (user: anonymous) from - ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The NFS server is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7050,11 +7109,12 @@ If unsure, say N. -System V and Coherent filesystem support +System V, Version 7 and Coherent filesystem support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read to and write from - their floppies and hard disk partitions. + machines, and Version 7 was used on the DEC PDP-11. Saying Y here + would allow you to read to and write from their floppies and hard disk + partitions. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order @@ -9502,6 +9562,11 @@ ISDN subsystem CONFIG_ISDN + CAUTION: the ISDN driver shipped with this kernel distribution + is outdated and might not work without problems. An updated driver + is available for download. Please read http://www.isdn4linux.de + on the WWW for a list of servers. + ISDN ("Integrated Services Digital Networks", called RNIS in France) is a special type of fully digital telephone service; it's mostly used to connect to your Internet service provider (with SLIP or diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/dcache.txt linux.ac/Documentation/filesystems/dcache.txt --- linux.vanilla/Documentation/filesystems/dcache.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/dcache.txt Thu Jan 14 04:02:58 1999 @@ -0,0 +1,173 @@ +Some dcache details + +A traditional Unix system has inodes (`index nodes') as in-core +descriptors of files. An inode refers to the actual file, not +to a directory entry naming it. Linux v2.1.43 introduced dentries +(`directory entries') as in-core descriptors of file names. + +The entire purpose of dentries is to make the map +filename -> inode fast. An interesting side effect +is that the kernel knows what name was used to open a file +and that a system call getcwd() is possible. + +Thus, the central part of the dcache code are the lines + dentry = reserved_lookup(base, &this); + if (!dentry) { + dentry = cached_lookup(base, &this); + if (!dentry) + dentry = real_lookup(base, &this); + } +in namei.c. The reserved_lookup() takes care of . and ..; +the cached_lookup() is what we have the dcache for, +and the real_lookup() goes to the filesystem. + +The cached_lookup() returns the value of d_lookup(), +but does a d_revalidate() before returning, and if that fails +and the dentry has no children, it returns NULL. + [This is a rather obscure part. The d_revalidate() + is allowed to fail for any reason - for example, + autofs uses a timeout to make d_revalidate fail - + which means that the final dentry we come up with + need not be the dentry that d_lookup() found. + This causes bugs in the vfat filesystem. + Moreover, if d_revalidate(D) fails but D still has + children, then D is used anyway. + This also causes bugs in the vfat filesystem. + I think also nfs has problems.] + + + + +A struct dentry has five members of type struct list_head: + struct list_head d_hash; /* lookup hash list */ + struct list_head d_lru; /* d_count = 0 LRU list */ + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ + + [Some of these names were very badly chosen, and lead + to confusion all the time. We should do a global replace + changing d_subdirs into d_children and d_child into d_sister.] + + + +1. d_hash + +The d_hash field of a dentry links the dentry into +the list of dentries for filenames with a given hash value +with list head dentry_hashtable[hashvalue] defined in dcache.c. +This list is used in d_lookup() to find a dentry with given name +and parent. It is used in d_validate() to find a dentry with +known hash and parent. + [The present code takes the parent into account when + computing a hash. Not doing this would make the code + simpler and faster, possibly at the expense of a few + more collisions. Has anyone investigated this?] +The d_hash field is an empty list when the file is a mount point +(cf. d_validate) or has been deleted, or when the dentry was +dropped for some other reason. + + +d_add(D,I) will put D into its hash chain and provide it +with the inode I. It is called by all filesystem lookup routines. + +d_drop(D) will remove D from its hash chain. A dentry is called +`unhashed' when its d_hash field is an empty list. +Sometimes dentries are dropped temporarily to make sure +no lookup will find them. The general routine vfs_rmdir(I,D) +will drop D if d_count=2, so that all filesystem rmdir() +routines can return -EBUSY when D still occurs in the hash list. +The filesystem routines for unlink and rmdir call d_delete() +which again calls d_drop(). + +[The d_hash field is referred to in many places that should +not know about its existence, in the phrase + if (list_empty(&dentry->d_hash)) ... +No doubt there should be a line + #define unhashed(d) (list_empty(&(d)->d_hash)) +in dcache.h, together with a comment describing the semantics +of being unhashed. Then all these occurrences of d_hash can +be removed. Next, d_drop() should be renamed d_unhash().] + +The dentry for the root of a mounted filesystem is returned by +d_alloc_root() and is unhashed. + + + +2. d_lru +The simplest list is the one joining the d_lru fields of +dentries that had d_count = 0 at some point in time. +The list head is the variable dentry_unused defined in dcache.c. +The number of elements in this list is dentry_stat.nr_unused. +There are no references to the d_lru field outside dcache.[ch]. + +Note that d_count is incremented by dget(), invoked by d_lookup(), +without removing the dentry from the LRU list. Thus, anyone hoping +to find unused dentries on this list must first check d_count. +If a dentry is not on the LRU list, its d_lru field is an +empty list (initialized by d_alloc()). + +dput(D) tries to get rid of D altogether when d_count = 0, but +puts D at the head of the LRU list if it is still on the hash list. +Thus, every D with d_count = 0 will be on the LRU list. + +select_dcache(ict,pct) removes D with d_count > 0 from the +LRU list, and moves D that are ready to be sacrificed for memory +to the end of the list. (If ict and/or pct is given, then we are +satisfied when the selected D's involve ict inodes or pct pages.) + +prune_dcache(ct) removes D with d_count > 0 from the LRU list, +and frees unused D, stopping when ct of them have been freed. + +shrink_dcache_sb(sb) removes all unused D with given superblock +from the LRU list. + +select_parent(D) move all unused descendants of D to the end +of the LRU list. + + + +3. d_child and d_subdirs +As already noted, the names are terrible. The d_child field +does not refer to a child but to a sibling, and the d_subdirs +field does not refer to a subdirectory but to a child, directory +or not. These two fields form a threaded tree: the d_subdirs field +points to the first child, and the d_child field is member of the +circularly linked list of all children of one parent. + +To be more precise: this circularly linked list of all children +of one parent P passes through the d_child fields of all children +and through the d_subdirs field of the parent P. + + + +4. d_alias +Somewhat similar to the above, where we had a circularly linked list +with one special element, we here have a circularly linked list +passing through the d_alias field of all dentries that are aliases +of one inode, and through the i_dentry field of the inode. + +The dentry is added to this list by d_instantiate(). +It is removed again by dentry_iput() which is called by dput() +and d_delete(). + + + + +So far about the lists in the dentry structure. +Some of the routines in dcache.c have been mentioned already. +Let me describe one of the more obscure ones. + +d_move(D,T) is the routine called by the filesystem code +just before finishing the rename(D,T) call. Since both +dentries D and T may be busy we cannot just throw one away. +Instead they are partially interchanged: +D and T interchange names, and D is put into T's hash queue, +and T is unhashed; D and T interchange parents, and are put +on the list of children of their new parent. +The result is that the file D that got renamed is now in perfect +shape again - it has been renamed. T, if it existed, lost its +name string, if it was short, but perhaps this is harmless - +let us hope no-one will ever ask for T's name anymore. + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/sysv-fs.txt linux.ac/Documentation/filesystems/sysv-fs.txt --- linux.vanilla/Documentation/filesystems/sysv-fs.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/filesystems/sysv-fs.txt Mon Mar 1 00:18:47 1999 @@ -2,20 +2,22 @@ It implements all of - Xenix FS, - SystemV/386 FS, + - Version 7 FS - Coherent FS. This is version beta 4. To install: -* Answer the 'System V and Coherent filesystem support' question with 'y' - when configuring the kernel. +* Answer the 'System V, Version 7 and Coherent filesystem support' question + with a 'y' when configuring the kernel. * To mount a disk or a partition, use mount [-r] -t sysv device mountpoint The file system type names -t sysv -t xenix + -t v7 -t coherent - may be used interchangeably, but the last two will eventually disappear. + the xenix and coherent options will eventually disappear. Bugs in the present implementation: - Coherent FS: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wan-router.txt linux.ac/Documentation/networking/wan-router.txt --- linux.vanilla/Documentation/networking/wan-router.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wan-router.txt Thu Mar 25 17:57:59 1999 @@ -1,19 +1,21 @@ ------------------------------------------------------------------------------ WAN Router for Linux Operating System ------------------------------------------------------------------------------ +Version 2.0.4 - Nov 26, 1998 +Version 2.0.3 - Aug 25, 1998 +Version 2.0.2 - Dec 09, 1997 Version 2.0.1 - Nov 28, 1997 Version 2.0.0 - Nov 06, 1997 Version 1.0.3 - June 3, 1997 Version 1.0.1 - January 30, 1997 Author: Jaspreet Singh - Gene Kozin Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR -AN UPGRADE. +AN UPGRADE. ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. INTRODUCTION @@ -121,6 +123,9 @@ were given by Mike McLagan and his implementation of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). +With the new implementation of the APIs being incorporated into the WANPIPE, +a special thank goes to Alan Cox in providing insight into BSD sockets. + Special thanks to all the WANPIPE users who performed field-testing, reported bugs and made valuable comments and suggestions that help us to improve this product. @@ -128,6 +133,27 @@ REVISION HISTORY + +2.0.4 Nov 26, 1998 - NEW Cisco Dual Port support. + - NEW support for BiSync Streaming API. + - NEW support for HDLC (LAPB) API. + - WANPIPE provides an API for application + development using the BSD socket interface. + +2.0.3 Aug 25, 1998 - NEW support for Cisco HDLC, with cpipemon + utility for monitoring + - CIR support for Frame-relay + - Support for PAP and CHAP for ppp has been + implemented + - Dynamic IP assignment for PPP + - Multiple channel IPX support for Frame-relay + and X25 + - Inverse Arp support for Frame-relay + - FT1 Configuration utility for linux + - Man Pages for router.conf, router, sdladump, + cfgft1, fpipemon, ppipemon and cpipemon + +2.0.2 Dev 09, 1997 - Implemented PAP and CHAP for ppp. 2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while "disable_irq()" has been enabled from any other diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.ac/Documentation/networking/wanpipe.txt --- linux.vanilla/Documentation/networking/wanpipe.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wanpipe.txt Thu Mar 25 18:02:00 1999 @@ -1,8 +1,8 @@ ------------------------------------------------------------------------------ WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------ -Release 4.1 -November 17, 1997 +VERSION 5.0 +August 25, 1998 Author: Jaspreet Singh Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ @@ -13,11 +13,11 @@ for personal computers (ISA bus) designed to provide PC connectivity to various communication links, such as leased lines and public data networks, at speeds up to T1/E1 using a variety of synchronous communications protocols, -including frame relay, PPP, X.25, SDLC, etc. +including frame relay, PPP, Cisco HDLC, X.25, SDLC, etc. -WANPIPE driver together with Linux WAN Router module allows you to build a -relatively inexpensive, yet high-performance multiprotocol WAN router. For -more information about the Linux WAN Router please read the file +The WANPIPE driver together with the Linux WAN Router module allows you to +build a relatively inexpensive, yet high-prformance multiprotocol WAN +router. For more information about Linux WAN Router please read file Documentation/networking/wan-router.txt. You must also obtain the WAN Tools package to be able to use the Linux WAN Router and WANPIPE driver. The package is available via the Internet from Sangoma Technologies' anonymous FTP server: @@ -26,7 +26,7 @@ or ftp.sangoma.com/pub/linux/wanpipe-X.Y.Z.tgz -The names of the packages differ only due to naming convention. The +The name of the package differs only due to naming convention. The functionality of wantools and wanpipe packages are the same. The latest version of the WAN Drivers is wanpipe-2.0.0. @@ -59,13 +59,11 @@ NEW IN THIS RELEASE - o This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU - OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR AN - UPGRADE. - o Protection of "enable_irq()" while "disable_irq()" has been enabled from - any other routine (for Frame Relay, PPP and X25). - o Added additional Stats for Fpipemon and Ppipemon. - o Improved Load Sharing for multiple boards +o Supports DUAL PORT Cisco HDLC. +o Supports HDLC (LAPB) API +o Supports BiSync Streaming code for S502E and S503 cards ONLY. +o Provides a BSD socket interface for creating applications using BiSync + streaming and HDLC LAPB. FILE LIST @@ -76,12 +74,18 @@ sdla_fr.c SDLA Frame Relay source code sdla_ppp.c SDLA PPP source code sdla_x25.c SDLA X.25 source code + sdla_chdlc.c SDLA Cisco HDLC source code + sdla_bstrm.c SDLA BiSync Streaming API source code + sdla_hdlc.c SDLA HDLC (LAPB) API source code sdlamain.c SDLA support source code include/linux: sdla_x25.h SDLA X.25 firmware API definitions sdla_fr.h SDLA frame relay firmware API definitions sdla_ppp.h SDLA PPP firmware API definitions + sdla_chdlc.h SDLA Cisco HDLC firmware API definitions + sdla_bstrm.h SDLA BiSync Streaming firmware API definitions + sdla_hdlc.h SDLA HDLC LAPB firmware API definitions wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions @@ -89,6 +93,20 @@ REVISION HISTORY + +5.0 August 25, 1998 + o This Version of WANPIPE supports only the S508 and S508/FT1 cards. + IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA + TECHNOLOGIES FOR AN UPGRADE. + o NEW support for Cisco HDLC, with cpipemon utility for monitoring + o CIR support for Frame-relay + o Support for PAP and CHAP for ppp has been implemented + o Dynamic IP assignment for PPP + o Multiple channel IPX support for Frame-relay and X25 + o Inverse Arp support for Frame-relay + o FT1 Configuration utility for linux + o Man Pages for router.conf, router, sdladump, cfgft1, fpipemon, + ppipemon and cpipemon 4.1 November 28, 1997 o Protection of "enable_irq()" while "disable_irq()" has been enabled diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Wed Mar 24 10:55:09 1999 +++ linux.ac/MAINTAINERS Wed Mar 24 11:00:21 1999 @@ -643,6 +643,11 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +SCSI GENERIC +L: linux-scsi@vger.rutgers.edu +M: douglas.gilbert@rbcds.com +S: Maintained + SCSI SUBSYSTEM L: linux-scsi@vger.rutgers.edu S: Unmaintained @@ -777,9 +782,9 @@ W: http://roadrunner.swansea.linux.org.uk/v4l.shtml S: Maintained -WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP) -P: Gene Kozin -M: genek@compuserve.com +WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) +P: Jaspreet Singh +M: jaspreet@sangoma.com M: dm@sangoma.com W: http://www.sangoma.com S: Supported diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Wed Mar 24 10:55:09 1999 +++ linux.ac/Makefile Thu Mar 25 17:50:30 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 4 -EXTRAVERSION = +EXTRAVERSION = -ac1 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -323,7 +323,7 @@ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ \ - ls *.o > $$MODLIB/.allmods; \ + for f in *.o; do [ -r $$f ] && echo $$f; done > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ @@ -343,7 +343,8 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f core `find . -name '*.[oas]' ! \( -regex '.*lxdialog/.*' \ + -o -regex '.*ksymoops/.*' \) -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -367,6 +368,7 @@ rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog + rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops rm -f .menuconfig.log rm -f include/asm rm -rf include/config @@ -379,8 +381,8 @@ distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ - -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz @@ -389,7 +391,7 @@ sums: find . -type f -print | sort | xargs sum > .SUMS -dep-files: scripts/mkdep archdep include/linux/version.h +dep-files: scripts/mkdep archdep include/linux/version.h new-genksyms scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend # set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep ;done @@ -399,7 +401,19 @@ MODVERFILE := ifdef CONFIG_MODVERSIONS + MODVERFILE := $(TOPDIR)/include/linux/modversions.h + +new-genksyms: + @$(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) /dev/null || ( echo -e "\nYou need a new version of the genksyms\ + program, which is part of\nthe modutils package. Please read the file\ + Documentation/Changes\nfor more information.\n"; exit 1 ) + +else + +new-genksyms: + endif depend dep: dep-files $(MODVERFILE) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/REPORTING-BUGS linux.ac/REPORTING-BUGS --- linux.vanilla/REPORTING-BUGS Tue Jan 19 02:57:22 1999 +++ linux.ac/REPORTING-BUGS Mon Mar 15 18:14:06 1999 @@ -23,7 +23,7 @@ This is a suggested format for a bug report sent to the Linux kernel mailing list. Having a standardized bug report form makes it easier for you not to overlook things, and easier for the developers to find the pieces of -information they're really interested in. +information they're really interested in. Don't feel you have to follow it. First run the ver_linux script included as scripts/ver_linux or at It checks out diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_cia.c linux.ac/arch/alpha/kernel/core_cia.c --- linux.vanilla/arch/alpha/kernel/core_cia.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_cia.c Tue Mar 16 18:57:45 1999 @@ -535,8 +535,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, * we may want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_pyxis.c linux.ac/arch/alpha/kernel/core_pyxis.c --- linux.vanilla/arch/alpha/kernel/core_pyxis.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_pyxis.c Tue Mar 16 18:57:45 1999 @@ -427,8 +427,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may * want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.ac/arch/alpha/kernel/process.c --- linux.vanilla/arch/alpha/kernel/process.c Sun Jan 24 19:55:29 1999 +++ linux.ac/arch/alpha/kernel/process.c Sun Jan 24 20:20:25 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/time.c linux.ac/arch/alpha/kernel/time.c --- linux.vanilla/arch/alpha/kernel/time.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/alpha/kernel/time.c Sat Mar 20 22:42:39 1999 @@ -95,14 +95,17 @@ /* * Calculate how many ticks have passed since the last update, * including any previous partial leftover. Save any resulting - * fraction for the next pass. + * fraction for the next pass. Don't change anything unless + * at least one tick has passed. */ now = rpcc(); delta = now - state.last_time; - state.last_time = now; delta = delta * state.scaled_ticks_per_cycle + state.partial_tick; - state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); nticks = delta >> FIX_SHIFT; + if (nticks) { + state.last_time = now; + state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); + } while (nticks > 0) { do_timer(regs); @@ -316,12 +319,14 @@ { unsigned long flags, now, delta_cycles, delta_usec; unsigned long sec, usec; + unsigned long partial_tick; - now = rpcc(); save_and_cli(flags); + now = rpcc(); sec = xtime.tv_sec; usec = xtime.tv_usec; delta_cycles = now - state.last_time; + partial_tick = state.partial_tick; restore_flags(flags); /* @@ -337,7 +342,8 @@ * with no clear gain. */ - delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625; + delta_usec = delta_cycles * state.scaled_ticks_per_cycle + partial_tick; + delta_usec *= 15625; delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; usec += delta_usec; @@ -353,8 +359,24 @@ void do_settimeofday(struct timeval *tv) { + unsigned long delta_usec; + + /* + * The offset that is added into time in do_gettimeofday above must + * be subtracted here to keep a coherent view of the time. Without + * this, a full-tick error is possible. + */ cli(); + delta_usec = (rpcc() - state.last_time) * state.scaled_ticks_per_cycle + + state.partial_tick; + delta_usec *= 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; xtime = *tv; + xtime.tv_usec -= delta_usec; + if (xtime.tv_usec < 0) { + xtime.tv_usec += 1000000; + xtime.tv_sec--; + } time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/Makefile linux.ac/arch/arm/Makefile --- linux.vanilla/arch/arm/Makefile Tue Dec 22 23:19:25 1998 +++ linux.ac/arch/arm/Makefile Sun Feb 28 22:29:39 1999 @@ -10,14 +10,13 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1995, 1996 by Russell King +# Copyright (C) 1995-1999 by Russell King CFLAGS_PROC := ASFLAGS_PROC := -# All processors get `-mshort-load-bytes' for now, to work around alignment -# problems. This is more of a hack that just happens to work than a real fix -# but it will do for now. +# GCC 2.7 uses different options to later compilers; sort out which we have +CONFIG_BINUTILS_NEW := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo @@ -25,6 +24,7 @@ ZTEXTADDR = 0x01800000 ZRELADDR = 0x02080000 ifeq ($(CONFIG_BINUTILS_NEW),y) + ELF_ARCH = elf32arm26 CFLAGS_PROC += -mapcs-26 -mshort-load-bytes ifeq ($(CONFIG_CPU_ARM2),y) CFLAGS_PROC += -mcpu=arm2 @@ -43,6 +43,7 @@ CFLAGS_PROC += -m3 ASFLAGS_PROC += -m3 endif + ELF_ARCH = elf_arm endif endif @@ -50,6 +51,7 @@ PROCESSOR = armv TEXTADDR = 0xC0008000 ifeq ($(CONFIG_BINUTILS_NEW),y) + ELF_ARCH = elf32arm CFLAGS_PROC += -mapcs-32 -mshort-load-bytes ifeq ($(CONFIG_CPU_ARM6),y) CFLAGS_PROC += -mcpu=arm6 @@ -62,16 +64,18 @@ endif else CFLAGS_PROC += -m6 + ELF_ARCH = elf_arm endif ASFLAGS_PROC += -m6 endif # Processor Architecture # CFLAGS_PROC - processor dependent CFLAGS -# PROCESSOR - processor type -# TEXTADDR - Uncompressed kernel link text address -# ZTEXTADDR - Compressed kernel link text address -# ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded). +# PROCESSOR - processor type +# TEXTADDR - Uncompressed kernel link text address +# ZTEXTADDR - Compressed kernel link text address +# ZRELADDR - Compressed kernel relocating address +# (point at which uncompressed kernel is loaded). # COMPRESSED_HEAD = head.o @@ -79,19 +83,16 @@ ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k ARCHDIR = arc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o endif ifeq ($(CONFIG_ARCH_ARC),y) MACHINE = arc ARCHDIR = arc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o endif ifeq ($(CONFIG_ARCH_RPC),y) MACHINE = rpc ARCHDIR = rpc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o ZTEXTADDR = 0x10008000 ZRELADDR = 0x10008000 endif @@ -103,7 +104,7 @@ ZRELADDR = 0x00008000 endif -ifeq ($(CONFIG_ARCH_EBSA285),y) +ifeq ($(CONFIG_HOST_FOOTBRIDGE),y) MACHINE = ebsa285 ARCHDIR = ebsa285 ZTEXTADDR = 0x00008000 @@ -119,31 +120,13 @@ COMPRESSED_HEAD = head-nexuspci.o endif -ifeq ($(CONFIG_ARCH_VNC),y) -TEXTADDR = 0xC000C000 -MACHINE = vnc -ARCHDIR = vnc -endif - -ifeq ($(CONFIG_ARCH_TBOX),y) -MACHINE = tbox -ARCHDIR = tbox -ZTEXTADDR = 0x80008000 -ZRELDIR = 0x80008000 -endif - PERL = perl -ifeq ($(CONFIG_BINUTILS_NEW),y) -LD = $(CROSS_COMPILE)ld -m elf32arm -else -LD = $(CROSS_COMPILE)ld -m elf_arm -endif +LD = $(CROSS_COMPILE)ld -m $(ELF_ARCH) OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S OBJDUMP = $(CROSS_COMPILE)objdump CPP = $(CC) -E ARCHCC := $(word 1,$(CC)) GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name` -#GCCARCH := -B/usr/bin/arm-linuxelf- HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=) ifeq ($(CONFIG_FRAME_POINTER),y) CFLAGS := $(CFLAGS:-fomit-frame-pointer=) @@ -153,64 +136,32 @@ LINKFLAGS = -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -Ttext $(TEXTADDR) ZLINKFLAGS = -Ttext $(ZTEXTADDR) -SUBDIRS := $(SUBDIRS:drivers=arch/arm/drivers) arch/arm/lib arch/arm/kernel arch/arm/mm -HEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o +# If we're intending to debug the kernel, make sure it has line number +# information. This gets stripped out when building (z)Image so it doesn't +# add anything to the footprint of the running kernel. +ifeq ($(CONFIG_DEBUG_INFO),y) +CFLAGS += -g +endif + +HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ + arch/arm/kernel/init_task.o +SUBDIRS := arch/arm/special $(SUBDIRS) arch/arm/lib arch/arm/kernel \ + arch/arm/mm arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) - -BLOCK_DRIVERS := drivers/block/block.a -CDROM_DRIVERS := drivers/cdrom/cdrom.a -ifeq ($(CONFIG_FB),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a -else -ifeq ($(CONFIG_VGA_CONSOLE),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a -else -CHAR_DRIVERS := arch/arm/drivers/char/char.a -endif -endif -MISC_DRIVERS := drivers/misc/misc.a -NET_DRIVERS := drivers/net/net.a -PARIDE_DRIVERS := drivers/block/paride/paride.a -PCI_DRIVERS := drivers/pci/pci.a -SCSI_DRIVERS := drivers/scsi/scsi.a -SOUND_DRIVERS := drivers/sound/sound.a -VIDEO_DRIVERS := drivers/video/video.a -PNP_DRIVERS := drivers/pnp/pnp.a +DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_ARCH_ACORN),y) -BLOCK_DRIVERS += drivers/acorn/block/acorn-block.a -CHAR_DRIVERS += drivers/acorn/char/acorn-char.a -NET_DRIVERS += drivers/acorn/net/acorn-net.a drivers/net/net.a -SCSI_DRIVERS += drivers/acorn/scsi/acorn-scsi.a +SUBDIRS += drivers/acorn/block drivers/acorn/char drivers/acorn/net \ + drivers/acorn/scsi +DRIVERS += drivers/acorn/block/acorn-block.a \ + drivers/acorn/char/acorn-char.a \ + drivers/acorn/net/acorn-net.a \ + drivers/acorn/scsi/acorn-scsi.a endif -DRIVERS := $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS) - -ifeq ($(CONFIG_FB),y) -DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS) -else -ifeq ($(CONFIG_VGA_CONSOLE),y) -DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS) -endif -endif -ifeq ($(CONFIG_SCSI),y) -DRIVERS := $(DRIVERS) $(SCSI_DRIVERS) -endif -ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),) -DRIVERS := $(DRIVERS) $(CDROM_DRIVERS) -endif -ifdef CONFIG_PCI -DRIVERS := $(DRIVERS) $(PCI_DRIVERS) -endif -ifeq ($(CONFIG_SOUND),y) -DRIVERS := $(DRIVERS) $(SOUND_DRIVERS) -endif -ifeq ($(CONFIG_PARIDE),y) -DRIVERS := $(DRIVERS) $(PARIDE_DRIVERS) -endif -ifdef CONFIG_PNP -DRIVERS := $(DRIVERS) $(PNP_DRIVERS) +ifeq ($(CONFIG_NWFPE),y) +DRIVERS += arch/arm/nwfpe/math-emu.a endif symlinks:: @@ -220,7 +171,7 @@ # Once we've finished integrating the sources, the @$(MAKE) will disappear archmrproper: rm -f include/asm-arm/arch include/asm-arm/proc - @$(MAKE) -C arch/$(ARCH)/drivers mrproper + @$(MAKE) -C arch/$(ARCH)/special mrproper arch/arm/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel @@ -257,4 +208,3 @@ archdep: @$(MAKEBOOT) dep -sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/boot/compressed/Makefile linux.ac/arch/arm/boot/compressed/Makefile --- linux.vanilla/arch/arm/boot/compressed/Makefile Sun Nov 8 15:08:42 1998 +++ linux.ac/arch/arm/boot/compressed/Makefile Wed Feb 24 23:48:59 1999 @@ -11,10 +11,15 @@ OBJS =$(HEAD) misc.o $(COMPRESSED_EXTRA) CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC) ARFLAGS =rc +FONTC =$(TOPDIR)/drivers/video/font_acorn_8x8.c + +ifeq ($(CONFIG_ARCH_ACORN),y) +OBJS += ll_char_wr.o font.o +endif all: vmlinux -vmlinux: piggy.o $(OBJS) +vmlinux: $(OBJS) piggy.o $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o $(HEAD): $(HEAD:.o=.S) @@ -28,6 +33,9 @@ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; + +font.o: $(FONTC) + $(CC) -Dstatic= -c -o $@ $(FONTC) clean:; rm -f vmlinux core diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S linux.ac/arch/arm/boot/compressed/ll_char_wr.S --- linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/boot/compressed/ll_char_wr.S Wed Feb 24 23:49:12 1999 @@ -0,0 +1,158 @@ +/* + * linux/arch/arm/lib/ll_char_wr.S + * + * Copyright (C) 1995, 1996 Russell King. + * + * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. + * + * 10-04-96 RMK Various cleanups & reduced register usage. + * 08-04-98 RMK Shifts re-ordered + */ + +@ Regs: [] = corruptible +@ {} = used +@ () = do not use +#define __ASSEMBLY__ +#include +#include + .text + +#define BOLD 0x01 +#define ITALIC 0x02 +#define UNDERLINE 0x04 +#define FLASH 0x08 +#define INVERSE 0x10 + +LC0: .word SYMBOL_NAME(bytes_per_char_h) + .word SYMBOL_NAME(video_size_row) + .word SYMBOL_NAME(acorndata_8x8) + .word SYMBOL_NAME(con_charconvtable) + +ENTRY(ll_write_char) + stmfd sp!, {r4 - r7, lr} +@ +@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ + eor ip, r1, #UNDERLINE << 9 +/* + * calculate colours + */ + tst r1, #INVERSE << 9 + moveq r2, r1, lsr #16 + moveq r3, r1, lsr #24 + movne r2, r1, lsr #24 + movne r3, r1, lsr #16 + and r3, r3, #255 + and r2, r2, #255 +/* + * calculate offset into character table + */ + mov r1, r1, lsl #23 + mov r1, r1, lsr #20 +/* + * calculate offset required for each row [maybe I should make this an argument to this fn. + * Have to see what the register usage is like in the calling routines. + */ + adr r4, LC0 + ldmia r4, {r4, r5, r6, lr} + ldr r4, [r4] + ldr r5, [r5] +/* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + eor r2, r3, r2 @ Create eor mask to change colour from bg + orr r3, r3, r3, lsl #8 @ to fg. + orr r3, r3, r3, lsl #16 + add r0, r0, r5, lsl #3 @ Move to bottom of character + add r1, r1, #7 + ldrb r7, [r6, r1] + tst ip, #UNDERLINE << 9 + eoreq r7, r7, #255 + teq r4, #8 + beq Lrow8bpplp +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ + orr r3, r3, r3, lsl #4 +Lrow4bpplp: ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ +Lrow8bpplp: mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ +Lrow1bpp: add r6, r6, r1 + ldmia r6, {r4, r7} + tst ip, #INVERSE << 9 + mvnne r4, r4 + mvnne r7, r7 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + tst ip, #UNDERLINE << 9 + mvneq r7, r7 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) + + .bss +ENTRY(con_charconvtable) + .space 1024 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/config.in linux.ac/arch/arm/config.in --- linux.vanilla/arch/arm/config.in Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/arm/config.in Tue Feb 9 21:43:52 1999 @@ -14,18 +14,25 @@ A5000 CONFIG_ARCH_A5K \ RiscPC CONFIG_ARCH_RPC \ EBSA-110 CONFIG_ARCH_EBSA110 \ - EBSA-285 CONFIG_ARCH_EBSA285 \ - NexusPCI CONFIG_ARCH_NEXUSPCI \ - Corel-VNC CONFIG_ARCH_VNC \ - Tbox CONFIG_ARCH_TBOX" RiscPC + FootBridge-based CONFIG_FOOTBRIDGE" RiscPC -if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then - bool ' Include support for CATS boards' CONFIG_CATS +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE + if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_ADDIN_FOOTBRIDGE y + else + define_bool CONFIG_ADDIN_FOOTBRIDGE n + fi +fi + +if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285 + bool ' Include support for Chalice CATS boards' CONFIG_CATS + bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER fi # Select various configuration options depending on the machine type # Easy check for Acorn-style architectures - if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -34,23 +41,19 @@ define_bool CONFIG_ARCH_ACORN n fi -if [ "$CONFIG_ARCH_TBOX" = "y" ]; then - define_bool CONFIG_BUS_I2C y -fi +#if [ "$CONFIG_ARCH_TBOX" = "y" ]; then +# define_bool CONFIG_BUS_I2C y +#fi # These machines always have PCI - if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then + "$CONFIG_FOOTBRIDGE" = "y" ]; then define_bool CONFIG_PCI y fi -if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then - bool "PCI support" CONFIG_PCI -fi # These machines have ISA-DMA if [ "$CONFIG_CATS" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then + "$CONFIG_ARCH_NETWINDER" = "y" ]; then define_bool CONFIG_ISA_DMA y else define_bool CONFIG_ISA_DMA n @@ -59,7 +62,6 @@ # Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has # ever built a machine that can take both, and now that ARM3 is obsolete # nobody is likely to either. - if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" ]; then define_bool CONFIG_CPU_32 n @@ -71,7 +73,6 @@ # Now allow the user to choose a more precise CPU. This is only used to set # the flags we pass to GCC, not in any code. - choice 'Optimise for CPU' \ "ARM2 CONFIG_CPU_ARM2 \ ARM3 CONFIG_CPU_ARM3 \ @@ -80,22 +81,21 @@ SA110 CONFIG_CPU_SA110" ARM6 if [ "$CONFIG_CPU_26" = "y" ]; then - # For 26-bit CPUs, the page size changes with the amount of physical RAM! # The default is 4MB but if the user has less they have to own up to it here. - choice 'Physical memory size' \ "4MB+ CONFIG_PAGESIZE_32 \ - 2MB CONFIG_PAGESIZE_16 \ - 1MB/512K CONFIG_PAGESIZE_8" 4MB+ + 2MB CONFIG_PAGESIZE_16" 4MB+ fi endmenu mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL -bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW -bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER +if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP +fi +bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS endmenu mainmenu_option next_comment @@ -113,13 +113,16 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Math emulation' CONFIG_NWFPE tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + if [ "$CONFIG_ARCH_ARC" = "y" ]; then + dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + fi dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT # If exactly one hardware type is selected then parport will optimise away # support for loading any others. Defeat this if the user is keen. @@ -129,11 +132,23 @@ fi fi fi -if [ "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then +if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_CATS" = "y" ]; then string 'Initial kernel command string' CONFIG_CMDLINE fi +if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" ]; then + bool 'Timer and CPU usage LEDs' CONFIG_LEDS + if [ "$CONFIG_LEDS" = "y" ]; then + if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" ]; then + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU + fi + fi +fi endmenu source drivers/pnp/Config.in @@ -144,13 +159,15 @@ source drivers/acorn/block/Config.in fi -if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then - source arch/arm/drivers/char/Config.in -else - source drivers/char/Config.in -fi +source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - source drivers/acorn/char/Config.in + if [ "$CONFIG_MOUSE" = "y" ]; then + if [ "$CONFIG_ARCH_RPC" != "y" ]; then + define_bool CONFIG_KBDMOUSE y + else + define_bool CONFIG_RPCMOUSE y + fi + fi fi if [ "$CONFIG_VT" = "y" ]; then @@ -166,9 +183,11 @@ if [ "$CONFIG_NET" = "y" ]; then source net/Config.in -fi -if [ "$CONFIG_NET" = "y" ]; then + source net/ax25/Config.in + + source net/irda/Config.in + mainmenu_option next_comment comment 'Network device support' @@ -179,6 +198,15 @@ endmenu fi +# mainmenu_option next_comment +# comment 'ISDN subsystem' +# +# tristate 'ISDN support' CONFIG_ISDN +# if [ "$CONFIG_ISDN" != "n" ]; then +# source drivers/isdn/Config.in +# fi +# endmenu + mainmenu_option next_comment comment 'SCSI support' @@ -200,21 +228,21 @@ endmenu fi -# mainmenu_option next_comment -# comment 'ISDN subsystem' -# -# tristate 'ISDN support' CONFIG_ISDN -# if [ "$CONFIG_ISDN" != "n" ]; then -# source drivers/isdn/Config.in -# fi -# endmenu - source fs/Config.in mainmenu_option next_comment comment 'Kernel hacking' -bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS +bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER +bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS +bool 'Verbose user fault messages' CONFIG_DEBUG_USER +bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +if [ "$CONFIG_CPU_26" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE +fi +if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'RISC OS personality' CONFIG_ARTHUR +fi endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/defconfig linux.ac/arch/arm/defconfig --- linux.vanilla/arch/arm/defconfig Wed Mar 10 21:13:00 1999 +++ linux.ac/arch/arm/defconfig Sun Mar 7 19:57:10 1999 @@ -4,47 +4,70 @@ CONFIG_ARM=y # +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +CONFIG_FOOTBRIDGE=y +CONFIG_HOST_FOOTBRIDGE=y +CONFIG_ADDIN_FOOTBRIDGE=y +CONFIG_ARCH_EBSA285=y +# CONFIG_CATS is not set +CONFIG_ARCH_NETWINDER=y +# CONFIG_ARCH_ACORN is not set +CONFIG_PCI=y +CONFIG_ISA_DMA=y +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM2 is not set +# CONFIG_CPU_ARM3 is not set +# CONFIG_CPU_ARM6 is not set +# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_SA110=y + +# # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set # # Loadable module support # CONFIG_MODULES=y -CONFIG_MODVERSIONS=y +# CONFIG_MODVERSIONS is not set CONFIG_KMOD=y # # General setup # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -CONFIG_ARCH_RPC=y -# CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_NEXUSPCI is not set -CONFIG_ARCH_ACORN=y -# CONFIG_PCI is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -CONFIG_CPU_SA110=y -CONFIG_FRAME_POINTER=y -# CONFIG_BINUTILS_NEW is not set -CONFIG_DEBUG_ERRORS=y CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_NWFPE=y CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=m -# CONFIG_BINFMT_JAVA is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,23 ide0=autotune" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +# CONFIG_LEDS_CPU is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set # -# Floppy, IDE, and other block devices +# Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -52,46 +75,177 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_IDE_PCMCIA is not set -CONFIG_BLK_DEV_IDE_CARDS=y -CONFIG_BLK_DEV_IDE_ICSIDE=y -# CONFIG_BLK_DEV_IDE_RAPIDE is not set -# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_OFFBOARD=y +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set # # Additional Block Devices # CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m +CONFIG_MD_MIRRORING=m +CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_PART=y +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m # CONFIG_BLK_DEV_HD is not set # +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=m +CONFIG_PRINTER_READBACK=y +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +CONFIG_WATCHDOG=y + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WDT is not set +CONFIG_SOFT_WATCHDOG=y +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +CONFIG_DS1620=y +CONFIG_NWBUTTON=y +CONFIG_NWBUTTON_REBOOT=y +# CONFIG_NVRAM is not set +CONFIG_RTC=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_CYBER2000=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +CONFIG_FONT_ACORN_8x8=y + +# # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set +CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ACCT is not set -# CONFIG_IP_MASQUERADE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +CONFIG_IP_ALIAS=y # CONFIG_SYN_COOKIES is not set # @@ -99,7 +253,7 @@ # # CONFIG_INET_RARP is not set CONFIG_IP_NOSR=y -# CONFIG_SKB_LARGE is not set +CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # @@ -111,155 +265,227 @@ # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_PROFILE is not set # -# SCSI support +# Amateur Radio support # -CONFIG_SCSI=y +# CONFIG_HAMRADIO is not set # -# SCSI support type (disk, tape, CD-ROM) +# IrDA subsystem support # -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -CONFIG_BLK_DEV_SR=y -# CONFIG_BLK_DEV_SR_VENDOR is not set -# CONFIG_CHR_DEV_SG is not set +# CONFIG_IRDA is not set # -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# Network device support # -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_3C515 is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_DE4X5 is not set +CONFIG_DEC_ELCP=m +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +CONFIG_NE2K_PCI=y +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_DLCI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m # -# SCSI low-level drivers +# CCP compressors for PPP are only built as modules. # -CONFIG_SCSI_ACORNSCSI_3=m -CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y -CONFIG_SCSI_ACORNSCSI_SYNC=y -CONFIG_SCSI_CUMANA_2=m -CONFIG_SCSI_POWERTECSCSI=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set # -# The following drives are not fully supported +# SCSI support # -CONFIG_SCSI_CUMANA_1=m -CONFIG_SCSI_OAK1=m -CONFIG_SCSI_PPA=m -CONFIG_SCSI_PPA_HAVE_PEDANTIC=2 +# CONFIG_SCSI is not set # -# Network device support +# Sound # -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_PPP=m +CONFIG_SOUND=m +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_SB is not set +CONFIG_SOUND_ADLIB=m +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +CONFIG_SOUND_OPL3SA2=m +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_VIDC is not set +CONFIG_SOUND_WAVEARTIST=m +CONFIG_WAVEARTIST_BASE=250 +CONFIG_WAVEARTIST_IRQ=28 +CONFIG_WAVEARTIST_DMA=5 +CONFIG_WAVEARTIST_DMA2=9 # -# CCP compressors for PPP are only built as modules. +# Additional low level sound drivers # -# CONFIG_SLIP is not set -CONFIG_ETHER1=m -CONFIG_ETHER3=m -CONFIG_ETHERH=m +# CONFIG_LOWLEVEL_SOUND is not set # # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -CONFIG_NFSD=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_ADFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -CONFIG_ADFS_FS=y -CONFIG_ADFS_FS=y -# CONFIG_MAC_PARTITION is not set -CONFIG_NLS=y # -# Native Language Support +# Network File Systems # -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set # -# Character devices +# Partition Types # -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -CONFIG_ATOMWIDE_SERIAL=y -CONFIG_DUALSP_SERIAL=y -CONFIG_MOUSE=y -CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -# CONFIG_UMISC is not set -# CONFIG_WATCHDOG is not set -CONFIG_RPCMOUSE=y +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ADFS=y +# CONFIG_ACORN_PARTITION_ICS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +# CONFIG_ACORN_PARTITION_RISCIX is not set +CONFIG_NLS=y # -# Sound +# Native Language Support # -CONFIG_SOUND=m -CONFIG_VIDC=y -CONFIG_AUDIO=y -DSP_BUFFSIZE=65536 +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_KOI8_R=m # # Kernel hacking # +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_ARTHUR is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/Makefile linux.ac/arch/arm/kernel/Makefile --- linux.vanilla/arch/arm/kernel/Makefile Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/Makefile Tue Jan 26 21:58:36 1999 @@ -9,31 +9,39 @@ ENTRY_OBJ = entry-$(PROCESSOR).o O_TARGET := kernel.o -O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \ +O_OBJS := $(ENTRY_OBJ) irq.o process.o ptrace.o setup.o \ signal.o sys_arm.o time.o traps.o -DMA_OBJS_arc = dma-arc.o -DMA_OBJS_a5k = dma-a5k.o -DMA_OBJS_rpc = dma-rpc.o -DMA_OBJS_ebsa110 = dma-dummy.o -DMA_OBJS_ebsa285 = dma-ebsa285.o -DMA_OBJS_nexuspci = -DMA_OBJS_vnc = dma-vnc.o - -O_OBJS_arc = ecard.o iic.o fiq.o oldlatches.o -O_OBJS_a5k = ecard.o iic.o fiq.o -O_OBJS_rpc = ecard.o iic.o fiq.o -O_OBJS_ebsa110 = leds-ebsa110.o -O_OBJS_ebsa285 = leds-ebsa285.o hw-ebsa285.o -O_OBJS_nexuspci = -O_OBJS_vnc = leds-ebsa285.o hw-vnc.o +ifeq ($(CONFIG_ISA_DMA),y) + ISA_DMA_OBJS += dma-isa.o +endif + +O_OBJS_arc = dma-arc.o iic.o fiq.o oldlatches.o +O_OBJS_a5k = dma-a5k.o iic.o fiq.o +O_OBJS_rpc = dma-rpc.o iic.o fiq.o +O_OBJS_ebsa110 = dma-dummy.o +O_OBJS_ebsa285 = dma-ebsa285.o $(ISA_DMA_OBJS) +O_OBJS_nexuspci = dma-dummy.o +O_OBJS_co285 = dma-ebsa285.o $(ISA_DMA_OBJS) + +OX_OBJS_arc = dma.o +OX_OBJS_a5k = dma.o +OX_OBJS_rpc = dma.o +OX_OBJS_ebsa110 = +OX_OBJS_ebsa285 = dma.o hw-ebsa285.o +OX_OBJS_nexuspci = +OX_OBJS_co285 = dma.o all: lib kernel.o $(HEAD_OBJ) init_task.o +O_OBJS += $(O_OBJS_$(MACHINE)) + ifeq ($(CONFIG_MODULES),y) OX_OBJS = armksyms.o -else - O_OBJS += armksyms.o +endif + +ifeq ($(CONFIG_ARCH_ACORN),y) + OX_OBJS += ecard.o endif ifeq ($(MACHINE),nexuspci) @@ -46,17 +54,23 @@ endif endif -ifneq ($(DMA_OBJS_$(MACHINE)),) - OX_OBJS += dma.o - O_OBJS += $(DMA_OBJS_$(MACHINE)) - ifeq ($(CONFIG_ISA_DMA),y) - O_OBJS += dma-isa.o - endif +ifdef CONFIG_LEDS + O_OBJS += leds-$(MACHINE).o +endif + +ifeq ($(CONFIG_MODULES),y) + OX_OBJS += $(OX_OBJS_$(MACHINE)) else - O_OBJS += dma-dummy.o + O_OBJS += $(OX_OBJS_$(MACHINE)) endif -O_OBJS += $(O_OBJS_$(MACHINE)) +ifeq ($(CONFIG_ARTHUR),y) + O_OBJS += arthur.o +else + ifeq ($(CONFIG_ARTHUR),m) + M_OBJS += arthur.o + endif +endif $(HEAD_OBJ): $(HEAD_OBJ:.o=.S) $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ @@ -72,3 +86,7 @@ lib: $(MAKE) -C ../lib constants.h + +# Spell out some dependencies that `make dep' doesn't spot +entry-armv.o: calls.S +entry-armo.o: calls.S diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/armksyms.c linux.ac/arch/arm/kernel/armksyms.c --- linux.vanilla/arch/arm/kernel/armksyms.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/armksyms.c Sun Feb 28 15:21:17 1999 @@ -7,11 +7,11 @@ #include #include -#include #include #include #include #include +#include #include #include @@ -20,6 +20,19 @@ extern void inswb(unsigned int port, void *to, int len); extern void outswb(unsigned int port, const void *to, int len); +extern unsigned int local_bh_count[NR_CPUS]; +extern unsigned int local_irq_count[NR_CPUS]; + +/* + * syscalls + */ +extern int sys_write(int, const char *, int); +extern int sys_read(int, char *, int); +extern int sys_lseek(int, off_t, int); +extern int sys_open(const char *, int, int); +extern int sys_exit(int); +extern int sys_wait4(int, int *, int, struct rusage *); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -43,6 +56,8 @@ extern void __umoddi3(void); extern void __umodsi3(void); +extern void ret_from_exception(void); +extern void fpundefinstr(void); extern void fp_enter(void); #define EXPORT_SYMBOL_ALIAS(sym,orig) \ const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \ @@ -57,19 +72,18 @@ EXPORT_SYMBOL_ALIAS(fp_printk,printk); EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); +#ifdef CONFIG_CPU_26 +EXPORT_SYMBOL(fpundefinstr); +EXPORT_SYMBOL(ret_from_exception); +#endif + /* platform dependent support */ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(xchg_str); - - /* expansion card support */ -#ifdef CONFIG_ARCH_ACORN -EXPORT_SYMBOL(ecard_startfind); -EXPORT_SYMBOL(ecard_find); -EXPORT_SYMBOL(ecard_readchunk); -EXPORT_SYMBOL(ecard_address); -#endif +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -79,10 +93,12 @@ EXPORT_SYMBOL(machine_type); /* io */ -EXPORT_SYMBOL(outswb); +EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); -EXPORT_SYMBOL(inswb); +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); +EXPORT_SYMBOL(insl); /* address translation */ #ifndef __virt_to_phys__is_a_macro @@ -98,7 +114,9 @@ EXPORT_SYMBOL(__bus_to_virt); #endif +#ifndef CONFIG_NO_PGT_CACHE EXPORT_SYMBOL(quicklists); +#endif EXPORT_SYMBOL(__bad_pmd); EXPORT_SYMBOL(__bad_pmd_kernel); @@ -167,3 +185,17 @@ EXPORT_SYMBOL(armidlist); EXPORT_SYMBOL(armidindex); EXPORT_SYMBOL(elf_platform); + + /* syscalls */ +EXPORT_SYMBOL(sys_write); +EXPORT_SYMBOL(sys_read); +EXPORT_SYMBOL(sys_lseek); +EXPORT_SYMBOL(sys_open); +EXPORT_SYMBOL(sys_exit); +EXPORT_SYMBOL(sys_wait4); + + /* semaphores */ +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); +EXPORT_SYMBOL_NOVERS(__up_wakeup); + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/arthur.c linux.ac/arch/arm/kernel/arthur.c --- linux.vanilla/arch/arm/kernel/arthur.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/kernel/arthur.c Sun Jan 3 10:05:59 1999 @@ -0,0 +1,88 @@ +/* + * Arthur personality + * Copyright (C) 1998 Philip Blundell + */ + +#include +#include +#include +#include +#include + +#include + +/* RISC OS doesn't have many signals, and a lot of those that it does + have don't map easily to any Linux equivalent. Never mind. */ + +#define RISCOS_SIGABRT 1 +#define RISCOS_SIGFPE 2 +#define RISCOS_SIGILL 3 +#define RISCOS_SIGINT 4 +#define RISCOS_SIGSEGV 5 +#define RISCOS_SIGTERM 6 +#define RISCOS_SIGSTAK 7 +#define RISCOS_SIGUSR1 8 +#define RISCOS_SIGUSR2 9 +#define RISCOS_SIGOSERROR 10 + +static unsigned long riscos_to_linux_signals[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static unsigned long linux_to_riscos_signals[32] = { + 0, -1, RISCOS_SIGINT, -1, + RISCOS_SIGILL, 5, RISCOS_SIGABRT, 7, + RISCOS_SIGFPE, 9, RISCOS_SIGUSR1, RISCOS_SIGSEGV, + RISCOS_SIGUSR2, 13, 14, RISCOS_SIGTERM, + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31 +}; + +static void arthur_lcall7(int nr, struct pt_regs *regs) +{ + struct siginfo info; + info.si_signo = SIGSWI; + info.si_code = nr; + /* Bounce it to the emulator */ + send_sig_info(SIGSWI, &info, current); +} + +static struct exec_domain riscos_exec_domain = { + "Arthur", /* name */ + (lcall7_func)arthur_lcall7, + PER_RISCOS, PER_RISCOS, + riscos_to_linux_signals, + linux_to_riscos_signals, +#ifdef MODULE + &__this_module, /* No usage counter. */ +#else + NULL, +#endif + NULL /* Nothing after this in the list. */ +}; + +/* + * We could do with some locking to stop Arthur being removed while + * processes are using it. + */ + +#ifdef MODULE +int init_module(void) +#else +int initialise_arthur(void) +#endif +{ + return register_exec_domain(&riscos_exec_domain); +} + +#ifdef MODULE +void cleanup_module(void) +{ + unregister_exec_domain(&riscos_exec_domain); +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/calls.S linux.ac/arch/arm/kernel/calls.S --- linux.vanilla/arch/arm/kernel/calls.S Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/calls.S Mon Jan 18 23:01:57 1999 @@ -110,7 +110,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */ .long SYMBOL_NAME(sys_statfs) /* 100 */ .long SYMBOL_NAME(sys_fstatfs) - .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_ioperm */ + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_socketcall) .long SYMBOL_NAME(sys_syslog) .long SYMBOL_NAME(sys_setitimer) @@ -119,7 +119,7 @@ .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) .long SYMBOL_NAME(sys_uname) -/* 110 */ .long SYMBOL_NAME(sys_iopl) +/* 110 */ .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_vhangup) .long SYMBOL_NAME(sys_idle) .long SYMBOL_NAME(sys_syscall) /* call a syscall */ @@ -196,6 +196,10 @@ .long SYMBOL_NAME(sys_capget) /* 185 */ .long SYMBOL_NAME(sys_capset) .long SYMBOL_NAME(sys_sigaltstack_wrapper) + .long SYMBOL_NAME(sys_sendfile) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) +/* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper) .rept NR_syscalls-186 .long SYMBOL_NAME(sys_ni_syscall) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dec21285.c linux.ac/arch/arm/kernel/dec21285.c --- linux.vanilla/arch/arm/kernel/dec21285.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dec21285.c Fri Jan 22 09:06:54 1999 @@ -17,8 +17,6 @@ extern void pcibios_fixup_ebsa285(struct pci_dev *dev); extern void pcibios_init_ebsa285(void); -extern void pcibios_fixup_vnc(struct pci_dev *dev); -extern void pcibios_init_vnc(void); int pcibios_present(void) @@ -151,10 +149,7 @@ struct pci_dev *dev; for (dev = pci_devices; dev; dev = dev->next) { - if (machine_is_ebsa285() || machine_is_cats()) - pcibios_fixup_ebsa285(dev); - if (machine_is_netwinder()) - pcibios_fixup_vnc(dev); + pcibios_fixup_ebsa285(dev); pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); @@ -164,18 +159,18 @@ dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->irq); } + /* + * this ought to have a better home + */ if (machine_is_netwinder()) hw_init(); } __initfunc(void pcibios_init(void)) { - if (machine_is_ebsa285() || machine_is_cats()) - pcibios_init_ebsa285(); - if (machine_is_netwinder()) - pcibios_init_vnc(); + pcibios_init_ebsa285(); - printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008); + printk(KERN_DEBUG "PCI: DEC21285 revision %02X\n", *(unsigned char *)0xfe000008); } __initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-a5k.c linux.ac/arch/arm/kernel/dma-a5k.c --- linux.vanilla/arch/arm/kernel/dma-a5k.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dma-a5k.c Tue Feb 2 20:31:32 1999 @@ -37,8 +37,9 @@ if (channel != DMA_VIRTUAL_FLOPPY) printk("arch_dma_count: invalid channel %d\n", channel); else { - extern int floppy_fiqresidual(void); - return floppy_fiqresidual(); + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; } return 0; } @@ -48,6 +49,7 @@ if (channel != DMA_VIRTUAL_FLOPPY) printk("arch_enable_dma: invalid channel %d\n", channel); else { + struct pt_regs regs; void *fiqhandler_start; unsigned int fiqhandler_length; extern void floppy_fiqsetup(unsigned long len, unsigned long addr, @@ -67,8 +69,10 @@ return; } memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); - flush_page_to_ram(0); - floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE); + regs.ARM_r9 = dma->buf.length; + regs.ARM_r10 = __bus_to_virt(dma->buf.address); + regs.ARM_fp = (int)PCIO_FLOPPYDMABASE; + set_fiq_regs(®s); enable_irq(dma->dma_irq); } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-arc.c linux.ac/arch/arm/kernel/dma-arc.c --- linux.vanilla/arch/arm/kernel/dma-arc.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/dma-arc.c Tue Feb 2 20:17:01 1999 @@ -1,10 +1,11 @@ /* * arch/arm/kernel/dma-arc.c * - * Copyright (C) 1998 Dave Gilbert / Russell King + * Copyright (C) 1998-1999 Dave Gilbert / Russell King * * DMA functions specific to Archimedes architecture */ +#include #include #include @@ -14,7 +15,7 @@ #include "dma.h" -int arch_request_dma(dmach_t channel, dma_t *dma) +int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id) { if (channel == DMA_VIRTUAL_FLOPPY0 || channel == DMA_VIRTUAL_FLOPPY1) @@ -25,16 +26,12 @@ void arch_free_dma(dmach_t channel, dma_t *dma) { - if (channel != DMA_VIRTUAL_FLOPPY0 && - channel != DMA_VIRTUAL_FLOPPY1) - return 0; - else - return -EINVAL; } void arch_enable_dma(dmach_t channel, dma_t *dma) { switch (channel) { +#ifdef CONFIG_BLK_DEV_FD case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ switch (dma->dma_mode) { case DMA_MODE_READ: /* read */ @@ -96,7 +93,36 @@ restore_flags(flags); } break; +#endif } +} + +int arch_get_dma_residue(dmach_t channel, dma_t *dma) +{ + switch (channel) { +#ifdef CONFIG_BLK_DEV_FD + case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ + extern unsigned int fdc1772_bytestogo; + + /* 10/1/1999 DAG - I presume its the number of bytes left? */ + return fdc1772_bytestogo; + }; + break; + + case DMA_VIRTUAL_FLOPPY1: { /* Command completed */ + /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ + extern unsigned int fdc1772_fdc_int_done; + + return (fdc1772_fdc_int_done==0)?1:0; /* Explicit! If the int done is 0 then 1 int to go */ + }; + break; + +#endif + + default: + printk("dma-arc.c:arch_get_dma_residue called with unknown/unconfigured DMA channel\n"); + return 0; + }; } void arch_disable_dma(dmach_t channel, dma_t *dma) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-dummy.c linux.ac/arch/arm/kernel/dma-dummy.c --- linux.vanilla/arch/arm/kernel/dma-dummy.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/dma-dummy.c Wed Feb 3 23:03:24 1999 @@ -9,6 +9,10 @@ #include #include +#include + +spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; + int request_dma(int channel, const char *device_id) { return -EINVAL; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-ebsa285.c linux.ac/arch/arm/kernel/dma-ebsa285.c --- linux.vanilla/arch/arm/kernel/dma-ebsa285.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dma-ebsa285.c Fri Jan 22 09:07:31 1999 @@ -30,10 +30,11 @@ case 0: case 1: /* 21285 internal channels */ return 0; - +#ifdef CONFIG_ISA_DMA case 2 ... 9: - if (machine_is_cats()) + if (machine_is_cats() || machine_is_netwinder()) return isa_request_dma(channel - 2, dma, dev_name); +#endif } return -EINVAL; @@ -52,10 +53,9 @@ case 0: case 1: break; -#ifdef CONFIG_CATS +#ifdef CONFIG_ISA_DMA case 2 ... 9: - if (machine_is_cats()) - residue = isa_get_dma_residue(channel - 2); + residue = isa_get_dma_residue(channel - 2, dma); #endif } return residue; @@ -70,10 +70,9 @@ * Not yet implemented */ break; -#ifdef CONFIG_CATS +#ifdef CONFIG_ISA_DMA case 2 ... 9: - if (machine_is_cats()) - isa_enable_dma(channel - 2, dma); + isa_enable_dma(channel - 2, dma); #endif } } @@ -87,15 +86,17 @@ * Not yet implemented */ break; -#ifdef CONFIG_CATS +#ifdef CONFIG_ISA_DMA case 2 ... 9: - if (machine_is_cats()) - isa_disable_dma(channel - 2, dma); + isa_disable_dma(channel - 2, dma); #endif } } __initfunc(void arch_dma_init(dma_t *dma)) { - /* Nothing to do */ +#ifdef CONFIG_ISA_DMA + if (machine_is_cats() || machine_is_netwinder()) + isa_init_dma(); +#endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-isa.c linux.ac/arch/arm/kernel/dma-isa.c --- linux.vanilla/arch/arm/kernel/dma-isa.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dma-isa.c Tue Feb 2 20:29:26 1999 @@ -11,6 +11,7 @@ * Copyright (C) 1998 Phil Blundell */ #include +#include #include #include @@ -18,6 +19,11 @@ #include "dma.h" #include "dma-isa.h" +#define ISA_DMA_MODE_READ 0x44 +#define ISA_DMA_MODE_WRITE 0x48 +#define ISA_DMA_MODE_CASCADE 0xc0 +#define ISA_DMA_AUTOINIT 0x10 + #define ISA_DMA_MASK 0 #define ISA_DMA_MODE 1 #define ISA_DMA_CLRFF 2 @@ -56,25 +62,27 @@ unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; int count; - count = 1 + inb(io_port) + (inb(io_port) << 8); + count = 1 + inb(io_port); + count |= inb(io_port) << 8; return channel < 4 ? count : (count << 1); } void isa_enable_dma(int channel, dma_t *dma) { - unsigned long address, length; - if (dma->invalid) { + unsigned long address, length; + unsigned int mode; + address = dma->buf.address; length = dma->buf.length - 1; - outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); + outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); if (channel >= 4) { address >>= 1; - length = (length >> 1) & 0xfe; /* why &0xfe? */ + length >>= 1; } outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); @@ -85,17 +93,31 @@ outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); - outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]); + mode = channel & 3; - switch (dma->dma_mode) { + switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: + mode |= ISA_DMA_MODE_READ; dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length); break; case DMA_MODE_WRITE: + mode |= ISA_DMA_MODE_WRITE; dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length); break; + + case DMA_MODE_CASCADE: + mode |= ISA_DMA_MODE_CASCADE; + break; + + default: + break; } + + if (dma->dma_mode & DMA_AUTOINIT) + mode |= ISA_DMA_AUTOINIT; + + outb(mode, isa_dma_port[channel][ISA_DMA_MODE]); dma->invalid = 0; } outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); @@ -104,4 +126,39 @@ void isa_disable_dma(int channel, dma_t *dma) { outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); +} + +__initfunc(void isa_init_dma(void)) +{ + int channel; + + outb(0xff, 0x0d); + outb(0xff, 0xda); + + for (channel = 0; channel < 8; channel++) + isa_disable_dma(channel, NULL); + + outb(0x40, 0x0b); + outb(0x41, 0x0b); + outb(0x42, 0x0b); + outb(0x43, 0x0b); + + outb(0xc0, 0xd6); + outb(0x41, 0xd6); + outb(0x42, 0xd6); + outb(0x43, 0xd6); + + outb(0, 0xd4); + + outb(0x10, 0x08); + outb(0x10, 0xd0); + + outb(0x30, 0x40b); + outb(0x31, 0x40b); + outb(0x32, 0x40b); + outb(0x33, 0x40b); + + outb(0x31, 0x4d6); + outb(0x32, 0x4d6); + outb(0x33, 0x4d6); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-isa.h linux.ac/arch/arm/kernel/dma-isa.h --- linux.vanilla/arch/arm/kernel/dma-isa.h Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dma-isa.h Sun Dec 27 21:51:17 1998 @@ -23,3 +23,7 @@ */ void isa_disable_dma(int channel, dma_t *dma); +/* + * Initialise DMA + */ +void isa_init_dma(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-rpc.c linux.ac/arch/arm/kernel/dma-rpc.c --- linux.vanilla/arch/arm/kernel/dma-rpc.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/dma-rpc.c Tue Feb 2 20:31:32 1999 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -223,8 +224,9 @@ break; case DMA_VIRTUAL_FLOPPY: { - extern int floppy_fiqresidual(void); - residue = floppy_fiqresidual(); + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; } break; } @@ -286,7 +288,6 @@ set_fiq_handler(fiqhandler_start, fiqhandler_length); set_fiq_regs(®s); enable_irq(dma->dma_irq); - } break; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-vnc.c linux.ac/arch/arm/kernel/dma-vnc.c --- linux.vanilla/arch/arm/kernel/dma-vnc.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/dma-vnc.c Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -/* - * arch/arm/kernel/dma-vnc.c - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "dma.h" -#include "dma-isa.h" - -int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) -{ - if (channel < 8) - return isa_request_dma(channel, dma, dev_name); - return -EINVAL; -} - -void arch_free_dma(dmach_t channel, dma_t *dma) -{ - isa_free_dma(channel, dma); -} - -int arch_get_dma_residue(dmach_t channel, dma_t *dma) -{ - return isa_get_dma_residue(channel, dma); -} - -void arch_enable_dma(dmach_t channel, dma_t *dma) -{ - isa_enable_dma(channel, dma); -} - -void arch_disable_dma(dmach_t channel, dma_t *dma) -{ - isa_disable_dma(channel, dma); -} - -__initfunc(void arch_dma_init(dma_t *dma)) -{ - /* Nothing to do */ -} - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/ecard.c linux.ac/arch/arm/kernel/ecard.c --- linux.vanilla/arch/arm/kernel/ecard.c Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/arm/kernel/ecard.c Sun Feb 28 09:55:43 1999 @@ -7,32 +7,41 @@ * * Created from information from Acorns RiscOS3 PRMs * - * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether podule slot. + * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether + * podule slot. * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. - * 12-Sep-1997 RMK Created new handling of interrupt enables/disables - cards can - * now register their own routine to control interrupts (recommended). - * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from - * Linux. (Caused cards not to respond under RiscOS without hard reset). + * 12-Sep-1997 RMK Created new handling of interrupt enables/disables + * - cards can now register their own routine to control + * interrupts (recommended). + * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled + * on reset from Linux. (Caused cards not to respond + * under RiscOS without hard reset). * 15-Feb-1998 RMK Added DMA support * 12-Sep-1998 RMK Added EASI support + * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. */ #define ECARD_C +#define __KERNEL_SYSCALLS__ #include +#include #include #include #include #include #include #include +#include +#include #include -#include -#include +#include #include +#include +#include #include -#include +#include #ifdef CONFIG_ARCH_ARC #include @@ -40,45 +49,419 @@ #define oldlatch_init() #endif -#define BLACKLIST_NAME(m,p,s) { m, p, NULL, s } -#define BLACKLIST_LOADER(m,p,l) { m, p, l, NULL } -#define BLACKLIST_NOLOADER(m,p) { m, p, noloader, blacklisted_str } -#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +enum req { + req_readbytes, + req_reset +}; -extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[]; -static const char blacklisted_str[] = "*loader s/w is not 32-bit compliant*"; +struct ecard_request { + enum req req; + ecard_t *ec; + unsigned int address; + unsigned int length; + unsigned int use_loader; + void *buffer; +}; -static const struct expcard_blacklist { +struct expcard_blacklist { unsigned short manufacturer; unsigned short product; - const loader_t loader; const char *type; -} blacklist[] = { -/* Cards without names */ - BLACKLIST_NAME(MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1"), - -/* Cards with corrected loader */ - BLACKLIST_LOADER(MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader), - BLACKLIST_LOADER(MANU_OAK, PROD_OAK_SCSI, oak_scsi_loader), +}; -/* Supported cards with broken loader */ - { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI" }, +static ecard_t *cards; +static ecard_t *slot_to_expcard[MAX_ECARDS]; +#ifdef HAS_EXPMASK +static unsigned int have_expmask; +#endif -/* Unsupported cards with no loader */ - BLACKLIST_NOLOADER(MANU_MCS, PROD_MCS_CONNECT32) +/* List of descriptions of cards which don't have an extended + * identification, or chunk directories containing a description. + */ +static const struct expcard_blacklist __init blacklist[] = { + { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } }; +asmlinkage extern int +ecard_loader_reset(volatile unsigned char *pa, loader_t loader); +asmlinkage extern int +ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); extern int setup_arm_irq(int, struct irqaction *); +extern void do_ecard_IRQ(int, struct pt_regs *); + + +static void +ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs); + +static struct irqaction irqexpansioncard = { + ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL +}; + +static inline unsigned short +ecard_getu16(unsigned char *v) +{ + return v[0] | v[1] << 8; +} + +static inline signed long +ecard_gets24(unsigned char *v) +{ + return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); +} +static inline ecard_t * +slot_to_ecard(unsigned int slot) +{ + return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; +} + +/* ===================== Expansion card daemon ======================== */ /* - * from linux/arch/arm/kernel/irq.c + * Since the loader programs on the expansion cards need to be run + * in a specific environment, create a separate task with this + * environment up, and pass requests to this task as and when we + * need to. + * + * This should allow 99% of loaders to be called from Linux. + * + * From a security standpoint, we trust the card vendors. This + * may be a misplaced trust. */ -extern void do_ecard_IRQ(int irq, struct pt_regs *); +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +#define POD_INT_ADDR(x) ((volatile unsigned char *)\ + ((BUS_ADDR((x)) - IO_BASE) + IO_START)) -static ecard_t expcard[MAX_ECARDS]; -static signed char irqno_to_expcard[16]; -static unsigned int ecard_numcards, ecard_numirqcards; -static unsigned int have_expmask; +static void +ecard_task_reset(struct ecard_request *req) +{ + if (req->ec == NULL) { + ecard_t *ec; + + for (ec = cards; ec; ec = ec->next) { + printk(KERN_DEBUG "Resetting card %d\n", + ec->slot_no); + + if (ec->loader) + ecard_loader_reset(POD_INT_ADDR(ec->podaddr), + ec->loader); + } + printk(KERN_DEBUG "All cards reset\n"); + } else if (req->ec->loader) + ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr), + req->ec->loader); +} + +static void +ecard_task_readbytes(struct ecard_request *req) +{ + unsigned char *buf = (unsigned char *)req->buffer; + volatile unsigned char *base_addr = + (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); + unsigned int len = req->length; + + if (req->ec->slot_no == 8) { + /* + * The card maintains an index which + * increments the address into a 4096-byte + * page on each access. We need to keep + * track of the counter. + */ + static unsigned int index; + unsigned int offset, page; + unsigned char byte = 0; /* keep gcc quiet */ + + offset = req->address & 4095; + page = req->address >> 12; + + if (page > 256) + return; + + page *= 4; + + if (offset == 0 || index > offset) { + /* + * We need to reset the index counter. + */ + *base_addr = 0; + index = 0; + } + + while (index <= offset) { + byte = base_addr[page]; + index += 1; + } + + while (len--) { + *buf++ = byte; + if (len) { + byte = base_addr[page]; + index += 1; + } + } + } else { + unsigned int off = req->address; + + if (!req->use_loader || !req->ec->loader) { + off *= 4; + while (len--) { + *buf++ = base_addr[off]; + off += 4; + } + } else { + while(len--) { + /* + * The following is required by some + * expansion card loader programs. + */ + *(unsigned long *)0x108 = 0; + *buf++ = ecard_loader_read(off++, base_addr, + req->ec->loader); + } + } + } + +} + +#ifdef CONFIG_CPU_32 +static pid_t ecard_pid; +static struct wait_queue *ecard_wait; +static struct wait_queue *ecard_done; +static struct ecard_request *ecard_req; + +/* + * Set up the expansion card daemon's environment. + */ +static void +ecard_init_task(void) +{ + /* We want to set up the page tables for the following mapping: + * Virtual Physical + * 0x03000000 0x03000000 + * 0x03010000 unmapped + * 0x03210000 0x03210000 + * 0x03400000 unmapped + * 0x08000000 0x08000000 + * 0x10000000 unmapped + * + * FIXME: we don't follow this 100% yet. + */ + pgd_t *src_pgd, *dst_pgd; + unsigned int dst_addr = IO_START; + + src_pgd = pgd_offset(current->mm, IO_BASE); + dst_pgd = pgd_offset(current->mm, dst_addr); + + while (dst_addr < IO_START + IO_SIZE) { + *dst_pgd++ = *src_pgd++; + dst_addr += PGDIR_SIZE; + } + + flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE); + + dst_addr = EASI_START; + src_pgd = pgd_offset(current->mm, EASI_BASE); + dst_pgd = pgd_offset(current->mm, dst_addr); + + while (dst_addr < EASI_START + EASI_SIZE) { + *dst_pgd++ = *src_pgd++; + dst_addr += PGDIR_SIZE; + } + + flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE); +} + +static int +ecard_task(void * unused) +{ + current->session = 1; + current->pgrp = 1; + + /* + * We don't want /any/ signals, not even SIGKILL + */ + sigfillset(¤t->blocked); + sigemptyset(¤t->signal); + + strcpy(current->comm, "kecardd"); + + /* + * Set up the environment + */ + ecard_init_task(); + + while (1) { + struct ecard_request *req; + + do { + req = xchg(&ecard_req, NULL); + + if (req == NULL) { + sigemptyset(¤t->signal); + interruptible_sleep_on(&ecard_wait); + } + } while (req == NULL); + + switch (req->req) { + case req_readbytes: + ecard_task_readbytes(req); + break; + + case req_reset: + ecard_task_reset(req); + break; + } + wake_up(&ecard_done); + } +} + +/* + * Wake the expansion card daemon to action our request. + * + * FIXME: The test here is not sufficient to detect if the + * kcardd is running. + */ +static inline void +ecard_call(struct ecard_request *req) +{ + /* + * If we're called from task 0, or from an + * interrupt (will be keyboard interrupt), + * we forcefully set up the memory map, and + * call the loader. We can't schedule, or + * sleep for this call. + */ + if ((current == task[0] || in_interrupt()) && + req->req == req_reset && req->ec == NULL) { + ecard_init_task(); + ecard_task_reset(req); + } else { + if (ecard_pid <= 0) + ecard_pid = kernel_thread(ecard_task, NULL, 0); + + ecard_req = req; + + wake_up(&ecard_wait); + + sleep_on(&ecard_done); + } +} +#else +/* + * On 26-bit processors, we don't need the kcardd thread to access the + * expansion card loaders. We do it directly. + */ +static inline void +ecard_call(struct ecard_request *req) +{ + if (req->req == req_reset) + ecard_task_reset(req); + else + ecard_task_readbytes(req); +} +#endif + +/* ======================= Mid-level card control ===================== */ +/* + * This is called to reset the loaders for each expansion card on reboot. + * + * This is required to make sure that the card is in the correct state + * that RiscOS expects it to be. + */ +void +ecard_reset(int slot) +{ + struct ecard_request req; + + req.req = req_reset; + + if (slot < 0) + req.ec = NULL; + else + req.ec = slot_to_ecard(slot); + + ecard_call(&req); + +#ifdef HAS_EXPMASK + if (have_expmask && slot < 0) { + have_expmask |= ~0; + EXPMASK_ENABLE = have_expmask; + } +#endif +} + +static void +ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) +{ + struct ecard_request req; + + req.req = req_readbytes; + req.ec = ec; + req.address = off; + req.length = len; + req.use_loader = useld; + req.buffer = addr; + + ecard_call(&req); +} + +int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +{ + struct ex_chunk_dir excd; + int index = 16; + int useld = 0; + + if (!ec->cid.cd) + return 0; + + while(1) { + ecard_readbytes(&excd, ec, index, 8, useld); + index += 8; + if (c_id(&excd) == 0) { + if (!useld && ec->loader) { + useld = 1; + index = 0; + continue; + } + return 0; + } + if (c_id(&excd) == 0xf0) { /* link */ + index = c_start(&excd); + continue; + } + if (c_id(&excd) == 0x80) { /* loader */ + if (!ec->loader) { + ec->loader = (loader_t)kmalloc(c_len(&excd), + GFP_KERNEL); + if (ec->loader) + ecard_readbytes(ec->loader, ec, + (int)c_start(&excd), + c_len(&excd), useld); + else + return 0; + } + continue; + } + if (c_id(&excd) == id && num-- == 0) + break; + } + + if (c_id(&excd) & 0x80) { + switch (c_id(&excd) & 0x70) { + case 0x70: + ecard_readbytes((unsigned char *)excd.d.string, ec, + (int)c_start(&excd), c_len(&excd), + useld); + break; + case 0x00: + break; + } + } + cd->start_offset = c_start(&excd); + memcpy(cd->d.string, excd.d.string, 256); + return 1; +} + +/* ======================= Interrupt control ============================ */ static void ecard_def_irq_enable(ecard_t *ec, int irqnr) { @@ -100,6 +483,11 @@ #endif } +static int ecard_def_irq_pending(ecard_t *ec) +{ + return !ec->irqmask || ec->irqaddr[0] & ec->irqmask; +} + static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) { panic("ecard_def_fiq_enable called - impossible"); @@ -110,11 +498,18 @@ panic("ecard_def_fiq_disable called - impossible"); } +static int ecard_def_fiq_pending(ecard_t *ec) +{ + return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask; +} + static expansioncard_ops_t ecard_default_ops = { ecard_def_irq_enable, ecard_def_irq_disable, + ecard_def_irq_pending, ecard_def_fiq_enable, - ecard_def_fiq_disable + ecard_def_fiq_disable, + ecard_def_fiq_pending }; /* @@ -125,10 +520,9 @@ */ void ecard_enableirq(unsigned int irqnr) { - irqnr &= 7; - if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + ecard_t *ec = slot_to_ecard(irqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -142,10 +536,9 @@ void ecard_disableirq(unsigned int irqnr) { - irqnr &= 7; - if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + ecard_t *ec = slot_to_ecard(irqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -156,10 +549,9 @@ void ecard_enablefiq(unsigned int fiqnr) { - fiqnr &= 7; - if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + ecard_t *ec = slot_to_ecard(fiqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -173,10 +565,9 @@ void ecard_disablefiq(unsigned int fiqnr) { - fiqnr &= 7; - if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + ecard_t *ec = slot_to_ecard(fiqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -185,41 +576,89 @@ } } -static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +static void +ecard_dump_irq_state(ecard_t *ec) { - const int num_cards = ecard_numirqcards; - int i, called = 0; + printk(" %d: %sclaimed, ", + ec->slot_no, + ec->claimed ? "" : "not "); + + if (ec->ops && ec->ops->irqpending && + ec->ops != &ecard_default_ops) + printk("irq %spending\n", + ec->ops->irqpending(ec) ? "" : "not "); + else + printk("irqaddr %p, mask = %02X, status = %02X\n", + ec->irqaddr, ec->irqmask, *ec->irqaddr); +} - for (i = 0; i < num_cards; i++) { - if (expcard[i].claimed && expcard[i].irq && - (!expcard[i].irqmask || - expcard[i].irqaddr[0] & expcard[i].irqmask)) { - do_ecard_IRQ(expcard[i].irq, regs); - called ++; +static void +ecard_check_lockup(void) +{ + static int last, lockup; + ecard_t *ec; + + /* + * If the timer interrupt has not run since the last million + * unrecognised expansion card interrupts, then there is + * something seriously wrong. Disable the expansion card + * interrupts so at least we can continue. + * + * Maybe we ought to start a timer to re-enable them some time + * later? + */ + if (last == jiffies) { + lockup += 1; + if (lockup > 1000000) { + printk(KERN_ERR "\nInterrupt lockup detected - " + "disabling all expansion card interrupts\n"); + + disable_irq(IRQ_EXPANSIONCARD); + + printk("Expansion card IRQ state:\n"); + + for (ec = cards; ec; ec = ec->next) + ecard_dump_irq_state(ec); } + } else + lockup = 0; + + /* + * If we did not recognise the source of this interrupt, + * warn the user, but don't flood the user with these messages. + */ + if (!last || time_after(jiffies, last + 5*HZ)) { + last = jiffies; + printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); } - cli(); - if (called == 0) { - static int last, lockup; +} - if (last == jiffies) { - lockup += 1; - if (lockup > 1000000) { - printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n"); - disable_irq(intr_no); - printk("Expansion card IRQ state:\n"); - for (i = 0; i < num_cards; i++) - printk(" %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32, - expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr); - } - } else - lockup = 0; +static void +ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +{ + ecard_t *ec; + int called = 0; + + for (ec = cards; ec; ec = ec->next) { + int pending; + + if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) + continue; + + if (ec->ops && ec->ops->irqpending) + pending = ec->ops->irqpending(ec); + else + pending = ecard_default_ops.irqpending(ec); - if (!last || time_after(jiffies, last + 5*HZ)) { - last = jiffies; - printk(KERN_ERR "\nUnrecognised interrupt from backplane\n"); + if (pending) { + do_ecard_IRQ(ec->irq, regs); + called ++; } } + cli(); + + if (called == 0) + ecard_check_lockup(); } #ifdef HAS_EXPMASK @@ -234,31 +673,35 @@ 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 }; -static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) +static void +ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) { const unsigned int statusmask = 15; unsigned int status; status = EXPMASK_STATUS & statusmask; if (status) { - unsigned int irqno; + unsigned int slot; ecard_t *ec; again: - irqno = first_set[status]; - ec = expcard + irqno_to_expcard[irqno]; + slot = first_set[status]; + ec = slot_to_ecard(slot); if (ec->claimed) { unsigned int oldexpmask; /* - * this ugly code is so that we can operate a prioritorising system. + * this ugly code is so that we can operate a + * prioritorising system: + * * Card 0 highest priority * Card 1 * Card 2 * Card 3 lowest priority + * * Serial cards should go in 0/1, ethernet/scsi in 2/3 * otherwise you will lose serial data at high speeds! */ oldexpmask = have_expmask; - EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]); + EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]); sti(); do_ecard_IRQ(ec->irq, regs); cli(); @@ -267,15 +710,18 @@ if (status) goto again; } else { - printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno); - EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno)); + printk(KERN_WARNING "card%d: interrupt from unclaimed " + "card???\n", slot); + EXPMASK_ENABLE = (have_expmask &= ~(1 << slot)); } } else printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -static int ecard_checkirqhw(void) +__initfunc(static void +ecard_probeirqhw(void)) { + ecard_t *ec; int found; EXPMASK_ENABLE = 0x00; @@ -283,62 +729,77 @@ found = ((EXPMASK_STATUS & 15) == 0); EXPMASK_ENABLE = 0xff; - return found; + if (!found) + return; + + printk(KERN_DEBUG "Expansion card interrupt " + "management hardware found\n"); + + irqexpansioncard.handler = ecard_irq_expmask; + + /* for each card present, set a bit to '1' */ + have_expmask = 0x80000000; + + for (ec = cards; ec; ec = ec->next) + have_expmask |= 1 << ec->slot_no; + + EXPMASK_ENABLE = have_expmask; } +#else +#define ecard_probeirqhw() #endif -static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) +unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { - extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader); - unsigned char *a = (unsigned char *)addr; - - if (ec->slot_no == 8) { - static unsigned int lowaddress; - unsigned int laddr, haddr; - unsigned char byte = 0; /* keep gcc quiet */ - - laddr = off & 4095; /* number of bytes to read from offset + base addr */ - haddr = off >> 12; /* offset into card from base addr */ + switch (ec->slot_no) { + case 0 ... 3: + switch (type) { + case ECARD_MEMC: + return IO_EC_MEMC_BASE + (ec->slot_no << 12); - if (haddr > 256) - return; + case ECARD_IOC: + return IO_EC_IOC_BASE + (speed << 17) + + (ec->slot_no << 12); - /* - * If we require a low address or address 0, then reset, and start again... - */ - if (!off || lowaddress > laddr) { - outb(0, ec->podaddr); - lowaddress = 0; - } - while (lowaddress <= laddr) { - byte = inb(ec->podaddr + haddr); - lowaddress += 1; - } - while (len--) { - *a++ = byte; - if (len) { - byte = inb(ec->podaddr + haddr); - lowaddress += 1; - } +#ifdef IO_EC_EASI_BASE + case ECARD_EASI: + return IO_EC_EASI_BASE + (ec->slot_no << 22); +#endif + default: + break; } - } else { - if (!useld || !ec->loader) { - while(len--) - *a++ = inb(ec->podaddr + (off++)); - } else { - while(len--) { - *(unsigned long *)0x108 = 0; /* hack for some loaders!!! */ - *a++ = ecard_loader_read(off++, BUS_ADDR(ec->podaddr), ec->loader); - } + break; + + case 4 ... 7: + switch (type) { +#ifdef IO_EC_IOC4_BASE + case ECARD_IOC: + return IO_EC_IOC4_BASE + (speed << 17) + + ((ec->slot_no - 4) << 12); +#endif +#ifdef IO_EC_EASI_BASE + case ECARD_EASI: + return IO_EC_EASI_BASE + (ec->slot_no << 22); +#endif + default: + break; } + break; + +#ifdef IO_EC_MEMC8_BASE + case 8: + return IO_EC_MEMC8_BASE; +#endif } + return 0; } static int ecard_prints(char *buffer, ecard_t *ec) { char *start = buffer; - buffer += sprintf(buffer, "\n %d: ", ec->slot_no); + buffer += sprintf(buffer, " %d: %s ", ec->slot_no, + ec->type == ECARD_EASI ? "EASI" : " "); if (ec->cid.id == 0) { struct in_chunk_dir incd; @@ -346,63 +807,59 @@ buffer += sprintf(buffer, "[%04X:%04X] ", ec->cid.manufacturer, ec->cid.product); - if (!ec->card_desc && ec->cid.is && ec->cid.cd && + if (!ec->card_desc && ec->cid.cd && ecard_readchunk(&incd, ec, 0xf5, 0)) ec->card_desc = incd.d.string; if (!ec->card_desc) ec->card_desc = "*unknown*"; - buffer += sprintf(buffer, "%s", ec->card_desc); + buffer += sprintf(buffer, "%s\n", ec->card_desc); } else - buffer += sprintf(buffer, "Simple card %d", ec->cid.id); + buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); return buffer - start; } -static inline unsigned short ecard_getu16(unsigned char *v) -{ - return v[0] | v[1] << 8; -} - -static inline signed long ecard_gets24(unsigned char *v) -{ - return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); -} - /* * Probe for an expansion card. * * If bit 1 of the first byte of the card is set, then the * card does not exist. */ -__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type)) +__initfunc(static int +ecard_probe(int slot, card_type_t type)) { - ecard_t *ec = expcard + freeslot; + ecard_t **ecp; + ecard_t *ec; struct ex_ecid cid; char buffer[200]; - int i; + int i, rc = -ENOMEM; + + ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - irqno_to_expcard[card] = -1; + if (!ec) + goto nodev; - ec->slot_no = card; + memset(ec, 0, sizeof(ecard_t)); + + ec->slot_no = slot; + ec->type = type; ec->irq = NO_IRQ; ec->fiq = NO_IRQ; ec->dma = NO_DMA; ec->card_desc = NULL; ec->ops = &ecard_default_ops; + rc = -ENODEV; if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) - return 0; + goto nodev; cid.r_zero = 1; ecard_readbytes(&cid, ec, 0, 16, 0); if (cid.r_zero) - return 0; - - irqno_to_expcard[card] = freeslot; + goto nodev; - ec->type = type; ec->cid.id = cid.r_id; ec->cid.cd = cid.r_cd; ec->cid.is = cid.r_is; @@ -415,9 +872,9 @@ ec->cid.fiqmask = cid.r_fiqmask; ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); ec->fiqaddr = - ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr); + ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr); - if (ec->cid.cd && ec->cid.is) { + if (ec->cid.is) { ec->irqmask = ec->cid.irqmask; ec->irqaddr += ec->cid.irqoff; ec->fiqmask = ec->cid.fiqmask; @@ -430,88 +887,69 @@ for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) if (blacklist[i].manufacturer == ec->cid.manufacturer && blacklist[i].product == ec->cid.product) { - ec->loader = blacklist[i].loader; ec->card_desc = blacklist[i].type; break; } - ecard_prints(buffer, ec); - printk("%s", buffer); - - ec->irq = 32 + card; + ec->irq = 32 + slot; #ifdef IO_EC_MEMC8_BASE - if (card == 8) + if (slot == 8) ec->irq = 11; #endif #ifdef CONFIG_ARCH_RPC /* On RiscPC, only first two slots have DMA capability */ - if (card < 2) - ec->dma = 2 + card; + if (slot < 2) + ec->dma = 2 + slot; #endif #if 0 /* We don't support FIQs on expansion cards at the moment */ - ec->fiq = 96 + card; + ec->fiq = 96 + slot; #endif - return 1; -} + rc = 0; -/* - * This is called to reset the loaders for each expansion card on reboot. - * - * This is required to make sure that the card is in the correct state - * that RiscOS expects it to be. - */ -void ecard_reset(int card) -{ - extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader); + for (ecp = &cards; *ecp; ecp = &(*ecp)->next); - if (card >= ecard_numcards) - return; - - if (card < 0) { - for (card = 0; card < ecard_numcards; card++) - if (expcard[card].loader) - ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), - expcard[card].loader); - } else - if (expcard[card].loader) - ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), - expcard[card].loader); + *ecp = ec; -#ifdef HAS_EXPMASK - if (have_expmask) { - have_expmask |= ~0; - EXPMASK_ENABLE = have_expmask; +nodev: + if (rc && ec) + kfree(ec); + else { + slot_to_expcard[slot] = ec; + + ecard_prints(buffer, ec); + printk("%s", buffer); } -#endif + return rc; } -static unsigned int ecard_startcard; +static ecard_t *finding_pos; void ecard_startfind(void) { - ecard_startcard = 0; + finding_pos = NULL; } ecard_t *ecard_find(int cid, const card_ids *cids) { - int card; + if (!finding_pos) + finding_pos = cards; + else + finding_pos = finding_pos->next; - if (!cids) { - for (card = ecard_startcard; card < ecard_numcards; card++) - if (!expcard[card].claimed && - (expcard[card].cid.id ^ cid) == 0) + for (; finding_pos; finding_pos = finding_pos->next) { + if (finding_pos->claimed) + continue; + + if (!cids) { + if ((finding_pos->cid.id ^ cid) == 0) break; - } else { - for (card = ecard_startcard; card < ecard_numcards; card++) { + } else { unsigned int manufacturer, product; int i; - if (expcard[card].claimed) - continue; - - manufacturer = expcard[card].cid.manufacturer; - product = expcard[card].cid.product; + manufacturer = finding_pos->cid.manufacturer; + product = finding_pos->cid.product; for (i = 0; cids[i].manufacturer != 65535; i++) if (manufacturer == cids[i].manufacturer && @@ -523,111 +961,24 @@ } } - ecard_startcard = card + 1; - - return card < ecard_numcards ? &expcard[card] : NULL; + return finding_pos; } -int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +__initfunc(static void ecard_free_all(void)) { - struct ex_chunk_dir excd; - int index = 16; - int useld = 0; + ecard_t *ec, *ecn; - if (!ec->cid.is || !ec->cid.cd) - return 0; - - while(1) { - ecard_readbytes(&excd, ec, index, 8, useld); - index += 8; - if (c_id(&excd) == 0) { - if (!useld && ec->loader) { - useld = 1; - index = 0; - continue; - } - return 0; - } - if (c_id(&excd) == 0xf0) { /* link */ - index = c_start(&excd); - continue; - } - if (c_id(&excd) == 0x80) { /* loader */ - if (!ec->loader) { - ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL); - ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld); - } - continue; - } - if (c_id(&excd) == id && num-- == 0) - break; - } + for (ec = cards; ec; ec = ecn) { + ecn = ec->next; - if (c_id(&excd) & 0x80) { - switch (c_id(&excd) & 0x70) { - case 0x70: - ecard_readbytes((unsigned char *)excd.d.string, ec, - (int)c_start(&excd), c_len(&excd), useld); - break; - case 0x00: - break; - } + kfree(ec); } - cd->start_offset = c_start(&excd); - memcpy(cd->d.string, excd.d.string, 256); - return 1; -} - -unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) -{ - switch (ec->slot_no) { - case 0 ... 3: - switch (type) { - case ECARD_MEMC: - return IO_EC_MEMC_BASE + (ec->slot_no << 12); - case ECARD_IOC: - return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12); - -#ifdef IO_EC_EASI_BASE - case ECARD_EASI: - return IO_EC_EASI_BASE + (ec->slot_no << 22); -#endif - } - break; - - case 4 ... 7: - switch (type) { -#ifdef IO_EC_IOC4_BASE - case ECARD_IOC: - return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12); -#endif -#ifdef IO_EC_EASI_BASE - case ECARD_EASI: - return IO_EC_EASI_BASE + (ec->slot_no << 22); -#endif - default: - break; - } - break; + cards = NULL; -#ifdef IO_EC_MEMC8_BASE - case 8: - return IO_EC_MEMC8_BASE; -#endif - } - return 0; + memset(slot_to_expcard, 0, sizeof(slot_to_expcard)); } -static struct irqaction irqexpansioncard = { - ecard_irq_noexpmask, - SA_INTERRUPT, - 0, - "expansion cards", - NULL, - NULL -}; - /* * Initialise the expansion card system. * Locate all hardware - interrupt management and @@ -635,51 +986,31 @@ */ __initfunc(void ecard_init(void)) { - int i, nc = 0; - - memset(expcard, 0, sizeof(expcard)); - -#ifdef HAS_EXPMASK - if (ecard_checkirqhw()) { - printk(KERN_DEBUG "Expansion card interrupt management hardware found\n"); - irqexpansioncard.handler = ecard_irq_expmask; - irqexpansioncard.flags |= SA_IRQNOMASK; - have_expmask = -1; - } -#endif + int slot; - printk("Installed expansion cards:"); + oldlatch_init(); - /* - * First of all, probe all cards on the expansion card interrupt line - */ - for (i = 0; i < 8; i++) - if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI)) - nc += 1; - else - have_expmask &= ~(1< + .equ ioc_base_high, IOC_BASE & 0xff000000 .equ ioc_base_low, IOC_BASE & 0x00ff0000 .macro disable_fiq @@ -186,113 +190,104 @@ .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 .endm -#elif defined(CONFIG_ARCH_EBSA285) +#elif defined(CONFIG_HOST_FOOTBRIDGE) +#include .macro disable_fiq .endm + .equ irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000 + .equ irq_mask_pci_err_low, IRQ_MASK_PCI_ERR & 0x00ff0000 + .macro get_irqnr_and_base, irqnr, irqstat, base mov r4, #0xfe000000 ldr \irqstat, [r4, #0x180] @ get interrupts - mov \irqnr, #0 -1001: tst \irqstat, #1 - addeq \irqnr, \irqnr, #1 - moveq \irqstat, \irqstat, lsr #1 - tsteq \irqnr, #32 - beq 1001b - teq \irqnr, #32 - .endm - .macro irq_prio_table - .endm + tst \irqstat, #IRQ_MASK_SDRAMPARITY + movne \irqnr, #IRQ_SDRAMPARITY + bne 1001f -#elif defined(CONFIG_ARCH_NEXUSPCI) + tst \irqstat, #IRQ_MASK_UART_RX + movne \irqnr, #IRQ_CONRX + bne 1001f - .macro disable_fiq - .endm + tst \irqstat, #IRQ_MASK_DMA1 + movne \irqnr, #IRQ_DMA1 + bne 1001f - .macro get_irqnr_and_base, irqnr, irqstat, base - ldr r4, =0xffe00000 - ldr \irqstat, [r4, #0x180] @ get interrupts - mov \irqnr, #0 -1001: tst \irqstat, #1 - addeq \irqnr, \irqnr, #1 - moveq \irqstat, \irqstat, lsr #1 - tsteq \irqnr, #32 - beq 1001b - teq \irqnr, #32 - .endm + tst \irqstat, #IRQ_MASK_DMA2 + movne \irqnr, #IRQ_DMA2 + bne 1001f - .macro irq_prio_table - .endm + tst \irqstat, #IRQ_MASK_IN0 + movne \irqnr, #IRQ_IN0 + bne 1001f -#elif defined(CONFIG_ARCH_VNC) + tst \irqstat, #IRQ_MASK_IN1 + movne \irqnr, #IRQ_IN1 + bne 1001f - .macro disable_fiq - .endm + tst \irqstat, #IRQ_MASK_IN2 + movne \irqnr, #IRQ_IN2 + bne 1001f - .equ pci_iack_high, PCI_IACK & 0xff000000 - .equ pci_iack_low, PCI_IACK & 0x00ff0000 + tst \irqstat, #IRQ_MASK_IN3 + movne \irqnr, #IRQ_IN3 + bne 1001f - .macro get_irqnr_and_base, irqnr, irqstat, base - mov r4, #IO_BASE_ARM_CSR - ldr \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones + tst \irqstat, #IRQ_MASK_PCI + movne \irqnr, #IRQ_PCI + bne 1001f - @ run through hard priorities - @ timer - tst \irqstat, #IRQ_MASK_TIMER0 - movne \irqnr, #IRQ_TIMER0 + tst \irqstat, #IRQ_MASK_I2OINPOST + movne \irqnr, #IRQ_I2OINPOST bne 1001f - @ ether10 - tst \irqstat, #IRQ_MASK_ETHER10 - movne \irqnr, #IRQ_ETHER10 + tst \irqstat, #IRQ_MASK_TIMER1 + movne \irqnr, #IRQ_TIMER1 bne 1001f - @ ether100 - tst \irqstat, #IRQ_MASK_ETHER100 - movne \irqnr, #IRQ_ETHER100 + tst \irqstat, #IRQ_MASK_TIMER2 + movne \irqnr, #IRQ_TIMER2 bne 1001f - @ video compressor - tst \irqstat, #IRQ_MASK_VIDCOMP - movne \irqnr, #IRQ_VIDCOMP + tst \irqstat, #IRQ_MASK_TIMER3 + movne \irqnr, #IRQ_TIMER3 bne 1001f - @ now try all the PIC sources - @ determine whether we have an irq - tst \irqstat, #IRQ_MASK_EXTERN_IRQ - beq 1002f - mov r4, #pci_iack_high - orr r4, r4, #pci_iack_low - ldrb \irqnr, [r4] @ get the IACK byte - b 1001f + tst \irqstat, #IRQ_MASK_UART_TX + movne \irqnr, #IRQ_CONTX + bne 1001f -1002: @ PCI errors - tst \irqstat, #IRQ_MASK_PCI_ERR + tst \irqstat, #irq_mask_pci_err_high + tsteq \irqstat, #irq_mask_pci_err_low movne \irqnr, #IRQ_PCI_ERR bne 1001f +1001: + .endm - @ softint - tst \irqstat, #IRQ_MASK_SOFTIRQ - movne \irqnr, #IRQ_SOFTIRQ - bne 1001f + .macro irq_prio_table + .endm - @ debug uart - tst \irqstat, #IRQ_MASK_UART_DEBUG - movne \irqnr, #IRQ_CONRX - bne 1001f +#elif defined(CONFIG_ARCH_NEXUSPCI) - @ watchdog - tst \irqstat, #IRQ_MASK_WATCHDOG - movne \irqnr, #IRQ_WATCHDOG + .macro disable_fiq + .endm -1001: @ If Z is set, then we will not enter an interrupt + .macro get_irqnr_and_base, irqnr, irqstat, base + ldr r4, =0xffe00000 + ldr \irqstat, [r4, #0x180] @ get interrupts + mov \irqnr, #0 +1001: tst \irqstat, #1 + addeq \irqnr, \irqnr, #1 + moveq \irqstat, \irqstat, lsr #1 + tsteq \irqnr, #32 + beq 1001b + teq \irqnr, #32 .endm .macro irq_prio_table .endm - #else #error Unknown architecture #endif @@ -348,25 +343,6 @@ msr cpsr, \temp .endm - .macro initialise_traps_extra - mrs r0, cpsr - bic r0, r0, #31 - orr r0, r0, #0xd3 - msr cpsr, r0 - .endm - - -#ifndef __ARM_ARCH_4__ -.Larm700bug: str lr, [r8] - ldr r0, [sp, #S_PSR] @ Get calling cpsr - msr spsr, r0 - ldmia sp, {r0 - lr}^ @ Get calling r0 - lr - mov r0, r0 - add sp, sp, #S_PC - ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 - movs pc, lr -#endif - .macro get_current_task, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 @@ -379,231 +355,89 @@ adr\cond \reg, \label .endm -/*============================================================================= - * Address exception handler - *----------------------------------------------------------------------------- - * These aren't too critical. - * (they're not supposed to happen, and won't happen in 32-bit mode). - */ - -vector_addrexcptn: - b vector_addrexcptn - -/*============================================================================= - * Undefined FIQs - *----------------------------------------------------------------------------- - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. - * Basically to switch modes, we *HAVE* to clobber one register... brain - * damage alert! I don't think that we can execute any code in here in any - * other mode than FIQ... Ok you can switch to another mode, but you can't - * get out of that mode without clobbering one register. - */ -_unexp_fiq: disable_fiq - subs pc, lr, #4 - -/*============================================================================= - * Interrupt entry dispatcher - *----------------------------------------------------------------------------- - * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC - */ -vector_IRQ: @ - @ save mode specific registers - @ - ldr r13, .LCirq - sub lr, lr, #4 - str lr, [r13] @ save lr_IRQ - mrs lr, spsr - str lr, [r13, #4] @ save spsr_IRQ - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr @ switch to SVC mode - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode and branches - b __irq_invalid @ 4 - 15 - b __irq_usr @ 0 (USR_26 / USR_32) - b __irq_invalid @ 1 (FIQ_26 / FIQ_32) - b __irq_invalid @ 2 (IRQ_26 / IRQ_32) - b __irq_svc @ 3 (SVC_26 / SVC_32) -/* - *------------------------------------------------------------------------------------------------ - * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC - */ -.LCirq: .word __temp_irq -.LCund: .word __temp_und -.LCabt: .word __temp_abt - -vector_undefinstr: - @ - @ save mode specific registers - @ - ldr r13, [pc, #.LCund - . - 8] - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode and branches - b __und_invalid @ 4 - 15 - b __und_usr @ 0 (USR_26 / USR_32) - b __und_invalid @ 1 (FIQ_26 / FIQ_32) - b __und_invalid @ 2 (IRQ_26 / IRQ_32) - b __und_svc @ 3 (SVC_26 / SVC_32) -/* - *------------------------------------------------------------------------------------------------ - * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in ABT mode, spsr = USR CPSR, lr = USR PC - */ -vector_prefetch: - @ - @ save mode specific registers - @ - sub lr, lr, #4 - ldr r13, .LCabt - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - adds pc, pc, lr, lsl #2 @ Changes mode and branches - b __pabt_invalid @ 4 - 15 - b __pabt_usr @ 0 (USR_26 / USR_32) - b __pabt_invalid @ 1 (FIQ_26 / FIQ_32) - b __pabt_invalid @ 2 (IRQ_26 / IRQ_32) - b __pabt_invalid @ 3 (SVC_26 / SVC_32) /* - *------------------------------------------------------------------------------------------------ - * Data abort dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + * Invalid mode handlers */ -vector_data: @ - @ save mode specific registers - @ - sub lr, lr, #8 - ldr r13, .LCabt - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode & branches - b __dabt_invalid @ 4 - 15 - b __dabt_usr @ 0 (USR_26 / USR_32) - b __dabt_invalid @ 1 (FIQ_26 / FIQ_32) - b __dabt_invalid @ 2 (IRQ_26 / IRQ_32) - b __dabt_svc @ 3 (SVC_26 / SVC_32) +__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - lr} @ Save XXX r0 - lr + ldr r4, .LCabt + mov r1, #BAD_PREFETCH + b 1f -/*============================================================================= - * Prefetch abort handler - *----------------------------------------------------------------------------- - */ -pabtmsg: .ascii "Pabt: %08lX\n\0" - .align -__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - r12} @ Save r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr +__dabt_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact] ldr r4, .LCabt - ldmia r4, {r5 - r7} @ Get USR pc, cpsr - stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + mov r1, #BAD_DATA + b 1f - mrs r7, cpsr @ Enable interrupts if they were - bic r7, r7, #I_BIT @ previously - msr cpsr, r7 - mov r0, r5 @ address (pc) - mov r1, sp @ regs - bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - teq r0, #0 @ Does this still apply??? - bne ret_from_exception @ Return from exception -#ifdef DEBUG_UNDEF - adr r0, t - bl SYMBOL_NAME(printk) -#endif - mov r0, r5 - mov r1, sp - and r2, r6, #31 - bl SYMBOL_NAME(do_undefinstr) - ldr lr, [sp, #S_PSR] @ Get USR cpsr - msr spsr, lr - ldmia sp, {r0 - pc}^ @ Restore USR registers +__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame + stmfd sp, {r0 - lr} @ Save r0 - lr + ldr r4, .LCirq + mov r1, #BAD_IRQ + b 1f -__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - lr} @ Save XXX r0 - lr - mov r7, r0 @ OLD R0 - ldr r4, .LCabt - ldmia r4, {r5 - r7} @ Get XXX pc, cpsr +__und_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} + ldr r4, .LCund + mov r1, #BAD_UNDEFINSTR @ int reason + +1: mov fp, #0 + ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0 add r4, sp, #S_PC stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0 - mov r0, sp @ Prefetch aborts are definitely *not* - mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant - and r2, r6, #31 @ recover from this problem. + mov r0, sp + and r2, r6, #31 @ int mode b SYMBOL_NAME(bad_mode) -#ifdef DEBUG_UNDEF -t: .ascii "*** undef ***\r\n\0" - .align -#endif -/*============================================================================= - * Data abort handler code - *----------------------------------------------------------------------------- +wfs_mask_data: .word 0x0e200110 @ WFS/RFS + .word 0x0fef0fff + .word 0x0d0d0100 @ LDF [sp]/STF [sp] + .word 0x0d0b0100 @ LDF [fp]/STF [fp] + .word 0x0f0f0f00 + +/* We get here if an undefined instruction happens and the floating + * point emulator is not present. If the offending instruction was + * a WFS, we just perform a normal return as if we had emulated the + * operation. This is a hack to allow some basic userland binaries + * to run so that the emulator module proper can be loaded. --philb */ -.LCprocfns: .word SYMBOL_NAME(processor) +fpe_not_present: + adr r10, wfs_mask_data + ldmia r10, {r4, r5, r6, r7, r8} + ldr r10, [sp, #S_PC] @ Load PC + sub r10, r10, #-4 + mask_pc r10, r10 + ldrt r10, [r10] @ get instruction + and r5, r10, r5 + teq r5, r4 @ Is it WFS? + moveq pc, r9 + and r5, r10, r8 + teq r5, r6 @ Is it LDF/STF on sp or fp? + teqne r5, r7 + movne pc, lr + tst r10, #0x00200000 @ Does it have WB + moveq pc, r9 + and r4, r10, #255 @ get offset + and r6, r10, #0x000f0000 + tst r10, #0x00800000 @ +/- + rsbeq r4, r4, #0 + ldr r5, [sp, r6, lsr #14] @ Load reg + add r5, r5, r4, lsl #2 + str r5, [sp, r6, lsr #14] @ Save reg + mov pc, r9 -__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - r12} @ save r0 - r12 - add r3, sp, #S_PC - stmdb r3, {sp, lr}^ - ldr r0, .LCabt - ldmia r0, {r0 - r2} @ Get USR pc, cpsr - stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 - mov fp, #0 - mrs r2, cpsr @ Enable interrupts if they were - bic r2, r2, #I_BIT @ previously - msr cpsr, r2 - ldr r2, .LCprocfns - mov lr, pc - ldr pc, [r2, #8] @ call processor specific code - mov r3, sp - bl SYMBOL_NAME(do_DataAbort) - b ret_from_sys_call - -__dabt_svc: sub sp, sp, #S_FRAME_SIZE +/* + * SVC mode handlers + */ + .align 5 +__dabt_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 ldr r2, .LCabt add r0, sp, #S_FRAME_SIZE + ldmia r2, {r2 - r4} @ get pc, cpsr add r5, sp, #S_SP mov r1, lr - ldmia r2, {r2 - r4} @ get pc, cpsr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro tst r3, #I_BIT mrseq r0, cpsr @ Enable interrupts if they were @@ -619,29 +453,15 @@ msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr -__dabt_invalid: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact] - mov r7, r0 - ldr r4, .LCabt - ldmia r4, {r5, r6} @ Get SVC pc, cpsr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} @ Save SVC pc, cpsr, old_r0 - mov r0, sp - mov r1, #BAD_DATA - and r2, r6, #31 - b SYMBOL_NAME(bad_mode) - -/*============================================================================= - * Interrupt (IRQ) handler - *----------------------------------------------------------------------------- - */ -__irq_usr: sub sp, sp, #S_FRAME_SIZE + .align 5 +__irq_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ - ldr r4, .LCirq - ldmia r4, {r5 - r7} @ get saved PC, SPSR - stmia r8, {r5 - r7} @ save pc, psr, old_r0 + ldr r7, .LCirq + add r5, sp, #S_FRAME_SIZE + ldmia r7, {r7 - r9} + add r4, sp, #S_SP + mov r6, lr + stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro 1: get_irqnr_and_base r0, r6, r5 movne r1, sp @ @@ -649,48 +469,97 @@ @ adrsvc ne, lr, 1b bne do_IRQ - b ret_with_reschedule - - irq_prio_table + ldr r0, [sp, #S_PSR] + msr spsr, r0 + ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr -__irq_svc: sub sp, sp, #S_FRAME_SIZE + .align 5 +__und_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 mov r6, lr - ldr r7, .LCirq + ldr r7, .LCund ldmia r7, {r7 - r9} add r5, sp, #S_FRAME_SIZE add r4, sp, #S_SP - stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + + adrsvc al, r9, 1f @ r9 = normal FP return + bl call_fpe @ lr = undefined instr return + + mov r0, r5 @ unsigned long pc + mov r1, sp @ struct pt_regs *regs + bl SYMBOL_NAME(do_undefinstr) + +1: ldr lr, [sp, #S_PSR] @ Get SVC cpsr + msr spsr, lr + ldmia sp, {r0 - pc}^ @ Restore SVC registers + + .align 5 +.LCirq: .word __temp_irq +.LCund: .word __temp_und +.LCabt: .word __temp_abt +.LCprocfns: .word SYMBOL_NAME(processor) +.LCfp: .word SYMBOL_NAME(fp_enter) + + irq_prio_table + +/* + * User mode handlers + */ +#ifdef DEBUG_UNDEF +t: .ascii "Prefetch -> undefined instruction\n\0" + .align +#endif + .align 5 +__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ save r0 - r12 + add r3, sp, #S_PC + stmdb r3, {sp, lr}^ + ldr r4, .LCabt + ldmia r4, {r0 - r2} @ Get USR pc, cpsr + stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 + +#ifdef CONFIG_ALIGNMENT_TRAP + ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)] + mcr p15, 0, r7, c1, c0 +#endif + + mov fp, #0 + mrs r2, cpsr @ Enable interrupts if they were + bic r2, r2, #I_BIT @ previously + msr cpsr, r2 + ldr r2, .LCprocfns + mov lr, pc + ldr pc, [r2, #8] @ call processor specific code + mov r3, sp + adrsvc al, lr, ret_from_sys_call + b SYMBOL_NAME(do_DataAbort) + + .align 5 +__irq_usr: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ + ldr r4, .LCirq + ldmia r4, {r5 - r7} @ get saved PC, SPSR + stmia r8, {r5 - r7} @ save pc, psr, old_r0 + +#ifdef CONFIG_ALIGNMENT_TRAP + ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_irq)] + mcr p15, 0, r7, c1, c0 +#endif + 1: get_irqnr_and_base r0, r6, r5 movne r1, sp + adrsvc ne, lr, 1b @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ - adrsvc ne, lr, 1b bne do_IRQ - ldr r0, [sp, #S_PSR] - msr spsr, r0 - ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr - -__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame - stmfd sp, {r0 - lr} @ Save r0 - lr - mov r7, #-1 - ldr r4, .LCirq - ldmia r4, {r5, r6} @ get saved pc, psr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} - mov fp, #0 - mov r0, sp - mov r1, #BAD_IRQ - b SYMBOL_NAME(bad_mode) - -/*============================================================================= - * Undefined instruction handler - *----------------------------------------------------------------------------- - * Handles floating point instructions - */ -.LC2: .word SYMBOL_NAME(fp_enter) + mov r4, #0 + b ret_with_reschedule + .align 5 __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia sp, {r0 - r12} @ Save r0 - r12 add r8, sp, #S_PC @@ -698,99 +567,311 @@ ldr r4, .LCund ldmia r4, {r5 - r7} stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + +#ifdef CONFIG_ALIGNMENT_TRAP + ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_und)] + mcr p15, 0, r7, c1, c0 +#endif + mov fp, #0 - adrsvc al, r9, ret_from_exception @ r9 = normal FP return + adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return -1: get_current_task r10 +call_fpe: get_current_task r10 mov r8, #1 strb r8, [r10, #TSK_USED_MATH] @ set current->used_math add r10, r10, #TSS_FPESAVE @ r10 = workspace - ldr r4, .LC2 + ldr r4, .LCfp ldr pc, [r4] @ Call FP module USR entry point -__und_svc: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} @ save r0 - r12 - mov r6, lr - ldr r7, .LCund - ldmia r7, {r7 - r9} - add r5, sp, #S_FRAME_SIZE - add r4, sp, #S_SP - stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro - - adrsvc al, r9, 3f @ r9 = normal FP return - bl 1b @ lr = undefined instr return - - mov r0, r5 @ unsigned long pc - mov r1, sp @ struct pt_regs *regs - bl SYMBOL_NAME(do_undefinstr) - -3: ldr lr, [sp, #S_PSR] @ Get SVC cpsr - msr spsr, lr - ldmia sp, {r0 - pc}^ @ Restore SVC registers - fpundefinstr: mov r0, lr mov r1, sp mrs r4, cpsr @ Enable interrupts bic r4, r4, #I_BIT msr cpsr, r4 - adrsvc al, lr, ret_from_exception + adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_undefinstr) -__und_invalid: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - lr} - mov r7, r0 - ldr r4, .LCund - ldmia r4, {r5, r6} @ Get UND/IRQ/FIQ/ABT pc, cpsr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0 - mov r0, sp @ struct pt_regs *regs - mov r1, #BAD_UNDEFINSTR @ int reason - and r2, r6, #31 @ int mode - b SYMBOL_NAME(bad_mode) @ Does not ever return... + .align 5 +__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ Save r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr + ldr r4, .LCabt + ldmia r4, {r5 - r7} @ Get USR pc, cpsr + stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 -/* We get here if an undefined instruction happens and the floating - * point emulator is not present. If the offending instruction was - * a WFS, we just perform a normal return as if we had emulated the - * operation. This is a hack to allow some basic userland binaries - * to run so that the emulator module proper can be loaded. --philb - */ -fpe_not_present: - adr r10, wfs_mask_data - ldmia r10, {r4, r5, r6, r7, r8} - ldr r10, [sp, #S_PC] @ Load PC - sub r10, r10, #4 - mask_pc r10, r10 - ldrt r10, [r10] @ get instruction - and r5, r10, r5 - teq r5, r4 @ Is it WFS? - moveq pc, r9 - and r5, r10, r8 - teq r5, r6 @ Is it LDF/STF on sp or fp? - teqne r5, r7 - movne pc, lr - tst r10, #0x00200000 @ Does it have WB - moveq pc, r9 - and r4, r10, #255 @ get offset - and r6, r10, #0x000f0000 - tst r10, #0x00800000 @ +/- - rsbeq r4, r4, #0 - ldr r5, [sp, r6, lsr #14] @ Load reg - add r5, r5, r4, lsl #2 - str r5, [sp, r6, lsr #14] @ Save reg - mov pc, r9 +#ifdef CONFIG_ALIGNMENT_TRAP + ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)] + mcr p15, 0, r7, c1, c0 +#endif -wfs_mask_data: .word 0x0e200110 @ WFS - .word 0x0fff0fff - .word 0x0d0d0100 @ LDF [sp]/STF [sp] - .word 0x0d0b0100 @ LDF [fp]/STF [fp] - .word 0x0f0f0f00 + mrs r7, cpsr @ Enable interrupts if they were + bic r7, r7, #I_BIT @ previously + msr cpsr, r7 + mov r0, r5 @ address (pc) + mov r1, sp @ regs + bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler + teq r0, #0 @ Does this still apply??? + bne ret_from_sys_call @ Return from exception +#ifdef DEBUG_UNDEF + adr r0, t + bl SYMBOL_NAME(printk) +#endif + mov r0, r5 + mov r1, sp + and r2, r6, #31 + bl SYMBOL_NAME(do_undefinstr) + ldr lr, [sp, #S_PSR] @ Get USR cpsr + msr spsr, lr + ldmia sp, {r0 - pc}^ @ Restore USR registers #include "entry-common.S" + .text + +#ifndef __ARM_ARCH_4__ +.Larm700bug: str lr, [r8] + ldr r0, [sp, #S_PSR] @ Get calling cpsr + msr spsr, r0 + ldmia sp, {r0 - lr}^ @ Get calling r0 - lr + mov r0, r0 + add sp, sp, #S_PC + ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 + movs pc, lr +#endif + + .section ".text.init",#alloc,#execinstr +/* + * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary, + * and we rely on each stub being exactly 48 (1.5 cache lines) in size. This + * means that we only ever load two cache lines for this code, or one if we're + * lucky. We also copy this code to 0x200 so that we can use branches in the + * vectors, rather than ldr's. + */ + .align 5 +__stubs_start: +/* + * Interrupt dispatcher + * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC + */ +vector_IRQ: @ + @ save mode specific registers + @ + ldr r13, .LCsirq + sub lr, lr, #4 + str lr, [r13] @ save lr_IRQ + mrs lr, spsr + str lr, [r13, #4] @ save spsr_IRQ + @ + @ now branch to the relevent MODE handling routine + @ + bic r13, lr, #63 + orr r13, r13, #0x93 + msr spsr, r13 @ switch to SVC_32 mode + + and lr, lr, #15 + adr r13, .LCtab_irq + ldr lr, [r13, lr, lsl #2] + movs pc, lr @ Changes mode and branches +/* + * Data abort dispatcher - dispatches it to the correct handler for the processor mode + * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + */ +vector_data: @ + @ save mode specific registers + @ + sub lr, lr, #8 + ldr r13, .LCsabt + str lr, [r13] + mrs lr, spsr + str lr, [r13, #4] + @ + @ now branch to the relevent MODE handling routine + @ + bic r13, lr, #63 + orr r13, r13, #0x93 + msr spsr, r13 @ switch to SVC_32 mode + + and lr, lr, #15 + adr r13, .LCtab_dabt + ldr lr, [r13, lr, lsl #2] + movs pc, lr @ Changes mode and branches + +/* + * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode + * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + */ +vector_prefetch: + @ + @ save mode specific registers + @ + sub lr, lr, #4 + ldr r13, .LCsabt + str lr, [r13] @ save lr_ABT + mrs lr, spsr + str lr, [r13, #4] @ save spsr_ABT + @ + @ now branch to the relevent MODE handling routine + @ + bic r13, lr, #63 + orr r13, r13, #0x93 + msr spsr, r13 @ switch to SVC_32 mode + + ands lr, lr, #15 + ldreq lr, .LCtab_pabt + ldrne lr, .LCtab_pabt + 4 + movs pc, lr + +/* + * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode + * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC + */ +vector_undefinstr: + @ + @ save mode specific registers + @ + ldr r13, .LCsund + str lr, [r13] @ save lr_UND + mrs lr, spsr + str lr, [r13, #4] @ save spsr_UND + @ + @ now branch to the relevent MODE handling routine + @ + bic r13, lr, #63 + orr r13, r13, #0x93 + msr spsr, r13 @ switch to SVC_32 mode + + and lr, lr, #15 + adr r13, .LCtab_und + ldr lr, [r13, lr, lsl #2] + movs pc, lr @ Changes mode and branches + +/*============================================================================= + * Undefined FIQs + *----------------------------------------------------------------------------- + * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC + * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. + * Basically to switch modes, we *HAVE* to clobber one register... brain + * damage alert! I don't think that we can execute any code in here in any + * other mode than FIQ... Ok you can switch to another mode, but you can't + * get out of that mode without clobbering one register. + */ +vector_FIQ: disable_fiq + subs pc, lr, #4 + +/*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen, and won't happen in 32-bit data mode). + */ + +vector_addrexcptn: + b vector_addrexcptn + +/* + * We group all the following data together to optimise + * for CPUs with separate I & D caches. + */ + .align 5 + +.LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32) + .word __irq_invalid @ 1 (FIQ_26 / FIQ_32) + .word __irq_invalid @ 2 (IRQ_26 / IRQ_32) + .word __irq_svc @ 3 (SVC_26 / SVC_32) + .word __irq_invalid @ 4 + .word __irq_invalid @ 5 + .word __irq_invalid @ 6 + .word __irq_invalid @ 7 + .word __irq_invalid @ 8 + .word __irq_invalid @ 9 + .word __irq_invalid @ a + .word __irq_invalid @ b + .word __irq_invalid @ c + .word __irq_invalid @ d + .word __irq_invalid @ e + .word __irq_invalid @ f + +.LCtab_und: .word __und_usr @ 0 (USR_26 / USR_32) + .word __und_invalid @ 1 (FIQ_26 / FIQ_32) + .word __und_invalid @ 2 (IRQ_26 / IRQ_32) + .word __und_svc @ 3 (SVC_26 / SVC_32) + .word __und_invalid @ 4 + .word __und_invalid @ 5 + .word __und_invalid @ 6 + .word __und_invalid @ 7 + .word __und_invalid @ 8 + .word __und_invalid @ 9 + .word __und_invalid @ a + .word __und_invalid @ b + .word __und_invalid @ c + .word __und_invalid @ d + .word __und_invalid @ e + .word __und_invalid @ f + +.LCtab_dabt: .word __dabt_usr @ 0 (USR_26 / USR_32) + .word __dabt_invalid @ 1 (FIQ_26 / FIQ_32) + .word __dabt_invalid @ 2 (IRQ_26 / IRQ_32) + .word __dabt_svc @ 3 (SVC_26 / SVC_32) + .word __dabt_invalid @ 4 + .word __dabt_invalid @ 5 + .word __dabt_invalid @ 6 + .word __dabt_invalid @ 7 + .word __dabt_invalid @ 8 + .word __dabt_invalid @ 9 + .word __dabt_invalid @ a + .word __dabt_invalid @ b + .word __dabt_invalid @ c + .word __dabt_invalid @ d + .word __dabt_invalid @ e + .word __dabt_invalid @ f + +.LCtab_pabt: .word __pabt_usr + .word __pabt_invalid + +.LCvswi: .word vector_swi + +.LCsirq: .word __temp_irq +.LCsund: .word __temp_und +.LCsabt: .word __temp_abt + +__stubs_end: + + .equ __real_stubs_start, .LCvectors + 0x200 + +.LCvectors: swi SYS_ERROR0 + b __real_stubs_start + (vector_undefinstr - __stubs_start) + ldr pc, __real_stubs_start + (.LCvswi - __stubs_start) + b __real_stubs_start + (vector_prefetch - __stubs_start) + b __real_stubs_start + (vector_data - __stubs_start) + b __real_stubs_start + (vector_addrexcptn - __stubs_start) + b __real_stubs_start + (vector_IRQ - __stubs_start) + b __real_stubs_start + (vector_FIQ - __stubs_start) + +ENTRY(trap_init) + stmfd sp!, {r4 - r6, lr} + adr r0, __stubs_start @ copy stubs to 0x200 + adr r1, __stubs_end + mov r2, #0x200 +1: ldr r3, [r0], #4 + str r3, [r2], #4 + cmp r0, r1 + blt 1b + + adr r1, .LCvectors @ set up the vectors + mov r0, #0 + ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr} + stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr} + LOADREGS(fd, sp!, {r4 - r6, pc}) + .data +/* + * Do not reorder these, and do not insert extra data between... + */ + __temp_irq: .word 0 @ saved lr_irq .word 0 @ saved spsr_irq .word -1 @ old_r0 @@ -800,3 +881,10 @@ __temp_abt: .word 0 @ Saved lr_abt .word 0 @ Saved spsr_abt .word -1 @ old_r0 + + .globl SYMBOL_NAME(cr_alignment) + .globl SYMBOL_NAME(cr_no_alignment) +SYMBOL_NAME(cr_alignment): + .space 4 +SYMBOL_NAME(cr_no_alignment): + .space 4 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/entry-common.S linux.ac/arch/arm/kernel/entry-common.S --- linux.vanilla/arch/arm/kernel/entry-common.S Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/entry-common.S Sun Mar 7 17:07:40 1999 @@ -1,51 +1,54 @@ /*============================================================================ * All exits to user mode from the kernel go through this code. */ - -#include - .globl ret_from_sys_call -ret_from_exception: - adr r0, 1f - ldmia r0, {r0, r1} + .align 5 +fast_syscall_return: + str r0, [sp, #S_R0 + 4] @ returned r0 +slow_syscall_return: + add sp, sp, #4 +ret_from_sys_call: + adr r0, bh_data + ldmia r0, {r0, r4} ldr r0, [r0] - ldr r1, [r1] + ldr r1, [r4] tst r0, r1 blne SYMBOL_NAME(do_bottom_half) -ret_from_intr: ldr r0, [sp, #S_PSR] - tst r0, #3 - beq ret_with_reschedule - b ret_from_all +ret_with_reschedule: + get_current_task r1 @ check for scheduling + ldr r0, [r1, #TSK_NEED_RESCHED] + teq r0, #0 + bne ret_reschedule + ldr r1, [r1, #TSK_SIGPENDING] + teq r1, #0 @ check for signals + bne ret_signal + +ret_from_all: restore_user_regs ret_signal: mov r1, sp adrsvc al, lr, ret_from_all + mov r2, r4 b SYMBOL_NAME(do_signal) -2: bl SYMBOL_NAME(schedule) +ret_reschedule: adrsvc al, lr, ret_with_reschedule + b SYMBOL_NAME(schedule) -ret_from_sys_call: - adr r0, 1f + .globl ret_from_exception +ret_from_exception: + adr r0, bh_data ldmia r0, {r0, r1} ldr r0, [r0] ldr r1, [r1] tst r0, r1 - adrsvc ne, lr, ret_from_intr - bne SYMBOL_NAME(do_bottom_half) - -ret_with_reschedule: - get_current_task r1 - ldr r0, [r1, #TSK_NEED_RESCHED] - teq r0, #0 - bne 2b - ldr r1, [r1, #TSK_SIGPENDING] - teq r1, #0 - bne ret_signal - -ret_from_all: restore_user_regs + mov r4, #0 + blne SYMBOL_NAME(do_bottom_half) + ldr r0, [sp, #S_PSR] + tst r0, #3 @ returning to user mode? + beq ret_with_reschedule + b ret_from_all -1: .word SYMBOL_NAME(bh_mask) - .word SYMBOL_NAME(bh_active) +#include "calls.S" /*============================================================================= * SWI handler @@ -57,84 +60,61 @@ * too worried. */ -#include "calls.S" - + .align 5 vector_swi: save_user_regs - mov fp, #0 mask_pc lr, lr - ldr r6, [lr, #-4]! @ get SWI instruction + mov fp, #0 + ldr r6, [lr, #-4] @ get SWI instruction arm700_bug_check r6, r7 enable_irqs r7 - + + str r4, [sp, #-4]! @ new style: (r0 = arg1, r4 = arg5) + adrsvc al, lr, fast_syscall_return + bic r6, r6, #0xff000000 @ mask off SWI op-code eor r6, r6, #OS_NUMBER<<20 @ check OS number cmp r6, #NR_syscalls @ check upper syscall limit bcs 2f - get_current_task r5 - ldr ip, [r5, #TSK_FLAGS] @ check for syscall tracing - tst ip, #PF_TRACESYS - bne 1f + adr r5, SYMBOL_NAME(sys_call_table) - adr ip, SYMBOL_NAME(sys_call_table) - str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) - mov lr, pc - ldr pc, [ip, r6, lsl #2] @ call sys routine - add sp, sp, #4 - str r0, [sp, #S_R0] @ returned r0 - b ret_from_sys_call + get_current_task r7 + ldr ip, [r7, #TSK_FLAGS] @ check for syscall tracing + tst ip, #PF_TRACESYS + ldreq pc, [r5, r6, lsl #2] @ call sys routine -1: ldr r7, [sp, #S_IP] @ save old IP + ldr r7, [sp, #S_IP + 4] @ save old IP mov r0, #0 - str r0, [sp, #S_IP] @ trace entry [IP = 0] + str r0, [sp, #S_IP + 4] @ trace entry [IP = 0] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP] - ldmia sp, {r0 - r3} @ have to reload r0 - r3 - adr ip, SYMBOL_NAME(sys_call_table) - str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) + str r7, [sp, #S_IP + 4] + + ldmib sp, {r0 - r3} @ have to reload r0 - r3 mov lr, pc - ldr pc, [ip, r6, lsl #2] @ call sys routine - add sp, sp, #4 - str r0, [sp, #S_R0] @ returned r0 + ldr pc, [r5, r6, lsl #2] @ call sys routine + str r0, [sp, #S_R0 + 4] @ returned r0 + mov r0, #1 - str r0, [sp, #S_IP] @ trace exit [IP = 1] + str r0, [sp, #S_IP + 4] @ trace exit [IP = 1] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP] - b ret_from_sys_call + str r7, [sp, #S_IP + 4] + b slow_syscall_return -2: tst r6, #0x00f00000 @ is it a Unix SWI? +2: add r1, sp, #4 + tst r6, #0x00f00000 @ is it a Unix SWI? bne 3f - cmp r6, #(KSWI_SYS_BASE - KSWI_BASE) - bcc 4f @ not private func - bic r0, r6, #0x000f0000 - mov r1, sp - bl SYMBOL_NAME(arm_syscall) - b ret_from_sys_call - -3: eor r0, r6, #OS_NUMBER<<20 @ Put OS number back - mov r1, sp - bl SYMBOL_NAME(deferred) - ldmfd sp, {r0 - r3} - b ret_from_sys_call - -4: bl SYMBOL_NAME(sys_ni_syscall) - str r0, [sp, #0] @ returned r0 - b ret_from_sys_call + subs r0, r6, #(KSWI_SYS_BASE - KSWI_BASE) + bcs SYMBOL_NAME(arm_syscall) + b SYMBOL_NAME(sys_ni_syscall) @ not private func -@ r0 = syscall number -@ r1 = syscall r0 -@ r5 = syscall r4 -@ ip = syscall table -SYMBOL_NAME(sys_syscall): - mov r6, r0 - eor r6, r6, #OS_NUMBER << 20 - cmp r6, #NR_syscalls @ check range - movgt r0, #-ENOSYS - movgt pc, lr - add sp, sp, #4 @ take of the save of our r4 - ldmib sp, {r0 - r4} @ get our args - str r4, [sp, #-4]! @ Put our arg on the stack - ldr pc, [ip, r6, lsl #2] +3: eor r0, r6, #OS_NUMBER <<20 @ Put OS number back + adrsvc al, lr, slow_syscall_return + b SYMBOL_NAME(deferred) + + .align 5 + +bh_data: .word SYMBOL_NAME(bh_mask) + .word SYMBOL_NAME(bh_active) ENTRY(sys_call_table) #include "calls.S" @@ -142,10 +122,25 @@ /*============================================================================ * Special system call wrappers */ +@ r0 = syscall number +@ r5 = syscall table +SYMBOL_NAME(sys_syscall): + eor r6, r0, #OS_NUMBER << 20 + cmp r6, #NR_syscalls @ check range + ldmleib sp, {r0 - r4} @ get our args + strle r4, [sp] @ Put our arg on the stack + ldrle pc, [r5, r6, lsl #2] + mov r0, #-ENOSYS + mov pc, lr + sys_fork_wrapper: add r0, sp, #4 b SYMBOL_NAME(sys_fork) +sys_vfork_wrapper: + add r0, sp, #4 + b SYMBOL_NAME(sys_vfork) + sys_execve_wrapper: add r3, sp, #4 b SYMBOL_NAME(sys_execve) @@ -191,99 +186,6 @@ sys_sigaltstack_wrapper: ldr r2, [sp, #4 + S_SP] b do_sigaltstack - -/* - *============================================================================= - * Low-level interface code - *----------------------------------------------------------------------------- - * Trap initialisation - *----------------------------------------------------------------------------- - * - * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20 - * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes - * some excess cycles). - * - * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000 - * (the kernel). - * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for - * the actual address to jump to. - */ - - .section ".text.init",#alloc,#execinstr - -#if defined(CONFIG_CPU_32) -/* - * these go into 0x00 - */ -.Lbranches: swi SYS_ERROR0 - ldr pc, .Lbranches + 0xe4 - ldr pc, .Lbranches + 0xe8 - ldr pc, .Lbranches + 0xec - ldr pc, .Lbranches + 0xf0 - ldr pc, .Lbranches + 0xf4 - ldr pc, .Lbranches + 0xf8 - ldr pc, .Lbranches + 0xfc -/* - * this is put into 0xe4 and above - */ -.Ljump_addresses: - .word vector_undefinstr @ 0xe4 - .word vector_swi @ 0xe8 - .word vector_prefetch @ 0xec - .word vector_data @ 0xf0 - .word vector_addrexcptn @ 0xf4 - .word vector_IRQ @ 0xf8 - .word _unexp_fiq @ 0xfc -/* - * initialise the trap system - */ -ENTRY(trap_init) - stmfd sp!, {r4 - r7, lr} - initialise_traps_extra - mov r0, #0xe4 - adr r1, .Ljump_addresses - ldmia r1, {r1 - r7} - stmia r0, {r1 - r7} - mov r0, #0 - adr r1, .Lbranches - ldmia r1, {r1 - r7} - stmia r0, {r1 - r7} - LOADREGS(fd, sp!, {r4 - r7, pc}) -#elif defined(CONFIG_CPU_26) -.Ljump_addresses: - swi SYS_ERROR0 - .word vector_undefinstr - 12 - .word vector_swi - 16 - .word vector_prefetch - 20 - .word vector_data - 24 - .word vector_addrexcptn - 28 - .word vector_IRQ - 32 - .word _unexp_fiq - 36 - b . + 8 -/* - * initialise the trap system - */ -ENTRY(trap_init) - stmfd sp!, {r4 - r7, lr} - adr r1, .Ljump_addresses - ldmia r1, {r1 - r7, ip, lr} - orr r2, lr, r2, lsr #2 - orr r3, lr, r3, lsr #2 - orr r4, lr, r4, lsr #2 - orr r5, lr, r5, lsr #2 - orr r6, lr, r6, lsr #2 - orr r7, lr, r7, lsr #2 - orr ip, lr, ip, lsr #2 - mov r0, #0 - stmia r0, {r1 - r7, ip} - ldmfd sp!, {r4 - r7, pc}^ -#endif - - .previous - -/*============================================================================ - * FP support - */ .data diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/fiq.c linux.ac/arch/arm/kernel/fiq.c --- linux.vanilla/arch/arm/kernel/fiq.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/fiq.c Tue Feb 2 20:27:00 1999 @@ -2,6 +2,8 @@ * linux/arch/arm/kernel/fiq.c * * Copyright (C) 1998 Russell King + * Copyright (C) 1998, 1999 Phil Blundell + * * FIQ support written by Philip Blundell , 1998. * * FIQ support re-written by Russell King to be more generic @@ -111,23 +113,74 @@ #endif } +/* + * Taking an interrupt in FIQ mode is death, so both these functions + * disable irqs for the duration. + */ void set_fiq_regs(struct pt_regs *regs) { - /* not yet - - * this is temporary to get the floppy working - * again on RiscPC. It *will* become more - * generic. - */ -#ifdef CONFIG_ARCH_ACORN - extern void floppy_fiqsetup(unsigned long len, unsigned long addr, - unsigned long port); - floppy_fiqsetup(regs->ARM_r9, regs->ARM_r10, regs->ARM_fp); + register unsigned long tmp, tmp2; + __asm__ volatile ( +#ifdef CONFIG_CPU_26 + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, #0x0c000001 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + ldmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" +#endif +#ifdef CONFIG_CPU_32 + "mrs %0, cpsr + bic %1, %0, #0xf + orr %1, %1, #0xc1 + msr cpsr, %1 @ select FIQ mode + mov r0, r0 + ldmia %2, {r8 - r14} + msr cpsr, %0 @ return to SVC mode + mov r0, r0" #endif + : "=r" (tmp), "=r" (tmp2) + : "r" (®s->ARM_r8) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); } void get_fiq_regs(struct pt_regs *regs) { - /* not yet */ + register unsigned long tmp, tmp2; + __asm__ volatile ( +#ifdef CONFIG_CPU_26 + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, #0x0c000001 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + stmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" +#endif +#ifdef CONFIG_CPU_32 + "mrs %0, cpsr + bic %1, %0, #0xf + orr %1, %1, #0xc1 + msr cpsr, %1 @ select FIQ mode + mov r0, r0 + stmia %2, {r8 - r14} + msr cpsr, %0 @ return to SVC mode + mov r0, r0" +#endif + : "=r" (tmp), "=r" (tmp2) + : "r" (®s->ARM_r8) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); } int claim_fiq(struct fiq_handler *f) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/head-armv.S linux.ac/arch/arm/kernel/head-armv.S --- linux.vanilla/arch/arm/kernel/head-armv.S Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/head-armv.S Wed Feb 17 20:56:36 1999 @@ -8,12 +8,20 @@ #include #include -#ifndef CONFIG_ARCH_VNC +#define DEBUG + + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 + + .section ".text.init",#alloc,#execinstr +ENTRY(stext) +ENTRY(_stext) + #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 #endif -#else - .text + +#if defined(CONFIG_ARCH_VNC) || defined(CONFIG_ARCH_NETWINDER) mov r0, r0 mov r0, r0 mov r0, r0 @@ -22,16 +30,34 @@ mov r0, r0 mov r0, r0 mov r0, r0 + + adr r2, 1f + ldmdb r2, {r7, r8} + and r3, r2, #0x0000c000 + teq r3, #0x00008000 + beq __entry + bic r3, r2, #0xc000 + orr r3, r3, #0x8000 + mov r0, r3 + mov r4, #32 + sub r5, r8, r7 + b 1f + + .word _stext + .word _end + +1: ldmia r2!, {r6, r7, r8, r9} + stmia r3!, {r6, r7, r8, r9} + subs r4, r4, #16 + bcs 1b + movs r4, r5 + mov r5, #0 + movne pc, r0 + mov r0, #0 mov r1, #5 #endif -#define DEBUG - - .globl SYMBOL_NAME(swapper_pg_dir) - .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 - - .text /* * Entry point and restart point. Entry *must* be called with r0 == 0, * MMU off. Note! These should be unique!!! Please read Documentation/ARM-README @@ -45,16 +71,15 @@ * r1 = 5 -> Corel Netwinder * r1 = 6 -> CATS * r1 = 7 -> tbox + * r1 = 8 -> SA110/21285 as co-processor */ -ENTRY(stext) -ENTRY(_stext) __entry: teq r0, #0 @ check for illegal entry... bne .Lerror @ loop indefinitely cmp r1, #8 @ Unknown machine architecture bge .Lerror -/* First thing to do is to get the page tables set up so that we can call the kernel - * in the correct place. This is relocatable code... +/* First thing to do is to get the page tables set up so that we can call + * the kernel in the correct place. This is relocatable code... * - Read processor ID register (CP#15, CR0). */ mrc p15, 0, r9, c0, c0 @ get Processor ID @@ -111,7 +136,11 @@ add r3, r3, #1 << 20 teq r0, r2 bne 1b -#ifdef CONFIG_ARCH_VNC +#ifdef CONFIG_ARCH_NETWINDER + teq r1, #5 + bne 1f +#endif +#if defined(CONFIG_ARCH_VNC) || defined(CONFIG_ARCH_NETWINDER) add r0, r4, #0x3f00 add r0, r0, #0x00f8 mov r3, #0x7c000000 @@ -120,6 +149,7 @@ add r3, r3, #1 << 20 str r3, [r0], #4 #endif +1: #endif #ifdef CONFIG_ARCH_RPC /* Map in screen at 0x02000000 & SCREEN2_BASE @@ -250,7 +280,11 @@ mcr p15, 0, r4, c2, c0 @ load page table pointer mov r0, #0x1f @ Domains 0, 1 = client mcr p15, 0, r0, c3, c0 @ load domain access register +#ifdef CONFIG_ALIGNMENT_TRAP + mov r0, #0x3f @ ....S..DPWCAM +#else mov r0, #0x3d @ ....S..DPWC.M +#endif orr r0, r0, #0x100 mov pc, lr @@ -261,7 +295,11 @@ mcr p15, 0, r4, c2, c0 @ load page table pointer mov r0, #0x1f @ Domains 0, 1 = client mcr p15, 0, r0, c3, c0 @ load domain access register +#ifdef CONFIG_ALIGNMENT_TRAP + mov r0, #0x7f @ ....S.LDPWCAM +#else mov r0, #0x7d @ ....S.LDPWC.M +#endif orr r0, r0, #0x100 mov pc, lr @@ -276,12 +314,14 @@ mrc p15, 0, r0, c1, c0 @ get control register v4 bic r0, r0, #0x0e00 bic r0, r0, #0x0002 +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #0x003f @ I...S..DPWCAM +#else orr r0, r0, #0x003d @ I...S..DPWC.M +#endif orr r0, r0, #0x1100 @ v4 supports separate I cache mov pc, lr - .section ".text.init",#alloc,#execinstr - .Lsa_fastclock: mcr p15, 0, r4, c15, c1, 2 @ Enable clock switching mov pc, lr @@ -290,18 +330,22 @@ .long SYMBOL_NAME(__bss_start) .long SYMBOL_NAME(processor_id) .long SYMBOL_NAME(_end) + .long SYMBOL_NAME(cr_alignment) .long SYMBOL_NAME(init_task_union)+8192 .align .Lalready_done_mmap: adr r4, .LC0 - ldmia r4, {r3, r4, r5, r6, r8, sp} @ Setup stack + ldmia r4, {r3, r4, r5, r6, r7, r8, sp} @ Setup stack add r10, r10, r3 @ Add base back in mov fp, #0 -1: cmp r5, r8 @ Clear BSS +1: cmp r5, r7 @ Clear BSS strcc fp, [r5],#4 bcc 1b + bic r2, r0, #2 @ Clear 'A' bit + stmia r8, {r0, r2} @ Save control register values + str r1, [r4] @ Save machine type str r9, [r6] @ Save processor ID mov lr, pc @@ -362,7 +406,9 @@ beq 1001b .endm -#elif defined(CONFIG_ARCH_EBSA285) +#elif defined(CONFIG_HOST_FOOTBRIDGE) +#if 1 +/* For EBSA285 debugging */ .macro addruart,rx mov \rx, #0xfe000000 .endm @@ -379,26 +425,8 @@ .macro waituart,rd,rx .endm - -#elif defined(CONFIG_ARCH_NEXUSPCI) - .macro addruart,rx - ldr \rx, =0xfff00000 - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #0xc] - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x4] - tst \rd, #1 << 0 - bne 1001b - .endm - - .macro waituart,rd,rx - .endm - -#elif defined(CONFIG_ARCH_VNC) +#else +/* For NetWinder debugging */ .macro addruart,rx mov \rx, #0xff000000 orr \rx, \rx, #0x00e00000 @@ -421,6 +449,24 @@ tst \rd, #0x10 beq 1001b .endm +#endif +#elif defined(CONFIG_ARCH_NEXUSPCI) + .macro addruart,rx + ldr \rx, =0xfff00000 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0xc] + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x4] + tst \rd, #1 << 0 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm #else #error Unknown architecture #endif @@ -475,8 +521,6 @@ mov r1, r0 mov r0, #0 b 1b - - .ltorg .bss hexbuf: .space 16 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/hw-ebsa285.c linux.ac/arch/arm/kernel/hw-ebsa285.c --- linux.vanilla/arch/arm/kernel/hw-ebsa285.c Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/arm/kernel/hw-ebsa285.c Wed Jan 27 22:57:31 1999 @@ -3,27 +3,37 @@ * * EBSA285 hardware specific functions * - * Copyright (C) 1998 Russell King, Phil Blundel + * Copyright (C) 1998 Russell King, Phil Blundell */ +#include +#include #include #include #include #include #include #include +#include +#include #include +#include +#include #include +#include #include -extern int setup_arm_irq(int, struct irqaction *); +#define ETHER10_IO_BASE 0x301 +#define DEC21143_IO_BASE 0x401 +#define DEC21143_MEM_BASE 0x00800000 +#define CYBER2000_MEM_BASE 0x01000000 +extern int setup_arm_irq(int, struct irqaction *); extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set); extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr); extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq); -static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 }; -static int irqmap_cats[] __initdata = { 18, 8, 9, 11 }; +static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; __initfunc(static int ebsa_irqval(struct pci_dev *dev)) { @@ -37,10 +47,13 @@ return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; } +#ifdef CONFIG_CATS +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + __initfunc(static int cats_irqval(struct pci_dev *dev)) { if (dev->irq >= 128) - return 32 + (dev->irq & 0x1f); + return 16 + (dev->irq & 0x1f); switch (dev->irq) { case 1: @@ -56,77 +69,179 @@ dev->bus->number, dev->devfn, dev->irq); return 0; } +#endif __initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) { - char cmd; + /* Latency timer of 32 */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); + /* 32-byte cache line size */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + /* Set SysErr enable, Parity enable */ + pci_set_cmd(dev, PCI_COMMAND_FAST_BACK, PCI_COMMAND_SERR | PCI_COMMAND_PARITY); /* sort out the irq mapping for this device */ switch (machine_type) { case MACH_TYPE_EBSA285: dev->irq = ebsa_irqval(dev); + /* Turn on bus mastering - boot loader doesn't + * - perhaps it should! - dag + */ + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); break; + +#ifdef CONFIG_CATS case MACH_TYPE_CATS: dev->irq = cats_irqval(dev); + /* Turn on bus mastering - boot loader doesn't + * - perhaps it should! - dag + */ + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); break; +#endif +#ifdef CONFIG_ARCH_NETWINDER + case MACH_TYPE_NETWINDER: + /* disable ROM */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + /* Ether 100 */ + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + pci_set_base_addr(dev, 0, DEC21143_IO_BASE); + pci_set_base_addr(dev, 1, DEC21143_MEM_BASE); + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + dev->irq = IRQ_NETWINDER_ETHER100; + break; + + /* Ether 10 */ + case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a): + pci_set_base_addr(dev, 0, ETHER10_IO_BASE); + pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); + dev->irq = IRQ_NETWINDER_ETHER10; + break; + + /* ISA bridge */ + case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553): + pci_set_base_addr(dev, 0, 0); + pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); + /* + * Enable all memory requests from ISA to be channeled to PCI + */ + pci_write_config_byte(dev, 0x48, 255); + /* + * Disable ping-pong (as per errata) + */ + pci_write_config_byte(dev, 0x42, 0); + /* + * Enable PCI packet retry + */ + pci_write_config_byte(dev, 0x40, 0x22); + /* + * Do not use PCI CPU park enable, park on + * last master, disable GAT bit + */ + pci_write_config_byte(dev, 0x83, 0x02); + /* + * Default rotating priorities + */ + pci_write_config_byte(dev, 0x80, 0xe0); + /* + * Rotate bank 4 + */ + pci_write_config_byte(dev, 0x81, 0x01); + break; + + /* IDE */ + case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105): + pci_set_base_addr(dev, 0, 0x1f1); + pci_set_base_addr(dev, 1, 0x3f5); + pci_set_base_addr(dev, 2, 0x171); + pci_set_base_addr(dev, 3, 0x375); + pci_set_base_addr(dev, 4, 0xe801); + pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO); + dev->irq = IRQ_NETWINDER_IDE; + break; + + /* VGA */ + case DEV(PCI_VENDOR_ID_INTERG,0x2000): + pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE); + pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + dev->irq = IRQ_NETWINDER_VGA; + break; + } +#endif } - - /* Turn on bus mastering - boot loader doesn't - * - perhaps it should! - dag - */ - pci_read_config_byte(dev, PCI_COMMAND, &cmd); - pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); } -static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) +static void +irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) { - const char *err = "unknown"; - unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff; - unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07; - static unsigned long next_warn[7]; - int idx = 6; - - switch(irq) { - case IRQ_PCIPARITY: - *(unsigned long *)0xfe000004 = cmd | 1 << 31; - idx = 0; - err = "parity"; - break; + static unsigned long next_warn; + unsigned long cmd = *CSR_PCICMD & 0x0000ffff; + unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; + unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; + struct pci_dev *dev; + int warn = time_after_eq(jiffies, next_warn); + + if (warn) { + next_warn = jiffies + 3 * HZ / 100; + printk(KERN_DEBUG "PCI: "); + } - case IRQ_PCITARGETABORT: - *(unsigned long *)0xfe000004 = cmd | 1 << 28; - idx = 1; - err = "target abort"; - break; + if (irqstatus & (1 << 31)) { + if (warn) + printk("parity error "); + cmd |= 1 << 31; + } - case IRQ_PCIMASTERABORT: - *(unsigned long *)0xfe000004 = cmd | 1 << 29; - idx = 2; - err = "master abort"; - break; + if (irqstatus & (1 << 30)) { + if (warn) + printk("target abort "); + cmd |= 1 << 28; + } - case IRQ_PCIDATAPARITY: - *(unsigned long *)0xfe000004 = cmd | 1 << 24; - idx = 3; - err = "data parity"; - break; + if (irqstatus & (1 << 29)) { + if (warn) + printk("master abort "); + cmd |= 1 << 29; + } - case IRQ_DISCARDTIMER: - *(unsigned long *)0xfe00013c = ctrl | 1 << 8; - idx = 4; - err = "discard timer"; - break; + if (irqstatus & (1 << 28)) { + if (warn) + printk("data parity error "); + cmd |= 1 << 24; + } - case IRQ_SERR: - *(unsigned long *)0xfe00013c = ctrl | 1 << 3; - idx = 5; - err = "system"; - break; + if (irqstatus & (1 << 27)) { + if (warn) + printk("discard timer expired "); + ctrl |= SA110_CNTL_DISCARDTIMER; } - if (time_after_eq(jiffies, next_warn[idx])) { - next_warn[idx] = jiffies + 3 * HZ / 100; - printk(KERN_ERR "PCI %s error detected\n", err); + + if (irqstatus & (1 << 23)) { + if (warn) + printk("system error "); + ctrl |= SA110_CNTL_RXSERR; + } + + if (warn) + printk("pc=%08lX\n", instruction_pointer(regs)); + + for (dev = pci_devices; dev; dev = dev->next) { + unsigned short status; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status & 0xf900) { + printk("PCI: [%04X:%04X] status = %X\n", + dev->vendor, dev->device, status); + + pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + } } + + *CSR_PCICMD = cmd; + *CSR_SA110_CNTL = ctrl; } static struct irqaction irq_pci_error = { @@ -135,27 +250,384 @@ __initfunc(void pcibios_init_ebsa285(void)) { - setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error); - setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error); - setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error); - setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error); - setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error); - setup_arm_irq(IRQ_SERR, &irq_pci_error); + unsigned int mem_size = (int)high_memory - PAGE_OFFSET; + + setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error); /* * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is slightly - * bizarre but apparently necessary to avoid problems with some - * video cards. - * - * We should really only do this if the central function is enabled. + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). */ - *(unsigned long *)0xfe000010 = 0; - *(unsigned long *)0xfe000018 = 0xe0000000; - *(unsigned long *)0xfe0000f8 = 0; - *(unsigned long *)0xfe0000fc = 0; - *(unsigned long *)0xfe000100 = 0x01fc0000; - *(unsigned long *)0xfe000104 = 0; - *(unsigned long *)0xfe000108 = 0x80000000; - *(unsigned long *)0xfe000004 = 0x17; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = 0; + *CSR_PCICSRIOBASE = 0; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY; + *CSR_PCIADDR_EXTN = 0; +} + +/* + * Netwinder stuff + */ +#ifdef CONFIG_ARCH_NETWINDER +/* + * This is a lock for accessing ports 0x338 and 0x33a + */ +spinlock_t __netwinder_data gpio_lock = SPIN_LOCK_UNLOCKED; + +static unsigned int __netwinder_data current_gpio_op = 0; +static unsigned int __netwinder_data current_gpio_io = 0; +static unsigned int __netwinder_data current_cpld = 0; + +void __netwinder_text gpio_modify_op(int mask, int set) +{ + unsigned int new_gpio, changed; +unsigned long flags; save_flags_cli(flags); +if ((flags & 128) == 0) {printk("gpio_modify_op called with IRQs enabled from %p\n", __builtin_return_address(0)); __backtrace(); } + + new_gpio = (current_gpio_op & ~mask) | set; + changed = new_gpio ^ current_gpio_op; + current_gpio_op = new_gpio; + + if (changed & 0xff) + outb(new_gpio, 0x338); + if (changed & 0xff00) + outb(new_gpio >> 8, 0x33a); +restore_flags(flags); +} + +static inline void __gpio_modify_io(int mask, int in) +{ + unsigned int new_gpio, changed; + int port; + + new_gpio = (current_gpio_io & ~mask) | in; + changed = new_gpio ^ current_gpio_io; + current_gpio_io = new_gpio; + + changed >>= 1; + new_gpio >>= 1; + + outb(7, 0x370); + outb(7, 0x371); + + for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { + outb(port, 0x370); + outb(new_gpio & 1, 0x371); + + port += 1; + new_gpio >>= 1; + } + + outb(7, 0x370); + outb(8, 0x371); + + for (port = 0xe8; changed && port < 0xec; changed >>= 1) { + outb(port, 0x370); + outb(new_gpio & 1, 0x371); + + port += 1; + new_gpio >>= 1; + } +} + +void __netwinder_text gpio_modify_io(int mask, int in) +{ + /* Open up the SuperIO chip */ + outb(0x87, 0x370); + outb(0x87, 0x370); + + __gpio_modify_io(mask, in); + + /* Close up the EFER gate */ + outb(0xaa, 0x370); +} + +int __netwinder_text gpio_read(void) +{ + return inb(0x338) | inb(0x33a) << 8; +} + +void __netwinder_text cpld_modify(int mask, int set) +{ + int msk; + + current_cpld = (current_cpld & ~mask) | set; + + gpio_modify_io(GPIO_DATA, 0); + gpio_modify_op(GPIO_IOLOAD, 0); + + for (msk = 8; msk; msk >>= 1) { + int bit = current_cpld & msk; + + gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); + gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); + } + + gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); + gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); + gpio_modify_op(GPIO_IOLOAD, 0); +} + +__initfunc(static void hw_init_cpld(void)) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(-1, CPLD_UNMUTE | 4); + spin_unlock_irqrestore(&gpio_lock, flags); } + +__initfunc(static void hw_init_wb553(void)) +{ + unsigned long flags; +#define WRITE_REG(r,v) do { outb((r), 0x370); outb((v), 0x371); } while (0) + + /* Open up the SuperIO chip */ + outb(0x87, 0x370); + outb(0x87, 0x370); + + /* Set the serial interrupt numbers */ + WRITE_REG(7, 5); /* keyboard subsection */ + WRITE_REG(0x72, 5); /* interrupt number for mouse - IRQ5 */ + + WRITE_REG(7, 6); /* Infrared */ + WRITE_REG(0x70, 6); /* IRQ 6 */ + + WRITE_REG(0x2a, 0xc1); /* Enable GP12, GP11, GP10 as I/O, CIRRX, IRRXH */ + + WRITE_REG(0x2b, 0x6b); /* Enable GP23, GP22, GP21, GP20, GP13 as I/O */ + + WRITE_REG(0x2c, 0x55); /* Enable GP17, GP16, GP15, GP14 as I/O */ + + current_gpio_io = -1; + __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); + + WRITE_REG(7, 7); /* Aux function group 1 (dev 7) */ + WRITE_REG(0x60, 0x03); /* Group controlled by IO port 0x338 */ + WRITE_REG(0x61, 0x38); /* GP 11, 12, 13, 14, 15, 16 */ + + WRITE_REG(0x70, 0x0a); /* IRQ10 for GP10 (Orange button) */ + + WRITE_REG(0xe0, 0x19); /* GP10 control reg set for debounce & input */ + WRITE_REG(0x30, 0x01); /* Turn on section 7 (aux function group 1) */ + + WRITE_REG(7, 8); /* Aux function group 2 (dev 8) */ + WRITE_REG(0x60, 0x03); /* Group controlled by IO port 0x33a */ + WRITE_REG(0x61, 0x3a); + + /* Clear watchdog timer regs */ + WRITE_REG(0xf2, 0x00); /* Watchdog timeout value (disabled) */ + WRITE_REG(0xf3, 0x00); /* Watchdog reg (reset to default) */ + WRITE_REG(0xf4, 0x00); /* Reset if in timed out state (bit 0) */ + + /* T.B.D. set IRDA inputs (touch reg 2A, EC, ED) */ + WRITE_REG(0x30, 0x01); /* Turn on section 8 (aux function group 2) */ + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); + spin_unlock_irqrestore(&gpio_loc, flags); + + /* Close up the EFER gate */ + outb(0xaa, 0x370); +} + +static unsigned char rwa_unlock[] __initdata = +{ 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 }; + +#ifndef DEBUG +#define dprintk if (0) printk +#else +#define dprintk printk +#endif + +__initfunc(static void hw_init_rwa010(void)) +{ + unsigned char si[9]; + int i, j; + +#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0) + + WRITE_RWA(2, 2); + mdelay(10); + + for (i = 0; i < sizeof(rwa_unlock); i++) + outb(rwa_unlock[i], 0x279); + + WRITE_RWA(3, 0); + WRITE_RWA(0, 128); + + outb(1, 0x279); + + mdelay(10); + + dprintk("Identifier: "); + for (i = 0; i < 9; i++) { + si[i] = 0; + for (j = 0; j < 8; j++) { + int bit; + mdelay(1); + inb(0x203); + mdelay(1); + bit = inb(0x203); + dprintk("%02X ", bit); + si[i] |= bit << j; + } + mdelay(10); + dprintk("%02X ", si[i]); + } + dprintk("\n"); + + WRITE_RWA(6, 2); // Assign a card no = 2 + + dprintk("Card no = %d\n", inb(0x203)); + + WRITE_RWA(7, 3); + WRITE_RWA(0x30, 0); + + WRITE_RWA(7, 4); + WRITE_RWA(0x30, 0); + + WRITE_RWA(7, 2); + WRITE_RWA(0x30, 0); + + WRITE_RWA(7, 5); + + dprintk("Slider base: "); + WRITE_RWA(0x61, 1); + i = inb(0x203); + + WRITE_RWA(0x60, 2); + dprintk("%02X%02X (201)\n", inb(0x203), i); + + WRITE_RWA(0x30, 1); + + + WRITE_RWA(7, 0); + + dprintk("WaveArtist base: "); + WRITE_RWA(0x61, 0x50); + i = inb(0x203); + + WRITE_RWA(0x60, 0x02); + dprintk("%02X%02X (250),", inb(0x203), i); + + WRITE_RWA(0x70, 3); + dprintk(" irq: %d (3),", inb(0x203)); + + WRITE_RWA(0x74, 7); + dprintk(" dma: %d (7)\n", inb(0x203)); + + WRITE_RWA(0x30, 1); + + WRITE_RWA(7, 1); + + dprintk("SoundBlaster base: "); + WRITE_RWA(0x61, 0x20); + i = inb(0x203); + + WRITE_RWA(0x60, 0x02); + dprintk("%02X%02X (220),", inb(0x203), i); + + dprintk(" irq: "); + WRITE_RWA(0x70, 3); + dprintk("%d (3),", inb(0x203)); + + dprintk(" 8-bit DMA: "); + WRITE_RWA(0x74, 1); + dprintk("%d (1)\n", inb(0x203)); + + dprintk("AdLib base: "); + WRITE_RWA(0x63, 0x88); + i = inb(0x203); + + WRITE_RWA(0x62, 0x03); + dprintk("%02X%02X (388)\n", inb(0x203), i); + + WRITE_RWA(0x30, 1); + + outb(1, 0x226); + udelay(3); + outb(0, 0x226); + + for (i = 0; i < 5; i++) { + if (inb(0x22e) & 0x80) + break; + mdelay(1); + } + if (i == 5) + printk("SoundBlaster: DSP reset failed\n"); + + dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: DSP not ready\n"); + else { + outb(0xe1, 0x22c); + + dprintk("SoundBlaster DSP id: "); + i = inb(0x22a); + udelay(1); + i |= inb(0x22a) << 8; + dprintk("%04X\n", i); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: could not turn speaker off\n"); + + outb(0xd3, 0x22c); + } +} + +__initfunc(void hw_init(void)) +{ + unsigned long flags; + + hw_init_wb553(); + hw_init_cpld(); + hw_init_rwa010(); +#if 0 + /* does anyone want to have this in? */ + drum(); +#endif + +#ifdef CONFIG_LEDS /* Clear both LEDs and start the LED driver up */ + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, 0); + spin_unlock_irqrestore(&gpio_lock, flags); + leds_event(led_start); +#else /* Set the green LED on and the red LED off */ + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, GPIO_GREEN_LED); + spin_unlock_irqrestore(&gpio_lock, flags); +#endif /* CONFIG_LEDS */ +} + +EXPORT_SYMBOL(gpio_lock); +EXPORT_SYMBOL(gpio_modify_op); +EXPORT_SYMBOL(gpio_modify_io); +EXPORT_SYMBOL(cpld_modify); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/iic.c linux.ac/arch/arm/kernel/iic.c --- linux.vanilla/arch/arm/kernel/iic.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/iic.c Sat Jan 9 16:40:25 1999 @@ -9,8 +9,11 @@ #include #include -#include #include +#include +#include + +#define FORCE_ONES 0xdc /* * if delay loop has been calibrated then us that, @@ -42,7 +45,7 @@ { unsigned char out; - out = inb(IOC_CONTROL) | 0xc2; + out = inb(IOC_CONTROL) | FORCE_ONES | 0x02; outb(out, IOC_CONTROL); iic_delay(); @@ -55,7 +58,7 @@ { unsigned char out; - out = inb(IOC_CONTROL) | 0xc3; + out = inb(IOC_CONTROL) | FORCE_ONES | 0x03; iic_delay(); outb(out ^ 1, IOC_CONTROL); @@ -69,7 +72,7 @@ unsigned char out, in; int i; - out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + out = (inb(IOC_CONTROL) & 0xfc) | FORCE_ONES; outb(out, IOC_CONTROL); for (i = 7; i >= 0; i--) { @@ -110,7 +113,7 @@ unsigned char out, in; int i; - out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + out = (inb(IOC_CONTROL) & 0xfc) | FORCE_ONES; outb(out, IOC_CONTROL); in = 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/init_task.c linux.ac/arch/arm/kernel/init_task.c --- linux.vanilla/arch/arm/kernel/init_task.c Tue Dec 22 23:19:26 1998 +++ linux.ac/arch/arm/kernel/init_task.c Mon Dec 28 10:05:48 1998 @@ -6,6 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/ioport.c linux.ac/arch/arm/kernel/ioport.c --- linux.vanilla/arch/arm/kernel/ioport.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/ioport.c Thu Jan 1 01:00:00 1970 @@ -1,29 +0,0 @@ -/* - * linux/arch/arm/kernel/ioport.c - * - * Io-port support is not used for ARM - */ - -#include -#include -#include -#include -#include - -/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ -/*asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) -{ -}*/ - -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) -{ - return -ENOSYS; -} - -asmlinkage int sys_iopl(long ebx,long ecx,long edx, - long esi, long edi, long ebp, long eax, long ds, - long es, long fs, long gs, long orig_eax, - long eip,long cs,long eflags,long esp,long ss) -{ - return -ENOSYS; -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/irq.c linux.ac/arch/arm/kernel/irq.c --- linux.vanilla/arch/arm/kernel/irq.c Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/arm/kernel/irq.c Wed Feb 17 20:56:22 1999 @@ -49,6 +49,7 @@ unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; spinlock_t irq_controller_lock; +int setup_arm_irq(int, struct irqaction *); extern int get_fiq_list(char *); extern void init_FIQ(void); @@ -60,7 +61,8 @@ unsigned int probing : 1; /* IRQ in use for a probe */ unsigned int probe_ok : 1; /* IRQ can be used for probe */ unsigned int valid : 1; /* IRQ claimable */ - unsigned int unused :26; + unsigned int noautoenable : 1; /* don't automatically enable IRQ */ + unsigned int unused :25; void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */ void (*mask)(unsigned int irq); /* Mask IRQ */ void (*unmask)(unsigned int irq); /* Unmask IRQ */ @@ -71,6 +73,12 @@ static struct irqdesc irq_desc[NR_IRQS]; /* + * Get architecture specific interrupt handlers + * and interrupt initialisation. + */ +#include + +/* * Dummy mask/unmask handler */ static void dummy_mask_unmask_irq(unsigned int irq) @@ -94,10 +102,12 @@ spin_lock_irqsave(&irq_controller_lock, flags); cliIF(); - irq_desc[irq].enabled = 1; irq_desc[irq].probing = 0; irq_desc[irq].triggered = 0; - irq_desc[irq].unmask(irq); + if (!irq_desc[irq].noautoenable) { + irq_desc[irq].enabled = 1; + irq_desc[irq].unmask(irq); + } spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -119,7 +129,7 @@ *p++ = '\n'; } -#ifdef CONFIG_ACORN +#ifdef CONFIG_ARCH_ACORN p += get_fiq_list(p); #endif return p - buf; @@ -130,10 +140,14 @@ */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { - struct irqdesc * desc = irq_desc + irq; + struct irqdesc * desc; struct irqaction * action; int status, cpu; + irq = fixup_irq(irq); + + desc = irq_desc + irq; + spin_lock(&irq_controller_lock); desc->mask_ack(irq); spin_unlock(&irq_controller_lock); @@ -252,19 +266,17 @@ if (!shared) { irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; - irq_desc[irq].enabled = 1; irq_desc[irq].probing = 0; - irq_desc[irq].unmask(irq); + if (!irq_desc[irq].noautoenable) { + irq_desc[irq].enabled = 1; + irq_desc[irq].unmask(irq); + } } spin_unlock_irqrestore(&irq_controller_lock, flags); return 0; } -/* - * Using "struct sigaction" is slightly silly, but there - * are historical reasons and it works well, so.. - */ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irq_flags, const char * devname, void *dev_id) { @@ -346,7 +358,6 @@ continue; irq_desc[i].probing = 1; - irq_desc[i].enabled = 1; irq_desc[i].triggered = 0; irq_desc[i].unmask(i); irqs += 1; @@ -364,7 +375,8 @@ */ spin_lock_irq(&irq_controller_lock); for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].probing && irq_desc[i].triggered) { + if (irq_desc[i].probing && + irq_desc[i].triggered) { irq_desc[i].probing = 0; irqs -= 1; } @@ -383,7 +395,7 @@ int probe_irq_off(unsigned long irqs) { unsigned int i; - int irq_found = -1; + int irq_found = NO_IRQ; /* * look at the interrupts, and find exactly one @@ -393,7 +405,7 @@ for (i = 0; i < NR_IRQS; i++) { if (irq_desc[i].probing && irq_desc[i].triggered) { - if (irq_found != -1) { + if (irq_found != NO_IRQ) { irq_found = NO_IRQ; goto out; } @@ -405,21 +417,19 @@ irq_found = NO_IRQ; out: spin_unlock_irq(&irq_controller_lock); + return irq_found; } -/* - * Get architecture specific interrupt handlers - * and interrupt initialisation. - */ -#include - __initfunc(void init_IRQ(void)) { extern void init_dma(void); int irq; for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].probe_ok = 0; + irq_desc[irq].valid = 0; + irq_desc[irq].noautoenable = 0; irq_desc[irq].mask_ack = dummy_mask_unmask_irq; irq_desc[irq].mask = dummy_mask_unmask_irq; irq_desc[irq].unmask = dummy_mask_unmask_irq; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/leds-ebsa285.c linux.ac/arch/arm/kernel/leds-ebsa285.c --- linux.vanilla/arch/arm/kernel/leds-ebsa285.c Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/kernel/leds-ebsa285.c Sat Jan 23 23:35:01 1999 @@ -9,36 +9,77 @@ * - Amber - On if system is not idle * - Red - currently unused */ +#include +#include +#include + #include #include +#include #include -static char led_state = XBUS_LED_RED | XBUS_LED_GREEN; +static int led_state; +static char ebsa_led_state = XBUS_LED_RED | XBUS_LED_GREEN; void leds_event(led_event_t ledevt) { unsigned long flags; + switch (ledevt) { + case led_start: + led_state = !machine_is_cats(); + return; + + case led_stop: + led_state = 0; + return; + + default: + break; + } + + if (!led_state) + return; + save_flags_cli(flags); switch(ledevt) { +#ifdef CONFIG_LEDS_CPU case led_idle_start: - led_state |= XBUS_LED_AMBER; + ebsa_led_state |= XBUS_LED_AMBER; break; case led_idle_end: - led_state &= ~XBUS_LED_AMBER; + ebsa_led_state &= ~XBUS_LED_AMBER; break; - +#endif +#ifdef CONFIG_LEDS_TIMER case led_timer: - led_state ^= XBUS_LED_GREEN; + ebsa_led_state ^= XBUS_LED_GREEN; break; - +#endif default: break; } restore_flags(flags); - *XBUS_LEDS = led_state; + switch (machine_type) { +#ifdef CONFIG_ARCH_EBSA285 + case MACH_TYPE_EBSA285: + *XBUS_LEDS = led_state; + break; +#endif +#ifdef CONFIG_ARCH_NETWINDER + case MACH_TYPE_NETWINDER: + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, + (ebsa_led_state & XBUS_LED_AMBER ? GPIO_RED_LED : 0) | + (ebsa_led_state & XBUS_LED_GREEN ? GPIO_GREEN_LED : 0)); + spin_unlock_irqrestore(&gpio_lock, flags); + break; +#endif + default: + break; + } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/oldlatches.c linux.ac/arch/arm/kernel/oldlatches.c --- linux.vanilla/arch/arm/kernel/oldlatches.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/oldlatches.c Mon Feb 22 21:52:36 1999 @@ -4,6 +4,7 @@ * (c) David Alan Gilbert 1995/1996 */ #include +#include #include #include @@ -40,7 +41,7 @@ } #endif -void oldlatch_init(void) +void __init oldlatch_init(void) { printk("oldlatch: init\n"); #ifdef LATCHAADDR diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/process.c linux.ac/arch/arm/kernel/process.c --- linux.vanilla/arch/arm/kernel/process.c Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/kernel/process.c Fri Jan 22 23:00:37 1999 @@ -55,46 +55,37 @@ } /* - * The idle loop on an arm.. + * The idle loop on an ARM... */ asmlinkage int sys_idle(void) { - int ret = -EPERM; - - lock_kernel(); if (current->pid != 0) - goto out; + return -EPERM; + /* endless idle loop with no priority at all */ - current->priority = -100; - for (;;) - { + while (1) { + if (!current->need_resched && !hlt_counter) + proc_idle(); + current->policy = SCHED_YIELD; + schedule(); +#ifndef CONFIG_NO_PGT_CACHE check_pgt_cache(); -#if 0 //def ARCH_IDLE_OK - if (!hlt_counter && !current->need_resched) - proc_idle (); #endif - run_task_queue(&tq_scheduler); - schedule(); } - ret = 0; -out: - unlock_kernel(); - return ret; } +static char reboot_mode = 'h'; + __initfunc(void reboot_setup(char *str, int *ints)) { + reboot_mode = str[0]; } -/* - * This routine reboots the machine by resetting the expansion cards via - * their loaders, turning off the processor cache (if ARM3), copying the - * first instruction of the ROM to 0, and executing it there. - */ void machine_restart(char * __unused) { - proc_hard_reset (); - arch_hard_reset (); + arch_reset(reboot_mode); + panic("Reboot failed\n"); + while (1); } void machine_halt(void) @@ -150,6 +141,67 @@ } /* + * Task structure and kernel stack allocation. + * + * Taken from the i386 version. + */ +#ifdef CONFIG_CPU_32 +#define EXTRA_TASK_STRUCT 8 +static struct task_struct *task_struct_stack[EXTRA_TASK_STRUCT]; +static int task_struct_stack_ptr = -1; +#endif + +struct task_struct *alloc_task_struct(void) +{ + struct task_struct *tsk; + +#ifndef EXTRA_TASK_STRUCT + tsk = ll_alloc_task_struct(); +#else + int index; + + index = task_struct_stack_ptr; + if (index >= EXTRA_TASK_STRUCT/2) + goto use_cache; + + tsk = ll_alloc_task_struct(); + + if (!tsk) { + index = task_struct_stack_ptr; + + if (index >= 0) { +use_cache: tsk = task_struct_stack[index]; + task_struct_stack_ptr = index - 1; + } + } +#endif +#ifdef CONFIG_SYSRQ + /* You need this if you want SYSRQ-T to give sensible stack + * usage information + */ + if (tsk) { + char *p = (char *)tsk; + memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); + } +#endif + + return tsk; +} + +void free_task_struct(struct task_struct *p) +{ +#ifdef EXTRA_TASK_STRUCT + int index = task_struct_stack_ptr + 1; + + if (index < EXTRA_TASK_STRUCT) { + task_struct_stack[index] = p; + task_struct_stack_ptr = index; + } else +#endif + ll_free_task_struct(p); +} + +/* * Free current thread data structures etc.. */ void exit_thread(void) @@ -179,9 +231,10 @@ childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; *childregs = *regs; childregs->ARM_r0 = 0; + childregs->ARM_sp = esp; save = ((struct context_save_struct *)(childregs)) - 1; - copy_thread_css(save); + init_thread_css(save); p->tss.save = save; return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/setup.c linux.ac/arch/arm/kernel/setup.c --- linux.vanilla/arch/arm/kernel/setup.c Tue Dec 22 23:19:27 1998 +++ linux.ac/arch/arm/kernel/setup.c Sun Feb 28 09:21:05 1999 @@ -56,12 +56,16 @@ #define SUPPORT_CPU_SA110 #endif -#ifndef CONFIG_CMDLINE -#define CONFIG_CMDLINE "root=/dev/nfs rw" -#endif #define MEM_SIZE (16*1024*1024) #define COMMAND_LINE_SIZE 256 +#ifndef CONFIG_CMDLINE +#define CONFIG_CMDLINE "" +#endif + +extern void reboot_setup(char *str, int *ints); +extern void disable_hlt(void); + struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info = { orig_video_lines: 30, @@ -87,20 +91,26 @@ /*-- Match -- --- Mask -- -- Manu -- Processor uname -m --- ELF STUFF --- --- processor asm funcs --- */ #if defined(CONFIG_CPU_26) + /* ARM2 fake ident */ { 0x41560200, 0xfffffff0, "ARM/VLSI", "arm2" , "armv1" , "v1", 0, &arm2_processor_functions }, + /* ARM250 fake ident */ { 0x41560250, 0xfffffff0, "ARM/VLSI", "arm250" , "armv2" , "v2", HWCAP_SWP, &arm250_processor_functions }, + /* ARM3 processors */ { 0x41560300, 0xfffffff0, "ARM/VLSI", "arm3" , "armv2" , "v2", HWCAP_SWP, &arm3_processor_functions }, #elif defined(CONFIG_CPU_32) #ifdef SUPPORT_CPU_ARM6 + /* ARM6 */ { 0x41560600, 0xfffffff0, "ARM/VLSI", "arm6" , "armv3" , "v3", HWCAP_SWP, &arm6_processor_functions }, + /* ARM610 */ { 0x41560610, 0xfffffff0, "ARM/VLSI", "arm610" , "armv3" , "v3", HWCAP_SWP, &arm6_processor_functions }, #endif #ifdef SUPPORT_CPU_ARM7 + /* ARM7's have a strange numbering */ { 0x41007000, 0xffffff00, "ARM/VLSI", "arm7" , "armv3" , "v3", HWCAP_SWP, &arm7_processor_functions }, /* ARM710 IDs are non-standard */ @@ -108,10 +118,16 @@ &arm7_processor_functions }, #endif #ifdef SUPPORT_CPU_SA110 - { 0x4401a100, 0xfffffff0, "DEC", "sa110" , "armv4" , "v3", HWCAP_SWP|HWCAP_HALF, +#ifdef CONFIG_ARCH_RPC + /* Acorn RiscPC's can't handle ARMv4 half-word instructions */ + { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP, + &sa110_processor_functions }, +#else + { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP|HWCAP_HALF, &sa110_processor_functions }, #endif #endif +#endif { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL } }; @@ -132,139 +148,10 @@ */ /* - * Risc-PC specific initialisation - */ -#ifdef CONFIG_ARCH_RPC - -#include - -unsigned int vram_half_sam; - -static void -setup_rpc(struct param_struct *params) -{ - extern void init_dram_banks(const struct param_struct *params); - - init_dram_banks(params); - - switch (params->u1.s.pages_in_vram) { - case 256: - vram_half_sam = 1024; - break; - case 512: - default: - vram_half_sam = 2048; - } -} -#else -#define setup_rpc(x) -#endif - -#ifdef PARAMS_BASE - -#ifdef CONFIG_ARCH_ACORN -int memc_ctrl_reg; -int number_ide_drives; -int number_mfm_drives; -#endif - -static struct param_struct *params = (struct param_struct *)PARAMS_BASE; - -__initfunc(static char * -setup_params(unsigned long *mem_end_p)) -{ - ROOT_DEV = to_kdev_t(params->u1.s.rootdev); - ORIG_X = params->u1.s.video_x; - ORIG_Y = params->u1.s.video_y; - ORIG_VIDEO_COLS = params->u1.s.video_num_cols; - ORIG_VIDEO_LINES = params->u1.s.video_num_rows; - -#ifdef CONFIG_ARCH_ACORN -#ifndef CONFIG_FB - { - extern int bytes_per_char_h; - extern int bytes_per_char_v; - - bytes_per_char_h = params->u1.s.bytes_per_char_h; - bytes_per_char_v = params->u1.s.bytes_per_char_v; - } -#endif - memc_ctrl_reg = params->u1.s.memc_control_reg; - number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3; - number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; - - setup_rpc(params); - - if (!(params->u1.s.flags & FLAG_READONLY)) - root_mountflags &= ~MS_RDONLY; -#endif -#ifdef CONFIG_BLK_DEV_RAM - { - extern int rd_doload; - extern int rd_prompt; - extern int rd_image_start; - - rd_image_start = params->u1.s.rd_start; - rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0; - rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0; - } -#endif - -#ifdef CONFIG_ARCH_ACORN - *mem_end_p = GET_MEMORY_END(params); -#elif defined(CONFIG_ARCH_EBSA285) - *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages; -#else - *mem_end_p = PAGE_OFFSET + MEM_SIZE; -#endif - - return params->commandline; -} - -#else - -static char default_command_line[] __initdata = CONFIG_CMDLINE; - -__initfunc(static char * -setup_params(unsigned long *mem_end_p)) -{ - ROOT_DEV = 0x00ff; - -#ifdef CONFIG_BLK_DEV_RAM - { - extern int rd_doload; - extern int rd_prompt; - extern int rd_image_start; - - rd_image_start = 0; - rd_prompt = 1; - rd_doload = 1; - } -#endif - - *mem_end_p = PAGE_OFFSET + MEM_SIZE; - - return default_command_line; -} -#endif - -/* * initial ram disk */ #ifdef CONFIG_BLK_DEV_INITRD __initfunc(static void -setup_initrd(const struct param_struct *params)) -{ - if (params->u1.s.initrd_start) { - initrd_start = params->u1.s.initrd_start; - initrd_end = initrd_start + params->u1.s.initrd_size; - } else { - initrd_start = 0; - initrd_end = 0; - } -} - -__initfunc(static void check_initrd(unsigned long mem_start, unsigned long mem_end)) { if (initrd_end > mem_end) { @@ -276,7 +163,6 @@ } #else -#define setup_initrd(p) #define check_initrd(ms,me) #endif @@ -289,48 +175,47 @@ armidlist[armidindex].mask) armidindex += 1; - if (armidlist[armidindex].id == 0) { -#ifdef CONFIG_ARCH_ACORN - int i; - - for (i = 0; i < 3200; i++) - ((unsigned long *)SCREEN2_BASE)[i] = 0x77113322; -#endif + if (armidlist[armidindex].id == 0) while (1); - } processor = *armidlist[armidindex].proc; processor._proc_init(); } +static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; __initfunc(static void -setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end)) +setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz)) { - char c, *to = command_line; + char c = ' ', *to = command_line; int len = 0; *mem_start = (unsigned long)&_end; for (;;) { - if (cmd_line[0] == ' ' && - cmd_line[1] == 'm' && - cmd_line[2] == 'e' && - cmd_line[3] == 'm' && - cmd_line[4] == '=') { - *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0); - switch(*cmd_line) { - case 'M': - case 'm': - *mem_end <<= 10; - case 'K': - case 'k': - *mem_end <<= 10; + if (c == ' ') { + if (cmd_line[0] == 'm' && + cmd_line[1] == 'e' && + cmd_line[2] == 'm' && + cmd_line[3] == '=') { + *mem_sz = simple_strtoul(cmd_line+4, &cmd_line, 0); + switch(*cmd_line) { + case 'M': + case 'm': + *mem_sz <<= 10; + case 'K': + case 'k': + *mem_sz <<= 10; + cmd_line++; + } + } + /* if there are two spaces, remove one */ + if (*cmd_line == ' ') { cmd_line++; + continue; } - *mem_end = *mem_end + PAGE_OFFSET; } c = *cmd_line++; if (!c) @@ -341,8 +226,50 @@ } *to = '\0'; + + /* remove trailing spaces */ + while (*--to == ' ' && to != command_line) + *to = '\0'; +} + +__initfunc(static void +setup_ram(int doload, int prompt, int image_start)) +{ +#ifdef CONFIG_BLK_DEV_RAM + extern int rd_doload; + extern int rd_prompt; + extern int rd_image_start; + + rd_image_start = image_start; + rd_prompt = prompt; + rd_doload = doload; +#endif } +/* + * initial ram disk + */ +__initfunc(static void +setup_initrd(unsigned int start, unsigned int size)) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if (start) { + initrd_start = start; + initrd_end = start + size; + } else { + initrd_start = 0; + initrd_end = 0; + } +#endif +} + +#ifdef CONFIG_ARCH_ACORN +int memc_ctrl_reg; +int number_mfm_drives; +unsigned int vram_size; +int acornfb_depth; +#endif + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { @@ -350,6 +277,11 @@ unsigned long memory_end; char endian = 'l'; char *from; +#ifdef PARAMS_BASE + struct param_struct *params = (struct param_struct *)PARAMS_BASE; +#else + struct param_struct *params = NULL; +#endif if (smptrap == 1) return; @@ -357,23 +289,153 @@ setup_processor(); - from = setup_params(&memory_end); - setup_initrd(params); + init_task.mm->start_code = TASK_SIZE; + init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; + init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; + init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + + /* + * Add your machine dependencies here + */ +#ifndef CONFIG_CPU_26 + switch (machine_type) { + case MACH_TYPE_EBSA110: + /* EBSA110 locks if we execute 'wait for interrupt' */ + disable_hlt(); + params = NULL; + break; + + case MACH_TYPE_CATS: + /* CATS must use soft-reboot */ + reboot_setup("s", NULL); + break; + + case MACH_TYPE_NETWINDER: + /* + * to be fixed in a future NeTTrom + */ + if (params->u1.s.page_size == 4096) { + if (params->u1.s.nr_pages != 0x2000 && + params->u1.s.nr_pages != 0x4000) { + printk("Warning: bad NeTTrom parameters detected, using defaults\n"); + /* + * This stuff doesn't appear to be initialised + * properly by NeTTrom 2.0.6 and 2.0.7 + */ + params->u1.s.nr_pages = 0x2000; /* 32MB */ + params->u1.s.ramdisk_size = 0; + params->u1.s.flags = FLAG_READONLY; + params->u1.s.initrd_start = 0; + params->u1.s.initrd_size = 0; + params->u1.s.rd_start = 0; + params->u1.s.video_x = 0; + params->u1.s.video_y = 0; + params->u1.s.video_num_cols = 80; + params->u1.s.video_num_rows = 30; + } + } else { + printk("Warning: no NeTTrom parameter page detected, using " + "compiled-in settings\n"); + params = NULL; + } + break; + + default: + break; + } +#endif + + if (params) { + memory_end = params->u1.s.page_size * + params->u1.s.nr_pages; + + ROOT_DEV = to_kdev_t(params->u1.s.rootdev); +#ifdef CONFIG_OLD_CONSOLE + ORIG_X = params->u1.s.video_x; + ORIG_Y = params->u1.s.video_y; + ORIG_VIDEO_COLS = params->u1.s.video_num_cols; + ORIG_VIDEO_LINES = params->u1.s.video_num_rows; +#endif + + setup_ram((params->u1.s.flags & FLAG_RDLOAD) == 0, + (params->u1.s.flags & FLAG_RDPROMPT) == 0, + params->u1.s.rd_start); + + setup_initrd(params->u1.s.initrd_start, + params->u1.s.initrd_size); + + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + +#ifdef CONFIG_ARCH_ACORN + memc_ctrl_reg = params->u1.s.memc_control_reg; + number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; +#ifdef CONFIG_OLD_CONSOLE + { + extern int bytes_per_char_h; + extern int bytes_per_char_v; + + bytes_per_char_h = params->u1.s.bytes_per_char_h; + bytes_per_char_v = params->u1.s.bytes_per_char_v; + } +#elif defined(CONFIG_FB_ACORN) + { + switch (params->u1.s.bytes_per_char_h) { + case 1: acornfb_depth = 1; break; + case 2: acornfb_depth = 2; break; + case 4: acornfb_depth = 4; break; + case 8: acornfb_depth = 8; break; + case 24: acornfb_depth = 24; break; + default: acornfb_depth = 8; break; + } + } +#endif + +#ifdef CONFIG_ARCH_RPC + { + extern void init_dram_banks(struct param_struct *); + init_dram_banks(params); + } +#endif + + vram_size = 0; + + switch (params->u1.s.pages_in_vram) { + case 512: + vram_size += PAGE_SIZE * 256; + case 256: + vram_size += PAGE_SIZE * 256; + default: + break; + } + + memory_end -= vram_size; +#endif + + from = params->commandline; + } else { + memory_end = MEM_SIZE; + ROOT_DEV = 0x00ff; + + setup_ram(1, 1, 0); + setup_initrd(0, 0); + + from = default_command_line; + } + +#ifdef CONFIG_NWFPE + fpe_init(); +#endif /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, from, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; setup_mem(from, memory_start_p, &memory_end); - check_initrd(*memory_start_p, memory_end); - init_task.mm->start_code = TASK_SIZE; - init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; - init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; - init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + memory_end += PAGE_OFFSET; - *cmdline_p = command_line; - *memory_end_p = memory_end; + check_initrd(*memory_start_p, memory_end); sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, endian); sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, endian); @@ -385,6 +447,9 @@ conswitchp = &dummy_con; #endif #endif + + *cmdline_p = command_line; + *memory_end_p = memory_end; } static const struct { @@ -393,11 +458,12 @@ } machine_desc[] = { { "DEC-EBSA110", "DEC" }, { "Acorn-RiscPC", "Acorn" }, - { "Nexus-NexusPCI", "PCI" }, + { "unknown", "PCI" }, + { "Nexus-FTV/PCI", "PCI" }, { "DEC-EBSA285", "PCI" }, - { "Corel-Netwinder", "PCI/ISA" }, - { "Chalice-CATS", "PCI" }, - { "unknown-TBOX", "PCI" } + { "Corel-NetWinder", "PCI/ISA" }, + { "Chalice-CATS", "PCI/ISA" }, + { "unknown-TBOX", "none" } }; #if defined(CONFIG_ARCH_ARC) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/signal.c linux.ac/arch/arm/kernel/signal.c --- linux.vanilla/arch/arm/kernel/signal.c Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/kernel/signal.c Fri Jan 15 22:25:42 1999 @@ -28,7 +28,7 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); extern int ptrace_cancel_bpt (struct task_struct *); extern int ptrace_set_bpt (struct task_struct *); @@ -50,7 +50,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs, 0)) return regs->ARM_r0; } } @@ -78,7 +78,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs, 0)) return regs->ARM_r0; } } @@ -260,6 +260,18 @@ return err; } +static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long framesize) +{ + unsigned long sp = regs->ARM_sp; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)(sp - framesize); +} + static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { @@ -267,9 +279,9 @@ unsigned long retcode; int err = 0; - frame = (struct sigframe *)regs->ARM_sp - 1; + frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame))) + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto segv_and_exit; err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); @@ -299,6 +311,11 @@ regs->ARM_sp = (unsigned long)frame; regs->ARM_lr = retcode; regs->ARM_pc = (unsigned long)ka->sa.sa_handler; +#if defined(CONFIG_CPU_32) + /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + regs->ARM_cpsr = USR_MODE; +#endif if (valid_user_regs(regs)) return; @@ -315,7 +332,8 @@ unsigned long retcode; int err = 0; - frame = (struct rt_sigframe *)regs->ARM_sp - 1; + frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto segv_and_exit; @@ -350,6 +368,11 @@ regs->ARM_sp = (unsigned long)frame; regs->ARM_lr = retcode; regs->ARM_pc = (unsigned long)ka->sa.sa_handler; +#if defined(CONFIG_CPU_32) + /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + regs->ARM_cpsr = USR_MODE; +#endif if (valid_user_regs(regs)) return; @@ -393,18 +416,19 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) { - unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4); struct k_sigaction *ka; siginfo_t info; - int single_stepping, swi_instr; + int single_stepping; + + if (!user_mode(regs)) + return 0; if (!oldset) oldset = ¤t->blocked; single_stepping = ptrace_cancel_bpt (current); - swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000); for (;;) { unsigned long signr; @@ -503,7 +527,7 @@ } /* Are we from a system call? */ - if (swi_instr) { + if (syscall) { switch (regs->ARM_r0) { case -ERESTARTNOHAND: regs->ARM_r0 = -EINTR; @@ -527,7 +551,7 @@ return 1; } - if (swi_instr && + if (syscall && (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTARTNOINTR)) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/sys_arm.c linux.ac/arch/arm/kernel/sys_arm.c --- linux.vanilla/arch/arm/kernel/sys_arm.c Tue Dec 22 23:19:27 1998 +++ linux.ac/arch/arm/kernel/sys_arm.c Sun Feb 7 17:47:11 1999 @@ -221,13 +221,7 @@ */ asmlinkage int sys_fork(struct pt_regs *regs) { - int ret; - - lock_kernel(); - ret = do_fork(SIGCHLD, regs->ARM_sp, regs); - unlock_kernel(); - - return ret; + return do_fork(SIGCHLD, regs->ARM_sp, regs); } /* Clone a task - this clones the calling program thread. @@ -235,14 +229,14 @@ */ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) { - int ret; - - lock_kernel(); if (!newsp) newsp = regs->ARM_sp; - ret = do_fork(clone_flags, newsp, regs); - unlock_kernel(); - return ret; + return do_fork(clone_flags, newsp, regs); +} + +asmlinkage int sys_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs); } /* sys_execve() executes a new program. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/time.c linux.ac/arch/arm/kernel/time.c --- linux.vanilla/arch/arm/kernel/time.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/arm/kernel/time.c Sat Mar 20 22:42:39 1999 @@ -129,27 +129,12 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti (); + sti(); } -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick. - */ -static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - if (reset_timer ()) - do_timer(regs); - - update_rtc (); -} - -static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL}; - __initfunc(void time_init(void)) { - xtime.tv_sec = setup_timer(); xtime.tv_usec = 0; - setup_arm_irq(IRQ_TIMER, &irqtimer); + setup_timer(); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/traps.c linux.ac/arch/arm/kernel/traps.c --- linux.vanilla/arch/arm/kernel/traps.c Tue Dec 22 23:19:27 1998 +++ linux.ac/arch/arm/kernel/traps.c Fri Jan 22 09:09:37 1999 @@ -54,7 +54,7 @@ if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory) return -EFAULT; #endif - return 0; + return 0; } /* @@ -199,9 +199,8 @@ void bad_user_access_alignment (const void *ptr) { - void *pc; - __asm__("mov %0, lr\n": "=r" (pc)); - printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc); + printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, + __builtin_return_address(0)); current->tss.error_code = 0; current->tss.trap_no = 11; force_sig (SIGBUS, current); @@ -210,6 +209,10 @@ asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode) { +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", + current->comm, current->pid, instruction_pointer(regs)); +#endif current->tss.error_code = 0; current->tss.trap_no = 6; force_sig (SIGILL, current); @@ -218,6 +221,10 @@ asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode) { +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", + current->comm, current->pid, instruction_pointer(regs)); +#endif current->tss.error_code = 0; current->tss.trap_no = 11; force_sig (SIGBUS, current); @@ -249,19 +256,14 @@ */ asmlinkage void math_state_restore (void) { - current->used_math = 1; + current->used_math = 1; } -asmlinkage void arm_syscall (int no, struct pt_regs *regs) +asmlinkage int arm_syscall (int no, struct pt_regs *regs) { switch (no) { case 0: /* branch through 0 */ force_sig(SIGSEGV, current); -// if (user_mode(regs)) { -// dump_state("branch through zero", regs, 0); -// if (regs->ARM_fp) -// c_backtrace (regs->ARM_fp, processor_mode(regs)); -// } die_if_kernel ("branch through zero", regs, 0, SIGSEGV); break; @@ -271,21 +273,54 @@ force_sig (SIGTRAP, current); break; + case 2: /* sys_cacheflush */ +#ifdef CONFIG_CPU_32 + /* r0 = start, r1 = length, r2 = flags */ + processor.u.armv3v4._flush_cache_area(regs->ARM_r0, + regs->ARM_r1, + 1); +#endif + break; + default: + /* Calls 9f00xx..9f07ff are defined to return -ENOSYS + if not implemented, rather than raising SIGILL. This + way the calling program can gracefully determine whether + a feature is supported. */ + if (no <= 0x7ff) + return -ENOSYS; +#ifdef CONFIG_DEBUG_USER + /* experiance shows that these seem to indicate that + * something catastrophic has happened + */ printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); - force_sig (SIGILL, current); if (user_mode(regs)) { show_regs (regs); c_backtrace (regs->ARM_fp, processor_mode(regs)); } +#endif + force_sig (SIGILL, current); die_if_kernel ("Oops", regs, no, SIGILL); break; } + return 0; } asmlinkage void deferred(int n, struct pt_regs *regs) { - dump_state("old system call", regs, n); + /* You might think just testing `handler' would be enough, but PER_LINUX + points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. */ + if (current->personality != PER_LINUX && current->exec_domain->handler) { + /* Hand it off to iBCS. The extra parameter and consequent type + forcing is necessary because of the weird ARM calling convention. */ + void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler; + (*handler)(n, regs); + return; + } +#ifdef CONFIG_DEBUG_USER + printk(KERN_ERR "[%d] %s: old system call.\n", current->pid, + current->comm); +#endif force_sig (SIGILL, current); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/Makefile linux.ac/arch/arm/lib/Makefile --- linux.vanilla/arch/arm/lib/Makefile Tue Dec 22 23:19:27 1998 +++ linux.ac/arch/arm/lib/Makefile Sun Feb 28 10:24:55 1999 @@ -6,14 +6,14 @@ L_TARGET := lib.a L_OBJS := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \ - system.o string.o uaccess.o + semaphore.o string.o system.o uaccess.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o endif ifdef CONFIG_ARCH_ACORN - L_OBJS += loaders.o ll_char_wr.o io-acorn.o + L_OBJS += loaders.o io-acorn.o ifdef CONFIG_ARCH_A5K L_OBJS += floppydma.o endif @@ -24,10 +24,6 @@ ifeq ($(MACHINE),ebsa110) L_OBJS += io-ebsa110.o -endif - -ifeq ($(MACHINE),vnc) - L_OBJS += io-ebsa285.o endif ifeq ($(MACHINE),ebsa285) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/checksum.S linux.ac/arch/arm/lib/checksum.S --- linux.vanilla/arch/arm/lib/checksum.S Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/lib/checksum.S Thu Dec 10 20:14:34 1998 @@ -520,13 +520,13 @@ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) ldr r4, [r0], #4 tst r2, #2 - beq Lexit + beq Lexit_r4 adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 mov r4, r4, lsr #8 - b Lexit + b Lexit_r4 Ltoo_small: teq r2, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) @@ -538,10 +538,12 @@ adds r3, r3, ip strb ip, [r1], #1 strb r8, [r1], #1 -Lexit: tst r2, #1 -Ltoo_small1: ldrneb ip, [r0], #1 - strneb ip, [r1], #1 - adcnes r3, r3, ip + tst r2, #1 +Ltoo_small1: ldrneb r4, [r0], #1 +Lexit_r4: tst r2, #1 + strneb r4, [r1], #1 + andne r4, r4, #255 + adcnes r3, r3, r4 adcs r0, r3, #0 LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) @@ -598,13 +600,13 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + beq Lexit_r4 adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 mov r4, r4, lsr #8 - b Lexit + b Lexit_r4 Lsrc2_aligned: mov r4, r4, lsr #16 adds r3, r3, #0 @@ -650,13 +652,13 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + beq Lexit_r4 adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 ldrb r4, [r0], #1 - b Lexit + b Lexit_r4 Lsrc3_aligned: mov r4, r4, lsr #24 adds r3, r3, #0 @@ -702,14 +704,14 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + beq Lexit_r4 adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 ldr r4, [r0], #4 strb r4, [r1], #1 adcs r3, r3, r4, lsl #24 mov r4, r4, lsr #8 - b Lexit + b Lexit_r4 ENTRY(__csum_ipv6_magic) stmfd sp!, {lr} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/floppydma.S linux.ac/arch/arm/lib/floppydma.S --- linux.vanilla/arch/arm/lib/floppydma.S Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/lib/floppydma.S Tue Feb 2 20:31:32 1999 @@ -26,32 +26,3 @@ strb r12, [r11, #-4] subs pc, lr, #4 SYMBOL_NAME(floppy_fiqout_end): - -@ Params: -@ r0 = length -@ r1 = address -@ r2 = floppy port -@ Puts these into R9_fiq, R10_fiq, R11_fiq -ENTRY(floppy_fiqsetup) - mov ip, sp - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #4 - MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode - mov r0, r0 - mov r9, r0 - mov r10, r1 - mov r11, r2 - RESTOREMODE(r3) @ back to normal - mov r0, r0 - LOADREGS(ea,fp,{fp, sp, pc}) - -ENTRY(floppy_fiqresidual) - mov ip, sp - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #4 - MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode - mov r0, r0 - mov r0, r9 - RESTOREMODE(r3) - mov r0, r0 - LOADREGS(ea,fp,{fp, sp, pc}) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-acorn.S linux.ac/arch/arm/lib/io-acorn.S --- linux.vanilla/arch/arm/lib/io-acorn.S Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/lib/io-acorn.S Sun Feb 28 19:12:36 1999 @@ -11,50 +11,514 @@ .text .align -#define OUT(reg) \ - mov r8, reg, lsl $16 ;\ - orr r8, r8, r8, lsr $16 ;\ - str r8, [r3, r0, lsl $2] ;\ - mov r8, reg, lsr $16 ;\ - orr r8, r8, r8, lsl $16 ;\ - str r8, [r3, r0, lsl $2] - -#define IN(reg) \ - ldr reg, [r0] ;\ - and reg, reg, ip ;\ - ldr lr, [r0] ;\ - orr reg, reg, lr, lsl $16 - - .equ pcio_base_high, PCIO_BASE & 0xff000000 - .equ pcio_base_low, PCIO_BASE & 0x00ff0000 - .equ io_base_high, IO_BASE & 0xff000000 - .equ io_base_low, IO_BASE & 0x00ff0000 - - .equ addr_io_diff_hi, pcio_base_high - io_base_high - .equ addr_io_diff_lo, pcio_base_low - io_base_low - - .macro addr reg, off - tst \off, #0x80000000 - .if addr_io_diff_hi - movne \reg, #IO_BASE - moveq \reg, #pcio_base_high - .if pcio_base_low - addeq \reg, \reg, #pcio_base_low - .endif - .else - mov \reg, #IO_BASE - addeq \reg, \reg, #addr_io_diff_lo - .endif + .equ diff_pcio_base, PCIO_BASE - IO_BASE + + .macro outw2 rd + mov r8, \rd, lsl #16 + orr r8, r8, r8, lsr #16 + str r8, [r3, r0, lsl #2] + mov r8, \rd, lsr #16 + orr r8, r8, r8, lsl #16 + str r8, [r3, r0, lsl #2] + .endm + + .macro inw2 rd, mask, temp + ldr \rd, [r0] + and \rd, \rd, \mask + ldr \temp, [r0] + orr \rd, \rd, \temp, lsl #16 + .endm + + .macro addr rd + tst \rd, #0x80000000 + mov \rd, \rd, lsl #2 + add \rd, \rd, #IO_BASE + addeq \rd, \rd, #diff_pcio_base .endm -@ Purpose: read a block of data from a hardware register to memory. -@ Proto : insw(int from_port, void *to, int len_in_words); -@ Proto : inswb(int from_port, void *to, int len_in_bytes); -@ Notes : increment to +.iosw_bad_align_msg: + .ascii "insw: bad buffer alignment (%p), called from %08lX\n\0" +.iosl_warning: + .ascii "<4>insl/outsl not implemented, called from %08lX\0" + .align + +/* + * These make no sense on Acorn machines. + * Print a warning message. + */ +ENTRY(insl) +ENTRY(outsl) + adr r0, .iosl_warning + mov r1, lr + b SYMBOL_NAME(printk) + +.iosw_bad_alignment: + adr r0, .iosw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) + + +/* Purpose: read a block of data from a hardware register to memory. + * Proto : void insw(int from_port, void *to, int len_in_words); + * Notes : increment to, 'to' must be 16-bit aligned + */ + +.insw_align: tst r1, #1 + bne .iosw_bad_alignment + + ldr r3, [r0] + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strb r3, [r1], #1 + + subs r2, r2, #1 + bne .insw_aligned ENTRY(insw) + teq r2, #0 + RETINSTR(moveq,pc,lr) + addr r0 + tst r1, #3 + bne .insw_align + +.insw_aligned: mov ip, #0xff + orr ip, ip, ip, lsl #8 + stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_insw_8 + +.insw_8_lp: ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + ldr r5, [r0] + and r5, r5, ip + ldr r6, [r0] + orr r5, r5, r6, lsl #16 + + ldr r6, [r0] + and r6, r6, ip + ldr lr, [r0] + orr r6, r6, lr, lsl #16 + + stmia r1!, {r3 - r6} + subs r2, r2, #8 + bpl .insw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_insw_8: tst r2, #4 + beq .no_insw_4 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + stmia r1!, {r3, r4} + +.no_insw_4: tst r2, #2 + beq .no_insw_2 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + str r3, [r1], #4 + +.no_insw_2: tst r2, #1 + ldrne r3, [r0] + strneb r3, [r1], #1 + movne r3, r3, lsr #8 + strneb r3, [r1] + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + +@ Purpose: write a block of data from memory to a hardware register. +@ Proto : outsw(int to_reg, void *from, int len_in_words); +@ Notes : increments from + +.outsw_align: tst r1, #1 + bne .iosw_bad_alignment + + add r1, r1, #2 + + ldr r3, [r1, #-4] + mov r3, r3, lsr #16 + orr r3, r3, r3, lsl #16 + str r3, [r0] + subs r2, r2, #1 + bne .outsw_aligned + +ENTRY(outsw) + teq r2, #0 + RETINSTR(moveq,pc,lr) + addr r0 + tst r1, #3 + bne .outsw_align + +.outsw_aligned: stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_outsw_8 +.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r5, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r5, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r6, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r6, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + subs r2, r2, #8 + bpl .outsw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_outsw_8: tst r2, #4 + beq .no_outsw_4 + + ldmia r1!, {r3, r4} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_4: tst r2, #2 + beq .no_outsw_2 + + ldr r3, [r1], #4 + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_2: tst r2, #1 + + ldrne r3, [r1] + + movne ip, r3, lsl #16 + orrne ip, ip, ip, lsr #16 + strne ip, [r0] + + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + +.insb_align: rsb ip, ip, #4 + cmp ip, r2 + movgt ip, r2 + cmp ip, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1], #1 + subs r2, r2, ip + bne .insb_aligned + +ENTRY(insb) + teq r2, #0 + moveq pc, lr + addr r0 + ands ip, r1, #3 + bne .insb_align + +.insb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .insb_no_16 + +.insb_16_lp: ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + ldrb r5, [r0] + ldrb r6, [r0] + orr r5, r5, r6, lsl #8 + ldrb r6, [r0] + orr r5, r5, r6, lsl #16 + ldrb r6, [r0] + orr r5, r5, r6, lsl #24 + ldrb r6, [r0] + ldrb ip, [r0] + orr r6, r6, ip, lsl #8 + ldrb ip, [r0] + orr r6, r6, ip, lsl #16 + ldrb ip, [r0] + orr r6, r6, ip, lsl #24 + stmia r1!, {r3 - r6} + subs r2, r2, #16 + bpl .insb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.insb_no_16: tst r2, #8 + beq .insb_no_8 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + stmia r1!, {r3, r4} + +.insb_no_8: tst r2, #4 + bne .insb_no_4 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + str r3, [r1], #4 + +.insb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1] + LOADREGS(fd, sp!, {r4 - r6, pc}) + + + +.outsb_align: rsb ip, ip, #4 + cmp ip, r2 + mov ip, r2 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1], #1 + strgtb r3, [r0] + subs r2, r2, ip + bne .outsb_aligned + +ENTRY(outsb) + teq r2, #0 + moveq pc, lr + addr r0 + ands ip, r1, #3 + bne .outsb_align + +.outsb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .outsb_no_16 + +.outsb_16_lp: ldmia r1!, {r3 - r6} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + subs r2, r2, #16 + bpl .outsb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.outsb_no_16: tst r2, #8 + beq .outsb_no_8 + + ldmia r1, {r3, r4} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + +.outsb_no_8: tst r2, #4 + bne .outsb_no_4 + + ldr r3, [r1], #4 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + +.outsb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1] + strgtb r3, [r0] + LOADREGS(fd, sp!, {r4 - r6, pc}) + + + + +@ Purpose: write a memc register +@ Proto : void memc_write(int register, int value); +@ Returns: nothing + +#if defined(CONFIG_CPU_26) +ENTRY(memc_write) + cmp r0, #7 + RETINSTR(movgt,pc,lr) + mov r0, r0, lsl #17 + mov r1, r1, lsl #15 + mov r1, r1, lsr #17 + orr r0, r0, r1, lsl #2 + add r0, r0, #0x03600000 + strb r0, [r0] + RETINSTR(mov,pc,lr) +#define CPSR2SPSR(rt) +#else +#define CPSR2SPSR(rt) \ + mrs rt, cpsr; \ + msr spsr, rt +#endif + +@ Purpose: call an expansion card loader to read bytes. +@ Proto : char read_loader(int offset, char *card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_read) + stmfd sp!, {r4 - r12, lr} + mov r11, r1 + mov r1, r0 + CPSR2SPSR(r0) + mov lr, pc + mov pc, r2 + LOADREGS(fd, sp!, {r4 - r12, pc}) + +@ Purpose: call an expansion card loader to reset the card +@ Proto : void read_loader(int card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_reset) + stmfd sp!, {r4 - r12, lr} + mov r11, r0 + CPSR2SPSR(r0) + mov lr, pc + add pc, r1, #8 + LOADREGS(fd, sp!, {r4 - r12, pc}) + + +#if 0 mov r2, r2, lsl#1 -ENTRY(inswb) mov ip, sp stmfd sp!, {r4 - r10, fp, ip, lr, pc} sub fp, ip, #4 @@ -122,14 +586,9 @@ bgt Linsw_notaligned LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) -@ Purpose: write a block of data from memory to a hardware register. -@ Proto : outsw(int to_reg, void *from, int len_in_words); -@ Proto : outswb(int to_reg, void *from, int len_in_bytes); -@ Notes : increments from ENTRY(outsw) - mov r2, r2, LSL#1 -ENTRY(outswb) + mov r2, r2, lsl#1 mov ip, sp stmfd sp!, {r4 - r8, fp, ip, lr, pc} sub fp, ip, #4 @@ -166,56 +625,5 @@ bgt 3b LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) -/* - * These make no sense on Acorn machines atm. - */ -ENTRY(insl) -ENTRY(outsl) - RETINSTR(mov,pc,lr) - -@ Purpose: write a memc register -@ Proto : void memc_write(int register, int value); -@ Returns: nothing - -#if defined(CONFIG_CPU_26) -ENTRY(memc_write) - cmp r0, #7 - RETINSTR(movgt,pc,lr) - mov r0, r0, lsl #17 - mov r1, r1, lsl #15 - mov r1, r1, lsr #17 - orr r0, r0, r1, lsl #2 - add r0, r0, #0x03600000 - strb r0, [r0] - RETINSTR(mov,pc,lr) -#define CPSR2SPSR(rt) -#else -#define CPSR2SPSR(rt) \ - mrs rt, cpsr; \ - msr spsr, rt #endif -@ Purpose: call an expansion card loader to read bytes. -@ Proto : char read_loader(int offset, char *card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_read) - stmfd sp!, {r4 - r12, lr} - mov r11, r1 - mov r1, r0 - CPSR2SPSR(r0) - mov lr, pc - mov pc, r2 - LOADREGS(fd, sp!, {r4 - r12, pc}) - -@ Purpose: call an expansion card loader to reset the card -@ Proto : void read_loader(int card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_reset) - stmfd sp!, {r4 - r12, lr} - mov r11, r0 - CPSR2SPSR(r0) - mov lr, pc - add pc, r1, #8 - LOADREGS(fd, sp!, {r4 - r12, pc}) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-ebsa110.S linux.ac/arch/arm/lib/io-ebsa110.S --- linux.vanilla/arch/arm/lib/io-ebsa110.S Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/lib/io-ebsa110.S Sun Feb 28 21:08:34 1999 @@ -22,6 +22,22 @@ ldr lr, [r0] ;\ orr reg, reg, lr, lsl $16 +/* + * These make no sense on these machines. + * Print a warning message. + */ +ENTRY(insl) +ENTRY(outsl) +ENTRY(insb) +ENTRY(outsb) + adr r0, io_long_warning + mov r1, lr + b SYMBOL_NAME(printk) + +io_long_warning: + .ascii "<4>ins?/outs? not implemented on this architecture\0" + .align + @ Purpose: read a block of data from a hardware register to memory. @ Proto : insw(int from_port, void *to, int len_in_words); @ Proto : inswb(int from_port, void *to, int len_in_bytes); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-ebsa285.S linux.ac/arch/arm/lib/io-ebsa285.S --- linux.vanilla/arch/arm/lib/io-ebsa285.S Tue Dec 22 23:19:27 1998 +++ linux.ac/arch/arm/lib/io-ebsa285.S Fri Jan 15 19:12:00 1999 @@ -1,8 +1,12 @@ #include + .macro ioaddr, rd,rn + add \rd, \rn, #0xff000000 + add \rd, \rd, #0x00e00000 + .endm + ENTRY(insl) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 ands ip, r1, #3 bne 2f @@ -14,49 +18,48 @@ 2: cmp ip, #2 ldr ip, [r0] - blt 3f - bgt 4f + blt 4f + bgt 6f strh ip, [r1], #2 mov ip, ip, lsr #16 -1: subs r2, r2, #1 +3: subs r2, r2, #1 ldrne r3, [r0] orrne ip, ip, r3, lsl #16 strne ip, [r1], #4 movne ip, r3, lsr #16 - bne 1b + bne 3b strh ip, [r1], #2 mov pc, lr -3: strb ip, [r1], #1 +4: strb ip, [r1], #1 mov ip, ip, lsr #8 strh ip, [r1], #2 mov ip, ip, lsr #16 -1: subs r2, r2, #1 +5: subs r2, r2, #1 ldrne r3, [r0] orrne ip, ip, r3, lsl #8 strne ip, [r1], #4 movne ip, r3, lsr #24 - bne 1b + bne 5b strb ip, [r1], #1 mov pc, lr -4: strb ip, [r1], #1 +6: strb ip, [r1], #1 mov ip, ip, lsr #8 -1: subs r2, r2, #1 +7: subs r2, r2, #1 ldrne r3, [r0] orrne ip, ip, r3, lsl #24 strne ip, [r1], #4 movne ip, r3, lsr #8 - bne 1b + bne 7b strb ip, [r1], #1 mov ip, ip, lsr #8 strh ip, [r1], #2 mov pc, lr ENTRY(outsl) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 ands ip, r1, #3 bne 2f @@ -70,31 +73,31 @@ cmp ip, #2 ldr ip, [r1], #4 mov ip, ip, lsr #16 - blt 3f - bgt 4f + blt 4f + bgt 5f -1: ldr r3, [r1], #4 +3: ldr r3, [r1], #4 orr ip, ip, r3, lsl #16 str ip, [r0] mov ip, r3, lsr #16 subs r2, r2, #1 - bne 1b + bne 3b mov pc, lr -3: ldr r3, [r1], #4 +4: ldr r3, [r1], #4 orr ip, ip, r3, lsl #8 str ip, [r0] mov ip, r3, lsr #24 subs r2, r2, #1 - bne 3b + bne 4b mov pc, lr -4: ldr r3, [r1], #4 +5: ldr r3, [r1], #4 orr ip, ip, r3, lsl #24 str ip, [r0] mov ip, r3, lsr #8 subs r2, r2, #1 - bne 4b + bne 5b mov pc, lr /* Nobody could say these are optimal, but not to worry. */ @@ -102,8 +105,7 @@ ENTRY(outswb) mov r2, r2, lsr #1 ENTRY(outsw) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 1: subs r2, r2, #1 ldrgeh r3, [r1], #2 strgeh r3, [r0] @@ -114,8 +116,7 @@ mov r2, r2, lsr #1 ENTRY(insw) stmfd sp!, {r4, r5, lr} - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 subs ip, r2, #8 blo too_little @@ -176,8 +177,7 @@ ENTRY(insb) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 1: teq r2, #0 ldrneb r3, [r0] strneb r3, [r1], #1 @@ -187,8 +187,7 @@ ENTRY(outsb) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 + ioaddr r0, r0 1: teq r2, #0 ldrneb r3, [r1], #1 strneb r3, [r0] diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/ll_char_wr.S linux.ac/arch/arm/lib/ll_char_wr.S --- linux.vanilla/arch/arm/lib/ll_char_wr.S Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/lib/ll_char_wr.S Thu Jan 1 01:00:00 1970 @@ -1,158 +0,0 @@ -/* - * linux/arch/arm/lib/ll_char_wr.S - * - * Copyright (C) 1995, 1996 Russell King. - * - * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. - * - * 10-04-96 RMK Various cleanups & reduced register usage. - * 08-04-98 RMK Shifts re-ordered - */ - -@ Regs: [] = corruptible -@ {} = used -@ () = do not use - -#include -#include - .text - -#define BOLD 0x01 -#define ITALIC 0x02 -#define UNDERLINE 0x04 -#define FLASH 0x08 -#define INVERSE 0x10 - -LC0: .word SYMBOL_NAME(bytes_per_char_h) - .word SYMBOL_NAME(video_size_row) - .word SYMBOL_NAME(cmap_80) - .word SYMBOL_NAME(con_charconvtable) - -ENTRY(ll_write_char) - stmfd sp!, {r4 - r7, lr} -@ -@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) -@ - eor ip, r1, #UNDERLINE << 9 -/* - * calculate colours - */ - tst r1, #INVERSE << 9 - moveq r2, r1, lsr #16 - moveq r3, r1, lsr #24 - movne r2, r1, lsr #24 - movne r3, r1, lsr #16 - and r3, r3, #255 - and r2, r2, #255 -/* - * calculate offset into character table - */ - mov r1, r1, lsl #23 - mov r1, r1, lsr #20 -/* - * calculate offset required for each row [maybe I should make this an argument to this fn. - * Have to see what the register usage is like in the calling routines. - */ - adr r4, LC0 - ldmia r4, {r4, r5, r6, lr} - ldr r4, [r4] - ldr r5, [r5] -/* - * Go to resolution-dependent routine... - */ - cmp r4, #4 - blt Lrow1bpp - eor r2, r3, r2 @ Create eor mask to change colour from bg - orr r3, r3, r3, lsl #8 @ to fg. - orr r3, r3, r3, lsl #16 - add r0, r0, r5, lsl #3 @ Move to bottom of character - add r1, r1, #7 - ldrb r7, [r6, r1] - tst ip, #UNDERLINE << 9 - eoreq r7, r7, #255 - teq r4, #8 - beq Lrow8bpplp -@ -@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) -@ - orr r3, r3, r3, lsl #4 -Lrow4bpplp: ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow4bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) - -@ -@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) -@ -Lrow8bpplp: mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow8bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) - -@ -@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) -@ -Lrow1bpp: add r6, r6, r1 - ldmia r6, {r4, r7} - tst ip, #INVERSE << 9 - mvnne r4, r4 - mvnne r7, r7 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - tst ip, #UNDERLINE << 9 - mvneq r7, r7 - strb r7, [r0], r5 - LOADREGS(fd, sp!, {r4 - r7, pc}) - - .bss -ENTRY(con_charconvtable) - .space 1024 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/semaphore.S linux.ac/arch/arm/lib/semaphore.S --- linux.vanilla/arch/arm/lib/semaphore.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/lib/semaphore.S Sun Jan 3 10:37:24 1999 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/semaphore.S + * + * Idea from i386 code, Copyright Linus Torvalds. + * Converted for ARM by Russell King + */ +#include +#include + +/* + * The semaphore operations have a special calling sequence + * that allows us to keep the distruption of the main code + * path to a minimum. These routines save and restore the + * registers that will be touched by __down etc. + */ +ENTRY(__down_failed) + stmfd sp!, {r0 - r3, ip, lr} + bl SYMBOL_NAME(__down) + LOADREGS(fd, sp!, {r0 - r3, ip, pc}) + +ENTRY(__down_interruptible_failed) + stmfd sp!, {r1 - r3, ip, lr} + bl SYMBOL_NAME(__down_interruptible) + LOADREGS(fd, sp!, {r1 - r3, ip, pc}) + +ENTRY(__up_wakeup) + stmfd sp!, {r0 - r3, ip, lr} + bl SYMBOL_NAME(__up) + LOADREGS(fd, sp!, {r0 - r3, ip, pc}) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/Makefile linux.ac/arch/arm/mm/Makefile --- linux.vanilla/arch/arm/mm/Makefile Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/mm/Makefile Sun Feb 7 22:59:05 1999 @@ -8,29 +8,20 @@ # Note 2! The CFLAGS definition is now in the main makefile... all: lib first_rule -ifeq ($(MACHINE),a5k) -MMARCH=arc -else -MMARCH=$(MACHINE) -endif O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o ifeq ($(PROCESSOR),armo) O_OBJS += proc-arm2,3.o endif ifeq ($(PROCESSOR),armv) - O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o + O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o endif include $(TOPDIR)/Rules.make -proc-arm2,3.o: ../lib/constants.h -proc-arm6,7.o: ../lib/constants.h -proc-sa110.o: ../lib/constants.h - %.o: %.S ifneq ($(CONFIG_BINUTILS_NEW),y) $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s @@ -42,3 +33,11 @@ .PHONY: lib lib:; @$(MAKE) -C ../lib constants.h + +# Special dependencies +fault-armv.o: fault-common.c +fault-armo.o: fault-common.c +proc-arm2,3.o: ../lib/constants.h +proc-arm6,7.o: ../lib/constants.h +proc-sa110.o: ../lib/constants.h + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-armo.c linux.ac/arch/arm/mm/fault-armo.c --- linux.vanilla/arch/arm/mm/fault-armo.c Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/fault-armo.c Sun Feb 7 23:09:50 1999 @@ -1,11 +1,10 @@ /* - * linux/arch/arm/mm/fault.c + * linux/arch/arm/mm/fault-armo.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995, 1996 Russell King + * Modifications for ARM processor (c) 1995-1999 Russell King */ -#include #include #include #include @@ -15,8 +14,7 @@ #include #include #include -#include -#include +#include #include #include @@ -27,35 +25,32 @@ #define FAULT_CODE_WRITE 0x02 #define FAULT_CODE_USER 0x01 -struct pgtable_cache_struct quicklists; +#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) +#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) -void __bad_pmd(pmd_t *pmd) +#include "fault-common.c" + +static void *alloc_table(int size, int prio) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + if (size != 128) + printk("invalid table size\n"); + return (void *)get_page_8k(prio); } -void __bad_pmd_kernel(pmd_t *pmd) +void free_table(void *table) { - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + free_page_8k((unsigned long)table); } pgd_t *get_pgd_slow(void) { - pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); + pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); pgd_t *init; - + if (pgd) { init = pgd_offset(&init_mm, 0); - memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); } return pgd; @@ -65,17 +60,17 @@ { pte_t *pte; - pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); set_pmd(pmd, mk_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); return NULL; } - kfree (pte); + free_table((void *)pte); if (pmd_bad(*pmd)) { __bad_pmd(pmd); return NULL; @@ -83,126 +78,22 @@ return (pte_t *) pmd_page(*pmd) + offset; } -extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); - -static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) -{ - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - pgd_t *pgd; - if (addr < PAGE_SIZE) - printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - else - printk (KERN_ALERT "Unable to handle kernel paging request"); - printk (" at virtual address %08lx\n", addr); - printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap); - pgd = pgd_offset (mm, addr); - printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd)); - if (!pgd_none (*pgd)) { - pmd_t *pmd; - pmd = pmd_offset (pgd, addr); - printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) - printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr))); - } - printk ("\n"); - die_if_kernel ("Oops", regs, mode, SIGKILL); - do_exit (SIGKILL); -} - -static void -handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs) -{ - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long fixup; - - lock_kernel(); - tsk = current; - mm = tsk->mm; - - down(&mm->mmap_sem); - vma = find_vma (mm, addr); - if (!vma) - goto bad_area; - if (addr >= vma->vm_start) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr)) - goto bad_area; - - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - if (!(mode & FAULT_CODE_WRITE)) { /* write? */ - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) - goto bad_area; - } else { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } - handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)); - up(&mm->mmap_sem); - goto out; - - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up(&mm->mmap_sem); - if (mode & FAULT_CODE_USER) { -//extern int console_loglevel; -//cli(); - tsk->tss.error_code = mode; - tsk->tss.trap_no = 14; -//console_loglevel = 9; - printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -//#ifdef DEBUG - show_regs (regs); - c_backtrace (regs->ARM_fp, 0); -//#endif - force_sig(SIGSEGV, tsk); -//while (1); - goto out; - } - - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); - regs->ARM_pc = fixup; - goto out; - } - - - kernel_page_fault (addr, mode, regs, tsk, mm); -out: - unlock_kernel(); -} - /* * Handle a data abort. Note that we have to handle a range of addresses * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write + * a copy-on-write. However, on the second page, we always force COW. */ asmlinkage void -do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) +do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) { - handle_dataabort (min_addr, mode, regs); + do_page_fault(min_addr, mode, regs); if ((min_addr ^ max_addr) >> PAGE_SHIFT) - handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs); + do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); } asmlinkage int -do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs) +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { #if 0 if (the memc mapping for this page exists - can check now...) { @@ -210,6 +101,6 @@ return 0; } #endif - handle_dataabort (addr, mode, regs); + do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs); return 1; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-armv.c linux.ac/arch/arm/mm/fault-armv.c --- linux.vanilla/arch/arm/mm/fault-armv.c Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/fault-armv.c Sun Feb 7 23:09:48 1999 @@ -1,10 +1,11 @@ /* - * linux/arch/arm/mm/fault.c + * linux/arch/arm/mm/fault-armv.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995, 1996 Russell King + * Modifications for ARM processor (c) 1995-1999 Russell King */ +#include #include #include #include @@ -14,42 +15,35 @@ #include #include #include -#include -#include +#include +#include +#include #include #include #include +#include #define FAULT_CODE_READ 0x02 #define FAULT_CODE_USER 0x01 -struct pgtable_cache_struct quicklists; +#define DO_COW(m) (!((m) & FAULT_CODE_READ)) +#define READ_FAULT(m) ((m) & FAULT_CODE_READ) -void __bad_pmd(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); -} - -void __bad_pmd_kernel(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); -} +#include "fault-common.c" pgd_t *get_pgd_slow(void) { /* * need to get a 16k page for level 1 */ - pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2); + pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); pgd_t *init; - + if (pgd) { init = pgd_offset(&init_mm, 0); - memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); } return pgd; @@ -59,17 +53,17 @@ { pte_t *pte; - pte = (pte_t *) get_small_page(GFP_KERNEL); + pte = (pte_t *)get_page_1k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); set_pmd(pmd, mk_user_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); return NULL; } - free_small_page ((unsigned long) pte); + free_page_1k((unsigned long) pte); if (pmd_bad(*pmd)) { __bad_pmd(pmd); return NULL; @@ -81,17 +75,17 @@ { pte_t *pte; - pte = (pte_t *) get_small_page(GFP_KERNEL); + pte = (pte_t *) get_page_1k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); set_pmd(pmd, mk_kernel_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); return NULL; } - free_small_page ((unsigned long) pte); + free_page_1k((unsigned long) pte); if (pmd_bad(*pmd)) { __bad_pmd_kernel(pmd); return NULL; @@ -99,10 +93,8 @@ return (pte_t *) pmd_page(*pmd) + offset; } -extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); - #ifdef DEBUG -static int sp_valid (unsigned long *sp) +static int sp_valid(unsigned long *sp) { unsigned long addr = (unsigned long) sp; @@ -114,187 +106,340 @@ } #endif -static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) +#ifdef CONFIG_ALIGNMENT_TRAP +/* + * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 + * /proc/sys/debug/alignment, modified and integrated into + * Linux 2.1 by Russell King + * + * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also, + * it seems to give a severe performance impact (1 abort/ms - NW runs at + * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS. + * + * IMHO, I don't think that the trap handler is advantageous on ARM6,7 + * processors (they'll run like an ARM3). We'll see. + */ +#define CODING_BITS(i) (i & 0x0e000000) + +#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ +#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ +#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ +#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ +#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ + +#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ +#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ + +#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ +#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ +#define RM_BITS(i) (i & 15) /* Rm */ + +#define REGMASK_BITS(i) (i & 0xffff) +#define OFFSET_BITS(i) (i & 0x0fff) + +#define IS_SHIFT(i) (i & 0x0ff0) +#define SHIFT_BITS(i) ((i >> 7) & 0x1f) +#define SHIFT_TYPE(i) (i & 0x60) +#define SHIFT_LSL 0x00 +#define SHIFT_LSR 0x20 +#define SHIFT_ASR 0x40 +#define SHIFT_RORRRX 0x60 + +static unsigned long ai_user; +static unsigned long ai_sys; +static unsigned long ai_skipped; +static unsigned long ai_half; +static unsigned long ai_word; +static unsigned long ai_multi; + +static int proc_alignment_read(char *page, char **start, off_t off, + int count, int *eof, void *data) { - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - pgd_t *pgd; - if (addr < PAGE_SIZE) - printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - else - printk (KERN_ALERT "Unable to handle kernel paging request"); - printk (" at virtual address %08lx\n", addr); - printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap); - pgd = pgd_offset (mm, addr); - printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd)); - if (!pgd_none (*pgd)) { - pmd_t *pmd; - pmd = pmd_offset (pgd, addr); - printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) - printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr))); - } - printk ("\n"); - die_if_kernel ("Oops", regs, mode, SIGKILL); - do_exit (SIGKILL); + char *p = page; + int len; + + p += sprintf(p, "User:\t\t%li\n", ai_user); + p += sprintf(p, "System:\t\t%li\n", ai_sys); + p += sprintf(p, "Skipped:\t%li\n", ai_skipped); + p += sprintf(p, "Half:\t\t%li\n", ai_half); + p += sprintf(p, "Word:\t\t%li\n", ai_word); + p += sprintf(p, "Multi:\t\t%li\n", ai_multi); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; } -static void page_fault (unsigned long addr, int mode, struct pt_regs *regs) +/* + * This needs to be done after sysctl_init, otherwise sys/ + * will be overwritten. + */ +void __init alignment_init(void) { - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long fixup; - - lock_kernel(); - tsk = current; - mm = tsk->mm; - - down(&mm->mmap_sem); - vma = find_vma (mm, addr); - if (!vma) - goto bad_area; - if (vma->vm_start <= addr) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr)) - goto bad_area; + struct proc_dir_entry *e; - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - if (mode & FAULT_CODE_READ) { /* read? */ - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) - goto bad_area; - } else { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } - handle_mm_fault (tsk, vma, addr & PAGE_MASK, !(mode & FAULT_CODE_READ)); - up(&mm->mmap_sem); - goto out; + e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL); - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up(&mm->mmap_sem); - if (mode & FAULT_CODE_USER) { - tsk->tss.error_code = mode; - tsk->tss.trap_no = 14; - printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -#ifdef DEBUG - { - unsigned int i, j; - unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid (sp); j++) { - printk ("%p: ", sp); - for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) - printk ("%08lx ", *sp); - printk ("\n"); + if (e) + e->read_proc = proc_alignment_read; +} + +static void +do_alignment_exception(struct pt_regs *regs) +{ + unsigned int instr, rd, rn, correction, nr_regs, regbits; + unsigned long eaddr; + union { unsigned long un; signed long sn; } offset; + + if (user_mode(regs)) { + set_cr(cr_no_alignment); + ai_user += 1; + return; + } + + ai_sys += 1; + + instr = *(unsigned long *)instruction_pointer(regs); + correction = 4; /* sometimes 8 on ARMv3 */ + regs->ARM_pc += correction + 4; + + rd = RD_BITS(instr); + rn = RN_BITS(instr); + eaddr = regs->uregs[rn]; + + switch(CODING_BITS(instr)) { + case 0x00000000: + if ((instr & 0x0ff00ff0) == 0x01000090) { + ai_skipped += 1; + printk(KERN_ERR "Unaligned trap: not handling swp instruction\n"); + break; + } + + if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) { + ai_half += 1; + if (LDSTH_I_BIT(instr)) + offset.un = (instr & 0xf00) >> 4 | (instr & 15); + else + offset.un = regs->uregs[RM_BITS(instr)]; + + if (LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; } + + if (LDST_L_BIT(instr)) + regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); + else + put_unaligned(regs->uregs[rd], (unsigned short *)eaddr); + + /* signed half-word? */ + if (instr & 0x40) + regs->uregs[rd] = (long)((short) regs->uregs[rd]); + + if (!LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + regs->uregs[rn] = eaddr; + } else if (LDST_W_BIT(instr)) + regs->uregs[rn] = eaddr; + break; } - show_regs (regs); - c_backtrace (regs->ARM_fp, regs->ARM_cpsr); -#endif - force_sig(SIGSEGV, tsk); - goto out; - } - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); - regs->ARM_pc = fixup; - goto out; + default: + ai_skipped += 1; + panic("Alignment trap: not handling instruction %08X at %08lX", + instr, regs->ARM_pc - correction - 4); + break; + + case 0x04000000: + offset.un = OFFSET_BITS(instr); + goto ldr_str; + + case 0x06000000: + offset.un = regs->uregs[RM_BITS(instr)]; + + if (IS_SHIFT(instr)) { + unsigned int shiftval = SHIFT_BITS(instr); + + switch(SHIFT_TYPE(instr)) { + case SHIFT_LSL: + offset.un <<= shiftval; + break; + + case SHIFT_LSR: + offset.un >>= shiftval; + break; + + case SHIFT_ASR: + offset.sn >>= shiftval; + break; + + case SHIFT_RORRRX: + if (shiftval == 0) { + offset.un >>= 1; + if (regs->ARM_cpsr & CC_C_BIT) + offset.un |= 1 << 31; + } else + offset.un = offset.un >> shiftval | + offset.un << (32 - shiftval); + break; + } + } + + ldr_str: + ai_word += 1; + if (LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + } else { + if (LDST_W_BIT(instr)) + printk(KERN_ERR "Not handling ldrt/strt correctly\n"); + } + + if (LDST_L_BIT(instr)) { + regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); + if (rd == 15) + correction = 0; + } else + put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); + + if (!LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + + regs->uregs[rn] = eaddr; + } else if (LDST_W_BIT(instr)) + regs->uregs[rn] = eaddr; + break; + + case 0x08000000: + if (LDM_S_BIT(instr)) + panic("Alignment trap: not handling LDM with s-bit\n"); + ai_multi += 1; + + for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) + nr_regs += 4; + + if (!LDST_U_BIT(instr)) + eaddr -= nr_regs; + + if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || + (LDST_U_BIT(instr) && LDST_P_BIT(instr))) + eaddr += 4; + + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); + if (rd == 15) + correction = 0; + } else + put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); + eaddr += 4; + } + + if (LDST_W_BIT(instr)) { + if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) + eaddr -= nr_regs; + else if (LDST_P_BIT(instr)) + eaddr -= 4; + else if (!LDST_U_BIT(instr)) + eaddr -= 4 + nr_regs; + regs->uregs[rn] = eaddr; + } + break; } - kernel_page_fault (addr, mode, regs, tsk, mm); -out: - unlock_kernel(); + regs->ARM_pc -= correction; } -/* - * Handle a data abort. Note that we have to handle a range of addresses - * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write - */ +#endif + asmlinkage void -do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs) +do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { if (user_mode(regs)) error_code |= FAULT_CODE_USER; + #define DIE(signr,nam)\ force_sig(signr, current);\ die_if_kernel(nam, regs, fsr, signr);\ - break; + break switch (fsr & 15) { case 2: - DIE(SIGKILL, "Terminal exception") + DIE(SIGKILL, "Terminal exception"); case 0: - DIE(SIGSEGV, "Vector exception") + DIE(SIGSEGV, "Vector exception"); case 1: case 3: - DIE(SIGBUS, "Alignment exception") +#ifdef CONFIG_ALIGNMENT_TRAP + do_alignment_exception(regs); +#else + /* this should never happen */ + DIE(SIGBUS, "Alignment exception"); +#endif + break; + case 12: case 14: - DIE(SIGBUS, "External abort on translation") + DIE(SIGBUS, "External abort on translation"); case 9: case 11: - DIE(SIGSEGV, "Domain fault") + DIE(SIGSEGV, "Domain fault"); case 13:/* permission fault on section */ +#ifdef CONFIG_DEBUG_USER + printk("%s: permission fault on section, address=0x%08lx, code %d\n", + current->comm, addr, error_code); #ifdef DEBUG { unsigned int i, j; unsigned long *sp; - printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n", - current->comm, addr, error_code); sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid (sp); j++) { - printk ("%p: ", sp); - for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) - printk ("%08lx ", *sp); - printk ("\n"); + for (j = 0; j < 20 && sp_valid(sp); j++) { + printk("%p: ", sp); + for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++) + printk("%08lx ", *sp); + printk("\n"); } - show_regs (regs); + show_regs(regs); c_backtrace(regs->ARM_fp, regs->ARM_cpsr); } #endif - DIE(SIGSEGV, "Permission fault") +#endif + DIE(SIGSEGV, "Permission fault"); case 15:/* permission fault on page */ case 5: /* page-table entry descriptor fault */ case 7: /* first-level descriptor fault */ - page_fault (addr, error_code, regs); + do_page_fault(addr, error_code, regs); break; case 4: case 6: - DIE(SIGBUS, "External abort on linefetch") + DIE(SIGBUS, "External abort on linefetch"); case 8: case 10: - DIE(SIGBUS, "External abort on non-linefetch") + DIE(SIGBUS, "External abort on non-linefetch"); } } asmlinkage int -do_PrefetchAbort (unsigned long addr, struct pt_regs *regs) +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { -#if 0 - /* does this still apply ? */ - if (the memc mapping for this page exists - can check now...) { - printk ("Page in, but got abort (undefined instruction?)\n"); - return 0; - } -#endif - page_fault (addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); + do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); return 1; } - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-common.c linux.ac/arch/arm/mm/fault-common.c --- linux.vanilla/arch/arm/mm/fault-common.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mm/fault-common.c Tue Feb 9 22:25:06 1999 @@ -0,0 +1,167 @@ +/* + * linux/arch/arm/mm/fault-common.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995-1999 Russell King + */ +#include + +extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); + +void __bad_pmd(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); +} + +void __bad_pmd_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); +} + +static void +kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs, + struct task_struct *tsk, struct mm_struct *mm) +{ + char *reason; + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + pgd_t *pgd; + + if (addr < PAGE_SIZE) + reason = "NULL pointer dereference"; + else + reason = "paging request"; + + printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", + reason, addr); + printk(KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap); + pgd = pgd_offset(mm, addr); + printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd)); + + if (!pgd_none(*pgd)) { + pmd_t *pmd; + pmd = pmd_offset(pgd, addr); + printk(", *pmd = %08lx", pmd_val(*pmd)); + if (!pmd_none(*pmd)) + printk(", *pte = %08lx", pte_val(*pte_offset(pmd, addr))); + } + + printk("\n"); + die_if_kernel("Oops", regs, mode, SIGKILL); + do_exit(SIGKILL); +} + +static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long fixup; + + tsk = current; + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto no_context; + + down(&mm->mmap_sem); + vma = find_vma(mm, addr); + if (!vma) + goto bad_area; + if (vma->vm_start <= addr) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr)) + goto bad_area; + + /* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + if (READ_FAULT(mode)) { /* read? */ + if (!(vma->vm_flags & (VM_READ|VM_EXEC))) + goto bad_area; + } else { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode))) + goto do_sigbus; + + up(&mm->mmap_sem); + return; + + /* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up(&mm->mmap_sem); + + /* User mode accesses just cause a SIGSEGV */ + if (mode & FAULT_CODE_USER) { + tsk->tss.error_code = mode; + tsk->tss.trap_no = 14; +#ifdef CONFIG_DEBUG_USER + printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", + tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); +#endif + force_sig(SIGSEGV, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", + tsk->comm, regs->ARM_pc, addr, fixup); +#endif + regs->ARM_pc = fixup; + return; + } + + kernel_page_fault(addr, mode, regs, tsk, mm); + return; + +do_sigbus: + /* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->tss.error_code = mode; + tsk->tss.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(mode & FAULT_CODE_USER)) + goto no_context; +} + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/init.c linux.ac/arch/arm/mm/init.c --- linux.vanilla/arch/arm/mm/init.c Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/init.c Sun Feb 7 19:37:58 1999 @@ -29,6 +29,9 @@ #include pgd_t swapper_pg_dir[PTRS_PER_PGD]; +#ifndef CONFIG_NO_PGT_CACHE +struct pgtable_cache_struct quicklists; +#endif extern char _etext, _stext, _edata, __bss_start, _end; extern char __init_begin, __init_end; @@ -36,6 +39,7 @@ int do_check_pgt_cache(int low, int high) { int freed = 0; +#ifndef CONFIG_NO_PGT_CACHE if(pgtable_cache_size > high) { do { if(pgd_quicklist) @@ -46,6 +50,7 @@ free_pte_slow(get_pte_fast()), freed++; } while(pgtable_cache_size > low); } +#endif return freed; } @@ -137,6 +142,9 @@ flush_tlb_all(); update_memc_all(); + end_mem &= PAGE_MASK; + high_memory = (void *)end_mem; + return free_area_init(start_mem, end_mem); } @@ -161,19 +169,18 @@ /* mark usable pages in the mem_map[] */ mark_usable_memory_areas(&start_mem, end_mem); +#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \ + (w) < (unsigned long)(max)) + for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) { if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp >= KERNTOPHYS(_stext) && - tmp < KERNTOPHYS(_edata)) { - if (tmp < KERNTOPHYS(_etext)) - codepages++; - else - datapages++; - } else if (tmp >= KERNTOPHYS(__init_begin) - && tmp < KERNTOPHYS(__init_end)) + if (BETWEEN(tmp, &__init_begin, &__init_end)) initpages++; - else if (tmp >= KERNTOPHYS(__bss_start) - && tmp < (unsigned long) start_mem) + else if (BETWEEN(tmp, &_stext, &_etext)) + codepages++; + else if (BETWEEN(tmp, &_etext, &_edata)) + datapages++; + else if (BETWEEN(tmp, &__bss_start, start_mem)) datapages++; else reservedpages++; @@ -181,13 +188,16 @@ } atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) + if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end)) #endif free_page(tmp); } - printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + +#undef BETWEEN + + printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), + max_mapnr >> (20 - PAGE_SHIFT), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), @@ -203,17 +213,45 @@ #endif } -void free_initmem (void) +static void free_area(unsigned long addr, unsigned long end, char *s) { - unsigned long addr; + unsigned int size = (end - addr) >> 10; - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + for (; addr < end; addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + + if (size) + printk(" %dk %s", size, s); +} + +void free_initmem (void) +{ + printk("Freeing unused kernel memory:"); + + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); + +#ifdef CONFIG_FOOTBRIDGE + { + extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end; + + if (!machine_is_netwinder()) + free_area((unsigned long)(&__netwinder_begin), + (unsigned long)(&__netwinder_end), + "netwinder"); + + if (!machine_is_ebsa285() && !machine_is_cats()) + free_area((unsigned long)(&__ebsa285_begin), + (unsigned long)(&__ebsa285_end), + "ebsa285/cats"); + } +#endif + + printk("\n"); } void si_meminfo(struct sysinfo *val) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/ioremap.c linux.ac/arch/arm/mm/ioremap.c --- linux.vanilla/arch/arm/mm/ioremap.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mm/ioremap.c Wed Jan 6 23:34:08 1999 @@ -0,0 +1,153 @@ +/* + * arch/arm/mm/ioremap.c + * + * Re-map IO memory to kernel address space so that we can access it. + * + * (C) Copyright 1995 1996 Linus Torvalds + * + * Hacked for ARM by Phil Blundell + * Hacked to allow all architectures to build, and various cleanups + * by Russell King + */ + +/* + * This allows a driver to remap an arbitrary region of bus memory into + * virtual space. One should *only* use readl, writel, memcpy_toio and + * so on with such remapped areas. + * + * Because the ARM only has a 32-bit address space we can't address the + * whole of the (physical) PCI space at once. PCI huge-mode addressing + * allows us to circumvent this restriction by splitting PCI space into + * two 2GB chunks and mapping only one at a time into processor memory. + * We use MMU protection domains to trap any attempt to access the bank + * that is not currently mapped. (This isn't fully implemented yet.) + * + * DC21285 currently has a bug in that the PCI address extension + * register affects the address of any writes waiting in the outbound + * FIFO. Unfortunately, it is not possible to tell the DC21285 to + * flush this - flushing the area causes the bus to lock. + */ + +#include +#include + +/* + * Only include this if we have valid_ioaddr() is defined + */ +#ifdef valid_ioaddr + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t pgprot) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (!pte_none(*pte)) + printk("remap_area_pte: page already exists\n"); + set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + pgprot_t pgprot; + + address &= ~PGDIR_MASK; + end = address + size; + + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + phys_addr -= address; + pgprot = __pgprot(PTE_TYPE_SMALL | _PTE_WRITE | flags); + do { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + while (address < end) { + pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + return -ENOMEM; + set_pgdir(address, *dir); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_all(); + return 0; +} + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset; + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + size = PAGE_ALIGN(size + offset); + + /* + * Don't allow mappings that wrap.. + */ + if (!size || size > phys_addr + size) + return NULL; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { + vfree(addr); + return NULL; + } + return (void *) (offset + (char *)addr); +} + +void iounmap(void *addr) +{ + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-arc.c linux.ac/arch/arm/mm/mm-arc.c --- linux.vanilla/arch/arm/mm/mm-arc.c Sun Nov 8 15:08:45 1998 +++ linux.ac/arch/arm/mm/mm-arc.c Thu Jan 1 01:00:00 1970 @@ -1,82 +0,0 @@ -/* - * arch/arm/mm/mm-arc.c - * - * Extra MM routines for the Archimedes architecture - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include - -unsigned long phys_screen_end; - -/* - * This routine needs more work to make it dynamically release/allocate mem! - */ -__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)) -{ - static int updated = 0; - - if (updated) - return 0; - - updated = update; - - if (update) { - unsigned long address = log_start, offset; - pgd_t *pgdp; - - kmem = (kmem + 3) & ~3; - - pgdp = pgd_offset (&init_mm, address); /* +31 */ - offset = SCREEN_START; - while (address < SCREEN1_END) { - unsigned long addr_pmd, end_pmd; - pmd_t *pmdp; - - /* if (pgd_none (*pgdp)) alloc pmd */ - pmdp = pmd_offset (pgdp, address); /* +0 */ - addr_pmd = address & ~PGDIR_MASK; /* 088000 */ - end_pmd = addr_pmd + SCREEN1_END - address; /* 100000 */ - if (end_pmd > PGDIR_SIZE) - end_pmd = PGDIR_SIZE; - - do { - unsigned long addr_pte, end_pte; - pte_t *ptep; - - if (pmd_none (*pmdp)) { - pte_t *new_pte = (pte_t *)kmem; - kmem += PTRS_PER_PTE * BYTES_PER_PTR; - memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd (pmdp, mk_pmd(new_pte)); - } - - ptep = pte_offset (pmdp, addr_pmd); /* +11 */ - addr_pte = addr_pmd & ~PMD_MASK; /* 088000 */ - end_pte = addr_pte + end_pmd - addr_pmd; /* 100000 */ - if (end_pte > PMD_SIZE) - end_pte = PMD_SIZE; - - do { - set_pte (ptep, mk_pte(offset, PAGE_KERNEL)); - addr_pte += PAGE_SIZE; - offset += PAGE_SIZE; - ptep++; - } while (addr_pte < end_pte); - - pmdp++; - addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK; - } while (addr_pmd < end_pmd); - - address = (address + PGDIR_SIZE) & PGDIR_MASK; - pgdp ++; - } - - phys_screen_end = offset; - flush_tlb_all (); - update_memc_all (); - } - return kmem; -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-ebsa285.c linux.ac/arch/arm/mm/mm-ebsa285.c --- linux.vanilla/arch/arm/mm/mm-ebsa285.c Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/mm-ebsa285.c Tue Jan 26 22:36:20 1999 @@ -16,24 +16,23 @@ #include /* - * This is to allow us to fiddle with the EEPROM - * This entry will go away in time, once the fmu - * can mmap() the flash. + * The first entry allows us to fiddle with the EEPROM from user-space. + * This entry will go away in time, once the fmu32 can mmap() the + * flash. It can't at the moment. * - * These ones are so that we can fiddle - * with the various cards (eg VGA) - * until we're happy with them... + * If you want to fiddle with PCI VGA cards from user space, then + * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }' + * You can then access the PCI bus at 0xe0000000 and 0xffe00000. */ #define MAPPING \ - { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \ - { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \ - { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \ + { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_IO , 0, 1 }, /* EEPROM */ \ + { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI memory */ \ { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ - { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ - { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ + { ARMCSR_BASE,DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ + { PCIO_BASE, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */ #include "mm-armv.c" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-vnc.c linux.ac/arch/arm/mm/mm-vnc.c --- linux.vanilla/arch/arm/mm/mm-vnc.c Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/mm-vnc.c Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -/* - * arch/arm/mm/mm-vnc.c - * - * Extra MM routines for the Corel VNC architecture - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Table describing the MMU translation mapping - * mainly used to set up the I/O mappings. - */ -#define MAPPING \ - { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \ - { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \ - { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ - { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ - { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ - { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ - { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ - { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ - -#include "mm-armv.c" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/proc-arm2,3.S linux.ac/arch/arm/mm/proc-arm2,3.S --- linux.vanilla/arch/arm/mm/proc-arm2,3.S Sun Nov 8 15:08:45 1998 +++ linux.ac/arch/arm/mm/proc-arm2,3.S Tue Feb 2 20:23:41 1999 @@ -193,7 +193,7 @@ movs pc, lr _arm2_3_check_bugs: - movs pc, lr + bics pc, lr, #0x04000000 @ Clear FIQ disable bit /* * Processor specific - ARM2 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/proc-sa110.S linux.ac/arch/arm/mm/proc-sa110.S --- linux.vanilla/arch/arm/mm/proc-sa110.S Tue Dec 22 23:19:28 1998 +++ linux.ac/arch/arm/mm/proc-sa110.S Sun Feb 28 12:19:05 1999 @@ -8,6 +8,7 @@ */ #include #include +#include #include "../lib/constants.h" /* This is the maximum size of an area which will be flushed. If the area @@ -21,7 +22,6 @@ /* * Function: sa110_flush_cache_all (void) - * * Purpose : Flush all cache lines */ .align 5 @@ -33,7 +33,7 @@ ands r1, r1, #1 eor r1, r1, #1 str r1, [r3] - ldr ip, =0xdf000000 + ldr ip, =FLUSH_BASE addne ip, ip, #32768 add r1, ip, #16384 @ only necessary for 16k 1: ldr r3, [ip], #32 @@ -47,11 +47,9 @@ /* * Function: sa110_flush_cache_area (unsigned long address, int end, int flags) - * * Params : address Area start address * : end Area end address * : flags b0 = I cache as well - * * Purpose : clean & flush all cache lines associated with this area of memory */ .align 5 @@ -74,10 +72,8 @@ /* * Function: sa110_cache_wback_area(unsigned long address, unsigned long end) - * * Params : address Area start address * : end Area end address - * * Purpose : ensure all dirty cachelines in the specified area have been * written out to memory (for DMA) */ @@ -99,13 +95,10 @@ /* * Function: sa110_cache_purge_area(unsigned long address, unsigned long end) - * * Params : address Area start address * : end Area end address - * * Purpose : throw away all D-cached data in specified region without - * an obligation to write it ack. - * + * an obligation to write it back. * Note : Must clean the D-cached entries around the boundaries if the * start and/or end address are not cache aligned. */ @@ -124,9 +117,7 @@ /* * Function: sa110_flush_cache_entry (unsigned long address) - * * Params : address Address of cache line to flush - * * Purpose : clean & flush an entry */ .align 5 @@ -139,9 +130,7 @@ /* * Function: sa110_flush_cache_pte (unsigned long address) - * * Params : address Address of cache line to clean - * * Purpose : Ensure that physical memory reflects cache at this location * for page table purposes. */ @@ -151,11 +140,9 @@ /* * Function: sa110_flush_ram_page (unsigned long page) - * * Params : address Area start address * : size size of area * : flags b0 = I cache as well - * * Purpose : clean & flush all cache lines associated with this area of memory */ .align 5 @@ -176,7 +163,6 @@ /* * Function: sa110_flush_tlb_all (void) - * * Purpose : flush all TLB entries in all caches */ .align 5 @@ -188,11 +174,9 @@ /* * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags) - * * Params : address Area start address * : end Area end address * : flags b0 = I cache as well - * * Purpose : flush a TLB entry */ .align 5 @@ -221,13 +205,10 @@ mov pc, lr /* * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next) - * * Params : prev Old task structure * : next New task structure for process to run - * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. - * * Notes : We don't fiddle with the FP registers here - we postpone this until * the new task actually uses FP. This way, we don't swap FP for tasks * that do not require it. @@ -237,6 +218,7 @@ stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC + ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC ldr r0, [r1, #TSK_ADDR_LIMIT] @@ -245,12 +227,25 @@ movne r0, #DOM_USERDOMAIN mcr p15, 0, r0, c3, c0 @ Set segment ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer +/* + * Flushing the cache is nightmarishly slow, so we take any excuse + * to get out of it. If the old page table is the same as the new, + * this is a CLONE_VM relative of the old task and there is no need + * to flush. The overhead of the tests isn't even on the radar + * compared to the cost of the flush itself. + */ +/* + * Disabled for the moment - it causes all sorts of havoc with + * kernel threads executing user commands (eg, kmod) - rmk + */ + teq r0, r2 + beq 2f ldr r3, =Lclean_switch ldr r2, [r3] ands r2, r2, #1 eor r2, r2, #1 str r2, [r3] - ldr r2, =0xdf000000 + ldr r2, =FLUSH_BASE addne r2, r2, #32768 add r1, r2, #16384 @ only necessary for 16k 1: ldr r3, [r2], #32 @@ -261,17 +256,14 @@ mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r1, c8, c7, 0 @ flush TLBs - ldmfd sp!, {ip} +2: ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously /* * Function: sa110_data_abort () - * * Params : r0 = address of aborted instruction - * * Purpose : obtain information about current aborted instruction - * * Returns : r0 = address of abort * : r1 = FSR * : r2 != 0 if writing @@ -289,10 +281,8 @@ /* * Function: sa110_set_pmd () - * * Params : r0 = Address to set * : r1 = value to set - * * Purpose : Set a PMD and flush it out of any WB cache */ .align 5 @@ -304,20 +294,19 @@ * Function: sa110_check_bugs (void) * : sa110_proc_init (void) * : sa110_proc_fin (void) - * * Notes : This processor does not require these */ _sa110_check_bugs: mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + _sa110_proc_init: _sa110_proc_fin: mov pc, lr /* * Function: sa110_reset - * * Notes : This sets up everything for a reset */ _sa110_reset: mrs r1, cpsr diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/small_page.c linux.ac/arch/arm/mm/small_page.c --- linux.vanilla/arch/arm/mm/small_page.c Sun Nov 8 15:08:45 1998 +++ linux.ac/arch/arm/mm/small_page.c Sun Feb 7 19:46:21 1999 @@ -5,6 +5,8 @@ * * Changelog: * 26/01/1996 RMK Cleaned up various areas to make little more generic + * 07/02/1999 RMK Support added for 16K and 32K page sizes + * containing 8K blocks */ #include @@ -19,21 +21,31 @@ #include #include +#if PAGE_SIZE == 4096 +/* 1K blocks */ #define SMALL_ALLOC_SHIFT (10) +#define NAME(x) x##_1k +#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384 +/* 8K blocks */ +#define SMALL_ALLOC_SHIFT (13) +#define NAME(x) x##_8k +#endif + #define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT) #define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE) +#define BLOCK_MASK ((1 << NR_BLOCKS) - 1) -#if NR_BLOCKS != 4 -#error I only support 4 blocks per page! -#endif - -#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15) +#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK) #define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off) #define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off)) #define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off))) #define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \ ((block) << SMALL_ALLOC_SHIFT))) +#if NR_BLOCKS != 2 && NR_BLOCKS != 4 +#error I only support 2 or 4 blocks per page +#endif + struct free_small_page { unsigned long next; unsigned long prev; @@ -52,6 +64,7 @@ 1, /* 0001 */ 0, /* 0010 */ 2, /* 0011 */ +#if NR_BLOCKS == 4 0, /* 0100 */ 1, /* 0101 */ 0, /* 0110 */ @@ -64,6 +77,7 @@ 1, /* 1101 */ 0, /* 1110 */ 4 /* 1111 */ +#endif }; static inline void clear_page_links(unsigned long page) @@ -113,7 +127,7 @@ } } -unsigned long get_small_page(int priority) +unsigned long NAME(get_page)(int priority) { struct free_small_page *fsp; unsigned long new_page; @@ -156,25 +170,26 @@ goto again; } -void free_small_page(unsigned long spage) +void NAME(free_page)(unsigned long spage) { struct free_small_page *ofsp, *cfsp; unsigned long flags; struct page *page; int offset, oldoffset; + if (!spage) + goto none; + offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1); spage -= offset << SMALL_ALLOC_SHIFT; page = mem_map + MAP_NR(spage); - if (!PageReserved(page) || !USED(page)) { - printk ("Trying to free non-small page from %p\n", __builtin_return_address(0)); - return; - } - if (IS_FREE(page, offset)) { - printk ("Trying to free free small page from %p\n", __builtin_return_address(0)); - return; - } + if (!PageReserved(page) || !USED(page)) + goto non_small; + + if (IS_FREE(page, offset)) + goto free; + save_flags_cli (flags); oldoffset = offsets[USED(page)]; CLEAR_USED(page, offset); @@ -197,4 +212,13 @@ } else *cfsp = *ofsp; restore_flags(flags); + return; + +non_small: + printk ("Trying to free non-small page from %p\n", __builtin_return_address(0)); + return; +free: + printk ("Trying to free free small page from %p\n", __builtin_return_address(0)); +none: + return; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/ARM-gcc.h linux.ac/arch/arm/nwfpe/ARM-gcc.h --- linux.vanilla/arch/arm/nwfpe/ARM-gcc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/ARM-gcc.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,128 @@ + +/* +------------------------------------------------------------------------------- +One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. +------------------------------------------------------------------------------- +*/ +#define LITTLEENDIAN + +/* +------------------------------------------------------------------------------- +The macro `BITS64' can be defined to indicate that 64-bit integer types are +supported by the compiler. +------------------------------------------------------------------------------- +*/ +#define BITS64 + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines the most convenient type that holds +integers of at least as many bits as specified. For example, `uint8' should +be the most convenient type that can hold unsigned integers of as many as +8 bits. The `flag' type must be able to hold either a 0 or 1. For most +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +to the same as `int'. +------------------------------------------------------------------------------- +*/ +typedef char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines a type that holds integers +of _exactly_ the number of bits specified. For instance, for most +implementation of C, `bits16' and `sbits16' should be `typedef'ed to +`unsigned short int' and `signed short int' (or `short int'), respectively. +------------------------------------------------------------------------------- +*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short int bits16; +typedef signed short int sbits16; +typedef unsigned int bits32; +typedef signed int sbits32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +#ifdef BITS64 +/* +------------------------------------------------------------------------------- +The `LIT64' macro takes as its argument a textual integer literal and if +necessary ``marks'' the literal as having a 64-bit integer type. For +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be +appended with the letters `LL' standing for `long long', which is `gcc's +name for the 64-bit integer type. Some compilers may allow `LIT64' to be +defined as the identity macro: `#define LIT64( a ) a'. +------------------------------------------------------------------------------- +*/ +#define LIT64( a ) a##LL +#endif + +/* +------------------------------------------------------------------------------- +The macro `INLINE' can be used before functions that should be inlined. If +a compiler does not support explicit inlining, this macro should be defined +to be `static'. +------------------------------------------------------------------------------- +*/ +#define INLINE extern __inline__ + + +/* For use as a GCC soft-float library we need some special function names. */ + +#ifdef __LIBFLOAT__ + +/* Some 32-bit ops can be mapped straight across by just changing the name. */ +#define float32_add __addsf3 +#define float32_sub __subsf3 +#define float32_mul __mulsf3 +#define float32_div __divsf3 +#define int32_to_float32 __floatsisf +#define float32_to_int32_round_to_zero __fixsfsi +#define float32_to_uint32_round_to_zero __fixunssfsi + +/* These ones go through the glue code. To avoid namespace pollution + we rename the internal functions too. */ +#define float32_eq ___float32_eq +#define float32_le ___float32_le +#define float32_lt ___float32_lt + +/* All the 64-bit ops have to go through the glue, so we pull the same + trick. */ +#define float64_add ___float64_add +#define float64_sub ___float64_sub +#define float64_mul ___float64_mul +#define float64_div ___float64_div +#define int32_to_float64 ___int32_to_float64 +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero +#define float64_to_float32 ___float64_to_float32 +#define float32_to_float64 ___float32_to_float64 +#define float64_eq ___float64_eq +#define float64_le ___float64_le +#define float64_lt ___float64_lt + +#if 0 +#define float64_add __adddf3 +#define float64_sub __subdf3 +#define float64_mul __muldf3 +#define float64_div __divdf3 +#define int32_to_float64 __floatsidf +#define float64_to_int32_round_to_zero __fixdfsi +#define float64_to_uint32_round_to_zero __fixunsdfsi +#define float64_to_float32 __truncdfsf2 +#define float32_to_float64 __extendsfdf2 +#endif + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/ChangeLog linux.ac/arch/arm/nwfpe/ChangeLog --- linux.vanilla/arch/arm/nwfpe/ChangeLog Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/ChangeLog Tue Feb 2 20:59:49 1999 @@ -0,0 +1,20 @@ +1998-11-23 Scott Bambrough + + * README.FPE - fix typo in description of lfm/sfm instructions + * NOTES - Added file to describe known bugs/problems + * fpmodule.c - Changed version number to 0.94 + +1998-11-20 Scott Bambrough + + * README.FPE - fix description of URD, NRM instructions + * TODO - remove URD, NRM instructions from TODO list + * single_cpdo.c - implement URD, NRM + * double_cpdo.c - implement URD, NRM + * extended_cpdo.c - implement URD, NRM + +1998-11-19 Scott Bambrough + + * ChangeLog - Added this file to track changes made. + * fpa11.c - added code to initialize register types to typeNone + * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to + typeDouble in switch statement) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/Makefile linux.ac/arch/arm/nwfpe/Makefile --- linux.vanilla/arch/arm/nwfpe/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/Makefile Tue Feb 2 20:59:49 1999 @@ -0,0 +1,33 @@ +# +# linux/arch/arm/nwfpe/Makefile +# +# Copyright (C) 1998 Philip Blundell +# + +CFLAGS += -freg-struct-return + +NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ + fpmodule.o fpopcode.o softfloat.o \ + single_cpdo.o double_cpdo.o extended_cpdo.o + +ifeq ($(CONFIG_CPU_26),y) +NWFPE_OBJS += entry26.o +else +NWFPE_OBJS += entry.o +endif + +L_TARGET := math-emu.a + +ifeq ($(CONFIG_NWFPE),y) +L_OBJS = $(NWFPE_OBJS) +else + ifeq ($(CONFIG_NWFPE),m) + M_OBJS = nwfpe.o + MI_OBJS = $(NWFPE_OBJS) + endif +endif + +include $(TOPDIR)/Rules.make + +nwfpe.o: $(MI_OBJS) $(MIX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/config.h linux.ac/arch/arm/nwfpe/config.h --- linux.vanilla/arch/arm/nwfpe/config.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/config.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,31 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#if 1 +#define C_SYMBOL_NAME(foo) foo +#else +#define C_SYMBOL_NAME(foo) _##foo +#endif + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/double_cpdo.c linux.ac/arch/arm/nwfpe/double_cpdo.c --- linux.vanilla/arch/arm/nwfpe/double_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/double_cpdo.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,283 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +extern FPA11 *fpa11; + +float64 getDoubleConstant(unsigned int); + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn,float64 rFm); +float64 float64_pol(float64 rFn,float64 rFm); + +unsigned int DoubleCPDO(const unsigned int opcode) +{ + float64 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //fp_printk("DoubleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getDoubleConstant(Fm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fValue.fDouble; + break; + + case typeExtended: + // !! patb + //fp_printk("not implemented! why not?\n"); + //!! ScottB + // should never get here, if extended involved + // then other operand should be promoted then + // ExtendedCPDO called. + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fValue.fDouble; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn); + break; + + case POW_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn); + break; + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm); + break; + + case POL_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm); + break; + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = rFm; + break; + + case MNF_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] ^= 0x80000000; + fpa11->fpreg[Fd].fValue.fDouble = rFm; + } + break; + + case ABS_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] &= 0x7fffffff; + fpa11->fpreg[Fd].fValue.fDouble = rFm; + } + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fDouble = + int32_to_float64(float64_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm); + break; + + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm); + break; + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble; + return nRc; +} + +float64 float64_exp(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_ln(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_sin(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_cos(float64 rFm) +{ + return rFm; + //series +} + +float64 float64_arcsin(float64 rFm) +{ +//series +} + +float64 float64_arctan(float64 rFm) +{ + //series +} + +float64 float64_log(float64 rFm) +{ + return float64_div(float64_ln(rFm),getDoubleConstant(7)); +} + +float64 float64_tan(float64 rFm) +{ + return float64_div(float64_sin(rFm),float64_cos(rFm)); +} + +float64 float64_arccos(float64 rFm) +{ +return rFm; + //return float64_sub(halfPi,float64_arcsin(rFm)); +} + +float64 float64_pow(float64 rFn,float64 rFm) +{ + return float64_exp(float64_mul(rFm,float64_ln(rFn))); +} + +float64 float64_pol(float64 rFn,float64 rFm) +{ + return float64_arctan(float64_div(rFn,rFm)); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/entry.S linux.ac/arch/arm/nwfpe/entry.S --- linux.vanilla/arch/arm/nwfpe/entry.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/entry.S Tue Feb 2 20:59:49 1999 @@ -0,0 +1,115 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + adrsvc al, r9, ret_from_exception @ r9 = normal FP return + adrsvc al, lr, fpundefinstr @ lr = undefined instr return + + get_current_task r10 + mov r8, #1 + strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + add r10, r10, #TSS_FPESAVE @ r10 = workspace + ldr r4, .LC2 + ldr pc, [r4] @ Call FP emulator entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception (passed in +r9) and the kernel takes care of returning control from the trap to +the user code. If the emulator is unable to emulate the instruction, +it returns via _fpundefinstr (passed via lr) and the kernel halts the +user program with a core dump. + +On entry to the emulator r10 points to an area of private FP workspace +reserved in the thread structure for this process. This is where the +emulator saves its registers across calls. The first word of this area +is used as a flag to detect the first time a process uses floating point, +so that the emulator startup cost can be avoided for tasks that don't +want it. + +This routine does three things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +3) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + /* ?? Could put userRegisters and fpa11 into fixed regs during + emulation. This would reduce load/store overhead at the expense + of stealing two regs from the register allocator. Not sure if + it's worth it. */ + ldr r4, =userRegisters + str sp, [r4] @ save pointer to user regs + ldr r4, =fpa11 + str r10, [r4] @ store pointer to our state + mov r4, sp @ use r4 for local pointer + mov r10, lr @ save the failure-return addresses + + ldr r5, [r4, #60] @ get contents of PC; + ldr r0, [r5, #-4] @ get actual instruction into r0 +emulate: + bl EmulateAll @ emulate the instruction + cmp r0, #0 @ was emulation successful + moveq pc, r10 @ no, return failure + +next: + ldr r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + movne pc, r9 @ return ok if not a fp insn + + str r5, [r4, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + ldr r1, [r4, #64] @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + b emulate @ if r0 != 0, goto EmulateAll diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/entry26.S linux.ac/arch/arm/nwfpe/entry26.S --- linux.vanilla/arch/arm/nwfpe/entry26.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/entry26.S Tue Feb 2 20:59:49 1999 @@ -0,0 +1,110 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "../lib/constants.h" + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + mov fp, #0 + teqp pc, #I_BIT | MODE_SVC + ldr r4, .LC2 + ldr pc, [r4] @ Call FP module USR entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception and the +kernel takes care of returning control from the trap to the user code. +If the emulator is unable to emulate the instruction, it returns to +fpundefinstr and the kernel halts the user program with a core dump. + +This routine does four things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It locates the FP emulator work area within the TSS structure and +points `fpa11' to it. + +3) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +4) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + ldr r4, =userRegisters + str sp, [r4] @ save pointer to user regs + + mov r10, sp, lsr #13 @ find workspace + mov r10, r10, lsl #13 + add r10, r10, #TSS_FPESAVE + + ldr r4, =fpa11 + str r10, [r4] @ store pointer to our state + mov r4, sp @ use r4 for local pointer + + ldr r5, [r4, #60] @ get contents of PC + and r9, r5, #0xfc000003 + eor r5, r5, r9 + ldr r0, [r5, #-4] @ get actual instruction into r0 +emulate: + bl EmulateAll @ emulate the instruction + cmp r0, #0 @ was emulation successful + beq fpundefinstr @ no, return failure + +next: + ldr r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + bne ret_from_exception @ return ok if not a fp insn + + orr r7, r5, r9 + str r7, [r4, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + ldr r1, [r4, #64] @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + b emulate @ if r0 != 0, goto EmulateAll diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/extended_cpdo.c linux.ac/arch/arm/nwfpe/extended_cpdo.c --- linux.vanilla/arch/arm/nwfpe/extended_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/extended_cpdo.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,268 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +floatx80 getExtendedConstant(unsigned int); + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); + +unsigned int ExtendedCPDO(const unsigned int opcode) +{ + floatx80 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //fp_printk("ExtendedCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getExtendedConstant(Fm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fValue.fExtended; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fValue.fExtended; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn); + break; + + case POW_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn); + break; + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm); + break; + + case POL_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm); + break; + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case MNF_CODE: + rFm.high ^= 0x8000; + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case ABS_CODE: + rFm.high &= 0x7fff; + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fExtended = + int32_to_floatx80(floatx80_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm); + break; + + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm); + break; + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended; + return nRc; +} + +floatx80 floatx80_exp(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_ln(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_sin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_cos(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arcsin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arctan(floatx80 rFm) +{ + //series +} + +floatx80 floatx80_log(floatx80 rFm) +{ + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); +} + +floatx80 floatx80_tan(floatx80 rFm) +{ + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); +} + +floatx80 floatx80_arccos(floatx80 rFm) +{ + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); +} + +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) +{ + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); +} + +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) +{ + return floatx80_arctan(floatx80_div(rFn,rFm)); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.c linux.ac/arch/arm/nwfpe/fpa11.c --- linux.vanilla/arch/arm/nwfpe/fpa11.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,206 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "fpa11.h" +#include "milieu.h" +#include "fpopcode.h" + +#include "fpmodule.h" +#include "fpmodule.inl" + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int EmulateCPRT(const unsigned int); + +/* Emulator registers */ +FPA11 *fpa11; + +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ +void resetFPA11(void) +{ + int i; + /* initialize the registers */ + for (i=0;i<=7;i++) + { + fpa11->fpreg[i].fType = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, clear all other bits */ + fpa11->fpsr = FP_EMULATOR; + + /* FPCR: set SB, AB and DA bits, clear all others */ +#if MAINTAIN_FPCR + fpa11->fpcr = MASK_RESET; +#endif +} + +void SetRoundingMode(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_MODE; +#endif + switch (opcode & MASK_ROUNDING_MODE) + { + default: + case ROUND_TO_NEAREST: + float_rounding_mode = float_round_nearest_even; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_NEAREST; +#endif + break; + + case ROUND_TO_PLUS_INFINITY: + float_rounding_mode = float_round_up; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; +#endif + break; + + case ROUND_TO_MINUS_INFINITY: + float_rounding_mode = float_round_down; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; +#endif + break; + + case ROUND_TO_ZERO: + float_rounding_mode = float_round_to_zero; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_ZERO; +#endif + break; + } +} + +void SetRoundingPrecision(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; +#endif + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + floatx80_rounding_precision = 32; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_SINGLE; +#endif + break; + + case ROUND_DOUBLE: + floatx80_rounding_precision = 64; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_DOUBLE; +#endif + break; + + case ROUND_EXTENDED: + floatx80_rounding_precision = 80; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_EXTENDED; +#endif + break; + + default: floatx80_rounding_precision = 80; + } +} + +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(unsigned int opcode) +{ + unsigned int nRc = 0; + + if (fpa11->initflag == 0) /* good place for __builtin_expect */ + { + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; + } + + if (TEST_OPCODE(opcode,MASK_CPRT)) + { + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDO)) + { + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDT)) + { + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } + + return(nRc); +} + +#if 0 +unsigned int EmulateAll1(unsigned int opcode) +{ + switch ((opcode >> 24) & 0xf) + { + case 0xc: + case 0xd: + if ((opcode >> 20) & 0x1) + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformLDF(opcode); break; + case 0x2: return PerformLFM(opcode); break; + default: return 0; + } + } + else + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformSTF(opcode); break; + case 0x2: return PerformSFM(opcode); break; + default: return 0; + } + } + break; + + case 0xe: + if (opcode & 0x10) + return EmulateCPDO(opcode); + else + return EmulateCPRT(opcode); + break; + + default: return 0; + } +} +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.h linux.ac/arch/arm/nwfpe/fpa11.h --- linux.vanilla/arch/arm/nwfpe/fpa11.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,61 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPA11_H__ +#define __FPA11_H__ + +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +typedef struct tagFPREG { + unsigned int fType; + union { + float32 fSingle; + float64 fDouble; + floatx80 fExtended; + } fValue; +} FPREG; + +/* FPA11 device model */ +typedef struct tagFPA11 { + int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ + FPREG fpreg[8]; /* 8 floating point registers */ + FPSR fpsr; /* floating point status register */ + FPCR fpcr; /* floating point control register */ +} FPA11; + +extern void resetFPA11(void); +extern void SetRoundingMode(const unsigned int); +extern void SetRoundingPrecision(const unsigned int); + +extern FPA11 *fpa11; + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.inl linux.ac/arch/arm/nwfpe/fpa11.inl --- linux.vanilla/arch/arm/nwfpe/fpa11.inl Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11.inl Tue Feb 2 20:59:49 1999 @@ -0,0 +1,47 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "fpa11.h" + +/* Read and write floating point status register */ +extern __inline__ unsigned int readFPSR(void) +{ + return(fpa11->fpsr); +} + +extern __inline__ void writeFPSR(FPSR reg) +{ + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); +} + +/* Read and write floating point control register */ +extern __inline__ FPCR readFPCR(void) +{ + /* clear SB, AB and DA bits before returning FPCR */ + return(fpa11->fpcr & ~MASK_RFC); +} + +extern __inline__ void writeFPCR(FPCR reg) +{ + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c linux.ac/arch/arm/nwfpe/fpa11_cpdo.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11_cpdo.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,117 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "fpa11.h" +#include "fpopcode.h" + +unsigned int SingleCPDO(const unsigned int opcode); +unsigned int DoubleCPDO(const unsigned int opcode); +unsigned int ExtendedCPDO(const unsigned int opcode); + +unsigned int EmulateCPDO(const unsigned int opcode) +{ + unsigned int Fd, nType, nDest, nRc = 1; + + //fp_printk("EmulateCPDO(0x%08x)\n",opcode); + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) return 0; + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fpreg[getFn(opcode)].fType; + + if (!CONSTANT_FM(opcode)) + { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fpreg[Fm].fType) + { + nType = fpa11->fpreg[Fm].fType; + } + } + + switch (nType) + { + case typeSingle : nRc = SingleCPDO(opcode); break; + case typeDouble : nRc = DoubleCPDO(opcode); break; + case typeExtended : nRc = ExtendedCPDO(opcode); break; + default : nRc = 0; + } + + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + Fd = getFd(opcode); + nType = fpa11->fpreg[Fd].fType; + if ((0 != nRc) && (nDest != nType)) + { + SetRoundingMode(opcode); + + switch (nDest) + { + case typeSingle: + { + if (typeDouble == nType) + fpa11->fpreg[Fd].fValue.fSingle = + float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble); + else + fpa11->fpreg[Fd].fValue.fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fValue.fDouble = + float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle); + else + fpa11->fpreg[Fd].fValue.fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fValue.fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle); + else + fpa11->fpreg[Fd].fValue.fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble); + } + break; + } + + fpa11->fpreg[Fd].fType = nDest; + } + + return nRc; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdt.c linux.ac/arch/arm/nwfpe/fpa11_cpdt.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cpdt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11_cpdt.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,330 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +#include + +extern __inline__ +void loadSingle(const unsigned int Fn,const unsigned int *pMem) +{ + fpa11->fpreg[Fn].fType = typeSingle; + get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem); +} + +extern __inline__ +void loadDouble(const unsigned int Fn,const unsigned int *pMem) +{ + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble; + fpa11->fpreg[Fn].fType = typeDouble; + get_user(p[0], &pMem[1]); + get_user(p[1], &pMem[0]); /* sign & exponent */ +} + +extern __inline__ +void loadExtended(const unsigned int Fn,const unsigned int *pMem) +{ + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended; + fpa11->fpreg[Fn].fType = typeExtended; + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[2]); /* ls bits */ + get_user(p[2], &pMem[1]); /* ms bits */ +} + +extern __inline__ +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) +{ + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); + get_user(x, &pMem[0]); + fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + case typeDouble: + { + get_user(p[0], &pMem[2]); /* Single */ + get_user(p[1], &pMem[1]); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + get_user(p[1], &pMem[2]); + get_user(p[2], &pMem[1]); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +extern __inline__ +void storeSingle(const unsigned int Fn,unsigned int *pMem) +{ + float32 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended); + break; + + default: val = fpa11->fpreg[Fn].fValue.fSingle; + } + + pMem[0] = p[0]; +} + +extern __inline__ +void storeDouble(const unsigned int Fn,unsigned int *pMem) +{ + float64 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended); + break; + + default: val = fpa11->fpreg[Fn].fValue.fDouble; + } + put_user(p[1], &pMem[0]); /* msw */ + put_user(p[0], &pMem[1]); /* lsw */ +} + +extern __inline__ +void storeExtended(const unsigned int Fn,unsigned int *pMem) +{ + floatx80 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + default: val = fpa11->fpreg[Fn].fValue.fExtended; + } + + put_user(p[0], &pMem[0]); /* sign & exp */ + put_user(p[1], &pMem[2]); + put_user(p[2], &pMem[1]); /* msw */ +} + +extern __inline__ +void storeMultiple(const unsigned int Fn,unsigned int *pMem) +{ + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); + nType = fpa11->fpreg[Fn].fType; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user(p[0], &pMem[2]); /* single */ + put_user(p[1], &pMem[1]); /* double msw */ + put_user(nType << 14, &pMem[0]); + } + break; + + case typeExtended: + { + put_user(p[2], &pMem[1]); /* msw */ + put_user(p[1], &pMem[2]); + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + } + break; + } +} + +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1; + + //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformSTF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1; + + //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal; + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal; + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //fp_printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c linux.ac/arch/arm/nwfpe/fpa11_cprt.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpa11_cprt.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,302 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" +#include "fpa11.inl" +#include "fpmodule.h" +#include "fpmodule.inl" + +extern flag floatx80_is_nan(floatx80); +extern flag float64_is_nan( float64); +extern flag float32_is_nan( float32); + +void SetRoundingMode(const unsigned int opcode); + +unsigned int PerformFLT(const unsigned int opcode); +unsigned int PerformFIX(const unsigned int opcode); + +static unsigned int +PerformComparison(const unsigned int opcode); + +unsigned int EmulateCPRT(const unsigned int opcode) +{ + unsigned int nRc = 1; + + //fp_printk("EmulateCPRT(0x%08x)\n",opcode); + + if (opcode & 0x800000) + { + /* This is some variant of a comparison (PerformComparison will + sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it makes + sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) + { + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; + + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; + + /* ?? Not at all sure about the mode checks here. Linux never + calls the emulator from a non-USR fault but we always run in SVC + mode. Is there even any point trying to emulate the way FPA11 + behaves in this respect? */ + case WFC_CODE >> 20: + { + int mode = 0; + __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); + nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ + if (nRc) writeFPCR(readRegister(getRd(opcode))); + } + break; + + case RFC_CODE >> 20: + { + int mode = 0; + __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); + nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ + if (nRc) writeRegister(getRd(opcode),readFPCR()); break; + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFLT(const unsigned int opcode) +{ + unsigned int nRc = 1; + SetRoundingMode(opcode); + SetRoundingPrecision(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + { + fpa11->fpreg[getFn(opcode)].fType = typeSingle; + fpa11->fpreg[getFn(opcode)].fValue.fSingle = + int32_to_float32(readRegister(getRd(opcode))); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fpreg[getFn(opcode)].fType = typeDouble; + fpa11->fpreg[getFn(opcode)].fValue.fDouble = + int32_to_float64(readRegister(getRd(opcode))); + } + break; + + case ROUND_EXTENDED: + { + fpa11->fpreg[getFn(opcode)].fType = typeExtended; + fpa11->fpreg[getFn(opcode)].fValue.fExtended = + int32_to_floatx80(readRegister(getRd(opcode))); + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFIX(const unsigned int opcode) +{ + unsigned int nRc = 1; + unsigned int Fn = getFm(opcode); + + SetRoundingMode(opcode); + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + { + writeRegister(getRd(opcode), + float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle)); + } + break; + + case typeDouble: + { + writeRegister(getRd(opcode), + float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble)); + } + break; + + case typeExtended: + { + writeRegister(getRd(opcode), + floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended)); + } + break; + + default: nRc = 0; + } + + return nRc; +} + + +static unsigned int __inline__ +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) +{ + unsigned int flags = 0; + + /* test for less than condition */ + if (floatx80_lt(Fn,Fm)) + { + flags |= CC_NEGATIVE; + } + + /* test for equal condition */ + if (floatx80_eq(Fn,Fm)) + { + flags |= CC_ZERO; + } + + /* test for greater than or equal condition */ + if (floatx80_lt(Fm,Fn)) + { + flags |= CC_CARRY; + } + + writeConditionCodes(flags); + return 1; +} + +/* This instruction sets the flags N, Z, C, V in the FPSR. */ + +static unsigned int PerformComparison(const unsigned int opcode) +{ + unsigned int Fn, Fm; + floatx80 rFn, rFm; + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + + //fp_printk("PerformComparison(0x%08x)\n",opcode); + + Fn = getFn(opcode); + Fm = getFm(opcode); + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + //fp_printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + //fp_printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + //fp_printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fValue.fExtended; + break; + + default: return 0; + } + + if (CONSTANT_FM(opcode)) + { + //fp_printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } + else + { + //fp_printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + //fp_printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + //fp_printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + break; + + case typeExtended: + //fp_printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fValue.fExtended; + break; + + default: return 0; + } + } + + if (n_flag) + { + rFm.high ^= 0x8000; + } + + return PerformComparisonOperation(rFn,rFm); + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + + if (BIT_AC & readFPSR()) flags |= CC_CARRY; + + if (e_flag) float_raise(float_flag_invalid); + + writeConditionCodes(flags); + return 1; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.c linux.ac/arch/arm/nwfpe/fpmodule.c --- linux.vanilla/arch/arm/nwfpe/fpmodule.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpmodule.c Wed Feb 17 20:56:57 1999 @@ -0,0 +1,167 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" + +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +/* XXX */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +/* XXX */ + +#include "softfloat.h" +#include "fpopcode.h" +#include "fpmodule.h" +#include "fpa11.h" +#include "fpa11.inl" + +/* external data */ +extern FPA11 *fpa11; + +/* kernel symbols required for signal handling */ +typedef struct task_struct* PTASK; + +#ifdef MODULE +int fp_printk(const char *,...); +void fp_send_sig(unsigned long sig, PTASK p, int priv); +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Scott Bambrough "); +MODULE_DESCRIPTION("NWFPE floating point emulator"); +#endif + +#else +#define fp_printk printk +#define fp_send_sig send_sig +#define kern_fp_enter fp_enter +#endif + +/* kernel function prototypes required */ +void C_SYMBOL_NAME(fp_setup)(void); + +/* external declarations for saved kernel symbols */ +extern unsigned int C_SYMBOL_NAME(kern_fp_enter); + +/* forward declarations */ +extern void nwfpe_enter(void); + +/* Original value of fp_enter from kernel before patched by fpe_init. */ +static unsigned int orig_fp_enter; + +/* Address of user registers on the kernel stack. */ +unsigned int *userRegisters; + +void __init C_SYMBOL_NAME(fpe_version)(void) +{ + static const char szTitle[] = "<4>NetWinder Floating Point Emulator "; + static const char szVersion[] = "V0.94.1 "; + static const char szCopyright[] = "(c) 1998 Corel Computer Corp.\n"; + C_SYMBOL_NAME(fp_printk)(szTitle); + C_SYMBOL_NAME(fp_printk)(szVersion); + C_SYMBOL_NAME(fp_printk)(szCopyright); +} + +int __init fpe_init(void) +{ + /* Display title, version and copyright information. */ + C_SYMBOL_NAME(fpe_version)(); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter); + C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter); + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return(fpe_init()); +} + +void cleanup_module(void) +{ + /* Restore the values we saved earlier. */ + C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter; +} +#endif + +#define _ARM_pc 60 +#define _ARM_cpsr 64 + +/* +ScottB: November 4, 1998 + +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). + +[1/1/99: Not quite true any more unfortunately. There is Linux-specific +code to access data in user space in some other source files at the +moment. --philb] + +float_exception_flags is a global variable in SoftFloat. + +This function is called by the SoftFloat routines to raise a floating +point exception. We check the trap enable byte in the FPSR, and raise +a SIGFPE exception if necessary. If not the relevant bits in the +cumulative exceptions flag byte are set and we return. +*/ + +void float_raise(signed char flags) +{ +#if 0 + printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags, + __builtin_return_address(0), userRegisters[15]); +#endif + + float_exception_flags |= flags; + if (readFPSR() & (flags << 16)) + { + /* raise exception */ + C_SYMBOL_NAME(fp_send_sig)(SIGFPE,C_SYMBOL_NAME(current),1); + } + else + { + /* set the cumulative exceptions flags */ + writeFPSR(flags); + } +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.h linux.ac/arch/arm/nwfpe/fpmodule.h --- linux.vanilla/arch/arm/nwfpe/fpmodule.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpmodule.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,45 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPMODULE_H__ +#define __FPMODULE_H__ + +#define REG_ORIG_R0 17 +#define REG_CPSR 16 +#define REG_PC 15 +#define REG_LR 14 +#define REG_SP 13 +#define REG_IP 12 +#define REG_FP 11 +#define REG_R10 10 +#define REG_R9 9 +#define REG_R9 9 +#define REG_R8 8 +#define REG_R7 7 +#define REG_R6 6 +#define REG_R5 5 +#define REG_R4 4 +#define REG_R3 3 +#define REG_R2 2 +#define REG_R1 1 +#define REG_R0 0 + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.inl linux.ac/arch/arm/nwfpe/fpmodule.inl --- linux.vanilla/arch/arm/nwfpe/fpmodule.inl Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpmodule.inl Tue Feb 2 20:59:49 1999 @@ -0,0 +1,78 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +/* Address of user registers on the kernel stack. */ +extern unsigned int *userRegisters; + +extern __inline__ +unsigned int readRegister(const unsigned int nReg) +{ + /* Note: The CPU thinks it has dealt with the current instruction. As + a result the program counter has been advanced to the next + instruction, and points 4 bytes beyond the actual instruction + that caused the invalid instruction trap to occur. We adjust + for this in this routine. LDF/STF instructions with Rn = PC + depend on the PC being correct, as they use PC+8 in their + address calculations. */ + unsigned int val = userRegisters[nReg]; + if (REG_PC == nReg) val -= 4; + return val; +} + +extern __inline__ +void writeRegister(const unsigned int nReg, const unsigned int val) +{ + userRegisters[nReg] = val; +} + +extern __inline__ +unsigned int readCPSR(void) +{ + return(readRegister(REG_CPSR)); +} + +extern __inline__ +void writeCPSR(const unsigned int val) +{ + writeRegister(REG_CPSR,val); +} + +extern __inline__ +unsigned int readConditionCodes(void) +{ +#ifdef __FPEM_TEST__ + return(0); +#else + return(readCPSR() & CC_MASK); +#endif +} + +extern __inline__ +void writeConditionCodes(const unsigned int val) +{ + writeCPSR((readCPSR() & ~CC_MASK) | (val & CC_MASK)); +} + +extern __inline__ +unsigned int readMemoryInt(unsigned int *pMem) +{ + return *pMem; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpopcode.c linux.ac/arch/arm/nwfpe/fpopcode.c --- linux.vanilla/arch/arm/nwfpe/fpopcode.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpopcode.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,164 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpsr.h" +#include "fpa11.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +static floatx80 floatx80Constant[] = { + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ +}; + +static float64 float64Constant[] = { + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; + +static float32 float32Constant[] = { + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; + +floatx80 getExtendedConstant(const unsigned int nIndex) +{ + return floatx80Constant[nIndex]; +} + +float64 getDoubleConstant(const unsigned int nIndex) +{ + return float64Constant[nIndex]; +} + +float32 getSingleConstant(const unsigned int nIndex) +{ + return float32Constant[nIndex]; +} + +unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case 0x00000000: nRc = 1; break; /* single precision */ + case 0x00008000: nRc = 2; break; /* double precision */ + case 0x00400000: nRc = 3; break; /* extended precision */ + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) + { + case 0x00000000: nRc = 4; break; + case 0x00008000: nRc = 1; break; + case 0x00400000: nRc = 2; break; + case 0x00408000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case 0x00000000: nRc = 1; break; + case 0x00000080: nRc = 2; break; + case 0x00080000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) + { + case 0x00000000: nRc = typeSingle; break; + case 0x00000080: nRc = typeDouble; break; + case 0x00080000: nRc = typeExtended; break; + default: nRc = typeNone; + } + + return(nRc); +} + +/* contition code lookup table + index into the table is test code: EQ, NE, ... LT, GT, AL, NV + bit position in short is condition code: NZCV */ +unsigned short aCC[16] = { + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV +}; + +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) +{ + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpopcode.h linux.ac/arch/arm/nwfpe/fpopcode.h --- linux.vanilla/arch/arm/nwfpe/fpopcode.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpopcode.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,376 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPOPCODE_H__ +#define __FPOPCODE_H__ + +/* +ARM Floating Point Instruction Classes +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +CPDT data transfer instructions + LDF, STF, LFM, SFM + +CPDO dyadic arithmetic instructions + ADF, MUF, SUF, RSF, DVF, RDF, + POW, RPW, RMF, FML, FDV, FRD, POL + +CPDO monadic arithmetic instructions + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM + +CPRT joint arithmetic/data transfer instructions + FIX (arithmetic followed by load/store) + FLT (load/store followed by arithmetic) + CMF, CNF CMFE, CNFE (comparisons) + WFS, RFS (write/read floating point status register) + WFC, RFC (write/read floating point control register) + +cond condition codes +P pre/post index bit: 0 = postindex, 1 = preindex +U up/down bit: 0 = stack grows down, 1 = stack grows up +W write back bit: 1 = update base register (Rn) +L load/store bit: 0 = store, 1 = load +Rn base register +Rd destination/source register +Fd floating point destination register +Fn floating point source register +Fm floating point source register or floating point constant + +uv transfer length (TABLE 1) +wx register count (TABLE 2) +abcd arithmetic opcode (TABLES 3 & 4) +ef destination size (rounding precision) (TABLE 5) +gh rounding mode (TABLE 6) +j dyadic/monadic bit: 0 = dyadic, 1 = monadic +i constant bit: 1 = constant (TABLE 6) +*/ + +/* +TABLE 1 ++-------------------------+---+---+---------+---------+ +| Precision | u | v | FPSR.EP | length | ++-------------------------+---+---+---------+---------+ +| Single | 0 ü 0 | x | 1 words | +| Double | 1 ü 1 | x | 2 words | +| Extended | 1 ü 1 | x | 3 words | +| Packed decimal | 1 ü 1 | 0 | 3 words | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | ++-------------------------+---+---+---------+---------+ +Note: x = don't care +*/ + +/* +TABLE 2 ++---+---+---------------------------------+ +| w | x | Number of registers to transfer | ++---+---+---------------------------------+ +| 0 ü 1 | 1 | +| 1 ü 0 | 2 | +| 1 ü 1 | 3 | +| 0 ü 0 | 4 | ++---+---+---------------------------------+ +*/ + +/* +TABLE 3: Dyadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: POW, RPW, POL are deprecated, and are available for backwards + compatibility only. +*/ + +/* +TABLE 4: Monadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are + available for backwards compatibility only. +*/ + +/* +TABLE 5 ++-------------------------+---+---+ +| Rounding Precision | e | f | ++-------------------------+---+---+ +| IEEE Single precision | 0 ü 0 | +| IEEE Double precision | 0 ü 1 | +| IEEE Extended precision | 1 ü 0 | +| undefined (trap) | 1 ü 1 | ++-------------------------+---+---+ +*/ + +/* +TABLE 5 ++---------------------------------+---+---+ +| Rounding Mode | g | h | ++---------------------------------+---+---+ +| Round to nearest (default) | 0 ü 0 | +| Round toward plus infinity | 0 ü 1 | +| Round toward negative infinity | 1 ü 0 | +| Round toward zero | 1 ü 1 | ++---------------------------------+---+---+ +*/ + +/* +=== +=== Definitions for load and store instructions +=== +*/ + +/* bit masks */ +#define BIT_PREINDEX 0x01000000 +#define BIT_UP 0x00800000 +#define BIT_WRITE_BACK 0x00200000 +#define BIT_LOAD 0x00100000 + +/* masks for load/store */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_OFFSET 0x000000ff +#define MASK_TRANSFER_LENGTH 0x00408000 +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH +#define MASK_COPROCESSOR 0x00000f00 + +/* Tests for transfer length */ +#define TRANSFER_SINGLE 0x00000000 +#define TRANSFER_DOUBLE 0x00008000 +#define TRANSFER_EXTENDED 0x00400000 +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH + +/* Get the coprocessor number from the opcode. */ +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) + +/* Get the offset from the opcode. */ +#define getOffset(opcode) (opcode & MASK_OFFSET) + +/* Tests for specific data transfer load/store opcodes. */ +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) + +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) + +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) + +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) + +/* +=== +=== Definitions for arithmetic instructions +=== +*/ +/* bit masks */ +#define BIT_MONADIC 0x00008000 +#define BIT_CONSTANT 0x00000008 + +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) + +/* instruction identification masks */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_ARITHMETIC_OPCODE 0x00f08000 +#define MASK_DESTINATION_SIZE 0x00080080 + +/* dyadic arithmetic opcodes. */ +#define ADF_CODE 0x00000000 +#define MUF_CODE 0x00100000 +#define SUF_CODE 0x00200000 +#define RSF_CODE 0x00300000 +#define DVF_CODE 0x00400000 +#define RDF_CODE 0x00500000 +#define POW_CODE 0x00600000 +#define RPW_CODE 0x00700000 +#define RMF_CODE 0x00800000 +#define FML_CODE 0x00900000 +#define FDV_CODE 0x00a00000 +#define FRD_CODE 0x00b00000 +#define POL_CODE 0x00c00000 +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ + +/* monadic arithmetic opcodes. */ +#define MVF_CODE 0x00008000 +#define MNF_CODE 0x00108000 +#define ABS_CODE 0x00208000 +#define RND_CODE 0x00308000 +#define SQT_CODE 0x00408000 +#define LOG_CODE 0x00508000 +#define LGN_CODE 0x00608000 +#define EXP_CODE 0x00708000 +#define SIN_CODE 0x00808000 +#define COS_CODE 0x00908000 +#define TAN_CODE 0x00a08000 +#define ASN_CODE 0x00b08000 +#define ACS_CODE 0x00c08000 +#define ATN_CODE 0x00d08000 +#define URD_CODE 0x00e08000 +#define NRM_CODE 0x00f08000 + +/* +=== +=== Definitions for register transfer and comparison instructions +=== +*/ + +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT_CODE 0x00f00000 +#define FLT_CODE 0x00000000 +#define FIX_CODE 0x00100000 +#define WFS_CODE 0x00200000 +#define RFS_CODE 0x00300000 +#define WFC_CODE 0x00400000 +#define RFC_CODE 0x00500000 +#define CMF_CODE 0x00900000 +#define CNF_CODE 0x00b00000 +#define CMFE_CODE 0x00d00000 +#define CNFE_CODE 0x00f00000 + +/* +=== +=== Common definitions +=== +*/ + +/* register masks */ +#define MASK_Rd 0x0000f000 +#define MASK_Rn 0x000f0000 +#define MASK_Fd 0x00007000 +#define MASK_Fm 0x00000007 +#define MASK_Fn 0x00070000 + +/* condition code masks */ +#define CC_MASK 0xf0000000 +#define CC_NEGATIVE 0x80000000 +#define CC_ZERO 0x40000000 +#define CC_CARRY 0x20000000 +#define CC_OVERFLOW 0x10000000 +#define CC_EQ 0x00000000 +#define CC_NE 0x10000000 +#define CC_CS 0x20000000 +#define CC_HS CC_CS +#define CC_CC 0x30000000 +#define CC_LO CC_CC +#define CC_MI 0x40000000 +#define CC_PL 0x50000000 +#define CC_VS 0x60000000 +#define CC_VC 0x70000000 +#define CC_HI 0x80000000 +#define CC_LS 0x90000000 +#define CC_GE 0xa0000000 +#define CC_LT 0xb0000000 +#define CC_GT 0xc0000000 +#define CC_LE 0xd0000000 +#define CC_AL 0xe0000000 +#define CC_NV 0xf0000000 + +/* rounding masks/values */ +#define MASK_ROUNDING_MODE 0x00000060 +#define ROUND_TO_NEAREST 0x00000000 +#define ROUND_TO_PLUS_INFINITY 0x00000020 +#define ROUND_TO_MINUS_INFINITY 0x00000040 +#define ROUND_TO_ZERO 0x00000060 + +#define MASK_ROUNDING_PRECISION 0x00080080 +#define ROUND_SINGLE 0x00000000 +#define ROUND_DOUBLE 0x00000080 +#define ROUND_EXTENDED 0x00080000 + +/* Get the condition code from the opcode. */ +#define getCondition(opcode) (opcode >> 28) + +/* Get the source register from the opcode. */ +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) + +/* Get the destination floating point register from the opcode. */ +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) + +/* Get the first source floating point register from the opcode. */ +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) + +/* Get the second source floating point register from the opcode. */ +#define getFm(opcode) (opcode & MASK_Fm) + +/* Get the destination register from the opcode. */ +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) + +/* Get the rounding mode from the opcode. */ +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) + +float32 getSingleConstant(const unsigned int nIndex); +float64 getDoubleConstant(const unsigned int nIndex); +floatx80 getExtendedConstant(const unsigned int nIndex); + +unsigned int getRegisterCount(const unsigned int opcode); +unsigned int getDestinationSize(const unsigned int opcode); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpsr.h linux.ac/arch/arm/nwfpe/fpsr.h --- linux.vanilla/arch/arm/nwfpe/fpsr.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/fpsr.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,108 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPSR_H__ +#define __FPSR_H__ + +/* +The FPSR is a 32 bit register consisting of 4 parts, each exactly +one byte. + + SYSTEM ID + EXCEPTION TRAP ENABLE BYTE + SYSTEM CONTROL BYTE + CUMULATIVE EXCEPTION FLAGS BYTE + +The FPCR is a 32 bit register consisting of bit flags. +*/ + +/* SYSTEM ID +------------ +Note: the system id byte is read only */ + +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ + +#define MASK_SYSID 0xff000000 +#define BIT_HARDWARE 0x80000000 +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ + +/* EXCEPTION TRAP ENABLE BYTE +----------------------------- */ + +#define MASK_TRAP_ENABLE 0x00ff0000 +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ + +/* SYSTEM CONTROL BYTE +---------------------- */ + +#define MASK_SYSTEM_CONTROL 0x0000ff00 +#define MASK_TRAP_STRICT 0x00001f00 + +#define BIT_AC 0x00100000 /* use alternative C-flag definition + for compares */ +#define BIT_EP 0x00080000 /* use expanded packed decimal format */ +#define BIT_SO 0x00040000 /* select synchronous operation of FPA */ +#define BIT_NE 0x00020000 /* NaN exception bit */ +#define BIT_ND 0x00010000 /* no denormalized numbers bit */ + +/* CUMULATIVE EXCEPTION FLAGS BYTE +---------------------------------- */ + +#define MASK_EXCEPTION_FLAGS 0x000000ff +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f + +#define BIT_IXC 0x00000010 /* inexact exception flag */ +#define BIT_UFC 0x00000008 /* underflow exception flag */ +#define BIT_OFC 0x00000004 /* overfloat exception flag */ +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ + +/* Floating Point Control Register +----------------------------------*/ + +#define BIT_RU 0x80000000 /* rounded up bit */ +#define BIT_IE 0x10000000 /* inexact bit */ +#define BIT_MO 0x08000000 /* mantissa overflow bit */ +#define BIT_EO 0x04000000 /* exponent overflow bit */ +#define BIT_SB 0x00000800 /* store bounce */ +#define BIT_AB 0x00000400 /* arithmetic bounce */ +#define BIT_RE 0x00000200 /* rounding exception */ +#define BIT_DA 0x00000100 /* disable FPA */ + +#define MASK_OP 0x00f08010 /* AU operation code */ +#define MASK_PR 0x00080080 /* AU precision */ +#define MASK_S1 0x00070000 /* AU source register 1 */ +#define MASK_S2 0x00000007 /* AU source register 2 */ +#define MASK_DS 0x00007000 /* AU destination register */ +#define MASK_RM 0x00000060 /* AU rounding mode */ +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ +#define MASK_WFC MASK_RESET +#define MASK_RFC ~MASK_RESET + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/milieu.h linux.ac/arch/arm/nwfpe/milieu.h --- linux.vanilla/arch/arm/nwfpe/milieu.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/milieu.h Tue Feb 2 20:59:49 1999 @@ -0,0 +1,48 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Include common integer types and flags. +------------------------------------------------------------------------------- +*/ +#include "ARM-gcc.h" + +/* +------------------------------------------------------------------------------- +Symbolic Boolean literals. +------------------------------------------------------------------------------- +*/ +enum { + FALSE = 0, + TRUE = 1 +}; + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/single_cpdo.c linux.ac/arch/arm/nwfpe/single_cpdo.c --- linux.vanilla/arch/arm/nwfpe/single_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/single_cpdo.c Tue Feb 2 20:59:49 1999 @@ -0,0 +1,256 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#include "config.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +float32 getSingleConstant(unsigned int); + +float32 float32_exp(float32 Fm); +float32 float32_ln(float32 Fm); +float32 float32_sin(float32 rFm); +float32 float32_cos(float32 rFm); +float32 float32_arcsin(float32 rFm); +float32 float32_arctan(float32 rFm); +float32 float32_log(float32 rFm); +float32 float32_tan(float32 rFm); +float32 float32_arccos(float32 rFm); +float32 float32_pow(float32 rFn,float32 rFm); +float32 float32_pol(float32 rFn,float32 rFm); + +unsigned int SingleCPDO(const unsigned int opcode) +{ + float32 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //fp_printk("SingleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getSingleConstant(Fm); + //fp_printk("constant Fm = %d 0x%08x\n",Fm,rFm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = fpa11->fpreg[Fm].fValue.fSingle; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = fpa11->fpreg[Fn].fValue.fSingle; + break; + + default: return 0; + } + //fp_printk("dyadic instruction\n"); + //fp_printk("Fn = %d, rFn = 0x%08x\n",Fn,rFn); + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn); + break; + + case POW_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn); + break; + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm); + break; + + case POL_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm); + break; + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case MNF_CODE: + rFm ^= 0x80000000; + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case ABS_CODE: + rFm &= 0x7fffffff; + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fSingle = + int32_to_float32(float32_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm); + break; + + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm); + break; + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle; + return nRc; +} + +float32 float32_exp(float32 Fm) +{ +//series +} + +float32 float32_ln(float32 Fm) +{ +//series +} + +float32 float32_sin(float32 rFm) +{ +//series +} + +float32 float32_cos(float32 rFm) +{ +//series +} + +float32 float32_arcsin(float32 rFm) +{ +//series +} + +float32 float32_arctan(float32 rFm) +{ + //series +} + +float32 float32_log(float32 rFm) +{ + return float32_div(float32_ln(rFm),getSingleConstant(7)); +} + +float32 float32_tan(float32 rFm) +{ + return float32_div(float32_sin(rFm),float32_cos(rFm)); +} + +float32 float32_arccos(float32 rFm) +{ + //return float32_sub(halfPi,float32_arcsin(rFm)); +} + +float32 float32_pow(float32 rFn,float32 rFm) +{ + return float32_exp(float32_mul(rFm,float32_ln(rFn))); +} + +float32 float32_pol(float32 rFn,float32 rFm) +{ + return float32_arctan(float32_div(rFn,rFm)); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat-macros linux.ac/arch/arm/nwfpe/softfloat-macros --- linux.vanilla/arch/arm/nwfpe/softfloat-macros Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/softfloat-macros Tue Feb 2 20:59:50 1999 @@ -0,0 +1,740 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 32, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 64, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + __asm__("@shift64RightJamming -- start"); + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + __asm__("@shift64RightJamming -- end"); + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +_plus_ the number of bits given in `count'. The shifted result is at most +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +bits shifted off form a second 64-bit result as follows: The _last_ bit +shifted off is the most-significant bit of the extra result, and the other +63 bits of the extra result are all zero if and only if _all_but_the_last_ +bits shifted off were all zero. This extra result is stored in the location +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. + (This routine makes more sense if `a0' and `a1' are considered to form a +fixed-point value with binary point between `a0' and `a1'. This fixed-point +value is shifted right by the number of bits given in `count', and the +integer part of the result is returned at the location pointed to by +`z0Ptr'. The fractional part of the result may be slightly corrupted as +described above, and is returned at the location pointed to by `z1Ptr'.) +------------------------------------------------------------------------------- +*/ +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' can be arbitrarily large; in particular, if `count' is greater +than 128, the result will be 0. The result is broken into two 64-bit pieces +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. If any nonzero bits are shifted off, they +are ``jammed'' into the least significant bit of the result by setting the +least significant bit to 1. The value of `count' can be arbitrarily large; +in particular, if `count' is greater than 128, the result will be either 0 +or 1, depending on whether the concatenation of `a0' and `a1' is zero or +nonzero. The result is broken into two 64-bit pieces which are stored at +the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' must be less than 64. The result is broken into two 64-bit +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/* +------------------------------------------------------------------------------- +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +by the number of bits given in `count'. Any bits shifted off are lost. +The value of `count' must be less than 64. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +any carry out is lost. The result is broken into two 64-bit pieces which +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/* +------------------------------------------------------------------------------- +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +modulo 2^192, so any carry out is lost. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +2^128, so any borrow out (carry out) is lost. The result is broken into two +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +`z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +result is broken into three 64-bit pieces which are stored at the locations +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +into two 64-bit pieces which are stored at the locations pointed to by +`z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to +obtain a 192-bit product. The product is broken into three 64-bit pieces +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +`z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +product. The product is broken into four 64-bit pieces which are stored at +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the 64-bit integer quotient obtained by dividing +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The +divisor `b' must be at least 2^63. If q is the exact quotient truncated +toward zero, the approximation returned lies between q and q + 2 inclusive. +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +unsigned integer is returned. +------------------------------------------------------------------------------- +*/ +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the square root of the 32-bit significand given +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +`aExp' (the least significant bit) is 1, the integer returned approximates +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +case, the approximation returned lies strictly within +/-2 of the exact +value. +------------------------------------------------------------------------------- +*/ +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 32 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 64 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +is equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +not equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat-specialize linux.ac/arch/arm/nwfpe/softfloat-specialize --- linux.vanilla/arch/arm/nwfpe/softfloat-specialize Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/softfloat-specialize Tue Feb 2 20:59:50 1999 @@ -0,0 +1,471 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Underflow tininess-detection mode, statically initialized to default value. +(The declaration in `softfloat.h' must match the `int8' type here.) +------------------------------------------------------------------------------- +*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/* +------------------------------------------------------------------------------- +Raises the exceptions specified by `flags'. Floating-point traps can be +defined here if desired. It is currently not possible for such a trap to +substitute a result value. If traps are not implemented, this routine +should be simply `float_exception_flags |= flags;'. + +ScottB: November 4, 1998 +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). +------------------------------------------------------------------------------- +void float_raise( int8 flags ) +{ + float_exception_flags |= flags; +} +*/ + +/* +------------------------------------------------------------------------------- +Internal canonical NaN format. +------------------------------------------------------------------------------- +*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/* +------------------------------------------------------------------------------- +The pattern for a default generated single-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float32_default_nan 0xFFFFFFFF + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float32ToCommonNaN( float32 a ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>31; + z.low = 0; + z.high = ( (bits64) a )<<41; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the single- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float32 commonNaNToFloat32( commonNaNT a ) +{ + + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two single-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float32 propagateFloat32NaN( float32 a, float32 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +/* +------------------------------------------------------------------------------- +The pattern for a default generated double-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_nan( float64 a ) +{ + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float64ToCommonNaN( float64 a ) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>63; + z.low = 0; + z.high = a<<12; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the double- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float64 commonNaNToFloat64( commonNaNT a ) +{ + + return + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF8000000000000 ) + | ( a.high>>12 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two double-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float64 propagateFloat64NaN( float64 a, float64 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a |= LIT64( 0x0008000000000000 ); + b |= LIT64( 0x0008000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated extended double-precision NaN. The +`high' and `low' values hold the most- and least-significant bits, +respectively. +------------------------------------------------------------------------------- +*/ +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_nan( floatx80 a ) +{ + + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_signaling_nan( floatx80 a ) +{ + //register int lr; + bits64 aLow; + + //__asm__("mov %0, lr" : : "g" (lr)); + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT floatx80ToCommonNaN( floatx80 a ) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low<<1; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the extended +double-precision floating-point format. +------------------------------------------------------------------------------- +*/ +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two extended double-precision floating-point values `a' and `b', one +of which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated quadruple-precision NaN. The `high' and +`low' values hold the most- and least-significant bits, respectively. +------------------------------------------------------------------------------- +*/ +#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float128_is_nan( float128 a ) +{ + + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float128_is_signaling_nan( float128 a ) +{ + + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float128ToCommonNaN( float128 a ) +{ + commonNaNT z; + + if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>63; + shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the quadruple- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float128 commonNaNToFloat128( commonNaNT a ) +{ + float128 z; + + shift128Right( a.high, a.low, 16, &z.high, &z.low ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two quadruple-precision floating-point values `a' and `b', one of +which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float128 propagateFloat128NaN( float128 a, float128 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float128_is_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsNaN = float128_is_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); + a.high |= LIT64( 0x0000800000000000 ); + b.high |= LIT64( 0x0000800000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat.c linux.ac/arch/arm/nwfpe/softfloat.c --- linux.vanilla/arch/arm/nwfpe/softfloat.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/softfloat.c Tue Feb 2 20:59:50 1999 @@ -0,0 +1,4877 @@ +/* +=============================================================================== + +This C source file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#include "milieu.h" +#include "softfloat.h" + +/* +------------------------------------------------------------------------------- +Floating-point rounding mode, extended double-precision rounding precision, +and exception flags. +------------------------------------------------------------------------------- +*/ +int8 float_rounding_mode = float_round_nearest_even; +int8 floatx80_rounding_precision = 80; +int8 float_exception_flags = 0; + +/* +------------------------------------------------------------------------------- +Primitive arithmetic functions, including multi-word arithmetic, and +division and square root approximations. (Can be specialized to target if +desired.) +------------------------------------------------------------------------------- +*/ +#include "softfloat-macros" + +/* +------------------------------------------------------------------------------- +Functions and definitions to determine: (1) whether tininess for underflow +is detected before or after rounding by default, (2) what (if anything) +happens when exceptions are raised, (3) how signaling NaNs are distinguished +from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +are propagated from function inputs to output. These details are target- +specific. +------------------------------------------------------------------------------- +*/ +#include "softfloat-specialize" + +/* +------------------------------------------------------------------------------- +Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +and 7, and returns the properly rounded 32-bit integer corresponding to the +input. If `zSign' is nonzero, the input is negated before being converted +to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point +input is simply rounded to an integer, with the inexact exception raised if +the input cannot be represented exactly as an integer. If the fixed-point +input is too large, however, the invalid exception is raised and the largest +positive or negative integer is returned. +------------------------------------------------------------------------------- +*/ +static int32 roundAndPackInt32( flag zSign, bits64 absZ ) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_exception_flags |= float_flag_invalid; + return zSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal single-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper single-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat32' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal double-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper double-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat64' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal extended double-precision floating-point value +represented by the denormalized significand `aSig'. The normalized exponent +and significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>48 ) & 0x7FFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the quadruple-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat128Sign( float128 a ) +{ + + return a.high>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal quadruple-precision floating-point value +represented by the denormalized significand formed by the concatenation of +`aSig0' and `aSig1'. The normalized exponent is stored at the location +pointed to by `zExpPtr'. The most significant 49 bits of the normalized +significand are stored at the location pointed to by `zSig0Ptr', and the +least significant 64 bits of the normalized significand are stored at the +location pointed to by `zSig1Ptr'. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat128Subnormal( + bits64 aSig0, + bits64 aSig1, + int32 *zExpPtr, + bits64 *zSig0Ptr, + bits64 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros64( aSig1 ) - 15; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 63 ); + } + else { + *zSig0Ptr = aSig1<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + float_exception_flags |= float_flag_inexact; + } + return aSign ? - z : z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float32_to_float64( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 float32_to_floatx80( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float32_to_float128( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Rounds the single-precision floating-point value `a' to an integer, and +returns the result as a single-precision floating-point value. The +operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the single-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the single- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the single-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_add( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign ); + } + else { + return subFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sub( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_mul( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the single-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_div( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the single-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_rem( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the single-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sqrt( float32 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0xFFFFFFFF; + } + else { + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + } + shift32RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat32( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq_signaling( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = 0x433 - aExp; + if ( shiftCount < 21 ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( 52 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the double-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the double- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the double-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_add( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign ); + } + else { + return subFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sub( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign ); + } + else { + return addFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_mul( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the double-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_div( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the double-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_rem( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the double-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sqrt( float64 a ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig; + bits64 rem0, rem1, term0, term1; //, shiftedRem; + //float64 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + zSig <<= 31; + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2; + if ( ( zSig & 0x3FF ) <= 5 ) { + if ( zSig < 2 ) { + zSig = LIT64( 0xFFFFFFFFFFFFFFFF ); + } + else { + aSig <<= 2; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + shortShift128Left( 0, zSig, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + } + shift64RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat64( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq_signaling( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic---which means in particular that the conversion +is rounded according to the current rounding mode. If `a' is a NaN, the +largest positive integer is returned. Otherwise, if the conversion +overflows, the largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic, except that the conversion is always rounded +toward zero. If `a' is a NaN, the largest positive integer is returned. +Otherwise, if the conversion overflows, the largest integer with the same +sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32_round_to_zero( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + shiftCount = 0x403E - aExp; + if ( shiftCount < 32 ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( 63 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the extended double- +precision floating-point values `a' and `b'. If `zSign' is true, the sum is +negated before being returned. `zSign' is ignored if the result is a NaN. +The addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + + zSig0 = aSig + bSig; + + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the extended +double-precision floating-point values `a' and `b'. If `zSign' is true, +the difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the extended double-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_add( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign ); + } + else { + return subFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sub( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign ); + } + else { + return addFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_mul( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the extended double-precision floating-point +value `a' by the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_div( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the extended double-precision floating-point value +`a' with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_rem( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the extended double-precision floating-point +value `a'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sqrt( floatx80 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + zSig0 <<= 31; + aSig1 = 0; + shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( (bits64) ( zSig1<<1 ) <= 10 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than or equal to the corresponding value `b', and 0 otherwise. The +comparison is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is equal +to the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq_signaling( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +do not cause an exception. Otherwise, the comparison is performed according +to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point +value `a' to the 32-bit two's complement integer format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float128_to_int32( float128 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; + if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x4028 - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); + return roundAndPackInt32( aSign, aSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point +value `a' to the 32-bit two's complement integer format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float128_to_int32_round_to_zero( float128 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1, savedASig; + int32 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x402F - aExp; + if ( shiftCount < 17 ) { + if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; + goto invalid; + } + else if ( 48 < shiftCount ) { + if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig0 |= LIT64( 0x0001000000000000 ); + savedASig = aSig0; + aSig0 >>= shiftCount; + z = aSig0; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig0<>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits64) z.low < 0 ) { + ++z.high; + if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp <= 0x3FFE ) { + if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat128Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) + && ( extractFloat128Frac0( a ) + | extractFloat128Frac1( a ) ) + ) { + return packFloat128( aSign, 0x3FFF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) + : packFloat128( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat128( 1, 0, 0, 0 ) + : packFloat128( 0, 0x3FFF, 0, 0 ); + } + return packFloat128( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x402F - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + float_exception_flags |= float_flag_inexact; + } + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the quadruple-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float128 addFloat128Sigs( float128 a, float128 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int32 expDiff; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b ); + } + return a; + } + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); + zSig2 = 0; + zSig0 |= LIT64( 0x0002000000000000 ); + zExp = aExp; + goto shiftRight1; + } + aSig0 |= LIT64( 0x0001000000000000 ); + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; + ++zExp; + shiftRight1: + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the quadruple- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float128 subFloat128Sigs( float128 a, float128 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int32 expDiff; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= LIT64( 0x4000000000000000 ); + bBigger: + sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= LIT64( 0x4000000000000000 ); + aBigger: + sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the quadruple-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_add( float128 a, float128 b ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return addFloat128Sigs( a, b, aSign ); + } + else { + return subFloat128Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the quadruple-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_sub( float128 a, float128 b ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return subFloat128Sigs( a, b, aSign ); + } + else { + return addFloat128Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the quadruple-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_mul( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x4000; + aSig0 |= LIT64( 0x0001000000000000 ); + shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); + mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the quadruple-precision floating-point value +`a' by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_div( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + goto invalid; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FFD; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { + shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); + mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 4 ) { + mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the quadruple-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_rem( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig0, bSig1; + bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1; + bits64 sigMean1; + sbits64 sigMean0; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), + aSig1, + 15 - ( expDiff < 0 ), + &aSig0, + &aSig1 + ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + q = le128( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); + shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); + sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 61; + } + if ( -64 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + expDiff += 52; + if ( expDiff < 0 ) { + shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits64) aSig0 ); + add128( + aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits64) aSig0 < 0 ); + if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the quadruple-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_sqrt( float128 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; + aSig0 |= LIT64( 0x0001000000000000 ); + zSig0 = estimateSqrt32( aExp, aSig0>>17 ); + zSig0 <<= 31; + shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is equal to +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_eq( float128 a, float128 b ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +or equal to the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_le( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_lt( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is equal to +the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_eq_signaling( float128 a, float128 b ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_le_quiet( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_lt_quiet( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat.h linux.ac/arch/arm/nwfpe/softfloat.h --- linux.vanilla/arch/arm/nwfpe/softfloat.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/nwfpe/softfloat.h Tue Feb 2 20:59:51 1999 @@ -0,0 +1,290 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#ifndef __SOFTFLOAT_H__ +#define __SOFTFLOAT_H__ + +/* +------------------------------------------------------------------------------- +The macro `FLOATX80' must be defined to enable the extended double-precision +floating-point format `floatx80'. If this macro is not defined, the +`floatx80' type will not be defined, and none of the functions that either +input or output the `floatx80' type will be defined. The same applies to +the `FLOAT128' macro and the quadruple-precision format `float128'. +------------------------------------------------------------------------------- +*/ +#define FLOATX80 +/* #define FLOAT128 */ + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point types. +------------------------------------------------------------------------------- +*/ +typedef unsigned long int float32; +typedef unsigned long long float64; +#ifdef FLOATX80 +typedef struct { + unsigned short high; + unsigned long long low; +} floatx80; +#endif +#ifdef FLOAT128 +typedef struct { + unsigned long long high, low; +} float128; +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point underflow tininess-detection mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_detect_tininess; +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point rounding mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_rounding_mode; +enum { + float_round_nearest_even = 0, + float_round_to_zero = 1, + float_round_down = 2, + float_round_up = 3 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point exception flags. +------------------------------------------------------------------------------- +extern signed char float_exception_flags; +enum { + float_flag_inexact = 1, + float_flag_underflow = 2, + float_flag_overflow = 4, + float_flag_divbyzero = 8, + float_flag_invalid = 16 +}; + +ScottB: November 4, 1998 +Changed the enumeration to match the bit order in the FPA11. +*/ + +extern signed char float_exception_flags; +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 2, + float_flag_overflow = 4, + float_flag_underflow = 8, + float_flag_inexact = 16 +}; + +/* +------------------------------------------------------------------------------- +Routine to raise any or all of the software IEC/IEEE floating-point +exception flags. +------------------------------------------------------------------------------- +*/ +void float_raise( signed char ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE integer-to-floating-point conversion routines. +------------------------------------------------------------------------------- +*/ +float32 int32_to_float32( signed int ); +float64 int32_to_float64( signed int ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( signed int ); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( signed int ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float32_to_int32( float32 ); +signed int float32_to_int32_round_to_zero( float32 ); +float64 float32_to_float64( float32 ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 ); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision operations. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 ); +float32 float32_add( float32, float32 ); +float32 float32_sub( float32, float32 ); +float32 float32_mul( float32, float32 ); +float32 float32_div( float32, float32 ); +float32 float32_rem( float32, float32 ); +float32 float32_sqrt( float32 ); +char float32_eq( float32, float32 ); +char float32_le( float32, float32 ); +char float32_lt( float32, float32 ); +char float32_eq_signaling( float32, float32 ); +char float32_le_quiet( float32, float32 ); +char float32_lt_quiet( float32, float32 ); +char float32_is_signaling_nan( float32 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float64_to_int32( float64 ); +signed int float64_to_int32_round_to_zero( float64 ); +float32 float64_to_float32( float64 ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision operations. +------------------------------------------------------------------------------- +*/ +float64 float64_round_to_int( float64 ); +float64 float64_add( float64, float64 ); +float64 float64_sub( float64, float64 ); +float64 float64_mul( float64, float64 ); +float64 float64_div( float64, float64 ); +float64 float64_rem( float64, float64 ); +float64 float64_sqrt( float64 ); +char float64_eq( float64, float64 ); +char float64_le( float64, float64 ); +char float64_lt( float64, float64 ); +char float64_eq_signaling( float64, float64 ); +char float64_le_quiet( float64, float64 ); +char float64_lt_quiet( float64, float64 ); +char float64_is_signaling_nan( float64 ); + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int floatx80_to_int32( floatx80 ); +signed int floatx80_to_int32_round_to_zero( floatx80 ); +float32 floatx80_to_float32( floatx80 ); +float64 floatx80_to_float64( floatx80 ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision rounding precision. Valid +values are 32, 64, and 80. +------------------------------------------------------------------------------- +*/ +extern signed char floatx80_rounding_precision; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision operations. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_round_to_int( floatx80 ); +floatx80 floatx80_add( floatx80, floatx80 ); +floatx80 floatx80_sub( floatx80, floatx80 ); +floatx80 floatx80_mul( floatx80, floatx80 ); +floatx80 floatx80_div( floatx80, floatx80 ); +floatx80 floatx80_rem( floatx80, floatx80 ); +floatx80 floatx80_sqrt( floatx80 ); +char floatx80_eq( floatx80, floatx80 ); +char floatx80_le( floatx80, floatx80 ); +char floatx80_lt( floatx80, floatx80 ); +char floatx80_eq_signaling( floatx80, floatx80 ); +char floatx80_le_quiet( floatx80, floatx80 ); +char floatx80_lt_quiet( floatx80, floatx80 ); +char floatx80_is_signaling_nan( floatx80 ); + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE quadruple-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float128_to_int32( float128 ); +signed int float128_to_int32_round_to_zero( float128 ); +float32 float128_to_float32( float128 ); +float64 float128_to_float64( float128 ); +#ifdef FLOATX80 +floatx80 float128_to_floatx80( float128 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE quadruple-precision operations. +------------------------------------------------------------------------------- +*/ +float128 float128_round_to_int( float128 ); +float128 float128_add( float128, float128 ); +float128 float128_sub( float128, float128 ); +float128 float128_mul( float128, float128 ); +float128 float128_div( float128, float128 ); +float128 float128_rem( float128, float128 ); +float128 float128_sqrt( float128 ); +char float128_eq( float128, float128 ); +char float128_le( float128, float128 ); +char float128_lt( float128, float128 ); +char float128_eq_signaling( float128, float128 ); +char float128_le_quiet( float128, float128 ); +char float128_lt_quiet( float128, float128 ); +char float128_is_signaling_nan( float128 ); + +#endif + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/vmlinux-armv.lds linux.ac/arch/arm/vmlinux-armv.lds --- linux.vanilla/arch/arm/vmlinux-armv.lds Sun Nov 8 15:08:45 1998 +++ linux.ac/arch/arm/vmlinux-armv.lds Fri Jan 22 14:10:49 1999 @@ -7,50 +7,64 @@ ENTRY(_start) SECTIONS { - _text = .; /* Text and read-only data */ - .text : { + _text = .; /* Text and read-only data */ + .text : { } /* Set text start address */ + + __init_begin = .; /* Init code and data */ + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __ebsa285_begin = .; + .text.ebsa285 : { *(.text.ebsa285) } + .data.ebsa285 : { *(.data.ebsa285) } + . = ALIGN(4096); + __ebsa285_end = .; + + __netwinder_begin = .; + .text.netwinder : { *(.text.netwinder) } + .data.netwinder : { *(.data.netwinder) } + . = ALIGN(4096); + __netwinder_end = .; + + .text.real : { /* Real text segment */ *(.text) *(.fixup) *(.gnu.warning) - } = 0x9090 + } + .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } - . = ALIGN(16); /* Exception table */ + . = ALIGN(16); /* Exception table */ __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .; - __start___ksymtab = .; /* Kernel symbol table */ + __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; - _etext = .; /* End of text section */ + _etext = .; /* End of text section */ . = ALIGN(8192); - .data : { /* Data */ + .data : { /* Data */ *(.init.task) *(.data) CONSTRUCTORS } - _edata = .; /* End of data section */ - - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(4096); - __init_end = .; + _edata = .; /* End of data section */ - __bss_start = .; /* BSS */ + __bss_start = .; /* BSS */ .bss : { *(.bss) } _end = . ; - /* Stabs debugging sections. */ + /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/i386/config.in Thu Mar 25 18:06:25 1999 @@ -81,6 +81,11 @@ fi fi +tristate 'I2O support' CONFIG_I2O +dep_tristate 'I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O +dep_tristate 'I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O +#dep_tristate 'I2O Network OSM' CONFIG_I2O_NET $CONFIG_I2O +dep_tristate 'I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/init_task.c linux.ac/arch/i386/kernel/init_task.c --- linux.vanilla/arch/i386/kernel/init_task.c Sun Nov 8 15:08:22 1998 +++ linux.ac/arch/i386/kernel/init_task.c Fri Dec 4 17:14:23 1998 @@ -7,7 +7,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/mca.c linux.ac/arch/i386/kernel/mca.c --- linux.vanilla/arch/i386/kernel/mca.c Sun Nov 8 15:08:22 1998 +++ linux.ac/arch/i386/kernel/mca.c Wed Mar 24 18:05:23 1999 @@ -26,6 +26,9 @@ * - Added the 'driver_loaded' flag in MCA_adapter * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter * + * David Weinehall March 24th, 1999 + * - Fixed the output of 'Driver Installed' in /proc/mca/pos + * - Made the Integrated Video & SCSI show up even if they have id 0000 */ #include @@ -49,12 +52,12 @@ * Other miscellaneous information follows. */ -typedef enum { - MCA_ADAPTER_NORMAL = 0, - MCA_ADAPTER_NONE = 1, - MCA_ADAPTER_DISABLED = 2, - MCA_ADAPTER_ERROR = 3 -} MCA_AdapterStatus; +typedef enum { + MCA_ADAPTER_NORMAL = 0, + MCA_ADAPTER_NONE = 1, + MCA_ADAPTER_DISABLED = 2, + MCA_ADAPTER_ERROR = 3 +} MCA_AdapterStatus; struct MCA_adapter { MCA_AdapterStatus status; /* is there a valid adapter? */ @@ -69,16 +72,17 @@ }; struct MCA_info { -/* one for each of the 8 possible slots, plus one for integrated SCSI - and one for integrated video. */ + /* one for each of the 8 possible slots, plus one for integrated SCSI + * and one for integrated video. + */ struct MCA_adapter slot[MCA_NUMADAPTERS]; -/* two potential addresses for integrated SCSI adapter - this will - * track which one we think it is - */ + /* two potential addresses for integrated SCSI adapter - this will + * track which one we think it is. + */ - unsigned char which_scsi; + unsigned char which_scsi; }; /* The mca_info structure pointer. If MCA bus is present, the function @@ -102,10 +106,10 @@ #ifdef CONFIG_PROC_FS -static void mca_do_proc_init( void ); -static int mca_default_procfn( char* buf, int slot ); +static void mca_do_proc_init(void); +static int mca_default_procfn(char* buf, int slot); -static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *); +static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *); static struct file_operations proc_mca_operations = { NULL, /* array_lseek */ @@ -146,13 +150,13 @@ /* Build the status info for the adapter */ -static void mca_configure_adapter_status( int slot ) { +static void mca_configure_adapter_status(int slot) { mca_info->slot[slot].status = MCA_ADAPTER_NONE; mca_info->slot[slot].id = mca_info->slot[slot].pos[0] + (mca_info->slot[slot].pos[1] << 8); - if( !mca_info->slot[slot].id ) { + if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) { /* id = 0x0000 usually indicates hardware failure, * however, ZP Gu (zpg@castle.net> reports that his 9556 @@ -162,7 +166,7 @@ mca_info->slot[slot].status = MCA_ADAPTER_ERROR; return; - } else if( mca_info->slot[slot].id != 0xffff ) { + } else if(mca_info->slot[slot].id != 0xffff) { /* 0xffff usually indicates that there's no adapter, * however, some integrated adapters may have 0xffff as @@ -174,21 +178,21 @@ mca_info->slot[slot].status = MCA_ADAPTER_NORMAL; } - if( (mca_info->slot[slot].id == 0xffff || - mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR ) { + if((mca_info->slot[slot].id == 0xffff || + mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) { int j; - for( j = 2; j < 8; j++ ) { - if( mca_info->slot[slot].pos[j] != 0xff ) { + for(j = 2; j < 8; j++) { + if(mca_info->slot[slot].pos[j] != 0xff) { mca_info->slot[slot].status = MCA_ADAPTER_NORMAL; break; } } } - if( !(mca_info->slot[slot].pos[2] & MCA_ENABLED) ) { + if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) { - /* enabled bit is in pos 2 */ + /* enabled bit is in POS 2 */ mca_info->slot[slot].status = MCA_ADAPTER_DISABLED; } @@ -198,22 +202,22 @@ __initfunc(void mca_init(void)) { - unsigned int i, j; + unsigned int i, j; unsigned long flags; /* WARNING: Be careful when making changes here. Putting an adapter - * and the motherboard simultaneously into setup mode may result in - * damage to chips (according to The Indispensible PC Hardware Book - * by Hans-Peter Messmer). Also, we disable system interrupts (so + * and the motherboard simultaneously into setup mode may result in + * damage to chips (according to The Indispensible PC Hardware Book + * by Hans-Peter Messmer). Also, we disable system interrupts (so * that we are not disturbed in the middle of this). */ /* Make sure the MCA bus is present */ - if (!MCA_bus) + if(!MCA_bus) return; - printk( "Micro Channel bus detected.\n" ); - save_flags( flags ); + printk("Micro Channel bus detected.\n"); + save_flags(flags); cli(); /* Allocate MCA_info structure (at address divisible by 8) */ @@ -225,67 +229,68 @@ outb_p(0, MCA_ADAPTER_SETUP_REG); /* Put motherboard into video setup mode, read integrated video - * pos registers, and turn motherboard setup off. + * POS registers, and turn motherboard setup off. */ outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG); mca_info->slot[MCA_INTEGVIDEO].name[0] = 0; - for (j=0; j<8; j++) { - mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) { + mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j)); } mca_configure_adapter_status(MCA_INTEGVIDEO); /* Put motherboard into scsi setup mode, read integrated scsi - * pos registers, and turn motherboard setup off. + * POS registers, and turn motherboard setup off. * - * It seems there are two possible SCSI registers. Martin says that + * It seems there are two possible SCSI registers. Martin says that * for the 56,57, 0xf7 is the one, but fails on the 76. * Alfredo (apena@vnet.ibm.com) says - * 0xfd works on his machine. We'll try both of them. I figure it's - * a good bet that only one could be valid at a time. This could + * 0xfd works on his machine. We'll try both of them. I figure it's + * a good bet that only one could be valid at a time. This could * screw up though if one is used for something else on the other * machine. */ outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG); mca_info->slot[MCA_INTEGSCSI].name[0] = 0; - for (j=0; j<8; j++) { - if( (mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff ) + for(j=0; j<8; j++) { + if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) { - /* 0xff all across means no device. 0x00 means something's - * broken, but a device is probably there. However, if you get - * 0x00 from a motherboard register it won't matter what we - * find. For the record, on the 57SLC, the integrated SCSI - * adapter has 0xffff for the adapter ID, but nonzero for - * other registers. + /* 0xff all across means no device. 0x00 means + * something's broken, but a device is probably there. + * However, if you get 0x00 from a motherboard + * register it won't matter what we find. For the + * record, on the 57SLC, the integrated SCSI + * adapter has 0xffff for the adapter ID, but + * nonzero for other registers. */ mca_info->which_scsi = 0xf7; } } - if( !mca_info->which_scsi ) { + if(!mca_info->which_scsi) { /* Didn't find it at 0xf7, try somewhere else... */ mca_info->which_scsi = 0xfd; outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG); - for (j=0; j<8; j++) - mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) + mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j)); } mca_configure_adapter_status(MCA_INTEGSCSI); - /* turn off motherboard setup */ + /* Turn off motherboard setup */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); /* Now loop over MCA slots: put each adapter into setup mode, and - * read its pos registers. Then put adapter setup off. + * read its POS registers. Then put adapter setup off. */ - for (i=0; islot[i].pos[j]=inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) { + mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j)); } mca_info->slot[i].name[0] = 0; mca_info->slot[i].driver_loaded = 0; @@ -295,7 +300,7 @@ /* Enable interrupts and return memory start */ - restore_flags( flags ); + restore_flags(flags); request_region(0x60,0x01,"system control port B (MCA)"); request_region(0x90,0x01,"arbitration (MCA)"); @@ -312,89 +317,90 @@ /*--------------------------------------------------------------------*/ -static void mca_handle_nmi_slot( int slot, int check_flag ) +static void mca_handle_nmi_slot(int slot, int check_flag) { - if( slot < MCA_MAX_SLOT_NR ) { - printk( "NMI: caused by MCA adapter in slot %d (%s)\n", slot+1, - mca_info->slot[slot].name ); - } else if( slot == MCA_INTEGSCSI ) { - printk( "NMI: caused by MCA integrated SCSI adapter (%s)\n", - mca_info->slot[slot].name ); - } else if( slot == MCA_INTEGVIDEO ) { - printk( "NMI: caused by MCA integrated video adapter (%s)\n", - mca_info->slot[slot].name ); - } - - /* more info available in pos 6 and 7? */ - - if( check_flag ) { - unsigned char pos6, pos7; - - pos6 = mca_read_pos( slot, 6 ); - pos7 = mca_read_pos( slot, 7 ); - - printk( "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7 ); - } - -} /* mca_handle_nmi_slot */ - -/*--------------------------------------------------------------------*/ + if(slot < MCA_MAX_SLOT_NR) { + printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot+1, + mca_info->slot[slot].name); + } else if(slot == MCA_INTEGSCSI) { + printk("NMI: caused by MCA integrated SCSI adapter (%s)\n", + mca_info->slot[slot].name); + } else if(slot == MCA_INTEGVIDEO) { + printk("NMI: caused by MCA integrated video adapter (%s)\n", + mca_info->slot[slot].name); + } + + /* More info available in POS 6 and 7? */ + + if(check_flag) { + unsigned char pos6, pos7; + + pos6 = mca_read_pos(slot, 6); + pos7 = mca_read_pos(slot, 7); + + printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7); + } + +} /* mca_handle_nmi_slot */ + +/*--------------------------------------------------------------------*/ -void mca_handle_nmi( void ) +void mca_handle_nmi(void) { int i; - unsigned char pos5; - - /* First try - scan the various adapters and see if a specific - * adapter was responsible for the error - */ - - for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) { - - /* bit 7 of POS 5 is reset when this adapter has a hardware - * error. bit 7 it reset if there's error information - * available in pos 6 and 7. */ - - pos5 = mca_read_pos( i, 5 ); - - if( !(pos5 & 0x80) ) { - mca_handle_nmi_slot( i, !(pos5 & 0x40) ); - return; - } - } - - /* if I recall correctly, there's a whole bunch of other things that - * we can do to check for NMI problems, but that's all I know about + unsigned char pos5; + + /* First try - scan the various adapters and see if a specific + * adapter was responsible for the error. + */ + + for(i = 0; i < MCA_NUMADAPTERS; i++) { + + /* Bit 7 of POS 5 is reset when this adapter has a hardware + * error. Bit 7 it reset if there's error information + * available in POS 6 and 7. + */ + + pos5 = mca_read_pos(i, 5); + + if(!(pos5 & 0x80)) { + mca_handle_nmi_slot(i, !(pos5 & 0x40)); + return; + } + } + + /* If I recall correctly, there's a whole bunch of other things that + * we can do to check for NMI problems, but that's all I know about * at the moment. - */ + */ - printk( "NMI generated from unknown source!\n" ); -} /* mca_handle_nmi */ + printk("NMI generated from unknown source!\n"); +} /* mca_handle_nmi */ /*--------------------------------------------------------------------*/ -int mca_find_adapter( int id, int start ) +int mca_find_adapter(int id, int start) { - if( mca_info == 0 || id == 0 || id == 0xffff ) { + if(mca_info == 0 || id == 0 || id == 0xffff) { return MCA_NOTFOUND; } - for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) { + for(; start >= 0 && start < MCA_NUMADAPTERS; start++) { - /* not sure about this. There's no point in returning + /* Not sure about this. There's no point in returning * adapters that aren't enabled, since they can't actually - * be used. However, they might be needed for statistical + * be used. However, they might be needed for statistical * purposes or something... But if that is the case, the * user is free to write a routine that manually iterates * through the adapters. */ - if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED ) { + if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) { continue; } - if( id == mca_info->slot[start].id ) { + if(id == mca_info->slot[start].id) { return start; } } @@ -404,28 +410,28 @@ /*--------------------------------------------------------------------*/ -int mca_find_unused_adapter( int id, int start ) +int mca_find_unused_adapter(int id, int start) { - if( mca_info == 0 || id == 0 || id == 0xffff ) { + if(mca_info == 0 || id == 0 || id == 0xffff) { return MCA_NOTFOUND; } - for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) { + for(; start >= 0 && start < MCA_NUMADAPTERS; start++) { - /* not sure about this. There's no point in returning + /* not sure about this. There's no point in returning * adapters that aren't enabled, since they can't actually - * be used. However, they might be needed for statistical + * be used. However, they might be needed for statistical * purposes or something... But if that is the case, the * user is free to write a routine that manually iterates * through the adapters. */ - if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED || - mca_info->slot[start].driver_loaded ) { + if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED || + mca_info->slot[start].driver_loaded) { continue; } - if( id == mca_info->slot[start].id ) { + if(id == mca_info->slot[start].id) { return start; } } @@ -435,68 +441,68 @@ /*--------------------------------------------------------------------*/ -unsigned char mca_read_stored_pos( int slot, int reg ) +unsigned char mca_read_stored_pos(int slot, int reg) { - if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0; - if( reg < 0 || reg >= 8 ) return 0; + if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0) return 0; + if(reg < 0 || reg >= 8) return 0; return mca_info->slot[slot].pos[reg]; } /* mca_read_stored_pos() */ /*--------------------------------------------------------------------*/ -unsigned char mca_read_pos( int slot, int reg ) +unsigned char mca_read_pos(int slot, int reg) { unsigned int byte = 0; unsigned long flags; - if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0; - if( reg < 0 || reg >= 8 ) return 0; + if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0) return 0; + if(reg < 0 || reg >= 8) return 0; - save_flags( flags ); + save_flags(flags); cli(); - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read in the appropriate register */ + /* Read in the appropriate register */ - if( slot == MCA_INTEGSCSI && mca_info->which_scsi ) { + if(slot == MCA_INTEGSCSI && mca_info->which_scsi) { - /* disable adapter setup, enable motherboard setup */ + /* Disable adapter setup, enable motherboard setup */ outb_p(0, MCA_ADAPTER_SETUP_REG); outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - } else if( slot == MCA_INTEGVIDEO ) { + } else if(slot == MCA_INTEGVIDEO) { - /* disable adapter setup, enable motherboard setup */ + /* Disable adapter setup, enable motherboard setup */ outb_p(0, MCA_ADAPTER_SETUP_REG); outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - } else if( slot < MCA_MAX_SLOT_NR ) { + } else if(slot < MCA_MAX_SLOT_NR) { - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read the appropriate register */ + /* Read the appropriate register */ outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); } - /* make sure the stored values are consistent, while we're here */ + /* Make sure the stored values are consistent, while we're here */ mca_info->slot[slot].pos[reg] = byte; - restore_flags( flags ); + restore_flags(flags); return byte; } /* mca_read_pos() */ @@ -513,44 +519,47 @@ * screws up. */ -void mca_write_pos( int slot, int reg, unsigned char byte ) +void mca_write_pos(int slot, int reg, unsigned char byte) { unsigned long flags; - if( slot < 0 || slot >= MCA_MAX_SLOT_NR ) return; - if( reg < 0 || reg >= 8 ) return; - if (mca_info == 0 ) return; + if(slot < 0 || slot >= MCA_MAX_SLOT_NR) + return; + if(reg < 0 || reg >= 8) + return; + if(mca_info == 0) + return; - save_flags( flags ); + save_flags(flags); cli(); - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read in the appropriate register */ + /* Read in the appropriate register */ outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG); - outb_p( byte, MCA_POS_REG(reg) ); + outb_p(byte, MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); - restore_flags( flags ); + restore_flags(flags); - /* update the global register list, while we have the byte */ + /* Update the global register list, while we have the byte */ mca_info->slot[slot].pos[reg] = byte; } /* mca_write_pos() */ /*--------------------------------------------------------------------*/ -void mca_set_adapter_name( int slot, char* name ) +void mca_set_adapter_name(int slot, char* name) { - if( mca_info == 0 ) return; + if(mca_info == 0) return; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { - if( name != NULL ) { - strncpy( mca_info->slot[slot].name, name, - sizeof(mca_info->slot[slot].name)-1 ); + if(slot >= 0 && slot < MCA_NUMADAPTERS) { + if(name != NULL) { + strncpy(mca_info->slot[slot].name, name, + sizeof(mca_info->slot[slot].name)-1); mca_info->slot[slot].name[ sizeof(mca_info->slot[slot].name)-1] = 0; } else { @@ -559,61 +568,61 @@ } } -void mca_set_adapter_procfn( int slot, MCA_ProcFn procfn, void* dev) +void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev) { - if( mca_info == 0 ) return; + if(mca_info == 0) return; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { mca_info->slot[slot].procfn = procfn; mca_info->slot[slot].dev = dev; } } -int mca_is_adapter_used( int slot ) +int mca_is_adapter_used(int slot) { return mca_info->slot[slot].driver_loaded; } -int mca_mark_as_used( int slot ) +int mca_mark_as_used(int slot) { if(mca_info->slot[slot].driver_loaded) return 1; mca_info->slot[slot].driver_loaded = 1; return 0; } -void mca_mark_as_unused( int slot ) +void mca_mark_as_unused(int slot) { mca_info->slot[slot].driver_loaded = 0; } -char *mca_get_adapter_name( int slot ) +char *mca_get_adapter_name(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == 0) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { return mca_info->slot[slot].name; } return 0; } -int mca_isadapter( int slot ) +int mca_isadapter(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == 0) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { - return (( mca_info->slot[slot].status == MCA_ADAPTER_NORMAL ) - || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED ) ); + if(slot >= 0 && slot < MCA_NUMADAPTERS) { + return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL) + || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED)); } return 0; } -int mca_isenabled( int slot ) +int mca_isenabled(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == 0) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL); } @@ -624,39 +633,37 @@ #ifdef CONFIG_PROC_FS -int get_mca_info(char *buf) +int get_mca_info(char *buf) { - int i, j, len = 0; + int i, j, len = 0; - if( MCA_bus && mca_info != 0 ) + if(MCA_bus && mca_info != 0) { - /* Format pos registers of eight MCA slots */ + /* Format POS registers of eight MCA slots */ - for (i=0; islot[i].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[i].name ); - } + len += sprintf(buf+len, " %s\n", mca_info->slot[i].name); + } - /* Format pos registers of integrated video subsystem */ + /* Format POS registers of integrated video subsystem */ len += sprintf(buf+len, "Video : "); - for (j=0; j<8; j++) + for(j=0; j<8; j++) len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name ); + len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name); - /* Format pos registers of integrated SCSI subsystem */ + /* Format POS registers of integrated SCSI subsystem */ len += sprintf(buf+len, "SCSI : "); - for (j=0; j<8; j++) + for(j=0; j<8; j++) len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name ); - } - else - { - /* Leave it empty if MCA not detected - this should *never* + len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name); + } else { + /* Leave it empty if MCA not detected - this should *never* * happen! */ } @@ -667,119 +674,119 @@ /*--------------------------------------------------------------------*/ -__initfunc(void mca_do_proc_init( void )) +__initfunc(void mca_do_proc_init(void)) { int i = 0; struct proc_dir_entry* node = 0; - if( mca_info == 0 ) return; /* should never happen */ + if(mca_info == 0) return; /* Should never happen */ - proc_register( &proc_mca, &(struct proc_dir_entry) { + proc_register(&proc_mca, &(struct proc_dir_entry) { PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO, - 1, 0, 0, 0, &proc_mca_inode_operations,} ); + 1, 0, 0, 0, &proc_mca_inode_operations,}); - proc_register( &proc_mca, &(struct proc_dir_entry) { + proc_register(&proc_mca, &(struct proc_dir_entry) { PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO, - 1, 0, 0, 0, &proc_mca_inode_operations,} ); + 1, 0, 0, 0, &proc_mca_inode_operations,}); - /* initialize /proc/mca entries for existing adapters */ + /* Initialize /proc/mca entries for existing adapters */ - for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) { + for(i = 0; i < MCA_NUMADAPTERS; i++) { mca_info->slot[i].procfn = 0; mca_info->slot[i].dev = 0; - if( ! mca_isadapter( i ) ) continue; + if(!mca_isadapter(i)) continue; node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); - if( i < MCA_MAX_SLOT_NR ) { + if(i < MCA_MAX_SLOT_NR) { node->low_ino = PROC_MCA_SLOT + i; - node->namelen = sprintf( mca_info->slot[i].procname, - "slot%d", i+1 ); - } else if( i == MCA_INTEGVIDEO ) { + node->namelen = sprintf(mca_info->slot[i].procname, + "slot%d", i+1); + } else if(i == MCA_INTEGVIDEO) { node->low_ino = PROC_MCA_VIDEO; - node->namelen = sprintf( mca_info->slot[i].procname, - "video" ); - } else if( i == MCA_INTEGSCSI ) { + node->namelen = sprintf(mca_info->slot[i].procname, + "video"); + } else if(i == MCA_INTEGSCSI) { node->low_ino = PROC_MCA_SCSI; - node->namelen = sprintf( mca_info->slot[i].procname, - "scsi" ); + node->namelen = sprintf(mca_info->slot[i].procname, + "scsi"); } node->name = mca_info->slot[i].procname; node->mode = S_IFREG | S_IRUGO; node->ops = &proc_mca_inode_operations; - proc_register( &proc_mca, node ); + proc_register(&proc_mca, node); } } /* mca_do_proc_init() */ /*--------------------------------------------------------------------*/ -int mca_default_procfn( char* buf, int slot ) +int mca_default_procfn(char* buf, int slot) { int len = 0, i; - /* this really shouldn't happen... */ + /* This really shouldn't happen... */ - if( mca_info == 0 ) { + if(mca_info == 0) { *buf = 0; return 0; } - /* print out the basic information */ + /* Print out the basic information */ - if( slot < MCA_MAX_SLOT_NR ) { - len += sprintf( buf+len, "Slot: %d\n", slot+1 ); - } else if( slot == MCA_INTEGSCSI ) { - len += sprintf( buf+len, "Integrated SCSI Adapter\n" ); - } else if( slot == MCA_INTEGVIDEO ) { - len += sprintf( buf+len, "Integrated Video Adapter\n" ); + if(slot < MCA_MAX_SLOT_NR) { + len += sprintf(buf+len, "Slot: %d\n", slot+1); + } else if(slot == MCA_INTEGSCSI) { + len += sprintf(buf+len, "Integrated SCSI Adapter\n"); + } else if(slot == MCA_INTEGVIDEO) { + len += sprintf(buf+len, "Integrated Video Adapter\n"); } - if( mca_info->slot[slot].name[0] ) { + if(mca_info->slot[slot].name[0]) { - /* drivers might register a name without /proc handler... */ + /* Drivers might register a name without /proc handler... */ - len += sprintf( buf+len, "Adapter Name: %s\n", - mca_info->slot[slot].name ); + len += sprintf(buf+len, "Adapter Name: %s\n", + mca_info->slot[slot].name); } else { - len += sprintf( buf+len, "Adapter Name: Unknown\n" ); + len += sprintf(buf+len, "Adapter Name: Unknown\n"); } - len += sprintf( buf+len, "Id: %02x%02x\n", - mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0] ); - len += sprintf( buf+len, "Enabled: %s\nPOS: ", - mca_isenabled(slot) ? "Yes" : "No" ); - len += sprintf( buf+len, "Driver Installed: %s\n", - mca_is_adapter_used(slot) ? "Yes" : "No" ); - for (i=0; i<8; i++) { + len += sprintf(buf+len, "Id: %02x%02x\n", + mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0]); + len += sprintf(buf+len, "Enabled: %s\nPOS: ", + mca_isenabled(slot) ? "Yes" : "No"); + for(i=0; i<8; i++) { len += sprintf(buf+len, "%02x ", mca_info->slot[slot].pos[i]); } + len += sprintf(buf+len, "\nDriver Installed: %s", + mca_is_adapter_used(slot) ? "Yes" : "No"); buf[len++] = '\n'; buf[len] = 0; return len; } /* mca_default_procfn() */ -static int get_mca_machine_info( char* buf ) +static int get_mca_machine_info(char* buf) { int len = 0; - len += sprintf( buf+len, "Model Id: 0x%x\n", machine_id ); - len += sprintf( buf+len, "Submodel Id: 0x%x\n", machine_submodel_id ); - len += sprintf( buf+len, "BIOS Revision: 0x%x\n", BIOS_revision ); + len += sprintf(buf+len, "Model Id: 0x%x\n", machine_id); + len += sprintf(buf+len, "Submodel Id: 0x%x\n", machine_submodel_id); + len += sprintf(buf+len, "BIOS Revision: 0x%x\n", BIOS_revision); return len; } -static int mca_fill( char* page, int pid, int type, char** start, +static int mca_fill(char* page, int pid, int type, char** start, loff_t *offset, int length) { int len = 0; int slot = 0; - switch( type ) { + switch(type) { case PROC_MCA_REGISTERS: - return get_mca_info( page ); + return get_mca_info(page); case PROC_MCA_MACHINE: - return get_mca_machine_info( page ); + return get_mca_machine_info(page); case PROC_MCA_VIDEO: slot = MCA_INTEGVIDEO; break; @@ -787,24 +794,24 @@ slot = MCA_INTEGSCSI; break; default: - if( type < PROC_MCA_SLOT || type >= PROC_MCA_LAST ) { + if(type < PROC_MCA_SLOT || type >= PROC_MCA_LAST) { return -EBADF; } slot = type - PROC_MCA_SLOT; break; } - /* if we made it here, we better have a valid slot */ + /* If we made it here, we better have a valid slot */ - /* get the standard info */ + /* Get the standard info */ - len = mca_default_procfn( page, slot ); + len = mca_default_procfn(page, slot); - /* do any device-specific processing, if there is any */ + /* Do any device-specific processing, if there is any */ - if( mca_info->slot[slot].procfn ) { - len += mca_info->slot[slot].procfn( page+len, slot, - mca_info->slot[slot].dev ); + if(mca_info->slot[slot].procfn) { + len += mca_info->slot[slot].procfn(page+len, slot, + mca_info->slot[slot].dev); } return len; @@ -814,7 +821,7 @@ #define PROC_BLOCK_SIZE (3*1024) -static ssize_t proc_mca_read( struct file* file, +static ssize_t proc_mca_read(struct file* file, char* buf, size_t count, loff_t *ppos) { unsigned long page; @@ -825,11 +832,11 @@ struct proc_dir_entry *dp; struct inode *inode = file->f_dentry->d_inode; - if (count < 0) + if(count < 0) return -EINVAL; - if (count > PROC_BLOCK_SIZE) + if(count > PROC_BLOCK_SIZE) count = PROC_BLOCK_SIZE; - if (!(page = __get_free_page(GFP_KERNEL))) + if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; type = inode->i_ino; pid = type >> 16; @@ -837,12 +844,12 @@ start = 0; dp = (struct proc_dir_entry *) inode->u.generic_ip; length = mca_fill((char *) page, pid, type, - &start, ppos, count); - if (length < 0) { + &start, ppos, count); + if(length < 0) { free_page(page); return length; } - if (start != 0) { + if(start != 0) { /* We have had block-adjusting processing! */ copy_to_user(buf, start, length); @@ -851,11 +858,11 @@ } else { /* Static 4kB (or whatever) block capacity */ - if (*ppos >= length) { + if(*ppos >= length) { free_page(page); return 0; } - if (count + *ppos > length) + if(count + *ppos > length) count = length - *ppos; end = count + *ppos; copy_to_user(buf, (char *) page + *ppos, count); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.ac/arch/i386/kernel/mtrr.c --- linux.vanilla/arch/i386/kernel/mtrr.c Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/i386/kernel/mtrr.c Thu Mar 11 12:27:24 1999 @@ -132,6 +132,11 @@ Fixed harmless compiler warning in include/asm-i386/mtrr.h Fixed version numbering and history for v1.23 -> v1.24. v1.26 + + v1.26ac Alan Cox + Added some K6-II/III support. This needs back merging with + Richard's current code before it goes to Linus really. + */ #include #include @@ -163,6 +168,7 @@ #include #include #include +#include #include #include "irq.h" @@ -197,7 +203,7 @@ # define MTRR_CHANGE_MASK_DEFTYPE 0x04 #endif -/* In the processor's MTRR interface, the MTRR type is always held in +/* In the intel processor's MTRR interface, the MTRR type is always held in an 8 bit field: */ typedef u8 mtrr_type; @@ -225,6 +231,7 @@ #ifdef CONFIG_PROC_FS static void compute_ascii (void); #endif +static int k6_has_ranges(void); struct set_mtrr_context @@ -236,28 +243,13 @@ }; /* - * Access to machine-specific registers (available on 586 and better only) - * Note: the rd* operations modify the parameters directly (without using - * pointer indirection), this allows gcc to optimize better + * No point continually digging through complex CPU conditionals.. */ -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdpmc(counter,low,high) \ - __asm__ __volatile__("rdpmc" \ - : "=a" (low), "=d" (high) \ - : "c" (counter)) + +static int mtrr_flags; +#define MTRR_PRESENT 1 +#define MTRR_WRCOMB 2 /* Put the processor into a state where MTRRs can be safely set. */ static void set_mtrr_prepare(struct set_mtrr_context *ctxt) @@ -267,13 +259,15 @@ /* disable interrupts locally */ __save_flags (ctxt->flags); __cli (); + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return; + /* save value of CR4 and clear Page Global Enable (bit 7) */ asm volatile ("movl %%cr4, %0\n\t" "movl %0, %1\n\t" "andb $0x7f, %b1\n\t" "movl %1, %%cr4\n\t" : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory"); - /* disable and flush caches. Note that wbinvd flushes the TLBs as a side-effect. */ asm volatile ("movl %%cr0, %0\n\t" @@ -294,6 +288,9 @@ { unsigned long tmp; + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return; + /* flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); @@ -319,6 +316,9 @@ static unsigned int get_num_var_ranges (void) { unsigned long config, dummy; + + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return 2; rdmsr(MTRRcap_MSR, config, dummy); return (config & 0xff); @@ -340,6 +340,46 @@ { unsigned long dummy, mask_lo, base_lo; + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + { + unsigned long low, high; + rdmsr(0xC0000085, low, high); + /* Upper dword is region 1, lower is region 0 */ + if(reg==1) + low=high; + /* The base masks off on the right alignment */ + *base=low&0xFFFE0000; + *type=0; + if(low&1) + *type=MTRR_TYPE_UNCACHABLE; + if(low&2) + *type=MTRR_TYPE_WRCOMB; + if(!(low&3)) + { + *size=0; + return; + } + + /* + * This needs a little explaining. The size is stored as an + * inverted mask of bits of 128K granularity 15 bits long offset + * 2 bits + * + * So to get a size we do invert the mask and add 1 to the lowest + * mask bit (4 as its 2 bits in). This gives us a size we then shift + * to turn into 128K blocks + * + * eg 111 1111 1111 1100 is 512K + * + * invert 000 0000 0000 0011 + * +1 000 0000 0000 0100 + * *128K ... + */ + + low=(~low)&0x1FFFC; + *size = (low+4)<<15; + return; + } rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy); if ((mask_lo & 0x800) == 0) { /* Invalid (i.e. free) range. */ @@ -381,16 +421,56 @@ struct set_mtrr_context ctxt; if (do_safe) set_mtrr_prepare (&ctxt); - if (size == 0) + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRRphysMask_MSR (reg), 0, 0); + if (size == 0) + { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); + } + else + { + wrmsr (MTRRphysBase_MSR (reg), base | type, 0); + wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0); + } } - else + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { - wrmsr (MTRRphysBase_MSR (reg), base | type, 0); - wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0); + u32 low, high; + unsigned long flags; + /* + * Low is MTRR0 , High MTRR 1 + */ + rdmsr(0xC0000085, low, high); + /* + * Blank to disable + */ + if(size==0) + *(reg?&high:&low)=0; + else + /* Set the register to the base (already shifted for us), the + type (off by one) and an inverted bitmask of the size + + The size is the only odd bit. We are fed say 512K + We invert this and we get 111 1111 1111 1011 but + if you subtract one and invert you get the desired + 111 1111 1111 1100 mask + */ + + *(reg?&high:&low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); + + /* + * The writeback rule is quite specific. See the manual. Its + * disable local interrupts, write back the cache, set the mtrr + */ + + save_flags(flags); + __cli(); + __asm__ __volatile__("wbinvd" : : : "memory"); + wrmsr(0xC0000085, low, high); + restore_flags(flags); } if (do_safe) set_mtrr_done (&ctxt); } /* End Function set_mtrr_up */ @@ -518,11 +598,17 @@ for (i = 0; i < nvrs; i++) get_mtrr_var_range(i, &vrs[i]); - get_fixed_ranges(state->fixed_ranges); + if(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + { + get_fixed_ranges(state->fixed_ranges); - rdmsr(MTRRdefType_MSR, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; + rdmsr(MTRRdefType_MSR, lo, dummy); + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; + return; + } + state->def_type = 0; + state->enabled = 1; } /* End Function get_mtrr_state */ @@ -545,6 +631,9 @@ unsigned int i; unsigned long change_mask = 0; + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return 0UL; + for (i = 0; i < state->num_var_ranges; i++) if (set_mtrr_var_range_testing(i, &state->var_ranges[i])) change_mask |= MTRR_CHANGE_MASK_VARIABLE; @@ -737,40 +826,58 @@ mtrr_type ltype; unsigned long lbase, lsize, last; - if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; - if ( (base & 0xfff) || (size & 0xfff) ) - { - printk ("mtrr: size and base must be multiples of 4kB\n"); - printk ("mtrr: size: %lx base: %lx\n", size, base); - return -EINVAL; + if (!(mtrr_flags&MTRR_PRESENT)) + return -ENODEV; + + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + { + /* Apply the K6 block alignment and size rules + In order + o Uncached or gathering only + o 128K or bigger block + o Power of 2 block + o base suitably aligned to the power + */ + if(type > 1 || size < (1<<17) || (size & ~(size-1))-size || (base&(size-1))) + return -EINVAL; } - if (base + size < 0x100000) + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { - printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n", - base, size); - return -EINVAL; - } - /* Check upper bits of base and last are equal and lower bits are 0 for - base and 1 for last */ - last = base + size - 1; - for (lbase = base; !(lbase & 1) && (last & 1); - lbase = lbase >> 1, last = last >> 1); - if (lbase != last) - { - printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", - base, size); - return -EINVAL; - } - if (type >= MTRR_NUM_TYPES) - { - printk ("mtrr: type: %u illegal\n", type); - return -EINVAL; - } - /* If the type is WC, check that this processor supports it */ - if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () ) - { - printk ("mtrr: your processor doesn't support write-combining\n"); - return -ENOSYS; + if ( (base & 0xfff) || (size & 0xfff) ) + { + printk ("mtrr: size and base must be multiples of 4kB\n"); + printk ("mtrr: size: %lx base: %lx\n", size, base); + return -EINVAL; + } + if (base + size < 0x100000) + { + printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n", + base, size); + return -EINVAL; + } + /* Check upper bits of base and last are equal and lower bits are 0 for + base and 1 for last */ + last = base + size - 1; + for (lbase = base; !(lbase & 1) && (last & 1); + lbase = lbase >> 1, last = last >> 1); + if (lbase != last) + { + printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", + base, size); + return -EINVAL; + } + if (type >= MTRR_NUM_TYPES) + { + printk ("mtrr: type: %u illegal\n", type); + return -EINVAL; + } + /* If the type is WC, check that this processor supports it */ + if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () ) + { + printk ("mtrr: your processor doesn't support write-combining\n"); + return -EINVAL; + } } increment = increment ? 1 : 0; max = get_num_var_ranges (); @@ -834,7 +941,7 @@ mtrr_type ltype; unsigned long lbase, lsize; - if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; + if ( !(mtrr_flags&MTRR_PRESENT) ) return -ENODEV; max = get_num_var_ranges (); spin_lock (&main_lock); if (reg < 0) @@ -1153,10 +1260,15 @@ __initfunc(void mtrr_init_boot_cpu (void)) { - if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); - - get_mtrr_state (&smp_mtrr_state); + if (boot_cpu_data.x86_capability & X86_FEATURE_MTRR) + { + get_mtrr_state (&smp_mtrr_state); + } + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && k6_has_ranges()) + { + get_mtrr_state (&smp_mtrr_state); + } } /* End Function mtrr_init_boot_cpu */ __initfunc(void mtrr_init_secondary_cpu (void)) @@ -1181,9 +1293,35 @@ #endif /* __SMP__ */ +/* + * The extended memory handling is available on the K6-III and the + * K6-II stepping 8 and higher only. + */ + +static int k6_has_ranges(void) +{ + if(boot_cpu_data.x86 !=5) + return 0; + if(boot_cpu_data.x86_model == 9 || + (boot_cpu_data.x86_model == 8 && + boot_cpu_data.x86_mask >= 8)) + return 1; + return 0; +} + __initfunc(int mtrr_init(void)) { - if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; + if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD && k6_has_ranges()) + { +# ifdef CONFIG_PROC_FS + proc_register (&proc_root, &proc_root_mtrr); +# endif + mtrr_flags|=MTRR_PRESENT|MTRR_WRCOMB; + init_table(); + return 0; + } + if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) + return 0; # ifndef __SMP__ printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); # endif @@ -1197,6 +1335,7 @@ proc_register (&proc_root, &proc_root_mtrr); # endif + mtrr_flags|=MTRR_PRESENT; init_table (); return 0; } /* End Function mtrr_init */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/setup.c linux.ac/arch/i386/kernel/setup.c --- linux.vanilla/arch/i386/kernel/setup.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/i386/kernel/setup.c Wed Mar 24 11:00:45 1999 @@ -39,6 +39,7 @@ #include #include #include +#include /* * Machine setup.. @@ -380,16 +381,6 @@ */ } - -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) __initfunc(static int get_model_name(struct cpuinfo_x86 *c)) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/smp.c linux.ac/arch/i386/kernel/smp.c --- linux.vanilla/arch/i386/kernel/smp.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/i386/kernel/smp.c Sat Mar 20 23:18:43 1999 @@ -39,6 +39,7 @@ #include #include #include +#include #include "irq.h" @@ -146,16 +147,7 @@ */ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 -/* - * Reads and clears the Pentium Timestamp-Counter - */ -#define READ_TSC(x) __asm__ __volatile__ ( "rdtsc" \ - :"=a" (((unsigned long*)&(x))[0]), \ - "=d" (((unsigned long*)&(x))[1])) - -#define CLEAR_TSC \ - __asm__ __volatile__ ("\t.byte 0x0f, 0x30;\n"::\ - "a"(0x00001000), "d"(0x00001000), "c"(0x10):"memory") +#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000) /* * Setup routine for controlling SMP activation @@ -1948,7 +1940,7 @@ /* * We wrapped around just now. Let's start: */ - READ_TSC(t1); + rdtscll(t1); tt1=apic_read(APIC_TMCCT); #define LOOPS (HZ/10) @@ -1959,7 +1951,7 @@ wait_8254_wraparound (); tt2=apic_read(APIC_TMCCT); - READ_TSC(t2); + rdtscll(t2); /* * The APIC bus clock counter is 32 bits only, it diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/time.c linux.ac/arch/i386/kernel/time.c --- linux.vanilla/arch/i386/kernel/time.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/i386/kernel/time.c Sat Mar 20 22:50:58 1999 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -83,8 +84,8 @@ register unsigned long edx asm("dx"); /* Read the Time Stamp Counter */ - __asm__("rdtsc" - :"=a" (eax), "=d" (edx)); + + rdtsc(eax,edx); /* .. relative to previous jiffy (32 bits is enough) */ eax -= last_tsc_low; /* tsc_low delta */ @@ -443,7 +444,8 @@ */ /* read Pentium cycle counter */ - __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx"); + + rdtscl(last_tsc_low); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -566,12 +568,12 @@ unsigned long endlow, endhigh; unsigned long count; - __asm__ __volatile__("rdtsc":"=a" (startlow),"=d" (starthigh)); + rdtsc(startlow,starthigh); count = 0; do { count++; } while ((inb(0x61) & 0x20) == 0); - __asm__ __volatile__("rdtsc":"=a" (endlow),"=d" (endhigh)); + rdtsc(endlow,endhigh); last_tsc_low = endlow; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/kernel/process.c linux.ac/arch/m68k/kernel/process.c --- linux.vanilla/arch/m68k/kernel/process.c Sun Jan 24 19:55:31 1999 +++ linux.ac/arch/m68k/kernel/process.c Sun Jan 24 20:22:53 1999 @@ -40,7 +40,6 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/init_task.c linux.ac/arch/mips/kernel/init_task.c --- linux.vanilla/arch/mips/kernel/init_task.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/init_task.c Fri Dec 4 17:14:23 1998 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixioctl.c linux.ac/arch/mips/kernel/irixioctl.c --- linux.vanilla/arch/mips/kernel/irixioctl.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/irixioctl.c Fri Dec 4 17:14:23 1998 @@ -33,7 +33,7 @@ { struct file *filp; - if(fd >= NR_OPEN || !(filp = current->files->fd[fd])) + if(fd >= current->files->max_fds || !(filp = current->files->fd[fd])) return ((struct tty_struct *) 0); if(filp->private_data) { struct tty_struct *ttyp = (struct tty_struct *) filp->private_data; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/sysirix.c linux.ac/arch/mips/kernel/sysirix.c --- linux.vanilla/arch/mips/kernel/sysirix.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/mips/kernel/sysirix.c Sat Mar 20 22:51:07 1999 @@ -787,7 +787,8 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) { error = -EBADF; goto out; } @@ -1110,7 +1111,8 @@ lock_kernel(); if(!(flags & MAP_ANONYMOUS)) { - if(fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if(fd >= current->files->max_fds || + !(file = current->files->fd[fd])) { retval = -EBADF; goto out; } @@ -1582,7 +1584,8 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) { error = -EBADF; goto out; } @@ -1726,7 +1729,8 @@ } if(!(flags & MAP_ANONYMOUS)) { - if(fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if(fd >= current->files->max_fds || + !(file = current->files->fd[fd])) { error = -EBADF; goto out; } @@ -1878,7 +1882,8 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) { error = -EBADF; goto out; } @@ -2039,7 +2044,8 @@ current->pid, fd, dirent, count, eob); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) goto out; dentry = file->f_dentry; @@ -2150,7 +2156,8 @@ current->pid, fd, dirent, cnt); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) goto out; dentry = file->f_dentry; @@ -2211,7 +2218,8 @@ current->pid, fd, dirent, cnt); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) goto out; dentry = file->f_dentry; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/syscalls.c linux.ac/arch/ppc/kernel/syscalls.c --- linux.vanilla/arch/ppc/kernel/syscalls.c Sun Nov 8 15:08:33 1998 +++ linux.ac/arch/ppc/kernel/syscalls.c Fri Dec 4 17:14:34 1998 @@ -205,7 +205,8 @@ lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) goto out; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/init_task.c linux.ac/arch/sparc/kernel/init_task.c --- linux.vanilla/arch/sparc/kernel/init_task.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/sparc/kernel/init_task.c Fri Dec 4 17:14:35 1998 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/init_task.c linux.ac/arch/sparc64/kernel/init_task.c --- linux.vanilla/arch/sparc64/kernel/init_task.c Sun Nov 8 15:08:40 1998 +++ linux.ac/arch/sparc64/kernel/init_task.c Fri Dec 4 17:14:35 1998 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/Makefile linux.ac/drivers/Makefile --- linux.vanilla/drivers/Makefile Thu Dec 3 13:48:34 1998 +++ linux.ac/drivers/Makefile Thu Dec 3 13:51:06 1998 @@ -101,4 +101,30 @@ MOD_SUB_DIRS += net/hamradio endif +# +# This will only be set if you've installed linux USB. +# +# If CONFIG_USB is set, core USB support is compiled in, but we want +# to allow having stuff as modules. +# +ifeq ($(CONFIG_USB),y) +SUB_DIRS += uusbd +MOD_SUB_DIRS += uusbd +else + ifeq ($(CONFIG_USB),m) + MOD_SUB_DIRS += uusbd + endif +endif +# +# i2o controller support +# +ifeq ($(CONFIG_I2O),y) +SUB_DIRS += i2o +MOD_SUB_DIRS += i2o +else + ifeq ($(CONFIG_I2O),m) + MOD_SUB_DIRS += i2o + endif +endif + include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Config.in linux.ac/drivers/acorn/block/Config.in --- linux.vanilla/drivers/acorn/block/Config.in Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/Config.in Mon Feb 22 23:41:47 1999 @@ -10,9 +10,12 @@ dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE fi -tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM -if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then - bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT +if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM + tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772 + if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT + fi fi endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Makefile linux.ac/drivers/acorn/block/Makefile --- linux.vanilla/drivers/acorn/block/Makefile Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/Makefile Sun Jan 3 21:26:43 1999 @@ -14,13 +14,11 @@ M_OBJS := MOD_LIST_NAME := ACORN_BLOCK_MODULES -ifeq ($(CONFIG_ARCH_ARC),y) - ifeq ($(CONFIG_BLK_DEV_FD),y) - L_OBJS += fd1772.o fd1772dma.o - else - ifeq ($(CONFIG_BLK_DEV_FD),m) - M_OBJS += fd1772_mod.o - endif +ifeq ($(CONFIG_BLK_DEV_FD1772),y) + L_OBJS += fd1772.o fd1772dma.o +else + ifeq ($(CONFIG_BLK_DEV_FD1772),m) + M_OBJS += fd1772_mod.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/fd1772.c linux.ac/drivers/acorn/block/fd1772.c --- linux.vanilla/drivers/acorn/block/fd1772.c Sat Jan 9 21:50:36 1999 +++ linux.ac/drivers/acorn/block/fd1772.c Tue Feb 2 20:08:35 1999 @@ -114,6 +114,8 @@ * I wish I knew why that timer didn't work..... * * 16/11/96 - Fiddled and frigged for 2.0.18 + * + * DAG 30/01/99 - Started frobbing for 2.2.1 */ #include @@ -136,14 +138,14 @@ #include #include #include +#include #include -#include #include #include #define MAJOR_NR FLOPPY_MAJOR #define FLOPPY_DMA 0 -#include "blk.h" +#include /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with * little additional rework in this file). But I'm not yet sure if diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/fd1772dma.S linux.ac/drivers/acorn/block/fd1772dma.S --- linux.vanilla/drivers/acorn/block/fd1772dma.S Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/fd1772dma.S Tue Feb 2 20:15:14 1999 @@ -4,45 +4,45 @@ .text - .global _fdc1772_dataaddr -_fdc1772_fiqdata: + .global fdc1772_dataaddr +fdc1772_fiqdata: @ Number of bytes left to DMA - .global _fdc1772_bytestogo -_fdc1772_bytestogo: + .global fdc1772_bytestogo +fdc1772_bytestogo: .word 0 @ Place to put/get data from in DMA - .global _fdc1772_dataaddr -_fdc1772_dataaddr: + .global fdc1772_dataaddr +fdc1772_dataaddr: .word 0 - .global _fdc1772_fdc_int_done -_fdc1772_fdc_int_done: + .global fdc1772_fdc_int_done +fdc1772_fdc_int_done: .word 0 - .global _fdc1772_comendstatus -_fdc1772_comendstatus: + .global fdc1772_comendstatus +fdc1772_comendstatus: .word 0 @ We hang this off DMA channel 1 - .global _fdc1772_comendhandler -_fdc1772_comendhandler: + .global fdc1772_comendhandler +fdc1772_comendhandler: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#2 subeqs pc,r14,#4 @ should I leave a space here orr r9,r8,#0x10000 @ FDC base - adr r8,_fdc1772_fdc_int_done + adr r8,fdc1772_fdc_int_done ldrb r10,[r9,#0] @ FDC status mov r9,#1 @ Got a FIQ flag stmia r8,{r9,r10} subs pc,r14,#4 - .global _fdc1772_dma_read -_fdc1772_dma_read: + .global fdc1772_dma_read +fdc1772_dma_read: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_read_notours + beq fdc1772_dma_read_notours orr r8,r8,#0x10000 @ FDC base ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt) ldmia r11,{r8,r9} @@ -51,19 +51,19 @@ strplb r10,[r9],#1 @ Store the data and increment the pointer stmplia r11,{r8,r9} @ Update count/pointers @ Handle any other interrupts if there are any -_fdc1772_dma_read_notours: +fdc1772_dma_read_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler - .global _fdc1772_dma_read_end -_fdc1772_dma_read_end: + .word fdc1772_comendhandler + .global fdc1772_dma_read_end +fdc1772_dma_read_end: - .global _fdc1772_dma_write -_fdc1772_dma_write: + .global fdc1772_dma_write +fdc1772_dma_write: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_write_notours + beq fdc1772_dma_write_notours orr r8,r8,#0x10000 @ FDC base ldmia r11,{r9,r10} subs r9,r9,#1 @ One less byte to go @@ -72,23 +72,23 @@ strplb r12,[r8,#0xc] @ write it to FDC data reg stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt @ Handle any other interrupts -_fdc1772_dma_write_notours: +fdc1772_dma_write_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler + .word fdc1772_comendhandler - .global _fdc1772_dma_write_end -_fdc1772_dma_write_end: + .global fdc1772_dma_write_end +fdc1772_dma_write_end: @ Setup the FIQ R11 to point to the data and store the count, address @ for this dma @ R0=count @ R1=address - .global _fdc1772_setupdma -_fdc1772_setupdma: + .global fdc1772_setupdma +fdc1772_setupdma: @ The big job is flipping in and out of FIQ mode - adr r2,_fdc1772_fiqdata @ This is what we really came here for + adr r2,fdc1772_fiqdata @ This is what we really came here for stmia r2,{r0,r1} mov r3, pc teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-ics.c linux.ac/drivers/acorn/block/ide-ics.c --- linux.vanilla/drivers/acorn/block/ide-ics.c Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/block/ide-ics.c Tue Feb 23 08:26:18 1999 @@ -44,7 +44,8 @@ #define ICS_ARCIN_V6_IDESTEPPING 4 static const card_ids icside_cids[] = { - { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, { 0xffff, 0xffff } }; @@ -81,6 +82,8 @@ icside_irqenable_arcin_v5, icside_irqdisable_arcin_v5, NULL, + NULL, + NULL, NULL }; @@ -106,9 +109,22 @@ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } +/* Prototype: icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + + return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + static const expansioncard_ops_t icside_ops_arcin_v6 = { icside_irqenable_arcin_v6, icside_irqdisable_arcin_v6, + icside_irqpending_arcin_v6, + NULL, NULL, NULL }; @@ -202,7 +218,7 @@ case ics_if_arcin_v5: port = ecard_address (ec, ECARD_MEMC, 0); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V5_INTRSTAT); + ec->irqaddr = (unsigned char *)ioaddr(port + ICS_ARCIN_V5_INTRSTAT); ec->irqmask = 1; ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; @@ -220,8 +236,6 @@ case ics_if_arcin_v6: port = ecard_address (ec, ECARD_IOC, ECARD_FAST); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1); - ec->irqmask = 1; ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-rapide.c linux.ac/drivers/acorn/block/ide-rapide.c --- linux.vanilla/drivers/acorn/block/ide-rapide.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/ide-rapide.c Fri Jan 22 15:48:13 1999 @@ -13,7 +13,6 @@ #include #include #include -#include #include "../../block/ide.h" @@ -28,14 +27,20 @@ static inline int rapide_register(struct expansion_card *ec) { unsigned long port = ecard_address (ec, ECARD_MEMC, 0); - ide_ioregspec_t spec; + hw_regs_t hw; - spec.base = port; - spec.ctrl = port + 0x206; - spec.offset = 1 << 4; - spec.irq = ec->irq; + int i; - return ide_register_port(&spec); + memset(&hw, 0, sizeof(hw)); + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw.io_ports[i] = (ide_ioreg_t)port; + port += 1 << 4; + } + hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206; + hw.irq = ec->irq; + + return ide_register_hw(&hw, NULL); } int rapide_init(void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/mfm.S linux.ac/drivers/acorn/block/mfm.S --- linux.vanilla/drivers/acorn/block/mfm.S Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/mfm.S Tue Feb 2 20:14:11 1999 @@ -1,44 +1,43 @@ -@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 -@ motherboard on ST506 podules. -@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996 +@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes +@ motherboard and on ST506 expansion podules. +@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999 #include -_hdc63463_irqdata: +hdc63463_irqdata: @ Controller base address - .global _hdc63463_baseaddress -_hdc63463_baseaddress: + .global hdc63463_baseaddress +hdc63463_baseaddress: .word 0 - .global _hdc63463_irqpolladdress -_hdc63463_irqpolladdress: + .global hdc63463_irqpolladdress +hdc63463_irqpolladdress: .word 0 - .global _hdc63463_irqpollmask -_hdc63463_irqpollmask: + .global hdc63463_irqpollmask +hdc63463_irqpollmask: .word 0 @ where to read/write data from the kernel data space - .global _hdc63463_dataptr -_hdc63463_dataptr: + .global hdc63463_dataptr +hdc63463_dataptr: .word 0 @ Number of bytes left to transfer - .global _hdc63463_dataleft -_hdc63463_dataleft: + .global hdc63463_dataleft +hdc63463_dataleft: .word 0 @ ------------------------------------------------------------------------- @ hdc63463_writedma: DMA from host to controller @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_writedma -_hdc63463_writedma: + .global hdc63463_writedma +hdc63463_writedma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} - writedma_again: @ test number of remaining bytes to transfer @@ -89,12 +88,12 @@ @ If we were too slow we had better go through again - DAG - took out with new interrupt routine @ sub r0,r0,#32+8 - @ adr r2,_hdc63463_irqdata + @ adr r2,hdc63463_irqdata @ ldr r2,[r2,#8] @ b writedma_again writedma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) @@ -103,10 +102,10 @@ @ hdc63463_readdma: DMA from controller to host @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_readdma -_hdc63463_readdma: + .global hdc63463_readdma +hdc63463_readdma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} readdma_again: @@ -157,7 +156,7 @@ @ b readdma_again readdma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/mfmhd.c linux.ac/drivers/acorn/block/mfmhd.c --- linux.vanilla/drivers/acorn/block/mfmhd.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/mfmhd.c Sat Jan 9 16:39:02 1999 @@ -123,6 +123,7 @@ #include #include #include +#include /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/Config.in linux.ac/drivers/acorn/char/Config.in --- linux.vanilla/drivers/acorn/char/Config.in Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/Config.in Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -if [ "$CONFIG_SERIAL" != "n" ]; then - tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL - tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL -fi - -if [ "$CONFIG_MOUSE" = "y" ]; then - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y - else - define_bool CONFIG_RPCMOUSE y - fi - fi -fi - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/Makefile linux.ac/drivers/acorn/char/Makefile --- linux.vanilla/drivers/acorn/char/Makefile Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/Makefile Sun Jan 24 09:50:13 1999 @@ -9,20 +9,21 @@ # parent makes.. # -L_TARGET := acorn-char.a -M_OBJS := -L_OBJS := +L_TARGET := acorn-char.a +M_OBJS := +L_OBJS := -ifeq ($(MACHINE),rpc) - MOUSE_OBJS += mouse_rpc.o - L_OBJS += keyb_ps2.o -endif +L_OBJS_arc := keyb_arc.o +L_OBJS_a5k := keyb_arc.o +L_OBJS_rpc := keyb_ps2.o -ifeq ($(CONFIG_MOUSE),y) - LX_OBJS += $(MOUSE_OBJS) -else - ifeq ($(CONFIG_MOUSE),m) - MX_OBJS += $(MOUSE_OBJS) +ifeq ($(MACHINE),rpc) + ifeq ($(CONFIG_MOUSE),y) + LX_OBJS += mouse_rpc.o + else + ifeq ($(CONFIG_MOUSE),m) + MX_OBJS += mouse_rpc.o + endif endif endif @@ -41,5 +42,7 @@ M_OBJS += serial-dualsp.o endif endif + +L_OBJS += $(L_OBJS_$(MACHINE)) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/keyb_arc.c linux.ac/drivers/acorn/char/keyb_arc.c --- linux.vanilla/drivers/acorn/char/keyb_arc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/char/keyb_arc.c Tue Feb 2 20:37:06 1999 @@ -0,0 +1,458 @@ +/* + * linux/arch/arm/drivers/char1/keyb_arc.c + * + * Acorn keyboard driver for ARM Linux. + * + * The Acorn keyboard appears to have a ***very*** buggy reset protocol - + * every reset behaves differently. We try to get round this by attempting + * a few things... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../char/mouse.h" + +extern void kbd_reset_kdown(void); + +#define VERSION 108 + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#include +#include + +static char kbd_txval[4]; +static unsigned char kbd_txhead, kbd_txtail; +#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3) +static int kbd_id = -1; +static struct wait_queue *kbd_waitq; +#ifdef CONFIG_KBDMOUSE +static int mousedev; +#endif + +/* + * Protocol codes to send the keyboard. + */ +#define HRST 0xff /* reset keyboard */ +#define RAK1 0xfe /* reset response */ +#define RAK2 0xfd /* reset response */ +#define BACK 0x3f /* Ack for first keyboard pair */ +#define SMAK 0x33 /* Last data byte ack (key scanning + mouse movement scanning) */ +#define MACK 0x32 /* Last data byte ack (mouse movement scanning) */ +#define SACK 0x31 /* Last data byte ack (key scanning) */ +#define NACK 0x30 /* Last data byte ack (no scanning, mouse data) */ +#define RQMP 0x22 /* Request mouse data */ +#define PRST 0x21 /* nothing */ +#define RQID 0x20 /* Request ID */ + +#define UP_FLAG 1 + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char a5kkbd_sysrq_xlate[] = +{ + 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + '`', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '-', '=', '£', 127, 0, + 0, 0, 0, '/', '*', '#', 9, 'q', + 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', + 'p', '[', ']', '\\', 22, 23, 25, '7', + '8', '9', '-', 0, 'a', 's', 'd', 'f', + 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, + '4', '5', '6', '+', 0, 0, 'z', 'x', + 'c', 'v', 'b', 'n', 'm', ',', '.', '/', + 0, 0, '1', '2', '3', 0, 0, ' ', + 0, 0, 0, 0, 0, '0', '.', 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; +#endif + +int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p) +{ + *uf_p = scancode & 0200; + *keycode_p = scancode & 0x7f; + return 1; +} + +/* + * This array converts the scancode that we get from the keyboard to the + * real rows/columns on the A5000 keyboard. This might be keyboard specific... + * + * It is these values that we use to maintain the key down array. That way, we + * should pick up on the ghost key presses (which is what happens when you press + * three keys, and the keyboard thinks you have pressed four!) + * + * Row 8 (0x80+c) is actually a column with one key per row. It is isolated from + * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc). + * + * Illegal scancodes are denoted by an 0xff (in other words, we don't know about + * them, and can't process them for ghosts). This does however, cause problems with + * autorepeat processing... + */ +static unsigned char scancode_2_colrow[256] = { + 0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60, + 0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79, + 0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a, + 0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34, + 0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12, + 0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03, + 0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff, +}; + +#define BITS_PER_SHORT (8*sizeof(unsigned short)) +static unsigned short ghost_down[128/BITS_PER_SHORT]; + +static void a5kkbd_key(unsigned int keycode, unsigned int up_flag) +{ + unsigned int real_keycode; + + if (keycode > 0x72) { +#ifdef KBD_REPORT_UNKN + printk ("kbd: unknown scancode 0x%04x\n", keycode); +#endif + return; + } + if (keycode >= 0x70) { +#ifdef CONFIG_KBDMOUSE + if (mousedev >= 0) + switch (keycode) { + case 0x70: /* Left mouse button */ + busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0); + break; + + case 0x71: /* Middle mouse button */ + busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0); + break; + + case 0x72:/* Right mouse button */ + busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0); + break; + } +#endif + return; + } + + /* + * We have to work out if we accept this key press as a real key, or + * if it is a ghost. IE. If you press three keys, the keyboard will think + * that you've pressed a fourth: (@ = key down, # = ghost) + * + * 0 1 2 3 4 5 6 7 + * | | | | | | | | + * 0-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 1-+-@-+-+-+-@-+-+- + * | | | | | | | | + * 2-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 3-+-@-+-+-+-#-+-+- + * | | | | | | | | + * + * This is what happens when you have a matrix keyboard... + */ + + real_keycode = scancode_2_colrow[keycode]; + + if ((real_keycode & 0x80) == 0) { + int rr, kc = (real_keycode >> 4) & 7; + int cc; + unsigned short res, kdownkc; + + kdownkc = ghost_down[kc] | (1 << (real_keycode & 15)); + + for (rr = 0; rr < 128/BITS_PER_SHORT; rr++) + if (rr != kc && (res = ghost_down[rr] & kdownkc)) { + /* + * we have found a second row with at least one key pressed in the + * same column. + */ + for (cc = 0; res; res >>= 1) + cc += (res & 1); + if (cc > 1) + return; /* ignore it */ + } + if (up_flag) + clear_bit (real_keycode, ghost_down); + else + set_bit (real_keycode, ghost_down); + } + + handle_scancode(keycode | (up_flag ? 0200 : 0)); +} + +static inline void a5kkbd_sendbyte(unsigned char val) +{ + kbd_txval[kbd_txhead] = val; + KBD_INCTXPTR(kbd_txhead); + enable_irq(IRQ_KEYBOARDTX); +} + +static inline void a5kkbd_reset(void) +{ + int i; + + for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++) + ghost_down[i] = 0; + + kbd_reset_kdown(); +} + +void a5kkbd_leds(unsigned char leds) +{ + leds = ((leds & (1<= 0) + busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy); +#endif + } + } + return kbd_state == KBD_IDLE ? 1 : 0; + +kbd_wontreset: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n", + kbd_state, keyval); +#endif + mdelay(1); + inb(IOC_KARTRX); + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; + +kbd_error: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard out of sync - resetting\n"); +#endif + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; +} + +static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + kbd_pt_regs = regs; + if (handle_rawcode(inb(IOC_KARTRX))) + mark_bh (KEYBOARD_BH); +} + +static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs) +{ + outb (kbd_txval[kbd_txtail], IOC_KARTTX); + KBD_INCTXPTR(kbd_txtail); + if (kbd_txtail == kbd_txhead) + disable_irq(irq); +} + +#ifdef CONFIG_KBDMOUSE +static struct busmouse a5kkbd_mouse = { + 6, "kbdmouse", NULL, NULL, 7 +}; +#endif + +__initfunc(void a5kkbd_init_hw (void)) +{ + unsigned long flags; + + save_flags_cli (flags); + if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard transmit IRQ!"); + disable_irq (IRQ_KEYBOARDTX); + if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard receive IRQ!"); + (void)inb(IOC_KARTRX); + restore_flags (flags); + + a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */ + + /* wait 1s for keyboard to initialise */ + interruptible_sleep_on_timeout(&kbd_waitq, HZ); + +#ifdef CONFIG_KBDMOUSE + mousedev = register_busmouse(&a5kkbd_mouse); + if (mousedev < 0) + printk(KERN_ERR "Unable to register mouse driver\n"); +#endif + + printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100); + if (kbd_id != -1) + printk ("id=%d ", kbd_id); + printk ("English)\n"); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/keyb_ps2.c linux.ac/drivers/acorn/char/keyb_ps2.c --- linux.vanilla/drivers/acorn/char/keyb_ps2.c Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/keyb_ps2.c Sat Jan 9 16:44:31 1999 @@ -25,6 +25,7 @@ #include #include #include +#include #include extern void kbd_reset_kdown(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/mouse_rpc.c linux.ac/drivers/acorn/char/mouse_rpc.c --- linux.vanilla/drivers/acorn/char/mouse_rpc.c Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/mouse_rpc.c Sat Jan 9 16:44:16 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/char/rpcmouse.c + * linux/drivers/char/mouse_rpc.c * * Copyright (C) 1996-1998 Russell King * @@ -16,6 +16,7 @@ #include #include #include +#include #include "../../char/mouse.h" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/serial-card.c linux.ac/drivers/acorn/char/serial-card.c --- linux.vanilla/drivers/acorn/char/serial-card.c Sun Nov 8 15:08:20 1998 +++ linux.ac/drivers/acorn/char/serial-card.c Fri Jan 29 22:33:39 1999 @@ -33,14 +33,20 @@ #ifdef MODULE static int __serial_ports[NUM_SERIALS]; static int __serial_pcount; +static int __serial_addr[NUM_SERIALS]; static struct expansion_card *expcard[MAX_ECARDS]; #define ADD_ECARD(ec,card) expcard[(card)] = (ec) -#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port) +#define ADD_PORT(port,addr) \ + do { \ + __serial_ports[__serial_pcount] = (port); \ + __serial_addr[__serial_pcount] = (addr); \ + __serial_pcount += 1; \ + } while (0) #undef MY_INIT #define MY_INIT init_module #else #define ADD_ECARD(ec,card) -#define ADD_PORT(port) +#define ADD_PORT(port,addr) #endif static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; @@ -75,12 +81,15 @@ cardaddr = MY_BASE_ADDRESS(ec); for (port = 0; port < MY_NUMPORTS; port ++) { + unsigned long address; int line; - line = serial_register_onedev (MY_PORT_ADDRESS(port, cardaddr), ec->irq); + address = MY_PORT_ADDRESS(port, cardaddr); + + line = serial_register_onedev (address, ec->irq); if (line < 0) break; - ADD_PORT(line); + ADD_PORT(line, address); } if (port) { @@ -97,8 +106,10 @@ { int i; - for (i = 0; i < __serial_pcount; i++) - unregister_serial (__serial_ports[i]); + for (i = 0; i < __serial_pcount; i++) { + unregister_serial(__serial_ports[i]); + release_region(__serial_addr[i], 8); + } for (i = 0; i < MAX_ECARDS; i++) if (expcard[i]) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/ether1.c linux.ac/drivers/acorn/net/ether1.c --- linux.vanilla/drivers/acorn/net/ether1.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/net/ether1.c Tue Feb 23 16:12:39 1999 @@ -71,7 +71,7 @@ #define BUS_16 16 #define BUS_8 8 -static const card_ids ether1_cids[] = { +static const card_ids __init ether1_cids[] = { { MANU_ACORN, PROD_ACORN_ETHER1 }, { 0xffff, 0xffff } }; @@ -128,7 +128,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -171,7 +171,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -659,12 +659,6 @@ /* Fill in the fields of the device structure with ethernet values */ ether_setup (dev); -#ifndef CLAIM_IRQ_AT_OPEN - if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) { - kfree (dev->priv); - return -EAGAIN; - } -#endif return 0; } @@ -759,18 +753,16 @@ ether1_open (struct device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; -#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; -#endif + MOD_INC_USE_COUNT; memset (&priv->stats, 0, sizeof (struct enet_statistics)); if (ether1_init_for_open (dev)) { -#ifdef CLAIM_IRQ_AT_OPEN free_irq (dev->irq, dev); -#endif MOD_DEC_USE_COUNT; return -EAGAIN; } @@ -1080,12 +1072,10 @@ static int ether1_close (struct device *dev) { -#ifdef CLAIM_IRQ_AT_OPEN - free_irq (dev->irq, dev); -#endif - ether1_reset (dev); + free_irq(dev->irq, dev); + dev->start = 0; dev->tbusy = 0; @@ -1117,56 +1107,46 @@ #ifdef MODULE -static char ethernames[MAX_ECARDS][9]; -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int init_module (void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for (i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy (ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether1_cids); i = 0; - ecard_startfind (); + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - do { - if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) + ether_devs[i].ec = ec; + ether_devs[i].dev.irq = ec->irq; + ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST); + ether_devs[i].dev.init = ether1_probe; + ether_devs[i].dev.name = ether_devs[i].name; + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; break; - - my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); - memset (my_ethers[i], 0, sizeof (struct device)); - - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST); - my_ethers[i]->init = ether1_probe; - my_ethers[i]->name = ethernames[i]; - - ecard_claim (ec[i]); - - if (register_netdev (my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if (my_ethers[i]) { - kfree (my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; - } - } - return -EIO; } - i++; - } while (i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + i += 1; + ec = ecard_find(0, ether1_cids); + } + + return i != 0 ? 0 : ret; } void @@ -1175,18 +1155,15 @@ int i; for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - unregister_netdev (my_ethers[i]); - release_region (my_ethers[i]->base_addr, 16); - release_region (my_ethers[i]->base_addr + 0x800, 4096); -#ifndef CLAIM_IRQ_AT_OPEN - free_irq (my_ethers[i]->irq, my_ethers[i]); -#endif - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 16); + release_region(ether_devs[i].dev.base_addr + 0x800, 4096); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/ether3.c linux.ac/drivers/acorn/net/ether3.c --- linux.vanilla/drivers/acorn/net/ether3.c Sun Nov 8 15:08:20 1998 +++ linux.ac/drivers/acorn/net/ether3.c Sun Feb 28 15:23:03 1999 @@ -33,11 +33,13 @@ * packet starts two bytes from the end of the * buffer, it corrupts the receiver chain, and * never updates the transmit status correctly. + * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. + * * TODO: * When we detect a fatal error on the interface, we should restart it. */ -static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n"; +static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.14\n"; #include #include @@ -66,7 +68,7 @@ #include "ether3.h" static unsigned int net_debug = NET_DEBUG; -static const card_ids ether3_cids[] = { +static const card_ids __init ether3_cids[] = { { MANU_ANT2, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */ @@ -77,9 +79,6 @@ static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); static void ether3_tx(struct device *dev, struct dev_priv *priv); -extern int inswb(int reg, void *buffer, int len); -extern int outswb(int reg, void *buffer, int len); - #define BUS_16 2 #define BUS_8 1 #define BUS_UNKNOWN 0 @@ -138,7 +137,7 @@ * write data to the buffer memory */ #define ether3_writebuffer(dev,data,length) \ - outswb(REG_BUFWIN, (data), (length)) + outsw(REG_BUFWIN, (data), (length) >> 1) #define ether3_writeword(dev,data) \ outw((data), REG_BUFWIN) @@ -153,7 +152,7 @@ * read data from the buffer memory */ #define ether3_readbuffer(dev,data,length) \ - inswb(REG_BUFWIN, (data), (length)) + insw(REG_BUFWIN, (data), (length) >> 1) #define ether3_readword(dev) \ inw(REG_BUFWIN) @@ -471,6 +470,25 @@ return error; } +__initfunc(static void +ether3_get_dev(struct device *dev, struct expansion_card *ec)) +{ + ecard_claim(ec); + + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + if (ec->cid.manufacturer == MANU_ANT && + ec->cid.product == PROD_ANT_ETHERB) { + dev->base_addr += 0x200; + } + + ec->irqaddr = ioaddr(dev->base_addr); + ec->irqmask = 0xf0; + + ether3_addr(dev->dev_addr, ec); +} + #ifndef MODULE __initfunc(int ether3_probe(struct device *dev)) @@ -485,12 +503,8 @@ if ((ec = ecard_find(0, ether3_cids)) == NULL) return ENODEV; - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->irq = ec->irq; - - ecard_claim(ec); + ether3_get_dev(dev, ec); - ether3_addr(dev->dev_addr, ec); return ether3_probe1(dev); } #endif @@ -915,76 +929,64 @@ #ifdef MODULE -char ethernames[MAX_ECARDS][9]; - -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int -init_module(void) +init_module (void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for(i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy(ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether3_cids); i = 0; - ecard_startfind(); - - do { - if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) - break; + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL); - memset(my_ethers[i], 0, sizeof(struct device)); + ether_devs[i].ec = ec; + ether_devs[i].dev.init = ether3_probe1; + ether_devs[i].dev.name = ether_devs[i].name; + ether3_get_dev(ðer_devs[i].dev, ec); + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0); - my_ethers[i]->init = ether3_probe1; - my_ethers[i]->name = ethernames[i]; - - ether3_addr(my_ethers[i]->dev_addr, ec[i]); - - ecard_claim(ec[i]); - - if(register_netdev(my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if(my_ethers[i]) { - kfree(my_ethers[i]); - my_ethers[i] = NULL; - } - if(ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; - } - } - return -EIO; + break; } - i++; + + i += 1; + ec = ecard_find(0, ether3_cids); } - while(i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + return i != 0 ? 0 : ret; } void -cleanup_module(void) +cleanup_module (void) { int i; + for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - release_region(my_ethers[i]->base_addr, 128); - unregister_netdev(my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 128); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } #endif /* MODULE */ + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/etherh.c linux.ac/drivers/acorn/net/etherh.c --- linux.vanilla/drivers/acorn/net/etherh.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/net/etherh.c Fri Mar 5 22:20:59 1999 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -50,13 +51,16 @@ #define DEBUG_INIT 2 static unsigned int net_debug = NET_DEBUG; -static const card_ids etherh_cids[] = { +static const card_ids __init etherh_cids[] = { { MANU_I3, PROD_I3_ETHERLAN500 }, { MANU_I3, PROD_I3_ETHERLAN600 }, { MANU_I3, PROD_I3_ETHERLAN600A }, { 0xffff, 0xffff } }; +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("i3 EtherH driver"); + static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ @@ -80,8 +84,8 @@ * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int -etherh_addr(char *addr, struct expansion_card *ec) +__initfunc(static int +etherh_addr(char *addr, struct expansion_card *ec)) { struct in_chunk_dir cd; char *s; @@ -216,10 +220,8 @@ if (ei_status.word16) outsw (dma_addr, buf, count >> 1); -#ifdef BIT8 else outsb (dma_addr, buf, count); -#endif dma_start = jiffies; @@ -268,11 +270,8 @@ insw (dma_addr, buf, count >> 1); if (count & 1) buf[count - 1] = inb (dma_addr); - } -#ifdef BIT8 - else + } else insb (dma_addr, buf, count); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -307,10 +306,8 @@ if (ei_status.word16) insw (dma_addr, hdr, sizeof (*hdr) >> 1); -#ifdef BIT8 else insb (dma_addr, hdr, sizeof (*hdr)); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -355,8 +352,8 @@ /* * This is the real probe routine. */ -static int -etherh_probe1(struct device *dev) +__initfunc(static int +etherh_probe1(struct device *dev)) { static int version_printed; unsigned int addr, i, reg0, tmp; @@ -461,10 +458,13 @@ etherh_irq_enable, etherh_irq_disable, NULL, + NULL, + NULL, NULL }; -static void etherh_initdev (ecard_t *ec, struct device *dev) +__initfunc(static void +etherh_initdev(ecard_t *ec, struct device *dev)) { ecard_claim (ec); @@ -492,17 +492,17 @@ } ec->ops = ðerh_ops; - etherh_addr (dev->dev_addr, ec); + etherh_addr(dev->dev_addr, ec); } #ifndef MODULE -int -etherh_probe(struct device *dev) +__initfunc(int +etherh_probe(struct device *dev)) { if (!dev) return ENODEV; - ecard_startfind (); + ecard_startfind(); if (!dev->base_addr) { struct expansion_card *ec; @@ -510,9 +510,9 @@ if ((ec = ecard_find (0, etherh_cids)) == NULL) return ENODEV; - etherh_initdev (ec, dev); + etherh_initdev(ec, dev); } - return etherh_probe1 (dev); + return etherh_probe1(dev); } #endif @@ -529,12 +529,10 @@ init_all_cards(void) { struct device *dev = NULL; - struct expansion_card *boguscards[MAX_ETHERH_CARDS]; int i, found = 0; for (i = 0; i < MAX_ETHERH_CARDS; i++) { my_ethers[i] = NULL; - boguscards[i] = NULL; ec[i] = NULL; strcpy (ethernames[i], " "); } @@ -571,7 +569,7 @@ if (register_netdev(dev) != 0) { printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); if (ec[i]) { - boguscards[i] = ec[i]; + ecard_release(ec[i]); ec[i] = NULL; } continue; @@ -582,12 +580,6 @@ if (dev) kfree (dev); - - for (i = 0; i < MAX_ETHERH_CARDS; i++) - if (boguscards[i]) { - boguscards[i]->ops = NULL; - ecard_release (boguscards[i]); - } return found ? 0 : -ENODEV; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/Config.in linux.ac/drivers/acorn/scsi/Config.in --- linux.vanilla/drivers/acorn/scsi/Config.in Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/Config.in Fri Mar 5 23:49:23 1999 @@ -7,11 +7,12 @@ bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI - comment 'The following drives are not fully supported' + comment 'The following drivers are not fully supported' dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/Makefile linux.ac/drivers/acorn/scsi/Makefile --- linux.vanilla/drivers/acorn/scsi/Makefile Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/Makefile Fri Mar 5 23:47:21 1999 @@ -24,6 +24,16 @@ endif endif +ifeq ($(CONFIG_SCSI_ARXESCSI),y) + L_OBJS += arxescsi.o + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_ARXESCSI),m) + M_OBJS += arxescsi.o + CONFIG_FAS216_MODULE=y + endif +endif + ifeq ($(CONFIG_SCSI_CUMANA_1),y) L_OBJS += cumana_1.o else @@ -34,12 +44,10 @@ ifeq ($(CONFIG_SCSI_CUMANA_2),y) L_OBJS += cumana_2.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_CUMANA_2),m) M_OBJS += cumana_2.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif @@ -62,41 +70,39 @@ ifeq ($(CONFIG_SCSI_POWERTECSCSI),y) L_OBJS += powertec.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_POWERTECSCSI),m) M_OBJS += powertec.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif ifeq ($(CONFIG_SCSI_EESOXSCSI),y) L_OBJS += eesox.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_EESOXSCSI),m) M_OBJS += eesox.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif -ifeq ($(CONFIG_QUEUE_BUILTIN),y) - LX_OBJS += queue.o msgqueue.o -else - ifeq ($(CONFIG_QUEUE_MODULE),y) - MX_OBJS += queue.o msgqueue.o - endif -endif - ifeq ($(CONFIG_FAS216_BUILTIN),y) LX_OBJS += fas216.o + CONFIG_QUEUE_BUILTIN=y else ifeq ($(CONFIG_FAS216_MODULE),y) MX_OBJS += fas216.o + CONFIG_QUEUE_MODULE=y + endif +endif + +ifeq ($(CONFIG_QUEUE_BUILTIN),y) + LX_OBJS += queue.o msgqueue.o +else + ifeq ($(CONFIG_QUEUE_MODULE),y) + MX_OBJS += queue.o msgqueue.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/acornscsi.c linux.ac/drivers/acorn/scsi/acornscsi.c --- linux.vanilla/drivers/acorn/scsi/acornscsi.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/scsi/acornscsi.c Wed Feb 24 23:49:54 1999 @@ -21,6 +21,8 @@ * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. * 15-Oct-1997 RMK Improved handling of commands. * 27-Jun-1998 RMK Changed asm/delay.h to linux/delay.h. + * 13-Dec-1998 RMK Better abort code and command handling. Extra state + * transitions added to allow dodgy devices to work. */ #define DEBUG_NO_WRITE 1 #define DEBUG_QUEUES 2 @@ -35,7 +37,7 @@ #define DEBUG_RESET 1024 #define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ - DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE) + DEBUG_DMA|DEBUG_QUEUES) /* DRIVER CONFIGURATION * @@ -123,8 +125,8 @@ #ifndef STRINGIFY #define STRINGIFY(x) #x #endif -#define STR(x) STRINGIFY(x) -#define NO_WRITE_STR STR(NO_WRITE) +#define STRx(x) STRINGIFY(x) +#define NO_WRITE_STR STRx(NO_WRITE) #include #include @@ -142,6 +144,7 @@ #include #include #include +#include #include #include "../../scsi/scsi.h" @@ -160,10 +163,6 @@ #error "Yippee! ABORT TAG is now defined! Remove this error!" #endif -#ifndef NO_IRQ -#define NO_IRQ 255 -#endif - #ifdef CONFIG_SCSI_ACORNSCSI_LINK #error SCSI2 LINKed commands not supported (yet)! #endif @@ -186,26 +185,7 @@ #define DMAC_BUFFER_SIZE 65536 #endif -/* - * This is used to dump the previous states of the SBIC - */ -static struct status_entry { - unsigned long when; - unsigned char ssr; - unsigned char ph; - unsigned char irq; - unsigned char unused; -} status[9][16]; -static unsigned char status_ptr[9]; - -#define ADD_STATUS(_q,_ssr,_ph,_irq) \ -({ \ - status[(_q)][status_ptr[(_q)]].when = jiffies; \ - status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ - status[(_q)][status_ptr[(_q)]].ph = (_ph); \ - status[(_q)][status_ptr[(_q)]].irq = (_irq); \ - status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \ -}) +#define STATUS_BUFFER_TO_PRINT 24 unsigned int sdtr_period = SDTR_PERIOD; unsigned int sdtr_size = SDTR_SIZE; @@ -214,31 +194,31 @@ PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); -static int acornscsi_reconnect_finish (AS_Host *host); -static void acornscsi_dma_cleanup (AS_Host *host); -static void acornscsi_abortcmd (AS_Host *host, unsigned char tag); +static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static int acornscsi_reconnect_finish(AS_Host *host); +static void acornscsi_dma_cleanup(AS_Host *host); +static void acornscsi_abortcmd(AS_Host *host, unsigned char tag); /* ==================================================================================== * Miscellaneous */ static inline void -sbic_arm_write (unsigned int io_port, int reg, int value) +sbic_arm_write(unsigned int io_port, int reg, int value) { - outb_t (reg, io_port); - outb_t (value, io_port + 4); + outb_t(reg, io_port); + outb_t(value, io_port + 4); } #define sbic_arm_writenext(io,val) \ - outb_t ((val), (io) + 4) + outb_t((val), (io) + 4) static inline -int sbic_arm_read (unsigned int io_port, int reg) +int sbic_arm_read(unsigned int io_port, int reg) { if(reg == ASR) return inl_t(io_port) & 255; - outb_t (reg, io_port); + outb_t(reg, io_port); return inl_t(io_port + 4) & 255; } @@ -247,129 +227,165 @@ #ifdef USE_DMAC #define dmac_read(io_port,reg) \ - inb ((io_port) + (reg)) + inb((io_port) + (reg)) #define dmac_write(io_port,reg,value) \ - ({ outb ((value), (io_port) + (reg)); }) + ({ outb((value), (io_port) + (reg)); }) #define dmac_clearintr(io_port) \ - ({ outb (0, (io_port)); }) + ({ outb(0, (io_port)); }) static inline -unsigned int dmac_address (unsigned int io_port) +unsigned int dmac_address(unsigned int io_port) { - return dmac_read (io_port, TXADRHI) << 16 | - dmac_read (io_port, TXADRMD) << 8 | - dmac_read (io_port, TXADRLO); + return dmac_read(io_port, TXADRHI) << 16 | + dmac_read(io_port, TXADRMD) << 8 | + dmac_read(io_port, TXADRLO); } static -void acornscsi_dumpdma (AS_Host *host, char *where) +void acornscsi_dumpdma(AS_Host *host, char *where) { unsigned int mode, addr, len; - mode = dmac_read (host->dma.io_port, MODECON); - addr = dmac_address (host->dma.io_port); - len = dmac_read (host->dma.io_port, TXCNTHI) << 8 | - dmac_read (host->dma.io_port, TXCNTLO); + mode = dmac_read(host->dma.io_port, MODECON); + addr = dmac_address(host->dma.io_port); + len = dmac_read(host->dma.io_port, TXCNTHI) << 8 | + dmac_read(host->dma.io_port, TXCNTLO); - printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", + printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", host->host->host_no, where, mode, addr, (len + 1) & 0xffff, - dmac_read (host->dma.io_port, MASKREG)); + dmac_read(host->dma.io_port, MASKREG)); - printk ("DMA @%06x, ", host->dma.start_addr); - printk ("BH @%p +%04x, ", host->scsi.SCp.ptr, + printk("DMA @%06x, ", host->dma.start_addr); + printk("BH @%p +%04x, ", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); - printk ("DT @+%04x ST @+%04x", host->dma.transferred, + printk("DT @+%04x ST @+%04x", host->dma.transferred, host->scsi.SCp.scsi_xferred); - printk ("\n"); + printk("\n"); } #endif static -unsigned long acornscsi_sbic_xfcount (AS_Host *host) +unsigned long acornscsi_sbic_xfcount(AS_Host *host) { unsigned long length; - length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; - length |= sbic_arm_readnext (host->scsi.io_port) << 8; - length |= sbic_arm_readnext (host->scsi.io_port); + length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16; + length |= sbic_arm_readnext(host->scsi.io_port) << 8; + length |= sbic_arm_readnext(host->scsi.io_port); return length; } -static -int acornscsi_sbic_issuecmd (AS_Host *host, int command) +static int +acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg) { - int asr; + int asr; - do { - asr = sbic_arm_read (host->scsi.io_port, ASR); - } while (asr & ASR_CIP); + do { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if ((asr & stat_mask) == stat) + return 0; + + udelay(1); + } while (--timeout); + + printk("scsi%d: timeout while %s\n", host->host->host_no, msg); + + return -1; +} - sbic_arm_write (host->scsi.io_port, CMND, command); +static +int acornscsi_sbic_issuecmd(AS_Host *host, int command) +{ + if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command")) + return -1; + + sbic_arm_write(host->scsi.io_port, CMND, command); return 0; } static void -acornscsi_csdelay (unsigned int cs) +acornscsi_csdelay(unsigned int cs) { unsigned long target_jiffies, flags; target_jiffies = jiffies + 1 + cs * HZ / 100; - save_flags (flags); - sti (); + save_flags(flags); + sti(); while (time_before(jiffies, target_jiffies)) barrier(); - restore_flags (flags); + restore_flags(flags); } static -void acornscsi_resetcard (AS_Host *host) +void acornscsi_resetcard(AS_Host *host) { - unsigned int i; + unsigned int i, timeout; /* assert reset line */ host->card.page_reg = 0x80; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* wait 3 cs. SCSI standard says 25ms. */ - acornscsi_csdelay (3); + acornscsi_csdelay(3); host->card.page_reg = 0; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* * Should get a reset from the card */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - sbic_arm_read (host->scsi.io_port, SSR); + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", + host->host->host_no); + + sbic_arm_read(host->scsi.io_port, ASR); + sbic_arm_read(host->scsi.io_port, SSR); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); /* * Command should cause a reset interrupt */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) - printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", host->host->host_no); - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_read(host->scsi.io_port, ASR); + if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01) + printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + host->host->host_no); + + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->card.page_reg = 0x40; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* setup dmac - uPC71071 */ dmac_write(host->dma.io_port, INIT, 0); @@ -391,7 +407,7 @@ } /* wait 25 cs. SCSI standard says 250ms. */ - acornscsi_csdelay (25); + acornscsi_csdelay(25); } /*============================================================================================= @@ -461,80 +477,101 @@ }; static -void print_scsi_status (unsigned int ssr) +void print_scsi_status(unsigned int ssr) { if (acornscsi_map[ssr] != -1) - printk ("%s:%s", + printk("%s:%s", acornscsi_interrupttype[(ssr >> 4)], acornscsi_interruptcode[acornscsi_map[ssr]]); else - printk ("%X:%X", ssr >> 4, ssr & 0x0f); + printk("%X:%X", ssr >> 4, ssr & 0x0f); } #endif static -void print_sbic_status (int asr, int ssr, int cmdphase) +void print_sbic_status(int asr, int ssr, int cmdphase) { #ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("sbic: %c%c%c%c%c%c ", + printk("sbic: %c%c%c%c%c%c ", asr & ASR_INT ? 'I' : 'i', asr & ASR_LCI ? 'L' : 'l', asr & ASR_BSY ? 'B' : 'b', asr & ASR_CIP ? 'C' : 'c', asr & ASR_PE ? 'P' : 'p', asr & ASR_DBR ? 'D' : 'd'); - printk ("scsi: "); - print_scsi_status (ssr); - printk (" ph %02X\n", cmdphase); + printk("scsi: "); + print_scsi_status(ssr); + printk(" ph %02X\n", cmdphase); #else - printk ("sbic: %02X scsi: %X:%X ph: %02X\n", + printk("sbic: %02X scsi: %X:%X ph: %02X\n", asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); #endif } -static -void acornscsi_dumplog (AS_Host *host, int target) +static void +acornscsi_dumplogline(AS_Host *host, int target, int line) { - unsigned int prev; - do { - signed int statptr; + unsigned long prev; + signed int ptr; - printk ("%c:", target == 8 ? 'H' : ('0' + target)); - statptr = status_ptr[target] - 10; + ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT; + if (ptr < 0) + ptr += STATUS_BUFFER_SIZE; - if (statptr < 0) - statptr += 16; + printk("%c: %3s:", target == 8 ? 'H' : '0' + target, + line == 0 ? "ph" : line == 1 ? "ssr" : "int"); - prev = status[target][statptr].when; + prev = host->status[target][ptr].when; - for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) { - if (status[target][statptr].when) { -#ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("%c%02X:S=", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph); - print_scsi_status (status[target][statptr].ssr); -#else - printk ("%c%02X:%02X", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph, - status[target][statptr].ssr); -#endif - printk ("+%02ld", - (status[target][statptr].when - prev) < 100 ? - (status[target][statptr].when - prev) : 99); - prev = status[target][statptr].when; - } + for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + unsigned long time_diff; + + if (!host->status[target][ptr].when) + continue; + + switch (line) { + case 0: + printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ', + host->status[target][ptr].ph); + break; + + case 1: + printk(" %02X", host->status[target][ptr].ssr); + break; + + case 2: + time_diff = host->status[target][ptr].when - prev; + prev = host->status[target][ptr].when; + if (time_diff == 0) + printk("==^"); + else if (time_diff >= 100) + printk(" "); + else + printk(" %02ld", time_diff); + break; + } } - printk ("\n"); + + printk("\n"); +} + +static +void acornscsi_dumplog(AS_Host *host, int target) +{ + do { + acornscsi_dumplogline(host, target, 0); + acornscsi_dumplogline(host, target, 1); + acornscsi_dumplogline(host, target, 2); + if (target == 8) break; + target = 8; } while (1); } static -char acornscsi_target (AS_Host *host) +char acornscsi_target(AS_Host *host) { if (host->SCpnt) return '0' + host->SCpnt->target; @@ -542,7 +579,7 @@ } /* - * Prototype: cmdtype_t acornscsi_cmdtype (int command) + * Prototype: cmdtype_t acornscsi_cmdtype(int command) * Purpose : differentiate READ from WRITE from other commands * Params : command - command to interpret * Returns : CMD_READ - command reads data, @@ -550,7 +587,7 @@ * CMD_MISC - everything else */ static inline -cmdtype_t acornscsi_cmdtype (int command) +cmdtype_t acornscsi_cmdtype(int command) { switch (command) { case WRITE_6: case WRITE_10: case WRITE_12: @@ -563,7 +600,7 @@ } /* - * Prototype: int acornscsi_datadirection (int command) + * Prototype: int acornscsi_datadirection(int command) * Purpose : differentiate between commands that have a DATA IN phase * and a DATA OUT phase * Params : command - command to interpret @@ -571,7 +608,7 @@ * DATADIR_IN - data in phase expected */ static -datadir_t acornscsi_datadirection (int command) +datadir_t acornscsi_datadirection(int command) { switch (command) { case CHANGE_DEFINITION: case COMPARE: case COPY: @@ -605,13 +642,13 @@ }; /* - * Prototype: int acornscsi_getperiod (unsigned char syncxfer) + * Prototype: int acornscsi_getperiod(unsigned char syncxfer) * Purpose : period for the synchronous transfer setting * Params : syncxfer SYNCXFER register value * Returns : period in ns. */ static -int acornscsi_getperiod (unsigned char syncxfer) +int acornscsi_getperiod(unsigned char syncxfer) { int i; @@ -626,14 +663,14 @@ } /* - * Prototype: int round_period (unsigned int period) + * Prototype: int round_period(unsigned int period) * Purpose : return index into above table for a required REQ period * Params : period - time (ns) for REQ * Returns : table index * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static inline -int round_period (unsigned int period) +int round_period(unsigned int period) { int i; @@ -646,7 +683,7 @@ } /* - * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) + * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) * Purpose : calculate value for 33c93s SYNC register * Params : period - time (ns) for REQ * offset - offset in bytes between REQ/ACK @@ -654,7 +691,7 @@ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static -unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) +unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) { return sync_xfer_table[round_period(period)].reg_value | ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); @@ -664,14 +701,14 @@ * Command functions */ /* - * Function: acornscsi_kick (AS_Host *host) + * Function: acornscsi_kick(AS_Host *host) * Purpose : kick next command to interface * Params : host - host to send command to * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING * Notes : interrupts are always disabled! */ static -intr_ret_t acornscsi_kick (AS_Host *host) +intr_ret_t acornscsi_kick(AS_Host *host) { int from_queue = 0; Scsi_Cmnd *SCpnt; @@ -682,7 +719,7 @@ /* retrieve next command */ if (!SCpnt) { - SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns); + SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns); if (!SCpnt) return INTR_IDLE; @@ -690,11 +727,11 @@ } if (host->scsi.disconnectable && host->SCpnt) { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); host->scsi.disconnectable = 0; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n", + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } @@ -703,9 +740,9 @@ * If we have an interrupt pending, then we may have been reselected. * In this case, we don't want to write to the registers */ - if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { - sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target); - sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN); + if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { + sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target); + sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN); } /* @@ -717,9 +754,10 @@ host->scsi.SCp = SCpnt->SCp; host->dma.xfer_setup = 0; host->dma.xfer_required = 0; + host->dma.xfer_done = 0; #if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) - DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n", + DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n", host->host->host_no, '0' + SCpnt->target, SCpnt->cmnd[0])); #endif @@ -736,11 +774,11 @@ SCpnt->tag = SCpnt->device->current_tag; } else #endif - set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); host->stats.removes += 1; - switch (acornscsi_cmdtype (SCpnt->cmnd[0])) { + switch (acornscsi_cmdtype(SCpnt->cmnd[0])) { case CMD_WRITE: host->stats.writes += 1; break; @@ -757,25 +795,25 @@ } /* - * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) * Purpose : complete processing for command * Params : host - interface that completed * result - driver byte of result */ static -void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) { Scsi_Cmnd *SCpnt = *SCpntp; /* clean up */ - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->stats.fins += 1; if (SCpnt) { *SCpntp = NULL; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; @@ -787,35 +825,63 @@ * It doesn't appear to be set to something meaningful by the higher * levels all the time. */ - if (host->scsi.SCp.ptr && result == DID_OK && - acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) { - switch (status_byte (SCpnt->result)) { - case CHECK_CONDITION: - case COMMAND_TERMINATED: - case BUSY: - case QUEUE_FULL: - case RESERVATION_CONFLICT: - break; + if (result == DID_OK) { + int xfer_warn = 0; - default: - printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", - host->host->host_no, SCpnt->result); - print_command (SCpnt->cmnd); - acornscsi_dumpdma (host, "done"); - acornscsi_dumplog (host, SCpnt->target); - SCpnt->result &= 0xffff; - SCpnt->result |= DID_ERROR << 16; - } + if (SCpnt->underflow == 0) { + if (host->scsi.SCp.ptr && + acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC) + xfer_warn = 1; + } else { + if (host->scsi.SCp.scsi_xferred < SCpnt->underflow || + host->scsi.SCp.scsi_xferred != host->dma.transferred) + xfer_warn = 1; + } + + /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6) + * Targets which break data transfers into multiple + * connections shall end each successful connection + * (except possibly the last) with a SAVE DATA + * POINTER - DISCONNECT message sequence. + * + * This makes it difficult to ensure that a transfer has + * completed. If we reach the end of a transfer during + * the command, then we can only have finished the transfer. + * therefore, if we seem to have some data remaining, this + * is not a problem. + */ + if (host->dma.xfer_done) + xfer_warn = 0; + + if (xfer_warn) { + switch (status_byte(SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", + host->host->host_no, SCpnt->result); + print_command(SCpnt->cmnd); + acornscsi_dumpdma(host, "done"); + acornscsi_dumplog(host, SCpnt->target); + SCpnt->result &= 0xffff; + SCpnt->result |= DID_ERROR << 16; + } + } } if (!SCpnt->scsi_done) - panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); + panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); - clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } else - printk ("scsi%d: null command in acornscsi_done", host->host->host_no); + printk("scsi%d: null command in acornscsi_done", host->host->host_no); host->scsi.phase = PHASE_IDLE; } @@ -828,7 +894,7 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length) +void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length) { SCp->ptr += length; SCp->this_residual -= length; @@ -839,13 +905,15 @@ SCp->buffers_residual--; SCp->ptr = (char *)SCp->buffer->address; SCp->this_residual = SCp->buffer->length; - } else + } else { SCp->ptr = NULL; + host->dma.xfer_done = 1; + } } } /* - * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : read data from DMA RAM * Params : host - host to transfer from @@ -855,16 +923,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_read (AS_Host *host, char *ptr, +void acornscsi_data_read(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_in (int port, char *buf, int len); + extern void __acornscsi_in(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -874,7 +942,7 @@ else this_len = len; - __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -883,14 +951,14 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* - * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : write data to DMA RAM * Params : host - host to transfer from @@ -900,16 +968,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_write (AS_Host *host, char *ptr, +void acornscsi_data_write(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_out (int port, char *buf, int len); + extern void __acornscsi_out(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -919,7 +987,7 @@ else this_len = len; - __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -928,10 +996,10 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* ========================================================================================= @@ -939,25 +1007,25 @@ */ #ifdef USE_DMAC /* - * Prototype: void acornscsi_dmastop (AS_Host *host) + * Prototype: void acornscsi_dmastop(AS_Host *host) * Purpose : stop all DMA * Params : host - host on which to stop DMA * Notes : This is called when leaving DATA IN/OUT phase, * or when interface is RESET */ static inline -void acornscsi_dma_stop (AS_Host *host) +void acornscsi_dma_stop(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "stop")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "stop")); #endif } /* - * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) + * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) * Purpose : setup DMA controller for data transfer * Params : host - host to setup * direction - data transfer direction @@ -965,19 +1033,19 @@ * while we're in a DATA I/O phase */ static -void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) +void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) { unsigned int address, length, mode; host->dma.direction = direction; - dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); if (direction == DMA_OUT) { #if (DEBUG & DEBUG_NO_WRITE) if (NO_WRITE & (1 << host->SCpnt->target)) { - printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", + host->host->host_no, acornscsi_target(host)); return; } #endif @@ -988,7 +1056,7 @@ /* * Allocate some buffer space, limited to half the buffer size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -998,27 +1066,27 @@ * Transfer data to DMA memory */ if (direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MODECON, mode); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MODECON, mode); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "strt")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "strt")); #endif host->dma.xfer_setup = 1; } } /* - * Function: void acornscsi_dma_cleanup (AS_Host *host) + * Function: void acornscsi_dma_cleanup(AS_Host *host) * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct * Params : host - host to finish * Notes : This is called when a command is: @@ -1026,10 +1094,10 @@ * : This must not return until all transfers are completed. */ static -void acornscsi_dma_cleanup (AS_Host *host) +void acornscsi_dma_cleanup(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Check for a pending transfer @@ -1037,7 +1105,7 @@ if (host->dma.xfer_required) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } @@ -1056,17 +1124,17 @@ /* * Calculate number of bytes transferred from DMA. */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->scsi.SCp.ptr, + acornscsi_data_read(host, host->scsi.SCp.ptr, host->dma.start_addr, transferred); /* * Update SCSI pointers */ - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); #if (DEBUG & DEBUG_DMA) DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo")); #endif @@ -1074,7 +1142,7 @@ } /* - * Function: void acornscsi_dmacintr (AS_Host *host) + * Function: void acornscsi_dmacintr(AS_Host *host) * Purpose : handle interrupts from DMAC device * Params : host - host to process * Notes : If reading, we schedule the read to main memory & @@ -1084,21 +1152,21 @@ * : Called whenever DMAC finished it's current transfer. */ static -void acornscsi_dma_intr (AS_Host *host) +void acornscsi_dma_intr(AS_Host *host) { unsigned int address, length, transferred; #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "inti")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "inti")); #endif - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Calculate amount transferred via DMA */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; /* @@ -1111,12 +1179,12 @@ host->dma.xfer_required = 1; } - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); /* * Allocate some buffer space, limited to half the on-board RAM size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -1126,19 +1194,19 @@ * Transfer data to DMA memory */ if (host->dma.direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "into")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "into")); #endif } else { host->dma.xfer_setup = 0; @@ -1149,48 +1217,48 @@ * attention condition. We continue giving one byte until * the device recognises the attention. */ - if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) { - acornscsi_abortcmd (host, host->SCpnt->tag); + if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) { + acornscsi_abortcmd(host, host->SCpnt->tag); - dmac_write (host->dma.io_port, TXCNTLO, 0); - dmac_write (host->dma.io_port, TXCNTHI, 0); - dmac_write (host->dma.io_port, TXADRLO, 0); - dmac_write (host->dma.io_port, TXADRMD, 0); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, 0); + dmac_write(host->dma.io_port, TXCNTHI, 0); + dmac_write(host->dma.io_port, TXADRLO, 0); + dmac_write(host->dma.io_port, TXADRMD, 0); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); } #endif } } /* - * Function: void acornscsi_dma_xfer (AS_Host *host) + * Function: void acornscsi_dma_xfer(AS_Host *host) * Purpose : transfer data between AcornSCSI and memory * Params : host - host to process */ static -void acornscsi_dma_xfer (AS_Host *host) +void acornscsi_dma_xfer(AS_Host *host) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } /* - * Function: void acornscsi_dma_adjust (AS_Host *host) + * Function: void acornscsi_dma_adjust(AS_Host *host) * Purpose : adjust DMA pointers & count for bytes transfered to * SBIC but not SCSI bus. * Params : host - host to adjust DMA count for */ static -void acornscsi_dma_adjust (AS_Host *host) +void acornscsi_dma_adjust(AS_Host *host) { if (host->dma.xfer_setup) { signed long transferred; #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adji")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adji")); #endif /* * Calculate correct DMA address - DMA is ahead of SCSI bus while @@ -1205,17 +1273,17 @@ */ transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred; if (transferred < 0) - printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", - host->host->host_no, acornscsi_target (host), transferred); + printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", + host->host->host_no, acornscsi_target(host), transferred); else if (transferred == 0) host->dma.xfer_setup = 0; else { transferred += host->dma.start_addr; - dmac_write (host->dma.io_port, TXADRLO, transferred); - dmac_write (host->dma.io_port, TXADRMD, transferred >> 8); - dmac_write (host->dma.io_port, TXADRHI, transferred >> 16); + dmac_write(host->dma.io_port, TXADRLO, transferred); + dmac_write(host->dma.io_port, TXADRMD, transferred >> 8); + dmac_write(host->dma.io_port, TXADRHI, transferred >> 16); #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo")); #endif } } @@ -1225,66 +1293,88 @@ /* ========================================================================================= * Data I/O */ +static int +acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout) +{ + unsigned int asr, timeout = max_timeout; + int my_ptr = *ptr; + + while (my_ptr < len) { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if (asr & ASR_DBR) { + timeout = max_timeout; + + sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]); + } else if (asr & ASR_INT) + break; + else if (--timeout == 0) + break; + udelay(1); + } + + *ptr = my_ptr; + + return (timeout == 0) ? -1 : 0; +} + /* - * Function: void acornscsi_sendcommand (AS_Host *host) + * Function: void acornscsi_sendcommand(AS_Host *host) * Purpose : send a command to a target * Params : host - host which is connected to target */ -static -void acornscsi_sendcommand (AS_Host *host) +static void +acornscsi_sendcommand(AS_Host *host) { Scsi_Cmnd *SCpnt = host->SCpnt; - unsigned int asr; - unsigned char *cmdptr, *cmdend; - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); - - cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command; - cmdend = SCpnt->cmnd + SCpnt->cmd_len; - - while (cmdptr < cmdend) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++); - else if (asr & ASR_INT) - break; - } - if (cmdptr >= cmdend) - host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd; + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); + + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); + + if (acornscsi_write_pio(host, SCpnt->cmnd, + (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000)) + printk("scsi%d: timeout while sending command\n", host->host->host_no); + host->scsi.phase = PHASE_COMMAND; } static -void acornscsi_sendmessage (AS_Host *host) +void acornscsi_sendmessage(AS_Host *host) { - unsigned int message_length = msgqueue_msglength (&host->scsi.msgs); - int msgnr; + unsigned int message_length = msgqueue_msglength(&host->scsi.msgs); + unsigned int msgnr; struct message *msg; #if (DEBUG & DEBUG_MESSAGES) - printk ("scsi%d.%c: sending message ", - host->host->host_no, acornscsi_target (host)); + printk("scsi%d.%c: sending message ", + host->host->host_no, acornscsi_target(host)); #endif switch (message_length) { case 0: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, NOP); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1"); + + sbic_arm_write(host->scsi.io_port, DATA, NOP); + host->scsi.last_message = NOP; #if (DEBUG & DEBUG_MESSAGES) - printk ("NOP"); + printk("NOP"); #endif break; case 1: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); msg = msgqueue_getmsg(&host->scsi.msgs, 0); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[0]); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2"); + + sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]); + host->scsi.last_message = msg->msg[0]; #if (DEBUG & DEBUG_MESSAGES) print_msg(msg->msg); @@ -1300,86 +1390,85 @@ * initiator. This provides an interlock so that the * initiator can determine which message byte is rejected. */ - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, message_length); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, message_length); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); msgnr = 0; while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) { - unsigned int asr, i; + unsigned int i; #if (DEBUG & DEBUG_MESSAGES) - print_msg (msg); + print_msg(msg); #endif - for (i = 0; i < msg->length;) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[i++]); - if (asr & ASR_INT) - break; - } + i = 0; + if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000)) + printk("scsi%d: timeout while sending message\n", host->host->host_no); + host->scsi.last_message = msg->msg[0]; if (msg->msg[0] == EXTENDED_MESSAGE) host->scsi.last_message |= msg->msg[2] << 8; - if (asr & ASR_INT) + + if (i != msg->length) break; } break; } #if (DEBUG & DEBUG_MESSAGES) - printk ("\n"); + printk("\n"); #endif } /* - * Function: void acornscsi_readstatusbyte (AS_Host *host) + * Function: void acornscsi_readstatusbyte(AS_Host *host) * Purpose : Read status byte from connected target * Params : host - host connected to target */ static -void acornscsi_readstatusbyte (AS_Host *host) +void acornscsi_readstatusbyte(AS_Host *host) { - acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - - host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT); + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte"); + host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA); } /* - * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) + * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) * Purpose : Read one message byte from connected target * Params : host - host connected to target */ static -unsigned char acornscsi_readmessagebyte (AS_Host *host) +unsigned char acornscsi_readmessagebyte(AS_Host *host) { unsigned char message; - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); - message = sbic_arm_read (host->scsi.io_port, DATA); + message = sbic_arm_read(host->scsi.io_port, DATA); /* wait for MSGIN-XFER-PAUSED */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte"); + + sbic_arm_read(host->scsi.io_port, SSR); return message; } /* - * Function: void acornscsi_message (AS_Host *host) + * Function: void acornscsi_message(AS_Host *host) * Purpose : Read complete message from connected target & action message * Params : host - host connected to target */ static -void acornscsi_message (AS_Host *host) +void acornscsi_message(AS_Host *host) { unsigned char message[16]; unsigned int msgidx = 0, msglen = 1; do { - message[msgidx] = acornscsi_readmessagebyte (host); + message[msgidx] = acornscsi_readmessagebyte(host); switch (msgidx) { case 0: @@ -1395,17 +1484,17 @@ } msgidx += 1; if (msgidx < msglen) { - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); /* wait for next msg-in */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack"); + sbic_arm_read(host->scsi.io_port, SSR); } } while (msgidx < msglen); #if (DEBUG & DEBUG_MESSAGES) printk("scsi%d.%c: message in: ", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); print_msg(message); printk("\n"); #endif @@ -1419,7 +1508,7 @@ */ if (message[0] == SIMPLE_QUEUE_TAG) host->scsi.reconnected.tag = message[1]; - if (acornscsi_reconnect_finish (host)) + if (acornscsi_reconnect_finish(host)) host->scsi.phase = PHASE_MSGIN; } @@ -1429,7 +1518,7 @@ case COMMAND_COMPLETE: if (host->scsi.phase != PHASE_STATUSIN) { printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); acornscsi_dumplog(host, host->SCpnt->target); } host->scsi.phase = PHASE_DONE; @@ -1443,7 +1532,7 @@ * direct the initiator to copy the active data pointer to * the saved data pointer for the current I/O process. */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt->SCp = host->scsi.SCp; host->SCpnt->SCp.sent_command = 0; host->scsi.phase = PHASE_MSGIN; @@ -1459,7 +1548,7 @@ * status pointers shall be restored to the beginning of * the present command and status areas.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.SCp = host->SCpnt->SCp; host->scsi.phase = PHASE_MSGIN; break; @@ -1474,7 +1563,7 @@ * message. When reconnection is completed, the most recent * saved pointer values are restored.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.phase = PHASE_DISCONNECT; break; @@ -1493,8 +1582,8 @@ /* * If we have any messages waiting to go out, then assert ATN now */ - if (msgqueue_msglength (&host->scsi.msgs)) - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + if (msgqueue_msglength(&host->scsi.msgs)) + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); switch (host->scsi.last_message) { #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE @@ -1507,21 +1596,21 @@ * message is received, it shall respond with a MESSAGE REJECT * message and accept the I/O process as if it were untagged. */ - printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", + host->host->host_no, acornscsi_target(host)); host->SCpnt->device->tagged_queue = 0; - set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); break; #endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): /* * Target can't handle synchronous transfers */ - printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", + host->host->host_no, acornscsi_target(host)); host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; default: @@ -1535,8 +1624,8 @@ case SIMPLE_QUEUE_TAG: /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ - printk ("scsi%d.%c: reconnect queue tag %02X\n", - host->host->host_no, acornscsi_target (host), + printk("scsi%d.%c: reconnect queue tag %02X\n", + host->host->host_no, acornscsi_target(host), message[1]); break; @@ -1552,26 +1641,26 @@ * and the target retries fail, then we fallback to asynchronous mode */ host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; - printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", + printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", host->host->host_no, acornscsi_target(host), message[4], message[3] * 4); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (message[3] * 4, message[4]); + calc_sync_xfer(message[3] * 4, message[4]); } else { unsigned char period, length; /* * Target requested synchronous transfers. The agreement is only * to be in operation AFTER the target leaves message out phase. */ - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - period = max (message[3], sdtr_period / 4); - length = min (message[4], sdtr_size); - msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + period = max(message[3], sdtr_period / 4); + length = min(message[4], sdtr_size); + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, period, length); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (period * 4, length); + calc_sync_xfer(period * 4, length); } - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; #else /* We do not accept synchronous transfers. Respond with a @@ -1584,9 +1673,9 @@ * to a wide data transfer request. */ default: - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); break; } break; @@ -1607,19 +1696,19 @@ * if there are more linked commands available. */ if (!host->SCpnt->next_link) { - printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", - instance->host_no, acornscsi_target (host), host->SCpnt->tag); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", + instance->host_no, acornscsi_target(host), host->SCpnt->tag); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } else { Scsi_Cmnd *SCpnt = host->SCpnt; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt = host->SCpnt->next_link; host->SCpnt->tag = SCpnt->tag; SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; - SCpnt->done (SCpnt); + SCpnt->done(SCpnt); /* initialise host->SCpnt->SCp */ } @@ -1628,42 +1717,42 @@ #endif default: /* reject message */ - printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", - host->host->host_no, acornscsi_target (host), + printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", + host->host->host_no, acornscsi_target(host), message[0]); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); host->scsi.phase = PHASE_MSGIN; break; } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); } /* - * Function: int acornscsi_buildmessages (AS_Host *host) + * Function: int acornscsi_buildmessages(AS_Host *host) * Purpose : build the connection messages for a host * Params : host - host to add messages to */ static -void acornscsi_buildmessages (AS_Host *host) +void acornscsi_buildmessages(AS_Host *host) { #if 0 /* does the device need resetting? */ if (cmd_reset) { - msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); + msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET); return; } #endif - msgqueue_addmsg (&host->scsi.msgs, 1, + msgqueue_addmsg(&host->scsi.msgs, 1, IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, host->SCpnt->lun)); #if 0 /* does the device need the current command aborted */ if (cmd_aborted) { - acornscsi_abortcmd (host->SCpnt->tag); + acornscsi_abortcmd(host->SCpnt->tag); return; } #endif @@ -1678,14 +1767,14 @@ tag_type = HEAD_OF_QUEUE_TAG; else tag_type = SIMPLE_QUEUE_TAG; - msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); + msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); } #endif #ifdef CONFIG_SCSI_ACORNSCSI_SYNC if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; - msgqueue_addmsg (&host->scsi.msgs, 5, + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, sdtr_period / 4, sdtr_size); } @@ -1693,29 +1782,29 @@ } /* - * Function: int acornscsi_starttransfer (AS_Host *host) + * Function: int acornscsi_starttransfer(AS_Host *host) * Purpose : transfer data to/from connected target * Params : host - host to which target is connected * Returns : 0 if failure */ static -int acornscsi_starttransfer (AS_Host *host) +int acornscsi_starttransfer(AS_Host *host) { int residual; if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { - printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", + host->host->host_no, acornscsi_target(host)); return 0; } residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); - sbic_arm_writenext (host->scsi.io_port, residual >> 16); - sbic_arm_writenext (host->scsi.io_port, residual >> 8); - sbic_arm_writenext (host->scsi.io_port, residual); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_writenext(host->scsi.io_port, residual >> 16); + sbic_arm_writenext(host->scsi.io_port, residual >> 8); + sbic_arm_writenext(host->scsi.io_port, residual); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); return 1; } @@ -1723,7 +1812,7 @@ * Connection & Disconnection */ /* - * Function : acornscsi_reconnect (AS_Host *host) + * Function : acornscsi_reconnect(AS_Host *host) * Purpose : reconnect a previously disconnected command * Params : host - host specific data * Remarks : SCSI spec says: @@ -1731,27 +1820,27 @@ * of saved pointers upon reconnection of the I/O process' */ static -int acornscsi_reconnect (AS_Host *host) +int acornscsi_reconnect(AS_Host *host) { unsigned int target, lun, ok = 0; - target = sbic_arm_read (host->scsi.io_port, SOURCEID); + target = sbic_arm_read(host->scsi.io_port, SOURCEID); if (!(target & 8)) - printk (KERN_ERR "scsi%d: invalid source id after reselection " + printk(KERN_ERR "scsi%d: invalid source id after reselection " "- device fault?\n", host->host->host_no); target &= 7; if (host->SCpnt && !host->scsi.disconnectable) { - printk (KERN_ERR "scsi%d.%d: reconnected while command in " + printk(KERN_ERR "scsi%d.%d: reconnected while command in " "progress to target %d?\n", host->host->host_no, target, host->SCpnt->target); host->SCpnt = NULL; } - lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; + lun = sbic_arm_read(host->scsi.io_port, DATA) & 7; host->scsi.reconnected.target = target; host->scsi.reconnected.lun = lun; @@ -1761,7 +1850,7 @@ host->SCpnt->target == target && host->SCpnt->lun == lun) ok = 1; - if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) + if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun)) ok = 1; ADD_STATUS(target, 0x81, host->scsi.phase, 0); @@ -1770,26 +1859,28 @@ host->scsi.phase = PHASE_RECONNECTED; } else { /* this doesn't seem to work */ - printk (KERN_ERR "scsi%d.%c: reselected with no command " + printk(KERN_ERR "scsi%d.%c: reselected with no command " "to reconnect with\n", host->host->host_no, '0' + target); - acornscsi_dumplog (host, target); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); - host->scsi.phase = PHASE_ABORTED; + acornscsi_dumplog(host, target); + acornscsi_abortcmd(host, 0); + if (host->SCpnt) { + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); + host->SCpnt = NULL; + } } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); return !ok; } /* - * Function: int acornscsi_reconect_finish (AS_Host *host) + * Function: int acornscsi_reconect_finish(AS_Host *host) * Purpose : finish reconnecting a command * Params : host - host to complete * Returns : 0 if failed */ static -int acornscsi_reconnect_finish (AS_Host *host) +int acornscsi_reconnect_finish(AS_Host *host) { if (host->scsi.disconnectable && host->SCpnt) { host->scsi.disconnectable = 0; @@ -1797,45 +1888,44 @@ host->SCpnt->lun == host->scsi.reconnected.lun && host->SCpnt->tag == host->scsi.reconnected.tag) { #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: reconnected", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: reconnected", + host->host->host_no, acornscsi_target(host))); #endif } else { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " + DBG(host->SCpnt, printk("scsi%d.%c: had to move command " "to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } } if (!host->SCpnt) { - host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, + host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected, host->scsi.reconnected.target, host->scsi.reconnected.lun, host->scsi.reconnected.tag); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: had to get command", + host->host->host_no, acornscsi_target(host))); #endif } - if (!host->SCpnt) { - acornscsi_abortcmd (host, host->scsi.reconnected.tag); - host->scsi.phase = PHASE_ABORTED; - } else { + if (!host->SCpnt) + acornscsi_abortcmd(host, host->scsi.reconnected.tag); + else { /* * Restore data pointer from SAVED pointers. */ host->scsi.SCp = host->SCpnt->SCp; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk (", data pointers: [%p, %X]", + printk(", data pointers: [%p, %X]", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); #endif } #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk ("\n"); + printk("\n"); #endif host->dma.transferred = host->scsi.SCp.scsi_xferred; @@ -1844,47 +1934,48 @@ } /* - * Function: void acornscsi_disconnect_unexpected (AS_Host *host) + * Function: void acornscsi_disconnect_unexpected(AS_Host *host) * Purpose : handle an unexpected disconnect * Params : host - host on which disconnect occurred */ static -void acornscsi_disconnect_unexpected (AS_Host *host) +void acornscsi_disconnect_unexpected(AS_Host *host) { - printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n", + host->host->host_no, acornscsi_target(host)); #if (DEBUG & DEBUG_ABORT) - acornscsi_dumplog (host, 8); + acornscsi_dumplog(host, 8); #endif - acornscsi_done (host, &host->SCpnt, DID_ABORT); + acornscsi_done(host, &host->SCpnt, DID_ERROR); } /* - * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) + * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag) * Purpose : abort a currently executing command * Params : host - host with connected command to abort * tag - tag to abort */ static -void acornscsi_abortcmd (AS_Host *host, unsigned char tag) +void acornscsi_abortcmd(AS_Host *host, unsigned char tag) { - sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); + host->scsi.phase = PHASE_ABORTED; + sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE if (tag) - msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); + msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag); else #endif - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } /* ========================================================================================== * Interrupt routines. */ /* - * Function: int acornscsi_sbicintr (AS_Host *host) + * Function: int acornscsi_sbicintr(AS_Host *host) * Purpose : handle interrupts from SCSI device * Params : host - host to process * Returns : INTR_PROCESS if expecting another SBIC interrupt @@ -1892,15 +1983,15 @@ * INTR_NEXT_COMMAND if we have finished processing the command */ static -intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq) +intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) { unsigned int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) return INTR_IDLE; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); #if (DEBUG & DEBUG_PHASES) print_sbic_status(asr, ssr, host->scsi.phase); @@ -1913,23 +2004,23 @@ switch (ssr) { case 0x00: /* reset state - not advanced */ - printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", + printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", host->host->host_no); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); return INTR_IDLE; case 0x01: /* reset state - advanced */ - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); - msgqueue_flush (&host->scsi.msgs); + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + msgqueue_flush(&host->scsi.msgs); return INTR_IDLE; case 0x41: /* unexpected disconnect aborted command */ - acornscsi_disconnect_unexpected (host); + acornscsi_disconnect_unexpected(host); return INTR_NEXT_COMMAND; } @@ -1939,35 +2030,35 @@ case 0x11: /* -> PHASE_CONNECTED */ /* BUS FREE -> SELECTION */ host->scsi.phase = PHASE_CONNECTED; - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); host->dma.transferred = host->scsi.SCp.scsi_xferred; /* 33C93 gives next interrupt indicating bus phase */ - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) break; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); ADD_STATUS(8, ssr, host->scsi.phase, 1); ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); goto connected; case 0x42: /* select timed out */ /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); + acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT); return INTR_NEXT_COMMAND; case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ /* BUS FREE -> RESELECTION */ host->origSCpnt = host->SCpnt; host->SCpnt = NULL; - msgqueue_flush (&host->scsi.msgs); - acornscsi_reconnect (host); + msgqueue_flush(&host->scsi.msgs); + acornscsi_reconnect(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; @@ -1977,12 +2068,12 @@ #ifdef NONSTANDARD case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* SELECTION -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; case 0x8b: /* -> PHASE_STATUS */ /* SELECTION -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; #endif @@ -1990,55 +2081,57 @@ case 0x8e: /* -> PHASE_MSGOUT */ /* SELECTION ->MESSAGE OUT */ host->scsi.phase = PHASE_MSGOUT; - acornscsi_buildmessages (host); - acornscsi_sendmessage (host); + acornscsi_buildmessages(host); + acornscsi_sendmessage(host); break; /* these should not happen */ case 0x85: /* target disconnected */ - acornscsi_done (host, &host->SCpnt, DID_ERROR); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ /* - * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase + * SCSI standard says that MESSAGE OUT phases can be followed by a + * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase */ switch (ssr) { - case 0x8a: + case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* MESSAGE OUT -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; + case 0x8b: /* -> PHASE_STATUS */ case 0x1b: /* -> PHASE_STATUS */ /* MESSAGE OUT -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; - case 0x4f: + case 0x4f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* MESSAGE OUT -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2047,43 +2140,43 @@ case 0x18: /* -> PHASE_DATAOUT */ /* COMMAND -> DATA OUT */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x19: /* -> PHASE_DATAIN */ /* COMMAND -> DATA IN */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x1b: /* -> PHASE_STATUS */ /* COMMAND -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ /* COMMAND -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* COMMAND -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2094,19 +2187,19 @@ host->scsi.phase = PHASE_IDLE; host->stats.disconnects += 1; } else { - printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_NEXT_COMMAND; case PHASE_IDLE: /* STATE: disconnected */ if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ - acornscsi_reconnect (host); + acornscsi_reconnect(host); else { - printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2119,54 +2212,54 @@ * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, * reconnect I_T_L command */ - if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) + if (ssr != 0x8f && !acornscsi_reconnect_finish(host)) return INTR_IDLE; ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); switch (ssr) { case 0x88: /* data out phase */ /* -> PHASE_DATAOUT */ /* MESSAGE IN -> DATA OUT */ - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x89: /* data in phase */ /* -> PHASE_DATAIN */ /* MESSAGE IN -> DATA IN */ - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x8a: /* command out */ /* MESSAGE IN -> COMMAND */ - acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ break; case 0x8b: /* status in */ /* -> PHASE_STATUSIN */ /* MESSAGE IN -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* message out */ /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x8f: /* message in */ - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2177,41 +2270,45 @@ */ switch (ssr) { case 0x19: /* -> PHASE_DATAIN */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x89: /* -> PHASE_DATAIN */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2222,58 +2319,69 @@ */ switch (ssr) { case 0x18: /* -> PHASE_DATAOUT */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x88: /* -> PHASE_DATAOUT */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_STATUSIN: /* STATE: status in complete */ - if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + switch (ssr) { + case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + case 0x8f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ /* STATUS -> MESSAGE IN */ - acornscsi_message (host); - else if (ssr == 0x1e) /* -> PHASE_MSGOUT */ + acornscsi_message(host); + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* STATUS -> MESSAGE OUT */ - acornscsi_sendmessage (host); - else { - printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_sendmessage(host); + break; + + default: + printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2281,78 +2389,93 @@ switch (ssr) { case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ case 0x2f: case 0x4f: case 0x8f: - acornscsi_message (host); + acornscsi_message(host); + break; + + case 0x85: + printk("scsi%d.%c: strange message in disconnection\n", + host->host->host_no, acornscsi_target(host)); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DONE: /* STATE: received status & message */ switch (ssr) { case 0x85: /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_OK); + acornscsi_done(host, &host->SCpnt, DID_OK); return INTR_NEXT_COMMAND; + case 0x1e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_ABORTED: switch (ssr) { case 0x85: - acornscsi_done (host, &host->SCpnt, DID_ABORT); + if (host->SCpnt) + acornscsi_done(host, &host->SCpnt, DID_ABORT); + else { + clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun, + host->busyluns); + host->scsi.phase = PHASE_IDLE; + } return INTR_NEXT_COMMAND; case 0x1e: case 0x2e: case 0x4e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; default: - printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; } /* - * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) + * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) * Purpose : handle interrupts from Acorn SCSI card * Params : irq - interrupt number * dev_id - device specific data (AS_Host structure) * regs - processor registers when interrupt occurred */ static -void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) +void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) { AS_Host *host = (AS_Host *)dev_id; intr_ret_t ret; @@ -2360,21 +2483,21 @@ int in_irq = 0; if (host->scsi.interrupt) - printk ("scsi%d: interrupt re-entered\n", host->host->host_no); + printk("scsi%d: interrupt re-entered\n", host->host->host_no); host->scsi.interrupt = 1; do { ret = INTR_IDLE; - iostatus = inb (host->card.io_intr); + iostatus = inb(host->card.io_intr); if (iostatus & 2) { - acornscsi_dma_intr (host); - iostatus = inb (host->card.io_intr); + acornscsi_dma_intr(host); + iostatus = inb(host->card.io_intr); } if (iostatus & 8) - ret = acornscsi_sbicintr (host, in_irq); + ret = acornscsi_sbicintr(host, in_irq); /* * If we have a transfer pending, start it. @@ -2382,10 +2505,10 @@ * it's data */ if (host->dma.xfer_required) - acornscsi_dma_xfer (host); + acornscsi_dma_xfer(host); if (ret == INTR_NEXT_COMMAND) - ret = acornscsi_kick (host); + ret = acornscsi_kick(host); in_irq = 1; } while (ret != INTR_IDLE); @@ -2398,29 +2521,29 @@ */ /* - * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * Purpose : queues a SCSI command * Params : cmd - SCSI command * done - function called on completion, with pointer to command descriptor * Returns : 0, or < 0 on error. */ -int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; if (!done) { /* there should be some way of rejecting errors like this without panicing... */ - panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]", + panic("scsi%d: queuecommand called with NULL done function [cmd=%p]", SCpnt->host->host_no, SCpnt); return -EINVAL; } #if (DEBUG & DEBUG_NO_WRITE) - if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { - printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", + if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { + printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", SCpnt->host->host_no, '0' + SCpnt->target); SCpnt->result = DID_NO_CONNECT << 16; - done (SCpnt); + done(SCpnt); return 0; } #endif @@ -2429,7 +2552,7 @@ SCpnt->host_scribble = NULL; SCpnt->result = 0; SCpnt->tag = 0; - SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]); + SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]); SCpnt->SCp.sent_command = 0; SCpnt->SCp.scsi_xferred = 0; SCpnt->SCp.Status = 0; @@ -2452,21 +2575,21 @@ { unsigned long flags; - if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) { + if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; - done (SCpnt); + done(SCpnt); return 0; } - save_flags_cli (flags); + save_flags_cli(flags); if (host->scsi.phase == PHASE_IDLE) - acornscsi_kick (host); - restore_flags (flags); + acornscsi_kick(host); + restore_flags(flags); } return 0; } /* - * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check @@ -2474,7 +2597,7 @@ * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. */ static inline -void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) { Scsi_Cmnd *SCpnt = *SCpntp1; @@ -2482,80 +2605,203 @@ *SCpntp1 = NULL; SCpnt->result = result; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } if (SCpnt == *SCpntp2) *SCpntp2 = NULL; } +enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; + +/* + * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : our abort status + */ +static enum res_abort +acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) +{ + enum res_abort res = res_not_running; + + if (queue_removecmd(&host->queues.issue, SCpnt)) { + /* + * The command was on the issue queue, and has not been + * issued yet. We can remove the command from the queue, + * and acknowledge the abort. Neither the devices nor the + * interface know about the command. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on issue queue "); +//#endif + res = res_success; + } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) { + /* + * The command was on the disconnected queue. Simply + * acknowledge the abort condition, and when the target + * reconnects, we will give it an ABORT message. The + * target should then disconnect, and we will clear + * the busylun bit. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on disconnected queue "); +//#endif + res = res_success; + } else if (host->SCpnt == SCpnt) { + unsigned long flags; + +//#if (DEBUG & DEBUG_ABORT) + printk("executing "); +//#endif + + save_flags(flags); + cli(); + switch (host->scsi.phase) { + /* + * If the interface is idle, and the command is 'disconnectable', + * then it is the same as on the disconnected queue. We simply + * remove all traces of the command. When the target reconnects, + * we will give it an ABORT message since the command could not + * be found. When the target finally disconnects, we will clear + * the busylun bit. + */ + case PHASE_IDLE: + if (host->scsi.disconnectable) { + host->scsi.disconnectable = 0; + host->SCpnt = NULL; + res = res_success; + } + break; + + /* + * If the command has connected and done nothing further, + * simply force a disconnect. We also need to clear the + * busylun bit. + */ + case PHASE_CONNECTED: + sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT); + host->SCpnt = NULL; + res = res_success_clear; + break; + + default: + acornscsi_abortcmd(host, host->SCpnt->tag); + res = res_snooze; + } + restore_flags(flags); + } else if (host->origSCpnt == SCpnt) { + /* + * The command will be executed next, but a command + * is currently using the interface. This is similar to + * being on the issue queue, except the busylun bit has + * been set. + */ + host->origSCpnt = NULL; +//#if (DEBUG & DEBUG_ABORT) + printk("waiting for execution "); +//#endif + res = res_success_clear; + } else + printk("unknown "); + + return res; +} + /* - * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt) * Purpose : abort a command on this host * Params : SCpnt - command to abort * Returns : one of SCSI_ABORT_ macros */ -int acornscsi_abort (Scsi_Cmnd *SCpnt) +int acornscsi_abort(Scsi_Cmnd *SCpnt) { - AS_Host *host = (AS_Host *) SCpnt->host->hostdata; - int result = SCSI_ABORT_NOT_RUNNING; + AS_Host *host = (AS_Host *) SCpnt->host->hostdata; + int result; - host->stats.aborts += 1; + host->stats.aborts += 1; #if (DEBUG & DEBUG_ABORT) - { - int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + { + int asr, ssr; + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_abort: "); - print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); - } + printk(KERN_WARNING "acornscsi_abort: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog(host, SCpnt->target); + } #endif - if (queue_removecmd (&host->queues.issue, SCpnt)) { - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command on issue queue\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) { - printk ("scsi%d: command on disconnected queue\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->SCpnt == SCpnt) { - acornscsi_abortcmd (host, host->SCpnt->tag); - printk ("scsi%d: command executing\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->origSCpnt == SCpnt) { - host->origSCpnt = NULL; - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command waiting for execution\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } + printk("scsi%d: ", host->host->host_no); + + switch (acornscsi_do_abort(host, SCpnt)) { + /* + * We managed to find the command and cleared it out. + * We do not expect the command to be executing on the + * target, but we have set the busylun bit. + */ + case res_success_clear: +//#if (DEBUG & DEBUG_ABORT) + printk("clear "); +//#endif + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + /* + * We found the command, and cleared it out. Either + * the command is still known to be executing on the + * target, or the busylun bit is not set. + */ + case res_success: +//#if (DEBUG & DEBUG_ABORT) + printk("success\n"); +//#endif + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + result = SCSI_ABORT_SUCCESS; + break; - if (result == SCSI_ABORT_NOT_RUNNING) { - printk ("scsi%d: abort(): command not running\n", host->host->host_no); - acornscsi_dumplog (host, SCpnt->target); + /* + * We did find the command, but unfortunately we couldn't + * unhook it from ourselves. Wait some more, and if it + * still doesn't complete, reset the interface. + */ + case res_snooze: +//#if (DEBUG & DEBUG_ABORT) + printk("snooze\n"); +//#endif + result = SCSI_ABORT_SNOOZE; + break; + + /* + * The command could not be found (either because it completed, + * or it got dropped. + */ + default: + case res_not_running: + acornscsi_dumplog(host, SCpnt->target); #if (DEBUG & DEBUG_ABORT) - result = SCSI_ABORT_SNOOZE; + result = SCSI_ABORT_SNOOZE; +#else + result = SCSI_ABORT_NOT_RUNNING; #endif - } - return result; +//#if (DEBUG & DEBUG_ABORT) + printk("not running\n"); +//#endif + break; + } + + return result; } /* - * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Purpose : reset a command on this host/reset this host * Params : SCpnt - command causing reset * result - what type of reset to perform * Returns : one of SCSI_RESET_ macros */ -int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; Scsi_Cmnd *SCptr; @@ -2566,16 +2812,16 @@ { int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_reset: "); + printk(KERN_WARNING "acornscsi_reset: "); print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); + acornscsi_dumplog(host, SCpnt->target); } #endif - acornscsi_dma_stop (host); + acornscsi_dma_stop(host); SCptr = host->SCpnt; @@ -2583,19 +2829,19 @@ * do hard reset. This resets all devices on this host, and so we * must set the reset status on all commands. */ - acornscsi_resetcard (host); + acornscsi_resetcard(host); /* * report reset on commands current connected/disconnected */ - acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET); + acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET); - while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL) - acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET); + while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL) + acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET); if (SCpnt) { SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS; @@ -2607,19 +2853,19 @@ static struct expansion_card *ecs[MAX_ECARDS]; /* - * Prototype: void acornscsi_init (AS_Host *host) + * Prototype: void acornscsi_init(AS_Host *host) * Purpose : initialise the AS_Host structure for one interface & setup hardware * Params : host - host to setup */ static -void acornscsi_init (AS_Host *host) +void acornscsi_init(AS_Host *host) { - memset (&host->stats, 0, sizeof (host->stats)); - queue_initialise (&host->queues.issue); - queue_initialise (&host->queues.disconnected); - msgqueue_initialise (&host->scsi.msgs); + memset(&host->stats, 0, sizeof (host->stats)); + queue_initialise(&host->queues.issue); + queue_initialise(&host->queues.disconnected); + msgqueue_initialise(&host->scsi.msgs); - acornscsi_resetcard (host); + acornscsi_resetcard(host); } int acornscsi_detect(Scsi_Host_Template * tpnt) @@ -2634,7 +2880,7 @@ for (i = 0; i < MAX_ECARDS; i++) ecs[i] = NULL; - ecard_startfind (); + ecard_startfind(); while(1) { ecs[count] = ecard_find(0, acornscsi_cids); @@ -2642,37 +2888,37 @@ break; if (ecs[count]->irq == 0xff) { - printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); + printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); continue; } ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */ - instance = scsi_register (tpnt, sizeof(AS_Host)); + instance = scsi_register(tpnt, sizeof(AS_Host)); host = (AS_Host *)instance->hostdata; - instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0); instance->irq = ecs[count]->irq; host->host = instance; - host->scsi.io_port = ioaddr (instance->io_port + 0x800); + host->scsi.io_port = ioaddr(instance->io_port + 0x800); host->scsi.irq = instance->irq; host->card.io_intr = POD_SPACE(instance->io_port) + 0x800; host->card.io_page = POD_SPACE(instance->io_port) + 0xc00; - host->card.io_ram = ioaddr (instance->io_port); + host->card.io_ram = ioaddr(instance->io_port); host->dma.io_port = instance->io_port + 0xc00; host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800; ecs[count]->irqaddr = (char *)ioaddr(host->card.io_intr); ecs[count]->irqmask = 0x0a; - request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)"); - request_region (host->card.io_intr, 1, "acornscsi(intr)"); - request_region (host->card.io_page, 1, "acornscsi(page)"); + request_region(instance->io_port + 0x800, 2, "acornscsi(sbic)"); + request_region(host->card.io_intr, 1, "acornscsi(intr)"); + request_region(host->card.io_page, 1, "acornscsi(page)"); #ifdef USE_DMAC - request_region (host->dma.io_port, 256, "acornscsi(dmac)"); + request_region(host->dma.io_port, 256, "acornscsi(dmac)"); #endif - request_region (instance->io_port, 2048, "acornscsi(ram)"); + request_region(instance->io_port, 2048, "acornscsi(ram)"); if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n", @@ -2680,7 +2926,7 @@ host->scsi.irq = NO_IRQ; } - acornscsi_init (host); + acornscsi_init(host); ++count; } @@ -2688,12 +2934,12 @@ } /* - * Function: int acornscsi_release (struct Scsi_Host *host) + * Function: int acornscsi_release(struct Scsi_Host *host) * Purpose : release all resources used by this adapter * Params : host - driver structure to release * Returns : nothing of any consequence */ -int acornscsi_release (struct Scsi_Host *instance) +int acornscsi_release(struct Scsi_Host *instance) { AS_Host *host = (AS_Host *)instance->hostdata; int i; @@ -2701,30 +2947,30 @@ /* * Put card into RESET state */ - outb (0x80, host->card.io_page); + outb(0x80, host->card.io_page); if (host->scsi.irq != NO_IRQ) - free_irq (host->scsi.irq, host); + free_irq(host->scsi.irq, host); - release_region (instance->io_port + 0x800, 2); - release_region (host->card.io_intr, 1); - release_region (host->card.io_page, 1); - release_region (host->dma.io_port, 256); - release_region (instance->io_port, 2048); + release_region(instance->io_port + 0x800, 2); + release_region(host->card.io_intr, 1); + release_region(host->card.io_page, 1); + release_region(host->dma.io_port, 256); + release_region(instance->io_port, 2048); for (i = 0; i < MAX_ECARDS; i++) - if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) - ecard_release (ecs[i]); + if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0)) + ecard_release(ecs[i]); - msgqueue_free (&host->scsi.msgs); - queue_free (&host->queues.disconnected); - queue_free (&host->queues.issue); + msgqueue_free(&host->scsi.msgs); + queue_free(&host->queues.disconnected); + queue_free(&host->queues.issue); return 0; } /* - * Function: char *acornscsi_info (struct Scsi_Host *host) + * Function: char *acornscsi_info(struct Scsi_Host *host) * Purpose : return a string describing this interface * Params : host - host to give information on * Returns : a constant string @@ -2736,7 +2982,7 @@ p = string; - p += sprintf (string, "%s at port %lX irq %d v%d.%d.%d" + p += sprintf(string, "%s at port %X irq %d v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2772,7 +3018,7 @@ host = (AS_Host *)instance->hostdata; - p += sprintf (p, "AcornSCSI driver v%d.%d.%d" + p += sprintf(p, "AcornSCSI driver v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2787,14 +3033,14 @@ #endif "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); - p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", + p += sprintf(p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", host->scsi.io_port, host->scsi.irq); #ifdef USE_DMAC - p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", + p += sprintf(p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", host->dma.io_port, host->scsi.irq); #endif - p += sprintf (p, "Statistics:\n" + p += sprintf(p, "Statistics:\n" "Queued commands: %-10u Issued commands: %-10u\n" "Done commands : %-10u Reads : %-10u\n" "Writes : %-10u Others : %-10u\n" @@ -2809,47 +3055,47 @@ for (devidx = 0; devidx < 9; devidx ++) { unsigned int statptr, prev; - p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); - statptr = status_ptr[devidx] - 10; + p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); + statptr = host->status_ptr[devidx] - 10; if ((signed int)statptr < 0) - statptr += 16; + statptr += STATUS_BUFFER_SIZE; - prev = status[devidx][statptr].when; + prev = host->status[devidx][statptr].when; - for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) { - if (status[devidx][statptr].when) { - p += sprintf (p, "%c%02X:%02X+%2ld", - status[devidx][statptr].irq ? '-' : ' ', - status[devidx][statptr].ph, - status[devidx][statptr].ssr, - (status[devidx][statptr].when - prev) < 100 ? - (status[devidx][statptr].when - prev) : 99); - prev = status[devidx][statptr].when; + for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + if (host->status[devidx][statptr].when) { + p += sprintf(p, "%c%02X:%02X+%2ld", + host->status[devidx][statptr].irq ? '-' : ' ', + host->status[devidx][statptr].ph, + host->status[devidx][statptr].ssr, + (host->status[devidx][statptr].when - prev) < 100 ? + (host->status[devidx][statptr].when - prev) : 99); + prev = host->status[devidx][statptr].when; } } } - p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); + p += sprintf(p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); for (scd = instance->host_queue; scd; scd = scd->next) { int len; - proc_print_scsidevice (scd, p, &len, 0); + proc_print_scsidevice(scd, p, &len, 0); p += len; - p += sprintf (p, "Extensions: "); + p += sprintf(p, "Extensions: "); if (scd->tagged_supported) - p += sprintf (p, "TAG %sabled [%d] ", + p += sprintf(p, "TAG %sabled [%d] ", scd->tagged_queue ? "en" : "dis", scd->current_tag); - p += sprintf (p, "\nTransfers: "); + p += sprintf(p, "\nTransfers: "); if (host->device[scd->id].sync_xfer & 15) - p += sprintf (p, "sync, offset %d, %d ns\n", + p += sprintf(p, "sync, offset %d, %d ns\n", host->device[scd->id].sync_xfer & 15, - acornscsi_getperiod (host->device[scd->id].sync_xfer)); + acornscsi_getperiod(host->device[scd->id].sync_xfer)); else - p += sprintf (p, "async\n"); + p += sprintf(p, "async\n"); pos = p - buffer; if (pos + begin < offset) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/acornscsi.h linux.ac/drivers/acorn/scsi/acornscsi.h --- linux.vanilla/drivers/acorn/scsi/acornscsi.h Sun Nov 8 15:08:18 1998 +++ linux.ac/drivers/acorn/scsi/acornscsi.h Sun Feb 7 19:24:48 1999 @@ -291,6 +291,27 @@ #include "queue.h" #include "msgqueue.h" +#define STATUS_BUFFER_SIZE 32 +/* + * This is used to dump the previous states of the SBIC + */ +struct status_entry { + unsigned long when; + unsigned char ssr; + unsigned char ph; + unsigned char irq; + unsigned char unused; +}; + +#define ADD_STATUS(_q,_ssr,_ph,_irq) \ +({ \ + host->status[(_q)][host->status_ptr[(_q)]].when = jiffies; \ + host->status[(_q)][host->status_ptr[(_q)]].ssr = (_ssr); \ + host->status[(_q)][host->status_ptr[(_q)]].ph = (_ph); \ + host->status[(_q)][host->status_ptr[(_q)]].irq = (_irq); \ + host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \ +}) + /* * AcornSCSI host specific data */ @@ -303,7 +324,7 @@ /* driver information */ struct { unsigned int io_port; /* base address of WD33C93 */ - unsigned char irq; /* interrupt */ + unsigned int irq; /* interrupt */ phase_t phase; /* current phase */ struct { @@ -361,6 +382,7 @@ char *xfer_ptr; /* pointer to area */ unsigned char xfer_required:1; /* set if we need to transfer something */ unsigned char xfer_setup:1; /* set if DMA is setup */ + unsigned char xfer_done:1; /* set if DMA reached end of BH list */ } dma; /* card info */ @@ -370,6 +392,9 @@ unsigned int io_ram; /* base address of RAM access */ unsigned char page_reg; /* current setting of page reg */ } card; + + unsigned char status_ptr[9]; + struct status_entry status[9][STATUS_BUFFER_SIZE]; } AS_Host; #endif /* ndef HOSTS_C */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/arxescsi.c linux.ac/drivers/acorn/scsi/arxescsi.c --- linux.vanilla/drivers/acorn/scsi/arxescsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/scsi/arxescsi.c Fri Mar 5 23:25:40 1999 @@ -0,0 +1,419 @@ +/* + * linux/arch/arm/drivers/scsi/cumana_2.c + * + * Copyright (C) 1997,1998 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. + * 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing + * by Stefan Hanske + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sd.h" +#include "hosts.h" +#include "arxescsi.h" +#include "fas216.h" + +/* Hmm - this should go somewhere else */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +/* Configuration */ +#define ARXESCSI_XTALFREQ 24 +#define ARXESCSI_ASYNC_PERIOD 200 +#define ARXESCSI_SYNC_DEPTH 0 + +/* + * List of devices that the driver will recognise + */ +#define ARXESCSI_LIST { MANU_ARXE, PROD_ARXE_SCSI } + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 2 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_arxescsi = { + PROC_SCSI_QLOGICFAS, 6, "arxescsi", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* + * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) + * Purpose : initialises DMA/PIO + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * min_type - minimum DMA support that we must have for this transfer + * Returns : 0 if we should not set CMD_WITHDMA for transfer info command + */ +static fasdmatype_t +arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, fasdmatype_t min_type) +{ + /* + * We don't do real DMA + */ + return fasdma_pseudo; +} + + + +/* Faster transfer routines, written by SH to speed up the loops */ + +static __inline__ unsigned char getb(unsigned int address, unsigned int reg) +{ + unsigned char value; + + __asm__ __volatile__( + "ldrb %0, [%1, %2, lsl #5]" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ unsigned int getw(unsigned int address, unsigned int reg) +{ + unsigned int value; + + __asm__ __volatile__( + "ldr %0, [%1, %2, lsl #5]\n\t" + "mov %0, %0, lsl #16\n\t" + "mov %0, %0, lsr #16" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value) +{ + __asm__ __volatile__( + "mov %0, %0, lsl #16\n\t" + "str %0, [%1, %2, lsl #5]" + : + : "r" (value), "r" (address), "r" (reg) ); +} + + +/* + * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer) + * Purpose : handles pseudo DMA + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * transfer - minimum number of bytes we expect to transfer + */ +void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + unsigned int length, io, error=0; + unsigned char *addr; + + length = SCp->this_residual; + addr = SCp->ptr; + io = __ioaddr(host->io_port); + + if (direction == DMA_OUT) { + while (length > 0) { + unsigned long word; + + + word = *addr | *(addr + 1) << 8; + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + putw(io, 16, word); + if (length > 1) { + addr += 2; + length -= 2; + } else { + addr += 1; + length -= 1; + } + } + } + else { + if (transfer && (transfer & 255)) { + while (length >= 256) { + if (getb(io, 4) & STAT_INT) { + error=1; + break; + } + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + insw(info->dmaarea, addr, 256 >> 1); + addr += 256; + length -= 256; + } + } + + if (!(error)) + while (length > 0) { + unsigned long word; + + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + word = getw(io, 16); + *addr++ = word; + if (--length > 0) { + *addr++ = word >> 8; + length --; + } + } + } +} + +/* + * Function: int arxescsi_dma_stop(host, SCpnt) + * Purpose : stops DMA/PIO + * Params : host - host + * SCpnt - command + */ +static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) +{ + /* + * no DMA to stop + */ +} + +/* + * Function: int arxescsi_detect(Scsi_Host_Template * tpnt) + * Purpose : initialises ARXE SCSI driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int arxescsi_detect(Scsi_Host_Template *tpnt) +{ + static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *host; + + tpnt->proc_dir = &proc_scsi_arxescsi; + memset(ecs, 0, sizeof (ecs)); + + ecard_startfind(); + + while (1) { + ARXEScsi_Info *info; + + ecs[count] = ecard_find(0, arxescsi_cids); + if (!ecs[count]) + break; + + ecard_claim(ecs[count]); + + host = scsi_register(tpnt, sizeof (ARXEScsi_Info)); + if (!host) { + ecard_release(ecs[count]); + break; + } + + host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0) + 0x0800; + host->irq = NO_IRQ; + host->dma_channel = NO_DMA; + host->can_queue = 0; /* no command queueing */ + info = (ARXEScsi_Info *)host->hostdata; + + info->info.scsi.io_port = host->io_port; + info->info.scsi.irq = host->irq; + info->info.scsi.io_shift = 3; + info->info.ifcfg.clockrate = ARXESCSI_XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.ifcfg.asyncperiod = ARXESCSI_ASYNC_PERIOD; + info->info.ifcfg.sync_max_depth = ARXESCSI_SYNC_DEPTH; + info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.disconnect_ok = 0; + info->info.ifcfg.wide_max_size = 0; + info->info.dma.setup = arxescsi_dma_setup; + info->info.dma.pseudo = arxescsi_dma_pseudo; + info->info.dma.stop = arxescsi_dma_stop; + info->dmaarea = host->io_port + 128; + info->cstatus = host->io_port + 384; + + ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port); + ecs[count]->irqmask = CSTATUS_IRQ; + + request_region(host->io_port , 120, "arxescsi-fas"); + request_region(host->io_port + 128, 384, "arxescsi-dma"); + + printk("scsi%d: Has no interrupts - using polling mode\n", + host->host_no); + + fas216_init(host); + ++count; + } + return count; +} + +/* + * Function: int arxescsi_release(struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int arxescsi_release(struct Scsi_Host *host) +{ + int i; + + fas216_release(host); + + release_region(host->io_port, 120); + release_region(host->io_port + 128, 384); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && host->io_port == (ecard_address(ecs[i], ECARD_MEMC, 0) + 0x0800)) + ecard_release(ecs[i]); + return 0; +} + +/* + * Function: const char *arxescsi_info(struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *arxescsi_info(struct Scsi_Host *host) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf(string, "%s at port %X irq %d v%d.%d.%d scsi %s", + host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* + * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int arxescsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin, first; + struct Scsi_Host *host = scsi_hostlist; + ARXEScsi_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (ARXEScsi_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf(buffer, + "ARXE 16-bit SCSI driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf(buffer + pos, + "Address: %08X IRQ : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, info->info.scsi.type); + + pos += sprintf(buffer+pos, + "Queued commands: %-10ld Issued commands: %-10ld\n" + "Done commands : %-10ld Reads : %-10ld\n" + "Writes : %-10ld Others : %-10ld\n" + "Disconnects : %-10ld Aborts : %-10ld\n" + "Resets : %-10ld\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + first = 1; + for (scd = scsi_devices; scd; scd = scd->next) { + if (scd->host == host) { + int len; + + if (first) { + pos += sprintf(buffer+pos, "\nAttached devices:\n"); + first = 0; + } + + proc_print_scsidevice(scd, buffer, &len, pos); + pos += len; + pos += sprintf(buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf(buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf(buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = ARXEScsi; + +#include "scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/arxescsi.h linux.ac/drivers/acorn/scsi/arxescsi.h --- linux.vanilla/drivers/acorn/scsi/arxescsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/scsi/arxescsi.h Fri Mar 5 23:13:19 1999 @@ -0,0 +1,82 @@ +/* + * ARXE SCSI card driver + * + * Copyright (C) 1997 Russell King + * Changes to support ARXE 16-bit SCSI card by Stefan Hanske + */ +#ifndef ARXE_SCSI_H +#define ARXE_SCSI_H + +#define MANU_ARXE 0x0041 +#define PROD_ARXE_SCSI 0x00be + +extern int arxescsi_detect (Scsi_Host_Template *); +extern int arxescsi_release (struct Scsi_Host *); +extern const char *arxescsi_info (struct Scsi_Host *); +extern int arxescsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#ifndef HOSTS_C +#include "fas216.h" +#endif + +#define ARXEScsi { \ + NULL, \ + NULL, \ + NULL, \ + arxescsi_proc_info, \ + "ARXE SCSI card", \ + arxescsi_detect, /* detect */ \ + arxescsi_release, /* release */ \ + arxescsi_info, /* info */ \ + fas216_command, /* command */ \ + fas216_queue_command, /* queuecommand */ \ + fas216_abort, /* abort */ \ + fas216_reset, /* reset */ \ + NULL, \ + scsicam_bios_param, /* biosparam */ \ + CAN_QUEUE, /* can queue */ \ + SCSI_ID, /* scsi host id */ \ + SG_ALL, /* sg_tablesize */ \ + CAN_QUEUE, /* cmd per lun */ \ + 0, /* number of boards */ \ + 0, /* unchecked isa dma */ \ + DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ + unsigned int cstatus; /* card status register */ + unsigned int dmaarea; /* Pseudo DMA area */ +} ARXEScsi_Info; + +#define CSTATUS_IRQ (1 << 0) +#define CSTATUS_DRQ (1 << 0) + +#endif /* HOSTS_C */ + +#endif /* ARXE_SCSI_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/cumana_2.c linux.ac/drivers/acorn/scsi/cumana_2.c --- linux.vanilla/drivers/acorn/scsi/cumana_2.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/cumana_2.c Sun Jan 10 22:36:51 1999 @@ -4,12 +4,12 @@ * Copyright (C) 1997-1998 Russell King * * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 30-08-1997 RMK 0.0.0 Created, READONLY version. + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 02-05-1998 RMK 0.0.2 Updated & added DMA support + * 02-05-1998 RMK 0.0.2 Updated & added DMA support. * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth + * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. */ #include @@ -117,6 +117,8 @@ cumanascsi_2_irqenable, cumanascsi_2_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -364,6 +366,7 @@ info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = cumanascsi_2_dma_setup; info->info.dma.pseudo = cumanascsi_2_dma_pseudo; info->info.dma.stop = cumanascsi_2_dma_stop; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/eesox.c linux.ac/drivers/acorn/scsi/eesox.c --- linux.vanilla/drivers/acorn/scsi/eesox.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/eesox.c Sun Feb 7 19:25:38 1999 @@ -38,9 +38,6 @@ #include "../../scsi/hosts.h" #include "eesox.h" -#define NO_IRQ 255 -#define NO_DMA 255 - /* Configuration */ #define EESOX_XTALFREQ 40 #define EESOX_ASYNC_PERIOD 200 @@ -123,6 +120,8 @@ eesoxscsi_irqenable, eesoxscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -379,6 +378,7 @@ info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = eesoxscsi_dma_setup; info->info.dma.pseudo = eesoxscsi_dma_pseudo; info->info.dma.stop = eesoxscsi_dma_stop; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/fas216.c linux.ac/drivers/acorn/scsi/fas216.c --- linux.vanilla/drivers/acorn/scsi/fas216.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/scsi/fas216.c Sun Mar 7 11:54:56 1999 @@ -24,9 +24,9 @@ * 02-05-1998 RMK Added extra checks in fas216_reset * 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h + * 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT * * Todo: - * - tighten up the MESSAGE_REJECT support. * - allow individual devices to enable sync xfers. */ @@ -57,7 +57,7 @@ #define VER_MAJOR 0 #define VER_MINOR 0 -#define VER_PATCH 4 +#define VER_PATCH 5 #define SCSI2_TAG @@ -86,6 +86,8 @@ */ #define SCSI2_SYNC +#define SCSI2_WIDE + #undef DEBUG_CONNECT #undef DEBUG_BUSSERVICE #undef DEBUG_FUNCTIONDONE @@ -132,8 +134,8 @@ printk(" SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n", info->scsi.SCp.ptr, info->scsi.SCp.this_residual, info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual); - printk(" msgs async_stp=%X last_message=%X disconnectable=%d aborting=%d }\n", - info->scsi.async_stp, info->scsi.last_message, + printk(" msgs async_stp=%X disconnectable=%d aborting=%d }\n", + info->scsi.async_stp, info->scsi.disconnectable, info->scsi.aborting); printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n" " disconnects=%X aborts=%X resets=%X }\n", @@ -144,10 +146,10 @@ info->ifcfg.clockrate, info->ifcfg.select_timeout, info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth); for (i = 0; i < 8; i++) { - printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X negstate=%X }\n", + printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n", i, info->busyluns[i], i, info->device[i].disconnect_ok, info->device[i].stp, - info->device[i].sof, info->device[i].negstate); + info->device[i].sof, info->device[i].sync_state); } printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", info->dma.transfer_type, info->dma.setup, @@ -192,19 +194,19 @@ static const char *fas216_drv_phase(FAS216_Info *info) { switch (info->scsi.phase) { - case PHASE_IDLE: return "idle"; - case PHASE_SELECTION: return "selection"; - case PHASE_MESSAGESENT: return "message sent"; - case PHASE_RECONNECTED: return "reconnected"; - case PHASE_DATAOUT: return "data out"; - case PHASE_DATAIN: return "data in"; - case PHASE_MSGOUT: return "message out"; - case PHASE_MSGIN: return "message in"; - case PHASE_AFTERMSGOUT: return "after message out"; - case PHASE_STATUS: return "status"; - case PHASE_DISCONNECT: return "disconnect"; - case PHASE_DONE: return "done"; - default: return "???"; + case PHASE_IDLE: return "idle"; + case PHASE_SELECTION: return "selection"; + case PHASE_COMMAND: return "command"; + case PHASE_RECONNECTED: return "reconnected"; + case PHASE_DATAOUT: return "data out"; + case PHASE_DATAIN: return "data in"; + case PHASE_MSGIN: return "message in"; + case PHASE_MSGIN_DISCONNECT: return "disconnect"; + case PHASE_MSGOUT_EXPECT: return "expect message out"; + case PHASE_MSGOUT: return "message out"; + case PHASE_STATUS: return "status"; + case PHASE_DONE: return "done"; + default: return "???"; } } @@ -262,6 +264,37 @@ return clock; } +/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos) + * Purpose : retrieve a last message from the list, using position in fifo + * Params : info - interface to search + * : pos - current fifo position + */ +static inline unsigned short +fas216_get_last_msg(FAS216_Info *info, int pos) +{ + unsigned short packed_msg = NOP; + struct message *msg; + int msgnr = 0; + + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + if (pos >= msg->fifo) + break; + } + + if (msg) { + if (msg->msg[0] == EXTENDED_MESSAGE) + packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8; + else + packed_msg = msg->msg[0]; + } + +#ifdef DEBUG_MESSAGES + printk("Message: %04X found at position %02X\n", + packed_msg, pos); +#endif + return packed_msg; +} + /* Function: int fas216_syncperiod(FAS216_Info *info, int ns) * Purpose : Calculate value to be loaded into the STP register * for a given period in ns @@ -303,6 +336,240 @@ outb(info->scsi.cfg[2], REG_CNTL3(info)); } +/* Synchronous transfer support + * + * Note: The SCSI II r10 spec says (5.6.12): + * + * (2) Due to historical problems with early host adapters that could + * not accept an SDTR message, some targets may not initiate synchronous + * negotiation after a power cycle as required by this standard. Host + * adapters that support synchronous mode may avoid the ensuing failure + * modes when the target is independently power cycled by initiating a + * synchronous negotiation on each REQUEST SENSE and INQUIRY command. + * This approach increases the SCSI bus overhead and is not recommended + * for new implementations. The correct method is to respond to an + * SDTR message with a MESSAGE REJECT message if the either the + * initiator or target devices does not support synchronous transfers + * or does not want to negotiate for synchronous transfers at the time. + * Using the correct method assures compatibility with wide data + * transfers and future enhancements. + * + * We will always initiate a synchronous transfer negociation request on + * every INQUIRY or REQUEST SENSE message, unless the target itself has + * at some point performed a synchronous transfer negociation request, or + * we have synchronous transfers disabled for this device. + */ + +/* Function: void fas216_handlesync(FAS216_Info *info, char *msg) + * Purpose : Handle a synchronous transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static void +fas216_handlesync(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { sync, async, none, reject } res = none; + +#ifdef SCSI2_SYNC + switch (msg[0]) { + case MESSAGE_REJECT: + /* Synchronous transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of synchronous + * data transfers shall not respond to an SDTR + * message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we disable + * negociation for this device. + */ + if (dev->sync_state == neg_inprogress) { + dev->sync_state = neg_invalid; + res = async; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->sync_state) { + /* We don't accept synchronous transfer requests. + * Respond with a MESSAGE_REJECT to prevent a + * synchronous transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a synchronous transfer, + * but the device sent us a negociation request. + * Honour the request by sending back a SDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[4] > info->ifcfg.sync_max_depth) + msg[4] = info->ifcfg.sync_max_depth; + if (msg[3] < 1000 / info->ifcfg.clockrate) + msg[3] = 1000 / info->ifcfg.clockrate; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + msg[3], msg[4]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + /* This is wrong. The agreement is not in effect + * until this message is accepted by the device + */ + dev->sync_state = neg_targcomplete; + res = sync; + break; + + /* We initiated the synchronous transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[4] <= info->ifcfg.sync_max_depth && + msg[3] >= 1000 / info->ifcfg.clockrate) { + dev->sync_state = neg_complete; + res = sync; + } + break; + } + } +#else + res = reject; +#endif + + switch (res) { + case sync: + dev->period = msg[3]; + dev->sof = msg[4]; + dev->stp = fas216_syncperiod(info, msg[3] * 4); + fas216_set_sync(info, info->SCpnt->target); + break; + + case reject: + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + case async: + dev->period = info->ifcfg.asyncperiod / 4; + dev->sof = 0; + dev->stp = info->scsi.async_stp; + fas216_set_sync(info, info->SCpnt->target); + break; + + case none: + break; + } +} + +/* Function: void fas216_handlewide(FAS216_Info *info, char *msg) + * Purpose : Handle a wide transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static void +fas216_handlewide(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { wide, bit8, none, reject } res = none; + +#ifdef SCSI2_WIDE + switch (msg[0]) { + case MESSAGE_REJECT: + /* Wide transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of wide + * data transfers shall not respond to a + * WDTR message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we never + * reattempt negociation for this device. + */ + if (dev->wide_state == neg_inprogress) { + dev->wide_state = neg_invalid; + res = bit8; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->wide_state) { + /* We don't accept wide data transfer requests. + * Respond with a MESSAGE REJECT to prevent a + * wide data transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a wide data transfer, + * but the device sent is a negociation request. + * Honour the request by sending back a WDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[3] > info->ifcfg.wide_max_size) + msg[3] = info->ifcfg.wide_max_size; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + msg[3]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + res = wide; + break; + + /* We initiated the wide data transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[3] <= info->ifcfg.wide_max_size) { + dev->wide_state = neg_complete; + res = wide; + } + break; + } + } +#else + res = reject; +#endif + + switch (res) { + case wide: + dev->wide_xfer = msg[3]; + break; + + case reject: + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + case bit8: + dev->wide_xfer = 0; + break; + + case none: + break; + } +} + /* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * Purpose : update data pointers after transfer suspended/paused * Params : info - interface's local pointer to update @@ -338,6 +605,9 @@ residual -= bytes_transferred; ptr += bytes_transferred; + if (residual == 0) + ptr = NULL; + info->scsi.SCp.ptr = ptr; info->scsi.SCp.this_residual = residual; } @@ -353,7 +623,7 @@ { unsigned int residual; char *ptr; - int correction; + int correction = 0; fas216_checkmagic(info, "fas216_pio"); @@ -361,23 +631,24 @@ ptr = info->scsi.SCp.ptr; if (direction == DMA_OUT) { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { +// while (residual > 0) { +// if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { outb(*ptr++, REG_FF(info)); residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = inb(REG_CFIS(info)) & CFIS_CF; +// } +// if (inb(REG_STAT(info)) & STAT_INT) +// break; +// } +// correction = inb(REG_CFIS(info)) & CFIS_CF; } else { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { +// while (residual > 0) { +// if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { *ptr++ = inb(REG_FF(info)); residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = 0; +// } +// if (inb(REG_STAT(info)) & STAT_INT) +// break; +// } } ptr -= correction; @@ -549,10 +820,11 @@ switch (info->scsi.phase) { case PHASE_SELECTION: /* while selecting - no target */ + case PHASE_SELSTEPS: fas216_done(info, DID_NO_CONNECT); break; - case PHASE_DISCONNECT: /* message in - disconnecting */ + case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */ outb(CMD_ENABLESEL, REG_CMD(info)); info->scsi.disconnectable = 1; info->scsi.reconnected.tag = 0; @@ -564,8 +836,8 @@ fas216_done(info, DID_OK); break; - case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */ - if (info->scsi.last_message == ABORT) { + case PHASE_MSGOUT: /* message out - possible ABORT message */ + if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) { info->scsi.aborting = 0; fas216_done(info, DID_ABORT); break; @@ -592,14 +864,17 @@ fas216_checkmagic(info, "fas216_reselected_intr"); - if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) { + if ((info->scsi.phase == PHASE_SELECTION || + info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) { Scsi_Cmnd *SCpnt = info->SCpnt; info->origSCpnt = SCpnt; info->SCpnt = NULL; - if (info->device[SCpnt->target].negstate == syncneg_sent) - info->device[SCpnt->target].negstate = syncneg_start; + if (info->device[SCpnt->target].wide_state == neg_inprogress) + info->device[SCpnt->target].wide_state = neg_wait; + if (info->device[SCpnt->target].sync_state == neg_inprogress) + info->device[SCpnt->target].sync_state = neg_wait; } #ifdef DEBUG_CONNECT @@ -607,15 +882,14 @@ fas216_target(info), info->scsi.phase); #endif - msgqueue_flush(&info->scsi.msgs); - if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", info->host->host_no); outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -636,13 +910,14 @@ if (!ok) { /* - * Something went wrong - abort the command on - * the target. Should this be INITIATOR_ERROR ? + * Something went wrong - send an initiator error to + * the target. */ outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -672,17 +947,20 @@ if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg)) ok = 1; + msgqueue_flush(&info->scsi.msgs); if (ok) { info->scsi.phase = PHASE_RECONNECTED; outb(target, REG_SDID(info)); } else { /* - * Our command structure not found - abort the command on the target - * Should this be INITIATOR_ERROR ? + * Our command structure not found - abort the + * command on the target. Since we have no + * record of this command, we can't send + * an INITIATOR DETECTED ERROR message. */ outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + info->scsi.phase = PHASE_MSGOUT_EXPECT; } outb(CMD_MSGACCEPTED, REG_CMD(info)); } @@ -733,8 +1011,14 @@ } if (!info->SCpnt) { outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + msgqueue_flush(&info->scsi.msgs); +#if 0 + if (info->scsi.reconnected.tag) + msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag); + else +#endif + msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; } else { /* @@ -751,6 +1035,28 @@ #endif } +static unsigned char fas216_get_msg_byte(FAS216_Info *info) +{ + int tout; + + outb(CMD_MSGACCEPTED, REG_CMD(info)); + for (tout = 1000000; tout; tout --) + if (inb(REG_STAT(info)) & STAT_INT) + break; + + inb(REG_INST(info)); + + outb(CMD_TRANSFERINFO, REG_CMD(info)); + + for (tout = 1000000; tout; tout --) + if (inb(REG_STAT(info)) & STAT_INT) + break; + + inb(REG_INST(info)); + + return inb(REG_FF(info)); +} + /* Function: void fas216_message(FAS216_Info *info) * Purpose : handle a function done interrupt from FAS216 chip * Params : info - interface which caused function done interrupt @@ -765,34 +1071,10 @@ message[0] = inb(REG_FF(info)); if (message[0] == EXTENDED_MESSAGE) { - int tout; - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - - message[1] = inb(REG_FF(info)); - - for (msglen = 2; msglen < message[1] + 2; msglen++) { - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); + message[1] = fas216_get_msg_byte(info); - message[msglen] = inb(REG_FF(info)); - } + for (msglen = 2; msglen < message[1] + 2; msglen++) + message[msglen] = fas216_get_msg_byte(info); } #ifdef DEBUG_MESSAGES @@ -806,6 +1088,7 @@ printk("\n"); } #endif + if (info->scsi.phase == PHASE_RECONNECTED) { if (message[0] == SIMPLE_QUEUE_TAG) info->scsi.reconnected.tag = message[1]; @@ -815,14 +1098,22 @@ switch (message[0]) { case COMMAND_COMPLETE: - printk("fas216: command complete with no status in MESSAGE_IN?\n"); + printk(KERN_ERR "scsi%d.%c: command complete with no " + "status in MESSAGE_IN?\n", + info->host->host_no, fas216_target(info)); break; case SAVE_POINTERS: /* * Save current data pointer to SAVED data pointer + * SCSI II standard says that we must not acknowledge + * this until we have really saved pointers. + * NOTE: we DO NOT save the command nor status pointers + * as required by the SCSI II standard. These always + * point to the start of their respective areas. */ info->SCpnt->SCp = info->scsi.SCp; + info->SCpnt->SCp.sent_command = 0; #if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) printk("scsi%d.%c: save data pointers: [%p, %X]\n", info->host->host_no, fas216_target(info), @@ -843,13 +1134,27 @@ break; case DISCONNECT: - info->scsi.phase = PHASE_DISCONNECT; + info->scsi.phase = PHASE_MSGIN_DISCONNECT; break; case MESSAGE_REJECT: - printk("scsi%d.%c: reject, last message %04X\n", - info->host->host_no, fas216_target(info), - info->scsi.last_message); + switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) { + case EXTENDED_MESSAGE | EXTENDED_SDTR << 8: + fas216_handlesync(info, message); + break; + + case EXTENDED_MESSAGE | EXTENDED_WDTR << 8: + fas216_handlewide(info, message); + break; + + default: + printk("scsi%d.%c: reject, last message %04X\n", + info->host->host_no, fas216_target(info), + fas216_get_last_msg(info, info->scsi.msgin_fifo)); + } + break; + + case NOP: break; case SIMPLE_QUEUE_TAG: @@ -862,49 +1167,18 @@ case EXTENDED_MESSAGE: switch (message[2]) { case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ - switch (info->device[info->SCpnt->target].negstate) { - case syncneg_invalid: - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; - - default: - if (message[4] > info->ifcfg.sync_max_depth) - message[4] = info->ifcfg.sync_max_depth; - if (message[3] < 1000 / info->ifcfg.clockrate) - message[3] = 1000 / info->ifcfg.clockrate; - - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - message[3], message[4]); - info->scsi.phase = PHASE_MSGOUT; - case syncneg_sent: - info->device[info->SCpnt->target].negstate = syncneg_complete; - info->device[info->SCpnt->target].period = message[3]; - info->device[info->SCpnt->target].sof = message[4]; - info->device[info->SCpnt->target].stp = - fas216_syncperiod(info, message[3] * 4); - printk(KERN_NOTICE "scsi%d.%c: using synchronous transfer, offset %d, %d ns\n", - info->host->host_no, fas216_target(info), message[4], message[3] * 4); - fas216_set_sync(info, info->SCpnt->target); - break; - } + fas216_handlesync(info, message); break; case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ - /* We don't do wide transfers - reject message */ + fas216_handlewide(info, message); + break; + default: printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[2]); - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; + goto reject_message; } break; @@ -912,13 +1186,17 @@ printk("scsi%d.%c: unrecognised message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[0]); - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; + goto reject_message; } outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + +reject_message: + outb(CMD_SETATN, REG_CMD(info)); + outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; } /* Function: void fas216_send_command(FAS216_Info *info) @@ -935,201 +1213,46 @@ outb(CMD_FLUSHFIFO, REG_CMD(info)); /* load command */ - for (i = 0; i < info->SCpnt->cmd_len; i++) + for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) outb(info->SCpnt->cmnd[i], REG_FF(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); -} - -/* Function: int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in selection phase - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - */ -static int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_selection"); - - switch (stat & STAT_BUSMASK) { - case STAT_DATAOUT: /* data out phase */ - fas216_starttransfer(info, DMA_OUT, 1); - return 1; - - case STAT_DATAIN: /* data in phase */ - fas216_starttransfer(info, DMA_IN, 0); - return 1; - - case STAT_STATUS: /* status phase */ - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - - case STAT_MESGOUT:{ /* message out phase */ - char *msg; - int start = 1, msglen; - - /* load message bytes, but don't forget to miss the first - * byte! - */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - int i; - - for (i = start; i < msglen; i++) - outb(msg[i], REG_FF(info)); - start = 0; - } - outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_MESSAGESENT; - return 1; - } - default: - return 0; - } -} - -/* Function: int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service after the IDENTIFY message has been sent - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - */ -static int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messagesent"); - - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_FLUSHFIFO, REG_CMD(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - return 1; - - default: - return 0; - } -} - -/* Function: int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in a data in/out phase. - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_dataphase"); - - switch (stat & STAT_BUSMASK) { - case STAT_DATAIN: /* continue data in phase */ - if (info->scsi.phase == PHASE_DATAIN) { - fas216_starttransfer(info, DMA_IN, 0); - return 1; - } else - return 0; - - case STAT_DATAOUT: /* continue data out phase */ - if (info->scsi.phase == PHASE_DATAOUT) { - fas216_starttransfer(info, DMA_OUT, 0); - return 1; - } else - return 0; - - case STAT_STATUS: /* status in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_MESGIN: /* message in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - default: - return 0; - } + info->scsi.phase = PHASE_COMMAND; } -/* Function: int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in after a reconnection +/* Function: void fas216_send_messageout(FAS216_Info *info, int start) + * Purpose : handle bus service to send a message * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt * Note : We do not allow the device to change the data direction! */ -static int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) +static void fas216_send_messageout(FAS216_Info *info, int start) { - fas216_checkmagic(info, "fas216_busservice_reconnected"); - - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; + unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs); - case STAT_STATUS: - fas216_finish_reconnect(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_DATAOUT: /* data out phase */ - fas216_finish_reconnect(info); - fas216_starttransfer(info, DMA_OUT, 1); - return 1; + fas216_checkmagic(info, "fas216_send_messageout"); - case STAT_DATAIN: /* data in phase */ - fas216_finish_reconnect(info); - fas216_starttransfer(info, DMA_IN, 0); - return 1; + outb(CMD_FLUSHFIFO, REG_CMD(info)); - default: - return 0; - } -} + if (tot_msglen) { + struct message *msg; + int msgnr = 0; -/* Function: int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service to send a message - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messageout"); - - if ((stat & STAT_BUSMASK) != STAT_MESGOUT) { - printk("scsi%d.%c: didn't manage MESSAGE OUT phase\n", - info->host->host_no, fas216_target(info)); - return 0; - } else { - unsigned int msglen = msgqueue_msglength(&info->scsi.msgs); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + int i; - outb(CMD_FLUSHFIFO, REG_CMD(info)); + for (i = start; i < msg->length; i++) + outb(msg->msg[i], REG_FF(info)); - if (msglen == 0) - outb(NOP, REG_FF(info)); - else { - char *msg; + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); + start = 0; + } + } else + outb(NOP, REG_FF(info)); - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - int i; + outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); - } - } - outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_AFTERMSGOUT; - return 1; - } + info->scsi.phase = PHASE_MSGOUT; } /* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) @@ -1151,91 +1274,150 @@ case IS_COMPLETE: /* last action completed */ outb(CMD_NOP, REG_CMD(info)); - switch (info->scsi.phase) { - case PHASE_SELECTION: /* while selecting - selected target */ - if (!fas216_busservice_selection(info, stat)) - printk("scsi%d.%c: bus phase %s after connect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; - - case PHASE_MESSAGESENT: - if (!fas216_busservice_messagesent(info, stat)) - printk("scsi%d.%c: bus phase %s after message sent?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; +#define STATE(st,ph) ((ph) << 3 | (st)) + /* This table describes the legal SCSI state transitions, + * as described by the SCSI II spec. + */ + switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) { + /* Reselmsgin -> Data In */ + case STATE(STAT_DATAIN, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ + case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ + case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ + fas216_starttransfer(info, DMA_IN, 0); + return; - case PHASE_DATAIN: /* while transfering data in */ - case PHASE_DATAOUT: /* while transfering data out */ - if (!fas216_busservice_dataphase(info, stat)) - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), fas216_drv_phase(info)); - break; + case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ + fas216_starttransfer(info, DMA_OUT, 0); + return; - case PHASE_RECONNECTED: /* newly reconnected device */ - /* - * Command reconnected - if MESGIN, get message - it may be - * the tag. If not, get command out of the disconnected queue - */ - if (!fas216_busservice_reconnected(info, stat)) - printk("scsi%d.%c: bus phase %s after reconnect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; + /* Reselmsgin -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ + fas216_starttransfer(info, DMA_OUT, 1); + return; + + /* Reselmsgin -> Status */ + case STATE(STAT_STATUS, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + goto status; + case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ + case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ + fas216_stoptransfer(info); + case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ + case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ + case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ + case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */ + status: + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + info->scsi.phase = PHASE_STATUS; + return; + + case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ + case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ + fas216_stoptransfer(info); + case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ + case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + info->scsi.phase = PHASE_MSGIN; + return; - case PHASE_MSGIN: - case PHASE_AFTERMSGOUT: - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; + /* Reselmsgin -> Message In */ + case STATE(STAT_MESGIN, PHASE_RECONNECTED): + case STATE(STAT_MESGIN, PHASE_MSGIN): + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + return; - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - info->scsi.phase = PHASE_SELECTION; - break; + /* Reselmsgin -> Command */ + case STATE(STAT_COMMAND, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */ + case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */ + fas216_send_command(info); + info->scsi.phase = PHASE_COMMAND; + return; + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELECTION): + fas216_send_messageout(info, 1); + return; + /* Any -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): + fas216_send_messageout(info, 0); + return; + + /* Error recovery rules. + * These either attempt to abort or retry the operation. + * TODO: we need more of these + */ + case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */ + /* error - we've sent out all the command bytes + * we have. + * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS + * to include the command bytes sent for this to work + * correctly. + */ + printk(KERN_ERR "scsi%d.%c: " + "target trying to receive more command bytes\n", + info->host->host_no, fas216_target(info)); + outb(CMD_SETATN, REG_CMD(info)); + outb(15, REG_STCL(info)); + outb(0, REG_STCM(info)); + outb(0, REG_STCH(info)); + outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + return; - default: - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), - fas216_drv_phase(info)); - } - break; + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELSTEPS): + case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out -> Message Out */ + /* If we get another message out phase, this + * usually means some parity error occurred. + * Resend complete set of messages. If we have + * more than 1 byte to send, we need to assert + * ATN again. + */ + if (msgqueue_msglength(&info->scsi.msgs) > 1) + outb(CMD_SETATN, REG_CMD(info)); - case PHASE_MSGOUT: - if (!fas216_busservice_messageout(info, stat)) - printk("scsi%d.%c: bus phase %s instead of message out?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; + fas216_send_messageout(info, 0); + return; + } - case PHASE_DISCONNECT: - printk("scsi%d.%c: disconnect message received, but bus service %s?\n", + if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) { + printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n", info->host->host_no, fas216_target(info), fas216_bus_phase(stat)); + msgqueue_flush(&info->scsi.msgs); outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT; + info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; - - default: - printk("scsi%d.%c: internal phase %s for bus service?" - " What do I do with this?\n", - info->host->host_no, fas216_target(info), - fas216_drv_phase(info)); + return; } - break; + printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n", + info->host->host_no, fas216_target(info), + fas216_bus_phase(stat), + fas216_drv_phase(info)); + print_debug_list(); + return; default: printk("scsi%d.%c: bus service at step %d?\n", info->host->host_no, fas216_target(info), ssr & IS_BITS); + print_debug_list(); } } @@ -1269,6 +1451,7 @@ case PHASE_MSGIN: /* message in phase */ case PHASE_RECONNECTED: /* reconnected command */ if ((stat & STAT_BUSMASK) == STAT_MESGIN) { + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; fas216_message(info); break; } @@ -1300,10 +1483,11 @@ if (stat & STAT_INT) { if (isr & INST_BUSRESET) - printk("scsi%d.H: fas216: bus reset detected\n", instance->host_no); - else if (isr & INST_ILLEGALCMD) + printk("scsi%d.H: bus reset detected\n", instance->host_no); + else if (isr & INST_ILLEGALCMD) { printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); - else if (isr & INST_DISCONNECT) + fas216_dumpstate(info); + } else if (isr & INST_DISCONNECT) fas216_disconnect_intr(info); else if (isr & INST_RESELECTED) /* reselected */ fas216_reselected_intr(info); @@ -1327,7 +1511,7 @@ static void fas216_kick(FAS216_Info *info) { Scsi_Cmnd *SCpnt; - int i, msglen, from_queue = 0; + int tot_msglen, from_queue = 0; fas216_checkmagic(info, "fas216_kick"); @@ -1380,7 +1564,8 @@ if (from_queue) { #ifdef SCSI2_TAG - if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE && + SCpnt->cmnd[0] != INQUIRY) { SCpnt->device->current_tag += 1; if (SCpnt->device->current_tag == 0) SCpnt->device->current_tag = 1; @@ -1409,6 +1594,7 @@ /* build outgoing message bytes */ msgqueue_flush(&info->scsi.msgs); + if (info->device[SCpnt->target].disconnect_ok) msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun)); else @@ -1418,15 +1604,29 @@ if (SCpnt->tag) msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); - /* add synchronous negociation */ - if (SCpnt->cmnd[0] == REQUEST_SENSE && - info->device[SCpnt->target].negstate == syncneg_start) { - info->device[SCpnt->target].negstate = syncneg_sent; +#ifdef SCSI2_WIDE + if (info->device[SCpnt->target].wide_state == neg_wait) { + info->device[SCpnt->target].wide_state = neg_inprogress; + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + info->ifcfg.wide_max_size); + } +#ifdef SCSI2_SYNC + else +#endif +#endif +#ifdef SCSI2_SYNC + if ((info->device[SCpnt->target].sync_state == neg_wait || + info->device[SCpnt->target].sync_state == neg_complete) && + (SCpnt->cmnd[0] == REQUEST_SENSE || + SCpnt->cmnd[0] == INQUIRY)) { + info->device[SCpnt->target].sync_state = neg_inprogress; msgqueue_addmsg(&info->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, 1000 / info->ifcfg.clockrate, info->ifcfg.sync_max_depth); } +#endif /* following what the ESP driver says */ outb(0, REG_STCL(info)); @@ -1444,25 +1644,29 @@ /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); - msglen = msgqueue_msglength(&info->scsi.msgs); + tot_msglen = msgqueue_msglength(&info->scsi.msgs); - if (msglen == 1 || msglen == 3) { + if (tot_msglen == 1 || tot_msglen == 3) { /* * We have an easy message length to send... */ - char *msg; + struct message *msg; + int msgnr = 0, i; + + info->scsi.phase = PHASE_SELSTEPS; /* load message bytes */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + for (i = 0; i < msg->length; i++) + outb(msg->msg[i], REG_FF(info)); + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); } /* load command */ for (i = 0; i < SCpnt->cmd_len; i++) outb(SCpnt->cmnd[i], REG_FF(info)); - if (msglen == 1) + if (tot_msglen == 1) outb(CMD_SELECTATN, REG_CMD(info)); else outb(CMD_SELECTATN3, REG_CMD(info)); @@ -1471,17 +1675,11 @@ * We have an unusual number of message bytes to send. * Load first byte into fifo, and issue SELECT with ATN and * stop steps. - * Note: we only peek at t his message - we need the rest - * later on! */ - int thismsg; - char *msg = msgqueue_peeknextmsg(&info->scsi.msgs, &thismsg); + struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); - if (!msg || thismsg < 1) - printk(KERN_CRIT "scsi%d.%c: no message to send, but %d bytes\n", - info->host->host_no, fas216_target(info), msglen); - else - outb(msg[0], REG_FF(info)); + outb(msg->msg[0], REG_FF(info)); + msg->fifo = 1; outb(CMD_SELECTATNSTOP, REG_CMD(info)); } @@ -1525,11 +1723,15 @@ /* * In theory, this should not happen, but just in case it does. */ - if (info->scsi.SCp.ptr && result == DID_OK) { + if (info->scsi.SCp.ptr && + info->scsi.SCp.this_residual && + result == DID_OK) { switch (SCpnt->cmnd[0]) { case INQUIRY: case START_STOP: case READ_CAPACITY: + case TEST_UNIT_READY: + case MODE_SENSE: break; default: @@ -1579,6 +1781,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + unsigned long flags; fas216_checkmagic(info, "fas216_queue_command"); @@ -1618,27 +1821,18 @@ info->stats.queues += 1; SCpnt->tag = 0; - if (info->scsi.irq != NO_IRQ) { - unsigned long flags; - - /* add command into execute queue and let it complete under - * the drivers interrupts. - */ - if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { - SCpnt->result = DID_ERROR << 16; - done(SCpnt); - } - save_flags_cli(flags); - if (!info->SCpnt || info->scsi.disconnectable) - fas216_kick(info); - restore_flags(flags); - } else { - /* no interrupts to rely on - we'll have to handle the - * command ourselves. For now, we give up. - */ + /* add command into execute queue and let it complete under + * whatever scheme we're using. + */ + if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; done(SCpnt); } + save_flags_cli(flags); + if (!info->SCpnt || info->scsi.disconnectable) + fas216_kick(info); + restore_flags(flags); + return 0; } @@ -1672,15 +1866,28 @@ /* * This wastes time, since we can't return until the command is - * complete. We can't seep either since we may get re-entered! + * complete. We can't sleep either since we may get re-entered! * However, we must re-enable interrupts, or else we'll be * waiting forever. */ save_flags(flags); sti(); - while (!info->internal_done) - barrier(); + while (!info->internal_done) { + /* + * If we don't have an IRQ, then we must + * poll the card for it's interrupt, and + * use that to call this driver's interrupt + * routine. That way, we keep the command + * progressing. + */ + if (info->scsi.irq == NO_IRQ) { + sti(); + while (!(inb(REG_STAT(info)) & STAT_INT)); + cli(); + fas216_intr(info->host); + } + } restore_flags(flags); @@ -1819,7 +2026,7 @@ */ static void fas216_reset_state(FAS216_Info *info) { - syncneg_t negstate; + neg_t sync_state, wide_state; int i; fas216_checkmagic(info, "fas216_reset_state"); @@ -1833,26 +2040,37 @@ info->scsi.reconnected.lun = 0; info->scsi.reconnected.tag = 0; info->scsi.disconnectable = 0; - info->scsi.last_message = 0; info->scsi.aborting = 0; info->scsi.phase = PHASE_IDLE; - info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); + info->scsi.async_stp = + fas216_syncperiod(info, info->ifcfg.asyncperiod); + + if (info->ifcfg.wide_max_size == 0) + wide_state = neg_invalid; + else +#ifdef SCSI2_WIDE + wide_state = neg_wait; +#else + wide_state = neg_invalid; +#endif if (info->host->dma_channel == NO_DMA || !info->dma.setup) - negstate = syncneg_invalid; + sync_state = neg_invalid; else #ifdef SCSI2_SYNC - negstate = syncneg_start; + sync_state = neg_wait; #else - negstate = syncneg_invalid; + sync_state = neg_invalid; #endif for (i = 0; i < 8; i++) { - info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; - info->device[i].negstate = negstate; - info->device[i].period = info->ifcfg.asyncperiod / 4; - info->device[i].stp = info->scsi.async_stp; - info->device[i].sof = 0; + info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; + info->device[i].sync_state = sync_state; + info->device[i].wide_state = wide_state; + info->device[i].period = info->ifcfg.asyncperiod / 4; + info->device[i].stp = info->scsi.async_stp; + info->device[i].sof = 0; + info->device[i].wide_xfer = 0; } } @@ -2083,6 +2301,49 @@ return 0; } +int fas216_print_stats(FAS216_Info *info, char *buffer) +{ + return sprintf(buffer, + "Queued commands: %-10u Issued commands: %-10u\n" + "Done commands : %-10u Reads : %-10u\n" + "Writes : %-10u Others : %-10u\n" + "Disconnects : %-10u Aborts : %-10u\n" + "Resets : %-10u\n", + info->stats.queues, info->stats.removes, + info->stats.fins, info->stats.reads, + info->stats.writes, info->stats.miscs, + info->stats.disconnects, info->stats.aborts, + info->stats.resets); +} + +int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer) +{ + struct fas216_device *dev = &info->device[scd->id]; + int len = 0; + char *p; + + proc_print_scsidevice(scd, buffer, &len, 0); + p = buffer + len; + + p += sprintf(p, " Extensions: "); + + if (scd->tagged_supported) + p += sprintf(p, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + + p += sprintf(p, "\n Transfers : %d-bit ", + 8 << dev->wide_xfer); + + if (dev->sof) + p += sprintf(p, "sync offset %d, %d ns\n", + dev->sof, dev->period * 4); + else + p += sprintf(p, "async\n"); + + return p - buffer; +} + EXPORT_SYMBOL(fas216_init); EXPORT_SYMBOL(fas216_abort); EXPORT_SYMBOL(fas216_reset); @@ -2094,7 +2355,8 @@ EXPORT_SYMBOL(fas216_eh_device_reset); EXPORT_SYMBOL(fas216_eh_bus_reset); EXPORT_SYMBOL(fas216_eh_host_reset); - +EXPORT_SYMBOL(fas216_print_stats); +EXPORT_SYMBOL(fas216_print_device); #ifdef MODULE int init_module(void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/fas216.h linux.ac/drivers/acorn/scsi/fas216.h --- linux.vanilla/drivers/acorn/scsi/fas216.h Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/fas216.h Fri Mar 5 23:09:08 1999 @@ -40,6 +40,7 @@ #define CMD_TRANSFERINFO 0x10 #define CMD_INITCMDCOMPLETE 0x11 #define CMD_MSGACCEPTED 0x12 +#define CMD_PADBYTES 0x18 #define CMD_SETATN 0x1a #define CMD_RSETATN 0x1b @@ -171,15 +172,17 @@ typedef enum { PHASE_IDLE, /* we're not planning on doing anything */ PHASE_SELECTION, /* selecting a device */ + PHASE_SELSTEPS, /* selection with command steps */ + PHASE_COMMAND, /* command sent */ PHASE_MESSAGESENT, /* selected, and we're sending cmd */ PHASE_RECONNECTED, /* reconnected */ PHASE_DATAOUT, /* data out to device */ PHASE_DATAIN, /* data in from device */ PHASE_MSGIN, /* message in from device */ - PHASE_MSGOUT, /* message out to device */ - PHASE_AFTERMSGOUT, /* after message out phase */ + PHASE_MSGIN_DISCONNECT, /* disconnecting from bus */ + PHASE_MSGOUT, /* after message out phase */ + PHASE_MSGOUT_EXPECT, /* expecting message out */ PHASE_STATUS, /* status from device */ - PHASE_DISCONNECT, /* disconnecting from bus */ PHASE_DONE /* Command complete */ } phase_t; @@ -197,13 +200,15 @@ } fasdmatype_t; typedef enum { - syncneg_start, /* Negociate with device for Sync xfers */ - syncneg_sent, /* Sync Xfer negociation sent */ - syncneg_complete, /* Sync Xfer complete */ - syncneg_invalid /* Sync Xfer not supported */ -} syncneg_t; + neg_wait, /* Negociate with device */ + neg_inprogress, /* Negociation sent */ + neg_complete, /* Negociation complete */ + neg_targcomplete, /* Target completed negociation */ + neg_invalid /* Negociation not supported */ +} neg_t; #define MAGIC 0x441296bdUL +#define NR_MSGS 8 typedef struct { unsigned long magic_start; @@ -231,7 +236,7 @@ MsgQueue_t msgs; /* message queue for connected device */ unsigned int async_stp; /* Async transfer STP value */ - unsigned short last_message; /* last message to be sent */ + unsigned char msgin_fifo; /* bytes in fifo at time of message in */ unsigned char disconnectable:1; /* this command can be disconnected */ unsigned char aborting:1; /* aborting command */ @@ -255,6 +260,7 @@ unsigned char clockrate; /* clock rate of FAS device (MHz) */ unsigned char select_timeout; /* timeout (R5) */ unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ + unsigned char wide_max_size; /* Maximum wide transfer size */ unsigned char cntl3; /* Control Reg 3 */ unsigned int asyncperiod; /* Async transfer period (ns) */ unsigned int disconnect_ok:1; /* Disconnects allowed? */ @@ -267,12 +273,14 @@ } queues; /* per-device info */ - struct { + struct fas216_device { unsigned char disconnect_ok:1; /* device can disconnect */ - unsigned int period; /* sync xfer period (*4ns) */ + unsigned char period; /* sync xfer period in (*4ns) */ unsigned char stp; /* synchronous transfer period */ unsigned char sof; /* synchronous offset register */ - syncneg_t negstate; /* synchronous transfer mode */ + unsigned char wide_xfer; /* currently negociated wide transfer */ + neg_t sync_state; /* synchronous transfer mode */ + neg_t wide_state; /* wide transfer mode */ } device[8]; unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ @@ -339,6 +347,9 @@ * Returns : 0 on success */ extern int fas216_release (struct Scsi_Host *instance); + +extern int fas216_print_stats(FAS216_Info *info, char *buffer); +extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer); /* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) * Purpose : abort this command diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/msgqueue.c linux.ac/drivers/acorn/scsi/msgqueue.c --- linux.vanilla/drivers/acorn/scsi/msgqueue.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/msgqueue.c Sun Dec 13 23:23:01 1998 @@ -83,45 +83,25 @@ int length = 0; for (mq = msgq->qe; mq; mq = mq->next) - length += mq->length; + length += mq->msg.length; return length; } /* - * Function: char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return a message & its length + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) + * Purpose : return a message * Params : msgq - queue to obtain message from - * length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) +struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) { struct msgqueue_entry *mq; - if ((mq = msgq->qe) != NULL) { - msgq->qe = mq->next; - mqe_free(msgq, mq); - *length = mq->length; - } - - return mq ? mq->msg : NULL; -} - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) -{ - struct msgqueue_entry *mq = msgq->qe; - - *length = mq ? mq->length : 0; + for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--); - return mq ? mq->msg : NULL; + return mq ? &mq->msg : NULL; } /* @@ -143,10 +123,11 @@ va_start(ap, length); for (i = 0; i < length; i++) - mq->msg[i] = va_arg(ap, unsigned char); + mq->msg.msg[i] = va_arg(ap, unsigned char); va_end(ap); - mq->length = length; + mq->msg.length = length; + mq->msg.fifo = 0; mq->next = NULL; mqp = &msgq->qe; @@ -178,8 +159,7 @@ EXPORT_SYMBOL(msgqueue_initialise); EXPORT_SYMBOL(msgqueue_free); EXPORT_SYMBOL(msgqueue_msglength); -EXPORT_SYMBOL(msgqueue_getnextmsg); -EXPORT_SYMBOL(msgqueue_peeknextmsg); +EXPORT_SYMBOL(msgqueue_getmsg); EXPORT_SYMBOL(msgqueue_addmsg); EXPORT_SYMBOL(msgqueue_flush); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/msgqueue.h linux.ac/drivers/acorn/scsi/msgqueue.h --- linux.vanilla/drivers/acorn/scsi/msgqueue.h Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/msgqueue.h Sun Dec 13 23:18:27 1998 @@ -6,9 +6,14 @@ #ifndef MSGQUEUE_H #define MSGQUEUE_H -struct msgqueue_entry { +struct message { char msg[8]; int length; + int fifo; +}; + +struct msgqueue_entry { + struct message msg; struct msgqueue_entry *next; }; @@ -21,60 +26,51 @@ } MsgQueue_t; /* - * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Function: void msgqueue_initialise(MsgQueue_t *msgq) * Purpose : initialise a message queue * Params : msgq - queue to initialise */ -extern void msgqueue_initialise (MsgQueue_t *msgq); +extern void msgqueue_initialise(MsgQueue_t *msgq); /* - * Function: void msgqueue_free (MsgQueue_t *msgq) + * Function: void msgqueue_free(MsgQueue_t *msgq) * Purpose : free a queue * Params : msgq - queue to free */ -extern void msgqueue_free (MsgQueue_t *msgq); +extern void msgqueue_free(MsgQueue_t *msgq); /* - * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Function: int msgqueue_msglength(MsgQueue_t *msgq) * Purpose : calculate the total length of all messages on the message queue * Params : msgq - queue to examine * Returns : number of bytes of messages in queue */ -extern int msgqueue_msglength (MsgQueue_t *msgq); +extern int msgqueue_msglength(MsgQueue_t *msgq); /* - * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) * Purpose : return a message & its length * Params : msgq - queue to obtain message from - * length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length); - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -extern char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length); +extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno); /* - * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) * Purpose : add a message onto a message queue * Params : msgq - queue to add message on * length - length of message * ... - message bytes * Returns : != 0 if successful */ -extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...); +extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...); /* - * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Function: void msgqueue_flush(MsgQueue_t *msgq) * Purpose : flush all messages from message queue * Params : msgq - queue to flush */ -extern void msgqueue_flush (MsgQueue_t *msgq); +extern void msgqueue_flush(MsgQueue_t *msgq); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/powertec.c linux.ac/drivers/acorn/scsi/powertec.c --- linux.vanilla/drivers/acorn/scsi/powertec.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/powertec.c Sun Jan 10 22:37:14 1999 @@ -114,6 +114,8 @@ powertecscsi_irqenable, powertecscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -271,8 +273,9 @@ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; - info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.cntl3 = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; @@ -443,31 +446,12 @@ host->io_port, host->irq, host->dma_channel, info->info.scsi.type, info->control.terms ? "on" : "off"); - pos += sprintf(buffer+pos, - "Queued commands: %-10u Issued commands: %-10u\n" - "Done commands : %-10u Reads : %-10u\n" - "Writes : %-10u Others : %-10u\n" - "Disconnects : %-10u Aborts : %-10u\n" - "Resets : %-10u\n", - info->info.stats.queues, info->info.stats.removes, - info->info.stats.fins, info->info.stats.reads, - info->info.stats.writes, info->info.stats.miscs, - info->info.stats.disconnects, info->info.stats.aborts, - info->info.stats.resets); + pos += fas216_print_stats(&info->info, buffer + pos); - pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + pos += sprintf (buffer+pos, "\nAttached devices:\n"); for (scd = host->host_queue; scd; scd = scd->next) { - int len; - - proc_print_scsidevice (scd, buffer, &len, pos); - pos += len; - pos += sprintf (buffer+pos, "Extensions: "); - if (scd->tagged_supported) - pos += sprintf (buffer+pos, "TAG %sabled [%d] ", - scd->tagged_queue ? "en" : "dis", - scd->current_tag); - pos += sprintf (buffer+pos, "\n"); + pos += fas216_print_device(&info->info, scd, buffer + pos); if (pos + begin < offset) { begin += pos; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/queue.c linux.ac/drivers/acorn/scsi/queue.c --- linux.vanilla/drivers/acorn/scsi/queue.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/queue.c Sat Jan 9 14:41:24 1999 @@ -55,6 +55,7 @@ q->magic = QUEUE_MAGIC_FREE; q->SCpnt = NULL; } + q -= 1; q->next = NULL; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/rd.c linux.ac/drivers/block/rd.c --- linux.vanilla/drivers/block/rd.c Wed Mar 10 21:13:01 1999 +++ linux.ac/drivers/block/rd.c Wed Mar 24 18:13:02 1999 @@ -158,8 +158,6 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err; - if (!inode || !inode->i_rdev) return -EINVAL; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/Config.in linux.ac/drivers/cdrom/Config.in --- linux.vanilla/drivers/cdrom/Config.in Sun Nov 8 15:08:06 1998 +++ linux.ac/drivers/cdrom/Config.in Wed Mar 24 18:08:59 1999 @@ -14,6 +14,10 @@ fi fi tristate 'Mitsumi (standard) [no XA/Multisession] CDROM support' CONFIG_MCD +if [ "$CONFIG_MCD" != "n" ]; then + int 'MCD IRQ' CONFIG_MCD_IRQ 11 + hex 'MCD I/O base' CONFIG_MCD_BASE 300 +fi tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX tristate 'Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD tristate 'Philips/LMS CM206 CDROM support' CONFIG_CM206 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/mcd.c linux.ac/drivers/cdrom/mcd.c --- linux.vanilla/drivers/cdrom/mcd.c Sun Nov 8 15:10:10 1998 +++ linux.ac/drivers/cdrom/mcd.c Wed Mar 24 18:08:59 1999 @@ -67,6 +67,7 @@ a CD. November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen. + March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian). */ #include @@ -83,6 +84,7 @@ #include #include #include +#include /* #define REALLY_SLOW_IO */ #include @@ -155,8 +157,8 @@ int mitsumi_bug_93_wait = 0; #endif /* WORK_AROUND_MITSUMI_BUG_93 */ -static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */ -static int mcd_irq = MCD_INTR_NR; /* must directly follow mcd_port */ +static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */ +static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */ MODULE_PARM(mcd, "1-2i"); static int McdTimeout, McdTries; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/mcd.h linux.ac/drivers/cdrom/mcd.h --- linux.vanilla/drivers/cdrom/mcd.h Sun Nov 8 15:08:07 1998 +++ linux.ac/drivers/cdrom/mcd.h Wed Mar 24 18:08:59 1999 @@ -21,20 +21,6 @@ * */ -/* *** change this to set the I/O port address */ -#define MCD_BASE_ADDR 0x300 - -/* *** change this to set the interrupt number */ -#define MCD_INTR_NR 11 - -/* *** make the following line uncommented, if you're sure, - * *** all configuration is done */ - -/* #define I_WAS_HERE */ - - - - /* Increase this if you get lots of timeouts */ #define MCD_STATUS_DELAY 1000 @@ -121,8 +107,3 @@ struct msf trackTime; struct msf diskTime; }; - -#ifndef I_WAS_HERE -#warning You have not edited mcd.h -#warning Perhaps irq and i/o settings are wrong. -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.c linux.ac/drivers/char/bttv.c --- linux.vanilla/drivers/char/bttv.c Wed Mar 10 21:13:02 1999 +++ linux.ac/drivers/char/bttv.c Tue Mar 23 23:20:57 1999 @@ -3751,6 +3751,8 @@ #ifdef MODULE +EXPORT_NO_SYMBOLS; + int init_module(void) { #else diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bw-qcam.c linux.ac/drivers/char/bw-qcam.c --- linux.vanilla/drivers/char/bw-qcam.c Wed Mar 24 10:55:15 1999 +++ linux.ac/drivers/char/bw-qcam.c Tue Mar 16 19:03:37 1999 @@ -986,11 +986,41 @@ kfree(qcam); } +/* The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue */ +#ifdef MODULE +static char *parport[MAX_CAMS] = { NULL, }; +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s"); +#endif + #ifdef MODULE int init_module(void) { struct parport *port; - + int n; + if(parport[0] && strncmp(parport[0], "auto", 4)){ + /* user gave parport parameters */ + for(n=0; parport[n] && nnext){ + if(r!=port->number) + continue; + init_bwqcam(port); + break; + } + } + return (num_cams)?0:-ENODEV; + } + /* no parameter or "auto" */ for (port = parport_enumerate(); port; port=port->next) init_bwqcam(port); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/esp.c linux.ac/drivers/char/esp.c --- linux.vanilla/drivers/char/esp.c Sun Nov 8 15:10:12 1998 +++ linux.ac/drivers/char/esp.c Sun Nov 8 14:58:21 1998 @@ -2186,7 +2186,7 @@ if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_before(orig_jiffies + timeout, jiffies)) break; serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/misc.c linux.ac/drivers/char/misc.c --- linux.vanilla/drivers/char/misc.c Wed Mar 10 21:13:03 1999 +++ linux.ac/drivers/char/misc.c Wed Mar 24 18:13:03 1999 @@ -73,6 +73,7 @@ extern void watchdog_init(void); extern void wdt_init(void); extern void acq_init(void); +extern void dtlk_init(void); extern void pcwatchdog_init(void); extern int rtc_init(void); extern int rtc_DP8570A_init(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.c linux.ac/drivers/char/pc_keyb.c --- linux.vanilla/drivers/char/pc_keyb.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/char/pc_keyb.c Mon Mar 1 14:30:53 1999 @@ -38,7 +38,6 @@ #include #include #include -#include /* Some configuration switches are present in the include file... */ @@ -442,6 +441,7 @@ static unsigned char handle_kbd_event(void) { unsigned char status = inb(KBD_STATUS_REG); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; @@ -457,6 +457,13 @@ } status = inb(KBD_STATUS_REG); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/fc4/soc.c linux.ac/drivers/fc4/soc.c --- linux.vanilla/drivers/fc4/soc.c Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/fc4/soc.c Sat Mar 20 22:58:10 1999 @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/Makefile linux.ac/drivers/i2o/Makefile --- linux.vanilla/drivers/i2o/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/Makefile Thu Mar 25 18:06:53 1999 @@ -0,0 +1,68 @@ +# +# Makefile for the kernel I2O OSM. +# +# 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 inherited from the +# parent makefile. +# + +# +# Note : at this point, these files are compiled on all systems. +# In the future, some of these should be built conditionally. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + + +L_TARGET := i2o.a +L_OBJS := +M_OBJS := + +ifeq ($(CONFIG_I2O_PCI),y) +L_OBJS += i2o_pci.o +else + ifeq ($(CONFIG_I2O_PCI),m) + M_OBJS += i2o_pci.o + endif +endif + +ifeq ($(CONFIG_I2O),y) +LX_OBJS += i2o_core.o i2o_config.o +else + ifeq ($(CONFIG_I2O),m) + MX_OBJS += i2o_core.o i2o_config.o + endif +endif + +ifeq ($(CONFIG_I2O_BLOCK),y) +LX_OBJS += i2o_block.o +else + ifeq ($(CONFIG_I2O_BLOCK),m) + MX_OBJS += i2o_block.o + endif +endif + +ifeq ($(CONFIG_I2O_NET),y) +LX_OBJS += i2o_net.o +else + ifeq ($(CONFIG_I2O_NET),m) + MX_OBJS += i2o_net.o + endif +endif + +ifeq ($(CONFIG_I2O_SCSI),y) +LX_OBJS += i2o_scsi.o +else + ifeq ($(CONFIG_I2O_SCSI),m) + MX_OBJS += i2o_scsi.o + endif +endif + + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/README linux.ac/drivers/i2o/README --- linux.vanilla/drivers/i2o/README Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/README Sat Mar 13 23:42:13 1999 @@ -0,0 +1,64 @@ + + Linux I2O Support (c) Copyright 1999 Red Hat Software + + 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. + +AUTHORS (so far) +Alan Cox, Building Number Three Ltd + + +CREDITS + + This work was made possible by + +Red Hat Sofware + Funding for the project + +Symbios Logic (Now LSI) + Host adapters, hints, known to work platforms when I hit + compatibility problems + +BoxHill Corporation + Loan of initial FibreChannel disk array used for development work. + +STATUS: + +o The core setup works within limits. +o The scsi layer seems to almost work. I'm still chasing down the hang + bug. +o The block OSM is fairly minimal but does seem to work. + + +TO DO: + +General: +o Support multiple IOP's and tell them about each other +o Provide hidden address space if asked +o Long term message flow control +o PCI IOP's without interrupts are not supported yet +o Use UtilClaim messages. +o Push FAIL handling into the core +o DDM control interfaces for module load etc + +Block: +o Real error handler +o Multiple major numbers +o Read ahead and cache handling stuff. Talk to Ingo and people +o Power management +o Finish Media changers + +SCSI: +o Find the hang problem +o Find the right way to associate drives/luns/busses +o Fix the 8 disk images bug (lun in the table too) + +Net: +o Port the existing RCPCI work to the frame work or write a new + driver. This one is with the Finns + +Tape: +o Anyone seen anything implementing this ? + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_block.c linux.ac/drivers/i2o/i2o_block.c --- linux.vanilla/drivers/i2o/i2o_block.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_block.c Thu Mar 25 21:42:10 1999 @@ -0,0 +1,971 @@ +/* + * I2O block device driver. + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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 is an initial test release. Most of the good code was taken + * from the nbd driver by Pavel Machek, who in turn took some of it + * from loop.c. Isn't free software great for reusability 8) + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define MAJOR_NR I2O_MAJOR + +#include + +#define MAX_I2OB 16 + + +/* + * Some of these can be made smaller later + */ + +static int i2ob_blksizes[MAX_I2OB<<4]; +static int i2ob_hardsizes[MAX_I2OB<<4]; +static int i2ob_sizes[MAX_I2OB<<4]; +static int i2ob_media_change_flag[MAX_I2OB]; + +static int i2ob_context; + +static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED; + +struct i2ob_device +{ + struct i2o_controller *controller; + int tid; + int flags; + int refcnt; + struct request *head, *tail; + int done_flag; +}; + +/* + * Each I2O disk is one of these. + */ + +static struct i2ob_device i2ob_dev[MAX_I2OB<<4]; +static int i2ob_devices = 0; +static struct hd_struct i2ob[MAX_I2OB<<4]; +static struct gendisk i2ob_gendisk; /* Declared later */ + +static atomic_t queue_depth; /* For flow control later on */ + +#define DEBUG( s ) +/* #define DEBUG( s ) printk( s ) + */ + +static int i2ob_install_device(struct i2o_controller *, int, int); +static void i2ob_end_request(struct request *); +static void do_i2ob_request(void); + +/* + * Get a message + */ + +static u32 i2ob_get(struct i2ob_device *dev) +{ + struct i2o_controller *c=dev->controller; + return *c->post_port; +} + +/* + * Turn a Linux block request into an I2O block read/write. + */ + +static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 base, int unit) +{ + struct i2o_controller *c = dev->controller; + int tid = dev->tid; + u32 *msg; + u64 offset; + static int old_qd = 2; + + /* + * Build a message + */ + + msg = bus_to_virt(c->mem_offset + m); + + msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_8; + msg[2] = i2ob_context|(unit<<8); + msg[3] = (u32)req; /* 64bit issue again here */ + msg[5] = req->current_nr_sectors << 9; + + /* This can be optimised later - just want to be sure its right for + starters */ + offset = ((u64)(req->sector+base)) << 9; + msg[6] = offset & 0xFFFFFFFF; + msg[7] = (offset>>32); + msg[9] = virt_to_bus(req->buffer); + + if(req->cmd == READ) + { + msg[1] = I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid; + /* We don't yet do cache/readahead and other magic */ + msg[4] = 1<<16; + msg[8] = 0xD0000000|(req->current_nr_sectors << 9); + } + else if(req->cmd == WRITE) + { + msg[1] = I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid; + msg[4] = 1<<16; + msg[8] = 0xD4000000|(req->current_nr_sectors << 9); + } + +// printk("Send for %p\n", req); + + i2o_post_message(c,m); + atomic_inc(&queue_depth); + if(atomic_read(&queue_depth)>old_qd) + { + old_qd=atomic_read(&queue_depth); + printk("Depth now %d.\n", old_qd); + } + return 0; +} + +/* + * Remove a request from the _locked_ request list. We update both the + * list chain and if this is the last item the tail pointer. + */ + +static void i2ob_unhook_request(struct i2ob_device *dev, struct request *req) +{ + struct request **p = &dev->head; + struct request *nt = NULL; + static int crap = 0; + + while(*p!=NULL) + { + if(*p==req) + { + if(dev->tail==req) + dev->tail = nt; + *p=req->next; + return; + } + nt=*p; + p=&(nt->next); + } + if(!crap++) + printk("i2o_block: request queue corrupt!\n"); +} + +/* + * Request completion handler + */ + +static void i2ob_end_request(struct request *req) +{ + if (end_that_request_first( req, !req->errors, "i2o block" )) + return; + end_that_request_last( req ); +} + + +/* + * OSM reply handler. This gets all the message replies + */ + +static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +{ + struct request *req; + u8 st; + u32 *m = (u32 *)msg; + u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ + + if(m[0] & (1<<13)) + { + printk("IOP fail.\n"); + printk("From %d To %d Cmd %d.\n", + (m[1]>>12)&0xFFF, + m[1]&0xFFF, + m[1]>>24); + printk("Failure Code %d.\n", m[4]>>24); + if(m[4]&(1<<16)) + printk("Format error.\n"); + if(m[4]&(1<<17)) + printk("Path error.\n"); + if(m[4]&(1<<18)) + printk("Path State.\n"); + if(m[4]&(1<<18)) + printk("Congestion.\n"); + + m=(u32 *)bus_to_virt(m[7]); + printk("Failing message is %p.\n", m); + + /* We need to up the request failure count here and maybe + abort it */ + req=(struct request *)m[3]; + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + + } + else + { + if(m[2]&0x80000000) + { + int * ptr = (int *)m[3]; + if(m[4]>>24) + *ptr = -1; + else + *ptr = 1; + return; + } + /* + * Lets see what is cooking. We stuffed the + * request in the context. + */ + + req=(struct request *)m[3]; + st=m[4]>>24; + + if(st!=0) + { + printk(KERN_ERR "i2ob: error %08X\n", m[4]); + /* + * Now error out the request block + */ + req->errors++; + } + } + /* + * Dequeue the request. + */ + + spin_lock(&io_request_lock); + spin_lock(&i2ob_lock); + i2ob_unhook_request(&i2ob_dev[unit], req); + i2ob_end_request(req); + + /* + * We may be able to do more I/O + */ + + atomic_dec(&queue_depth); + do_i2ob_request(); + spin_unlock(&i2ob_lock); + spin_unlock(&io_request_lock); +} + +static struct i2o_handler i2o_block_handler = +{ + i2o_block_reply, + "I2O Block OSM", + 0 +}; + + +/* + * Flush all pending requests as errors. Must call with the queue + * locked. + */ + +static void i2ob_clear_queue(struct i2ob_device *dev) +{ + struct request *req; + + while (1) { + req = dev->tail; + if (!req) + return; + req->errors++; + i2ob_end_request(req); + + if (dev->tail == dev->head) + dev->head = NULL; + dev->tail = dev->tail->next; + } +} + +/* + * Write handling needs some work here, as we should issue multiple + * parallel writes. + */ + +static void do_i2ob_request(void) +{ + struct request *req; + int unit; + struct i2ob_device *dev; + u32 m; + + while (CURRENT) { + /* + * On an IRQ completion if there is an inactive + * request on the queue head it means it isnt yet + * ready to dispatch. + */ + if(CURRENT->rq_status == RQ_INACTIVE) + return; + + req = CURRENT; + unit = MINOR(req->rq_dev); + dev = &i2ob_dev[(unit&0xF0)]; + /* Get a message */ + m = i2ob_get(dev); + /* No messages -> punt + FIXME: if we have no messages, and there are no messages + we deadlock now. Need a timer/callback ?? */ + if(m==0xFFFFFFFF) + { + printk("i2ob: no messages!\n"); + break; + } + req->errors = 0; + CURRENT = CURRENT->next; + req->next = NULL; + + if (dev->head == NULL) { + dev->head = req; + dev->tail = req; + } else { + dev->tail->next = req; + dev->tail = req; + } + i2ob_send(m, dev, req, i2ob[unit].start_sect, (unit&0xF0)); + /* + * Queue depths probably belong with some kind of + * generic IOP commit control. Certainly its not right + * its global! + */ + if(atomic_read(&queue_depth)>=12) + break; + } +} + +static void i2ob_request(void) +{ + unsigned long flags; + spin_lock_irqsave(&i2ob_lock, flags); + do_i2ob_request(); + spin_unlock_irqrestore(&i2ob_lock, flags); +} + +/* + * SCSI-CAM for ioctl geometry mapping + * Duplicated with SCSI - this should be moved into somewhere common + * perhaps genhd ? + */ + +static void i2o_block_biosparam( + unsigned long capacity, + unsigned short *cyls, + unsigned char *hds, + unsigned char *secs) +{ + unsigned long heads, sectors, cylinders, temp; + + cylinders = 1024L; /* Set number of cylinders to max */ + sectors = 62L; /* Maximize sectors per track */ + + temp = cylinders * sectors; /* Compute divisor for heads */ + heads = capacity / temp; /* Compute value for number of heads */ + if (capacity % temp) { /* If no remainder, done! */ + heads++; /* Else, increment number of heads */ + temp = cylinders * heads; /* Compute divisor for sectors */ + sectors = capacity / temp; /* Compute value for sectors per + track */ + if (capacity % temp) { /* If no remainder, done! */ + sectors++; /* Else, increment number of sectors */ + temp = heads * sectors; /* Compute divisor for cylinders */ + cylinders = capacity / temp;/* Compute number of cylinders */ + } + } + /* if something went wrong, then apparently we have to return + a geometry with more than 1024 cylinders */ + if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) + { + unsigned long temp_cyl; + + heads = 64; + sectors = 32; + temp_cyl = capacity / (heads * sectors); + if (temp_cyl > 1024) + { + heads = 255; + sectors = 63; + } + cylinders = capacity / (heads * sectors); + } + *cyls = (unsigned int) cylinders; /* Stuff return values */ + *secs = (unsigned int) sectors; + *hds = (unsigned int) heads; +} + +/* + * Rescan the partition tables + */ + +static int do_i2ob_revalidate(kdev_t dev, int maxu) +{ + int minor=MINOR(dev); + int i; + + minor&=0xF0; + + i2ob_dev[minor].refcnt++; + if(i2ob_dev[minor].refcnt>maxu+1) + { + i2ob_dev[minor].refcnt--; + return -EBUSY; + } + + for( i = 15; i>=0 ; i--) + { + int m = minor+i; + kdev_t d = MKDEV(MAJOR_NR, m); + struct super_block *sb = get_super(d); + + sync_dev(d); + if(sb) + invalidate_inodes(sb); + invalidate_buffers(d); + i2ob_gendisk.part[m].start_sect = 0; + i2ob_gendisk.part[m].nr_sects = 0; + } + + /* + * Do a physical check and then reconfigure + */ + + i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].tid, + minor); + i2ob_dev[minor].refcnt--; + return 0; +} + +/* + * Issue device specific ioctl calls. + */ + +static int i2ob_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct i2ob_device *dev; + int minor; + + /* Anyone capable of this syscall can do *real bad* things */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= MAX_I2OB) + return -ENODEV; + + dev = &i2ob_dev[minor]; + switch (cmd) { + case BLKRASET: + if(!capable(CAP_SYS_ADMIN)) return -EACCES; + if(arg > 0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return 0; + + case BLKRAGET: + if (!arg) return -EINVAL; + return put_user(read_ahead[MAJOR(inode->i_rdev)], + (long *) arg); + case BLKGETSIZE: + return put_user(i2ob[minor].nr_sects, (long *) arg); + + case BLKFLSBUF: + if(!capable(CAP_SYS_ADMIN)) return -EACCES; + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case HDIO_GETGEO: + { + struct hd_geometry g; + int u=minor&0xF0; + i2o_block_biosparam(i2ob_sizes[u]<<1, + &g.cylinders, &g.heads, &g.sectors); + g.start = i2ob[minor].start_sect; + return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0; + } + + RO_IOCTLS(inode->i_rdev,arg); + + case BLKRRPART: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + return do_i2ob_revalidate(inode->i_rdev,1); + + default: + return -EINVAL; + } +} + +/* + * Issue UTIL_CLAIM messages + */ + +static int i2ob_claim_device(struct i2ob_device *dev, int onoff) +{ + return i2o_issue_claim(dev->controller, dev->tid, i2ob_context, onoff, &dev->done_flag); +} + +/* + * Close the block device down + */ + +static int i2ob_release(struct inode *inode, struct file *file) +{ + struct i2ob_device *dev; + int minor; + + minor = MINOR(inode->i_rdev); + if (minor >= MAX_I2OB) + return -ENODEV; + sync_dev(inode->i_rdev); + dev = &i2ob_dev[(minor&0xF0)]; + if (dev->refcnt <= 0) + printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); + dev->refcnt--; + if(dev->refcnt==0 && i2ob_claim_device(dev, 0)<0) + printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); + if(dev->refcnt==0) + { + /* + * Flush the onboard cache on unmount + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done); + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done); + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Open the block device. + */ + +static int i2ob_open(struct inode *inode, struct file *file) +{ + int minor; + struct i2ob_device *dev; + + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= MAX_I2OB<<4) + return -ENODEV; + dev=&i2ob_dev[(minor&0xF0)]; + + if(dev->refcnt++==0) + { + u32 msg[6]; + int *query_done; + + + if(i2ob_claim_device(dev, 1)<0) + { + dev->refcnt--; + return -EBUSY; + } + + query_done = &dev->done_flag; + /* + * Mount the media if needed. Note that we don't use + * the lock bit. Since we have to issue a lock if it + * refuses a mount (quite possible) then we might as + * well just send two messages out. + */ + msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + msg[5] = 0; + i2o_post_wait(dev->controller, dev->tid, msg, 24, query_done); + /* + * Lock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done); + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + } + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Issue a device query + */ + +static int i2ob_query_device(struct i2ob_device *dev, int table, + int field, void *buf, int buflen) +{ + return i2o_query_scalar(dev->controller, dev->tid, i2ob_context, + table, field, buf, buflen, &dev->done_flag); +} + + +/* + * Install the I2O block device we found. + */ + +static int i2ob_install_device(struct i2o_controller *c, int tid, int unit) +{ + u64 size; + u32 blocksize; + u8 type; + u32 flags, status; + struct i2ob_device *dev=&i2ob_dev[unit]; + + dev->controller = c; + dev->tid = tid; + + /* + * Ask for the current media data. If that isn't supported + * then we ask for the device capacity data + */ + + if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 + || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) + { + i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); + i2ob_query_device(dev, 0x0000, 4, &size, 8); + } + + i2ob_query_device(dev, 0x0000, 5, &flags, 4); + i2ob_query_device(dev, 0x0000, 5, &status, 5); + i2ob_sizes[unit] = (int)(size>>10); + i2ob_hardsizes[unit] = blocksize; + i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit]; + + i2ob[unit].nr_sects = (int)(size>>9); + + i2ob_query_device(dev, 0x0000, 0, &type, 1); + + printk("i2ohd%c: ", (unit>>4)+'a'); + if(status&(1<<10)) + printk("RAID "); + switch(type) + { + case 0: printk("Disk Storage");break; + case 4: printk("WORM");break; + case 5: printk("CD-ROM");break; + case 7: printk("Optical device");break; + default: + printk("Type %d", type); + } + if(((flags & (1<<3)) && !(status & (1<<3))) || + ((flags & (1<<4)) && !(status & (1<<4)))) + { + printk(" Not loaded.\n"); + return 0; + } + printk(" %dMb, %d byte sectors", + (int)(size>>20), blocksize); + if(status&(1<<0)) + { + u32 cachesize; + i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); + cachesize>>=10; + if(cachesize>4095) + printk(", %dMb cache", cachesize>>10); + else + printk(", %dKb cache", cachesize); + } + printk(".\n"); + resetup_one_dev(&i2ob_gendisk, unit>>4); + return 0; +} + +static void i2ob_probe(void) +{ + int i; + int unit = 0; + int warned = 0; + + for(i=0; i< MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *c=i2o_find_controller(i); + struct i2o_device *d; + + if(c==NULL) + continue; + for(d=c->devices;d!=NULL;d=d->next) + { + int class = d->type & 0xFFFF; + + if(class!=0x1010) + continue; + if(unitid,unit); + unit+=16; + } + else + { + if(!warned++) + printk("i2o_block: too many controllers, registering only %d.\n", unit); + } + } + } + i2ob_devices = unit; +} + +/* + * Have we seen a media change ? + */ + +static int i2ob_media_change(kdev_t dev) +{ + int i=MINOR(dev); + i>>=4; + if(i2ob_media_change_flag[i]) + { + i2ob_media_change_flag[i]=0; + return 1; + } + return 0; +} + +static int i2ob_revalidate(kdev_t dev) +{ + return do_i2ob_revalidate(dev, 0); +} + +static int i2ob_reboot_event(struct notifier_block *n, unsigned long code, void *p) +{ + int i; + + if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) + return NOTIFY_DONE; + for(i=0;irefcnt!=0) + { + /* + * Flush the onboard cache on power down + * also unlock the media + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done); + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done); + } + } + return NOTIFY_DONE; +} + +struct notifier_block i2ob_reboot_notifier = +{ + i2ob_reboot_event, + NULL, + 0 +}; + +static struct file_operations i2ob_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + i2ob_ioctl, /* ioctl */ + NULL, /* mmap */ + i2ob_open, /* open */ + NULL, /* flush */ + i2ob_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + i2ob_media_change, /* Media Change */ + i2ob_revalidate, /* Revalidate */ + NULL /* File locks */ +}; + +/* + * Partitioning + */ + +static void i2ob_geninit(struct gendisk *gd) +{ +} + +static struct gendisk i2ob_gendisk = +{ + MAJOR_NR, + "i2ohd", + 4, + 1<<4, + MAX_I2OB, + i2ob_geninit, + i2ob, + i2ob_sizes, + 0, + NULL, + NULL +}; + +/* + * And here should be modules and kernel interface + * (Just smiley confuses emacs :-) + */ + +#ifdef MODULE +#define i2ob_init init_module +#endif + +int i2ob_init(void) +{ + int i; + + printk("I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n"); + + /* + * Register the block device interfaces + */ + + if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) { + printk("Unable to get major number %d for i2o_block\n", + MAJOR_NR); + return -EIO; + } +#ifdef MODULE + printk("i2o_block: registered device at major %d\n", MAJOR_NR); +#endif + + /* + * Now fill in the boiler plate + */ + + blksize_size[MAJOR_NR] = i2ob_blksizes; + hardsect_size[MAJOR_NR] = i2ob_hardsizes; + blk_size[MAJOR_NR] = i2ob_sizes; + blk_dev[MAJOR_NR].request_fn = i2ob_request; + for (i = 0; i < MAX_I2OB << 4; i++) { + i2ob_dev[i].refcnt = 0; + i2ob_dev[i].flags = 0; + i2ob_dev[i].controller = NULL; + i2ob_dev[i].tid = 0; + i2ob_dev[i].head = NULL; + i2ob_dev[i].tail = NULL; + i2ob_blksizes[i] = 1024; + } + + /* + * Register the OSM handler as we will need this to probe for + * drives, geometry and other goodies. + */ + + if(i2o_install_handler(&i2o_block_handler)<0) + { + unregister_blkdev(MAJOR_NR, "i2o_block"); + printk(KERN_ERR "i2o_block: unable to register OSM.\n"); + return -EINVAL; + } + i2ob_context = i2o_block_handler.context; + + /* + * Finally see what is actually plugged in to our controllers + */ + + i2ob_probe(); + + register_reboot_notifier(&i2ob_reboot_notifier); + return 0; +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Block Device OSM"); + +void cleanup_module(void) +{ + struct gendisk **gdp; + + unregister_reboot_notifier(&i2ob_reboot_notifier); + + /* + * Flush the OSM + */ + + i2o_remove_handler(&i2o_block_handler); + + /* + * Return the block device + */ + if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) + printk("i2o_block: cleanup_module failed\n"); + else + printk("i2o_block: module cleaned up.\n"); + + /* + * Why isnt register/unregister gendisk in the kernel ??? + */ + + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) + if (*gdp == &i2ob_gendisk) + break; + +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_config.c linux.ac/drivers/i2o/i2o_config.c --- linux.vanilla/drivers/i2o/i2o_config.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_config.c Sat Mar 13 22:28:08 1999 @@ -0,0 +1,342 @@ +/* + * I2O Configuration Interface Driver + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int i2o_cfg_context = -1; +static void *page_buf; +static void *i2o_buffer; +static int i2o_ready; +static int i2o_pagelen; +static int i2o_error; +static int cfg_inuse; +static int i2o_eof; +struct wait_queue *i2o_wait_queue; + +/* + * This is the callback for any message we have posted. The message itself + * will be returned to the message pool when we return from the IRQ + * + * This runs in irq context so be short and sweet. + */ + +static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) +{ +// u32 *mp=(u32 *)m; + /* Error check .. */ + + printk("i2o_cfg:reply received.\n"); + /* Wake up */ + i2o_ready=1; + i2o_eof=0; + i2o_pagelen=strnlen(page_buf, 4096); + printk("%d byte page.\n", i2o_pagelen); + wake_up_interruptible(&i2o_wait_queue); + printk("freeing buffer.\n"); + if(i2o_buffer) + { + kfree(i2o_buffer); + i2o_buffer=NULL; + } + printk("done\n"); +} + +/* + * Each of these describes an i2o message handler. They are + * multiplexed by the i2o_core code + */ + +struct i2o_handler cfg_handler= +{ + i2o_cfg_reply, + "Configuration", + 0 +}; + +static long long cfg_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +/* i2ocontroller/i2odevice/page/?data */ + +static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + char *ptr; + char *tail; + char *work; + + u32 *msg; + u32 controller, tid, page; + u32 m; + + struct i2o_controller *c; + + if(count > 4096) + return -EMSGSIZE; + if((ptr=kmalloc(count, GFP_KERNEL))==NULL) + return -ENOBUFS; + if(copy_from_user(ptr, buf, count)) + { + kfree(ptr); + return -EFAULT; + } + /* + * Ok we have it in kernel space now we can play with it + */ + tail=strchr(buf, '?'); + if(tail) + *tail++=0; + + controller=simple_strtoul(ptr, &work, 10); + if(!work || *work!='/') + goto bad; + tid=simple_strtoul(work+1, &work, 10); + if(!work || *work!='/') + goto bad; + page=simple_strtoul(work+1, &work, 10); + if(!work || *work!='/') + goto bad; + work++; + + printk("Parsed.\n"); + + /* + * You'd normally do this when binding a driver not each run. + * The find function also locks the controller into memory. Nobody + * can delete it during use then. + */ + + c=i2o_find_controller(controller); + if(c==NULL) + { + kfree(ptr); + return -ENXIO; + } + + printk("Controller\n"); + + /* + * Message ? + */ + + do + { + m= *c->post_port; + if(m!=0xFFFFFFFF) + break; + schedule_timeout(HZ/10); + } + while(1); + + /* + * Maybe I should make a macro of this ? + */ + + msg = (u32 *)(c->mem_offset+m); + + printk("Make MSG\n"); + + /* + * Fill in the buffer + */ + + msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|tid; + msg[2] = i2o_cfg_context; + msg[3] = 0; + msg[4] = page; + msg[5] = 0xD0000000|4096; + msg[6] = virt_to_bus(page_buf); + if(tail==NULL) /* Check for post data */ + msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; + else + { + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[5] = 0x50000000|4096; + msg[7] = 0xD4000000|strlen(tail); + msg[8] = virt_to_bus(tail); + } + + printk("Post\n"); + + /* + * Send it + */ + + i2o_buffer = ptr; + *c->post_port = m; + i2o_unlock_controller(c); + printk("Done\n"); + return count; +bad: + kfree(ptr); + return -EINVAL; +} + +static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + unsigned long flags; + int len; + + if(i2o_eof == i2o_pagelen) + { + i2o_eof++; + return 0; + } + + if(i2o_eof > i2o_pagelen) + i2o_ready = 0; + + save_flags(flags); + cli(); + while(!i2o_ready) + { + interruptible_sleep_on(&i2o_wait_queue); + if(signal_pending(current)) + { + restore_flags(flags); + return -EINTR; + } + } + if(i2o_error) + { + int err=i2o_error; + i2o_error=0; + i2o_eof = i2o_pagelen; + i2o_ready = 0; + restore_flags(flags); + return err; + } + + restore_flags(flags); + + len=i2o_pagelen-i2o_eof; + if(len>count) + len=count; + if(copy_to_user(buf, page_buf+i2o_eof, len)) + return -EFAULT; + i2o_eof+=len; + return len; +} + +static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -EINVAL; +} + +static int cfg_open(struct inode *inode, struct file *file) +{ + if(cfg_inuse) + return -EBUSY; + MOD_INC_USE_COUNT; + cfg_inuse=1; + return 0; +} + +static int cfg_release(struct inode *inode, struct file *file) +{ + cfg_inuse = 0; + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct file_operations config_fops = +{ + cfg_llseek, + cfg_read, + cfg_write, + NULL, + NULL /*cfg_poll*/, + cfg_ioctl, + NULL, /* No mmap */ + cfg_open, + NULL, /* No flush */ + cfg_release +}; + +static struct miscdevice i2o_miscdev = { + I2O_MINOR, + "i2octl", + &config_fops +}; + +#ifdef MODULE +int init_module(void) +#else +int i2o_config_init(void) +#endif +{ + printk(KERN_INFO "i2o configuration manager v 0.02\n"); + + if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) + { + printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); + return -ENOBUFS; + } + if(misc_register(&i2o_miscdev)==-1) + { + printk(KERN_ERR "i2o_config: can't register device.\n"); + kfree(page_buf); + return -EBUSY; + } + /* + * Install our handler + */ + if(i2o_install_handler(&cfg_handler)<0) + { + kfree(page_buf); + printk(KERN_ERR "i2o_config: handler register failed.\n"); + misc_deregister(&i2o_miscdev); + return -EBUSY; + } + /* + * The low 16bits of the transaction context must match this + * for everything we post. Otherwise someone else gets our mail + */ + i2o_cfg_context = cfg_handler.context; + return 0; +} + +#ifdef MODULE + +void cleanup_module(void) +{ + misc_deregister(&i2o_miscdev); + + if(page_buf) + kfree(page_buf); + if(i2o_cfg_context != -1) + i2o_remove_handler(&cfg_handler); + if(i2o_buffer) + kfree(i2o_buffer); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Configuration"); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_core.c linux.ac/drivers/i2o/i2o_core.c --- linux.vanilla/drivers/i2o/i2o_core.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_core.c Sun Mar 21 17:30:34 1999 @@ -0,0 +1,1330 @@ +/* + * Core I2O structure managment + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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. + * + * A lot of the I2O message side code from this is taken from the + * Red Creek RCPCI45 adapter driver by Red Creek Communications + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Size of the I2O module table + */ + + +static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; +static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; + + +extern int i2o_online_controller(struct i2o_controller *c); + +/* + * I2O configuration spinlock. This isnt a big deal for contention + * so we have one only + */ + +static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; + +/* + * Install an I2O handler - these handle the asynchronous messaging + * from the card once it has initialised. + */ + +int i2o_install_handler(struct i2o_handler *h) +{ + int i; + spin_lock(&i2o_configuration_lock); + for(i=0;icontext = i; + i2o_handlers[i]=h; + spin_unlock(&i2o_configuration_lock); + return 0; + } + } + spin_unlock(&i2o_configuration_lock); + return -ENOSPC; +} + +int i2o_remove_handler(struct i2o_handler *h) +{ + i2o_handlers[h->context]=NULL; + return 0; +} + + +/* + * Each I2O controller has a chain of devices on it - these match + * the useful parts of the LCT of the board. + */ + +int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) +{ + spin_lock(&i2o_configuration_lock); + d->controller=c; + d->owner=NULL; + d->next=c->devices; + c->devices=d; + spin_unlock(&i2o_configuration_lock); + return 0; +} + + +int i2o_delete_device(struct i2o_device *d) +{ + struct i2o_device **p; + + spin_lock(&i2o_configuration_lock); + + p=&(d->controller->devices); + + /* + * Hey we have a driver! + */ + + if(d->owner) + { + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + + /* + * Seek, locate + */ + + while(*p!=NULL) + { + if(*p==d) + { + /* + * Destroy + */ + *p=d->next; + kfree(d); + spin_unlock(&i2o_configuration_lock); + return 0; + } + p=&((*p)->next); + } + spin_unlock(&i2o_configuration_lock); + printk(KERN_ERR "i2o_destroy_device: passed invalid device.\n"); + return -EINVAL; +} + + +/* + * Add and remove controllers from the I2O controller list + */ + +int i2o_install_controller(struct i2o_controller *c) +{ + int i; + spin_lock(&i2o_configuration_lock); + for(i=0;inext=i2o_controller_chain; + i2o_controller_chain=c; + c->unit = i; + sprintf(c->name, "i2o%d", i); + spin_unlock(&i2o_configuration_lock); + return 0; + } + } + printk(KERN_ERR "No free i2o controller slots.\n"); + return -EBUSY; +} + +int i2o_delete_controller(struct i2o_controller *c) +{ + struct i2o_controller **p; + + spin_lock(&i2o_configuration_lock); + if(atomic_read(&c->users)) + { + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + while(c->devices) + { + if(i2o_delete_device(c->devices)<0) + { + /* Shouldnt happen */ + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + } + c->destructor(c); + + p=&i2o_controller_chain; + + while(*p) + { + if(*p==c) + { + *p=c->next; + spin_unlock(&i2o_configuration_lock); + if(c->page_frame); + kfree(c->page_frame); + i2o_controllers[c->unit]=NULL; + kfree(c); + return 0; + } + p=&((*p)->next); + } + spin_unlock(&i2o_configuration_lock); + printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); + return -ENOENT; +} + +void i2o_unlock_controller(struct i2o_controller *c) +{ + atomic_dec(&c->users); +} + +struct i2o_controller *i2o_find_controller(int n) +{ + struct i2o_controller *c; + + if(n<0 || n>=MAX_I2O_CONTROLLERS) + return NULL; + + spin_lock(&i2o_configuration_lock); + c=i2o_controllers[n]; + if(c!=NULL) + atomic_inc(&c->users); + spin_unlock(&i2o_configuration_lock); + return c; +} + + +/* + * Track if a device is being used by a driver + */ + +int i2o_claim_device(struct i2o_device *d, struct i2o_driver *r) +{ + spin_lock(&i2o_configuration_lock); + if(d->owner) + { + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + atomic_inc(&d->controller->users); + d->owner=r; + spin_unlock(&i2o_configuration_lock); + return 0; +} + +int i2o_release_device(struct i2o_device *d) +{ + spin_lock(&i2o_configuration_lock); + if(d->owner==NULL) + { + spin_unlock(&i2o_configuration_lock); + return -EINVAL; + } + atomic_dec(&d->controller->users); + d->owner=NULL; + spin_unlock(&i2o_configuration_lock); + return 0; +} + +/* + * This is called by the bus specific driver layer when an interrupt + * or poll of this card interface is desired. + */ + +void i2o_run_queue(struct i2o_controller *c) +{ + struct i2o_message *m; + u32 mv; + + while((mv=*c->read_port)!=0xFFFFFFFF) + { + struct i2o_handler *i; + m=(struct i2o_message *)bus_to_virt(mv); + /* + * Temporary Debugging + */ + if(((m->function_addr>>24)&0xFF)==0x15) + printk("UTFR!\n"); +// printk("dispatching.\n"); + i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; + if(i) + i->reply(i,c,m); + else + printk("Spurious reply\n"); + i2o_flush_reply(c,mv); + mb(); + } +} + + +/* + * Wait up to 5 seconds for a message slot to be available. + */ + +static u32 i2o_wait_message(struct i2o_controller *c, char *why) +{ + long time=jiffies; + u32 m; + while((m=*c->post_port)==0xFFFFFFFF) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "%s: Timeout waiting for message to send %s.\n", + c->name, why); + return 0xFFFFFFFF; + } + schedule(); + barrier(); + } + return m; +} + + +/* + * Wait up to 5 seconds for a reply to be available. + */ + +static u32 i2o_wait_reply(struct i2o_controller *c, char *why) +{ + u32 m; + long time=jiffies; + + while((m=*c->read_port)==0xFFFFFFFF) + { + if(jiffies-time >= 5*HZ ) + { + printk(KERN_ERR "%s: timeout waiting for %s reply.\n", + c->name, why); + return 0xFFFFFFFF; + } + schedule(); + } + return m; +} + + + +/* + * i2o table walking. We just provide a single element retrieve. You can + * all sorts of fancy lookups in I2O but we have no performance critical + * lookups so why write all the code for it. + */ + + +static int i2o_query_table_polled(struct i2o_controller *c, int tid, void *buf, int buflen, + int group, int field, u32 *key, int keylen) +{ + u32 m; + u32 *msg; + u16 op[64]; + u32 *p; + int i; + u32 *rbuf; + + op[0]=1; /* One Operation */ + op[1]=0; /* PAD */ + op[2]=2; /* LIST_GET */ + op[3]=group; /* group number */ + op[4]=1; /* 1 field */ + op[5]=field; /* Field number */ + op[6]=1; /* Key count */ + memcpy(op+7, key, keylen); /* Key */ + + m=i2o_wait_message(c, "I2O query table."); + if(m==0xFFFFFFFF) + { + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + rbuf=kmalloc(buflen+32, GFP_KERNEL); + if(rbuf==NULL) + { + printk(KERN_ERR "No free memory for table read.\n"); + return -ENOMEM; + } + msg[0]=FIVE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=0; /* Context */ + msg[3]=0; + msg[4]=0; + msg[5]=0x54000000|12; + msg[6]=virt_to_bus(op); + msg[7]=0xD0000000|(32+buflen); + msg[8]=virt_to_bus(rbuf); + + i2o_post_message(c,m); + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Table read timeout"); + + if(m==0xFFFFFFFF) + { + kfree(rbuf); + return -ETIMEDOUT; + } + + msg = (u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + printk(KERN_WARNING "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + + p=rbuf; + + /* Ok 'p' is the reply block - lets see what happened */ + /* p0->p2 are the header */ + + /* FIXME: endians - turn p3 to little endian */ + + i=(p[0]&0xFFFF)<<2; /* Message size */ + if(iname); + kfree(rbuf); + return -EBADR; + } + + /* p[1] holds the more flag and row count - we dont care */ + + /* Ok it worked p[2]-> hold the data */ + memcpy(buf, p+2, buflen); + + kfree(rbuf); + + /* Finally return the message */ + *c->read_port=m; + return buflen; +} + + +static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, + int group, int field) +{ + u32 m; + u32 *msg; + u16 op[8]; + u32 *p; + int i; + u32 *rbuf; + + op[0]=1; /* One Operation */ + op[1]=0; /* PAD */ + op[2]=1; /* FIELD_GET */ + op[3]=group; /* group number */ + op[4]=1; /* 1 field */ + op[5]=field; /* Field number */ + + m=i2o_wait_message(c, "I2O query scalar."); + if(m==0xFFFFFFFF) + { + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + rbuf=kmalloc(buflen+32, GFP_KERNEL); + if(rbuf==NULL) + { + printk(KERN_ERR "No free memory for scalar read.\n"); + return -ENOMEM; + } + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=0; /* Context */ + msg[3]=0; + msg[4]=0; + msg[5]=0x54000000|12; + msg[6]=virt_to_bus(op); + msg[7]=0xD0000000|(32+buflen); + msg[8]=virt_to_bus(rbuf); + + i2o_post_message(c,m); + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Scalar read timeout"); + + if(m==0xFFFFFFFF) + { + kfree(rbuf); + return -ETIMEDOUT; + } + + msg = (u32 *)bus_to_virt(m); + if(msg[4]>>24) + { + printk(KERN_WARNING "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + + p=rbuf; + + /* Ok 'p' is the reply block - lets see what happened */ + /* p0->p2 are the header */ + + /* FIXME: endians - turn p3 to little endian */ + + if((p[0]&0xFFFF)!=1) + printk(KERN_WARNING "Suspicious field read return 0x%08X\n", p[0]); + + i=(p[1]&0xFFFF)<<2; /* Message size */ + if(iname); + kfree(rbuf); + return -EBADR; + } + + /* p[1] holds the more flag and row count - we dont care */ + + /* Ok it worked p[2]-> hold the data */ + memcpy(buf, p+2, buflen); + + kfree(rbuf); + + /* Finally return the message */ + *c->read_port=m; + return buflen; +} + +/* + * Dump the information block associated with a given unit (TID) + */ + +void i2o_report_controller_unit(struct i2o_controller *c, int unit) +{ + char buf[64]; + + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 3)>=0) + { + buf[16]=0; + printk("Vendor: %s", buf); + } + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 4)>=0) + { + buf[16]=0; + printk("Device: %s", buf); + } + if(i2o_query_scalar_polled(c, unit, buf, 8, 0xF100, 6)>=0) + { + buf[8]=0; + printk("Rev: %s", buf); + } +#if 0 + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 5)>=0) + { + buf[16]=0; + printk(KERN_INFO "Description: %s\n", buf); + } +#endif + printk("\n"); +} + + +/* + * Parse the hardware resource table. Right now we print it out + * and don't do a lot with it. We should collate these and then + * interact with the Linux resource allocation block. + * + * Lets prove we can read it first eh ? + * + * This is full of endianisms! + */ + +static int i2o_parse_hrt(struct i2o_controller *c, u8 *p) +{ + u32 *rows=(u32 *)p; + u8 *d; + int count; + int length; + int i; + int state; + + if(p[3]!=0) + { + printk(KERN_ERR "i2o: HRT table for controller is too new a version.\n"); + return -1; + } + + count=p[0]|(p[1]<<8); + length = p[2]; + + printk(KERN_INFO "HRT has %d entries of %d bytes each.\n", + count, length<<2); + + rows+=2; + + for(i=0;i>=12; + if(state&(1<<0)) + printk("H"); + if(state&(1<<2)) + { + printk("P"); + if(state&(1<<1)) + printk("C"); + } + if(state>9) + printk("*"); + + printk("]:"); + + switch(p[3]&0xFFFF) + { + case 0: + /* Adapter private bus - easy */ + printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", + p[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + case 1: + /* ISA bus */ + printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", + p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 2: /* EISA bus */ + printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 3: /* MCA bus */ + printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 4: /* PCI bus */ + printk("PCI %d: Bus %d Device %d Function %d", + p[2], d[2], d[1], d[0]); + break; + + case 0x80: /* Other */ + default: + printk("Unsupported bus type."); + break; + } + printk("\n"); + rows+=length; + } + return 0; +} + +/* + * The logical configuration table tells us what we can talk to + * on the board. Most of the stuff isn't interesting to us. + */ + +static int i2o_parse_lct(struct i2o_controller *c, u32 *lct) +{ + + int i; + int max; + int tid; + u32 *p; + struct i2o_device *d; + + max=lct[0]&0xFFFF; + + max-=3; + max/=9; + + printk(KERN_INFO "LCT has %d entries.\n", max); + if(lct[1]&(1<<0)) + printk(KERN_WARNING "Configuration dialog desired.\n"); + + p=lct+3; + + for(i=0;icontroller = c; + d->next = NULL; + + d->id = tid = (p[0]>>16)&0xFFF; + d->type = p[3]; + d->parent = (p[5]>>12)&0xFFF; + d->flags = 0; + + printk(KERN_INFO "TID %d.\n", tid); + printk(KERN_INFO " "); + + i2o_report_controller_unit(c, tid); + + i2o_install_device(c, d); + + printk(KERN_INFO " Category: "); + + switch(p[3]) + { + case 0x1000: + printk("Executive "); + break; + case 0x1001: + printk("Device Driver Manager"); + break; + case 0x1010: + printk("Block Device "); + break; + case 0x1011: + printk("Tape Device "); + break; + case 0x1020: + printk("LAN Inteface "); + break; + case 0x1030: + printk("WAN Interface "); + break; + case 0x1040: + printk("Fibre Channel Port "); + break; + case 0x1041: + printk("FC Connection "); + break; + case 0x1051: + printk("SCSI Device "); + break; + case 0x1060: + printk("ATE Port "); + break; + case 0x1061: + printk("ATE Device "); + break; + case 0x1080: + printk("Secondary Bus Port "); + break; + default: + printk("0x%08X ", p[3]); + break; + } + + printk(" Subclass: 0x%08X Flags: ", + p[4]); + + if(p[2]&(1<<0)) + printk("C"); + if(p[2]&(1<<1)) + printk("M"); + if(!(p[2]&(1<<4))) + printk("P"); + if(!(p[2]&(1<<5))) + printk("m"); + printk("\n"); + p+=9; + } + return 0; +} + +/* + * Bring an I2O controller into HOLD state. See the 1.5 + * spec. Basically we go + * + * Wait for the message queue to initialise. + * If it didnt -> controller is dead + * + * Send a get status using the message queue + * Poll for a reply block 88 bytes long + * + * Send an initialise outbound queue + * Poll for a reply + * + * Post our blank messages to the queue FIFO + * + * Send GetHRT, Parse it + */ + +int i2o_activate_controller(struct i2o_controller *c) +{ + long time; + u32 m; + u8 *workspace; + u32 *msg; + int i; + + printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", (u32)c->mem_phys); + + m=i2o_wait_message(c, "initialise"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + workspace = (void *)kmalloc(88, GFP_KERNEL); + if(workspace==NULL) + { + printk(KERN_ERR "IOP initialisation failed - no free memory.\n"); + return -ENOMEM; + } + + memset(workspace, 0, 88); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_phys(workspace); + msg[7]=0; /* 64bit host FIXME */ + msg[8]=88; + + i2o_post_message(c,m); + + /* + * Wait for a reply + */ + + time=jiffies; + + while(workspace[87]!=0xFF) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "IOP get status timeout.\n"); + kfree(workspace); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + /* + * Ok the reply has arrived. Fill in the important stuff + */ + + c->status = workspace[10]; + c->inbound_size = workspace[12]|(workspace[13]<<8); + + + /* + * If the board is running, reset it - we have no idea + * what kind of a mess the previous owner left it in. + */ + +// if(c->status == ADAPTER_STATE_OPERATIONAL) +// i2o_reset_device(c); + + + m=i2o_wait_message(c, "initqueue"); + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; + msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= DEFAULT_RECV_INIT_CONTEXT; + msg[3]= 0x0106; /* Transaction context */ + msg[4]= 4096; /* Host page frame size */ + msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ + msg[6]= 0xD0000004; /* Simple SG LE, EOB */ + msg[7]= virt_to_phys(workspace); + *((u32 *)workspace)=0; + + /* + * Post it + */ + + i2o_post_message(c,m); + + barrier(); + + time=jiffies; + + while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "IOP outbound initialise failed.\n"); + kfree(workspace); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + kfree(workspace); + + c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); + if(c->page_frame==NULL) + { + printk(KERN_ERR "IOP init failed: no memory for message page.\n"); + return -ENOMEM; + } + + m=virt_to_phys(c->page_frame); + + for(i=0; i< NMBR_MSG_FRAMES; i++) + { + *c->read_port=m; + mb(); + m+=MSG_FRAME_SIZE; + } + + /* + * The outbound queue is initialised and loaded, + * + * Now we need the Hardware Resource Table. We must ask for + * this next we can't issue random messages yet. + */ + + + workspace=kmalloc(2048, GFP_KERNEL); + if(workspace==NULL) + { + printk(KERN_ERR "IOP init failed; no memory.\n"); + return -ENOMEM; + } + + m=i2o_wait_message(c, "I2O HRT timeout."); + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= DEFAULT_RECV_INIT_CONTEXT; + msg[3]= 0x0; /* Transaction context */ + msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */ + msg[5]= virt_to_phys(workspace); /* Dump it here */ + *((u32 *)workspace)=0xFFFFFFFF; + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + m=i2o_wait_reply(c, "HRT table"); + + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + printk(KERN_WARNING "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + *c->read_port = m; + + i2o_parse_hrt(c, workspace); + + kfree(workspace); + + i2o_online_controller(c); +// i2o_report_controller_unit(c, ADAPTER_TID); + return 0; +} + + +/* + * Bring a controller online. Needs completing for multiple controllers + */ + +int i2o_online_controller(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + u32 systab[32]; + u32 bustab[2]; + u32 *workspace; + + systab[0]=1; + systab[1]=0; + systab[2]=0; + systab[3]=0; + systab[4]=0; /* Organisation ID */ + systab[5]=2; /* Ident 2 for now */ + systab[6]=1; /* Memory mapped, v0, segment 1 */ + systab[7]=MSG_FRAME_SIZE>>2; /* Message size */ + systab[8]=0; + systab[9]=0; /* Should be cpabilities */ + systab[10]=virt_to_phys(c->post_port); + systab[11]=0; + + bustab[0]=0xD0000000; /* hardcoded for Alans box FIXME */ + bustab[1]=0x00010000; + + m=i2o_wait_message(c, "SetSysTab"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + /* Now we build the systab */ + msg=(u32 *)(c->mem_offset+m); + + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + msg[4] = (1<<16)|(2<<12); /* Host 1 I2O 2 */ + msg[5] = 1; /* Segment 1 */ + + /* + * Scatter Gather List + */ + + msg[6] = 0x54000000|48; /* One table for now */ + msg[7] = virt_to_phys(systab); + msg[8] = 0xD4000000|48; /* One table for now */ + msg[9] = virt_to_phys(bustab); + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Systab read"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + printk(KERN_ERR "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + *c->read_port = m; + + /* + * Finally we go online + */ + + m=i2o_wait_message(c, "No message for SysEnable"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SYS_ENABLE<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Enable"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + printk(KERN_ERR "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + *c->read_port = m; + + /* + * Grab the LCT, see what is attached + */ + + m=i2o_wait_message(c, "No message for LCT"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + + workspace = kmalloc(2048, GFP_KERNEL); + if(workspace==NULL) + { + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]= HOST_TID<<12|ADAPTER_TID; /* NOP */ + i2o_post_message(c,m); + printk(KERN_ERR "No free memory for i2o controller buffer.\n"); + return -ENOMEM; + } + + memset(workspace, 0, 2048); + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|2048; + msg[7] = virt_to_bus(workspace); + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + m=i2o_wait_reply(c, "LCT"); + + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + printk(KERN_ERR "ERROR 0x%08X\n", msg[4]&0xFF00FFFF); + } + + i2o_parse_lct(c, workspace); + kfree(workspace); + + *c->read_port = m; + + return 0; +} + +/* + * Run time support routines + */ + +/* + * Generic "post and forget" helpers. This is less efficient - we do + * a memcpy for example that isnt strictly needed, but for most uses + * this is simply not worth optimising + */ + +int i2o_post_this(struct i2o_controller *c, int tid, u32 *data, int len) +{ + u32 m; + u32 *msg; + unsigned long t=jiffies; + + do + { + mb(); + m = *c->post_port; + } + while(m==0xFFFFFFFF && (jiffies-t)mem_offset + m); + memcpy(msg, data, len); + i2o_post_message(c,m); + return 0; +} + +/* + * Post a message and wait for a response flag to be set. This API will + * change to use wait_queue's one day + */ + +int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *flag) +{ + unsigned long t=jiffies; + + *flag = 0; + + if(i2o_post_this(c, tid, data, len)) + return -1; + + while(!*flag && (jiffies-t)<2*HZ) + { + schedule(); + mb(); + } + if(*flag <= 0) + return -1; + return 0; +} + +/* + * Issue UTIL_CLAIM messages + */ + +int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag) +{ + u32 msg[6]; + + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + if(onoff) + msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid; + else + msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid; + + /* The 0x80000000 convention for flagging is assumed by this helper */ + + msg[2] = 0x80000000|context; + msg[3] = (u32)flag; + msg[4] = 0x01<<24; /* Primary user */ + + return i2o_post_wait(c, tid, msg, 20, flag); +} + +/* + * Query a scalar value + */ + +int i2o_query_scalar(struct i2o_controller *c, int tid, int context, + int table, int field, void *buf, int buflen, int *flag) +{ + static u16 opdata[]={1,0,1,0,1,4}; + u32 *bl; + u32 msg[9]; + + bl=kmalloc(buflen+32, GFP_KERNEL); + if(bl==NULL) + { + printk(KERN_ERR "i2o: no memory for query buffer.\n"); + return -ENOMEM; + } + + opdata[3]=table; + opdata[5]=field; + memcpy(bl, opdata, 12); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=context|0x80000000; /* So we can pick it out */ + msg[3]=(u32)flag; + msg[4]=0; + msg[5]=0x54000000|12; + msg[6]=virt_to_bus(bl); + msg[7]=0xD0000000|buflen; + msg[8]=virt_to_bus(bl+4); + + bl[4]=0xFCFCFCFC; + bl[5]=0xFAFAFCFC; + + /* + * Post the message and await a reply + */ + + if(i2o_post_wait(c, tid, msg, 36, flag)<0) + return -1; + + if(bl[5]&0x80000000) /* Error ? */ + { + kfree(bl); + return -1; + } + if((bl[4]&0xFFFF)!=1) + { + printk(KERN_ERR "i2o: query: umm ??? 0x%08X\n", bl[4]); + } + + memcpy(buf, bl+6, buflen); + kfree(bl); + return 0; +} + + +EXPORT_SYMBOL(i2o_install_handler); +EXPORT_SYMBOL(i2o_remove_handler); +EXPORT_SYMBOL(i2o_install_device); +EXPORT_SYMBOL(i2o_delete_device); +EXPORT_SYMBOL(i2o_install_controller); +EXPORT_SYMBOL(i2o_delete_controller); +EXPORT_SYMBOL(i2o_unlock_controller); +EXPORT_SYMBOL(i2o_find_controller); +EXPORT_SYMBOL(i2o_claim_device); +EXPORT_SYMBOL(i2o_release_device); +EXPORT_SYMBOL(i2o_run_queue); +EXPORT_SYMBOL(i2o_report_controller_unit); +EXPORT_SYMBOL(i2o_activate_controller); +EXPORT_SYMBOL(i2o_online_controller); + +EXPORT_SYMBOL(i2o_query_scalar); +EXPORT_SYMBOL(i2o_post_this); +EXPORT_SYMBOL(i2o_post_wait); +EXPORT_SYMBOL(i2o_issue_claim); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Core"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_pci.c linux.ac/drivers/i2o/i2o_pci.c --- linux.vanilla/drivers/i2o/i2o_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_pci.c Wed Mar 24 18:09:50 1999 @@ -0,0 +1,235 @@ +/* + * Find I2O capable controllers on the PCI bus, and register/install + * them with the I2O layer + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Free bus specific resources + */ + +static void i2o_pci_dispose(struct i2o_controller *c) +{ + *c->irq_mask=0xFFFFFFFF; + if(c->bus.pci.irq > 0) + free_irq(c->bus.pci.irq, c); + iounmap(((u8 *)c->post_port)-0x40); +} + +/* + * No real bus specific handling yet (note that later we will + * need to 'steal' PCI devices on i960 mainboards) + */ + +static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Bus specific interrupt handler + */ + +static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +{ + struct i2o_controller *c = dev_id; + i2o_run_queue(c); +} + +/* + * Install a PCI (or in theory AGP) i2o controller + */ + +int __init i2o_pci_install(struct pci_dev *dev) +{ + struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), + GFP_KERNEL); + u8 *mem; + u32 memptr = 0; + u32 size; + + int i; + + if(c==NULL) + { + printk(KERN_ERR "i2o_pci: insufficient memory to add controller.\n"); + return -ENOMEM; + } + memset(c, 0, sizeof(*c)); + + for(i=0; i<6; i++) + { + /* Skip I/O spaces */ + if(!(dev->base_address[i]&PCI_BASE_ADDRESS_SPACE)) + { + memptr=PCI_BASE_ADDRESS_MEM_MASK&dev->base_address[i]; + break; + } + } + + if(i==6) + { + printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n"); + return -ENOMEM; + } + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, 0xFFFFFFFF); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, &size); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, dev->base_address[i]); + + /* Map the I2O controller */ + + printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size); + mem = ioremap(memptr, -size); + + c->bus.pci.irq = -1; + + c->irq_mask = (volatile u32 *)(mem+0x34); + c->post_port = (volatile u32 *)(mem+0x40); + c->read_port = (volatile u32 *)(mem+0x44); + + c->mem_phys = memptr; + c->mem_offset = mem; + c->destructor = i2o_pci_dispose; + + c->bind = i2o_pci_bind; + c->unbind = i2o_pci_unbind; + + c->type = I2O_TYPE_PCI; + + *c->irq_mask = 0xFFFFFFFF; + + i = i2o_install_controller(c); + + if(i<0) + { + printk(KERN_ERR "i2o: unable to install controller.\n"); + return i; + } + + c->bus.pci.irq = dev->irq; + if(c->bus.pci.irq) + { + i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ, + c->name, c); + if(i<0) + { + printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", + c->name, dev->irq); + c->bus.pci.irq = -1; + i2o_delete_controller(c); + return -EBUSY; + } + } + return 0; +} + +int __init i2o_pci_scan(void) +{ + struct pci_dev *dev; + int count=0; + + printk(KERN_INFO "Checking for PCI I2O controllers...\n"); + + for(dev=pci_devices; dev!=NULL; dev=dev->next) + { + if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) + continue; + if((dev->class&0xFF)>1) + { + printk(KERN_INFO "I2O controller found but does not support I2O 1.5 (skipping).\n"); + continue; + } + printk(KERN_INFO "I2O controller on bus %d at %d.\n", + dev->bus->number, dev->devfn); + if(!dev->master) + printk(KERN_WARNING "Controller not master enabled.\n"); + if(i2o_pci_install(dev)==0) + count++; + } + if(count) + printk(KERN_INFO "%d I2O controller%s found and installed.\n", count, + count==1?"":"s"); + return count?count:-ENODEV; +} + +static void i2o_pci_unload(void) +{ + int i=0; + struct i2o_controller *c; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c=i2o_find_controller(i); + if(c==NULL) + continue; + if(c->type == I2O_TYPE_PCI) + i2o_delete_controller(c); + i2o_unlock_controller(c); + } +} + +static void i2o_pci_activate(void) +{ + int i=0; + struct i2o_controller *c; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c=i2o_find_controller(i); + if(c==NULL) + continue; + if(c->type == I2O_TYPE_PCI) + { + i2o_activate_controller(c); + *c->irq_mask = 0; + } + i2o_unlock_controller(c); + } +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O PCI Interface"); + +int init_module(void) +{ + if(i2o_pci_scan()<0) + return -ENODEV; + i2o_pci_activate(); + return 0; +} + +void cleanup_module(void) +{ + i2o_pci_unload(); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_scsi.c linux.ac/drivers/i2o/i2o_scsi.c --- linux.vanilla/drivers/i2o/i2o_scsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_scsi.c Wed Mar 24 17:19:06 1999 @@ -0,0 +1,776 @@ +/* + * 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. + * + * Complications for I2O scsi + * + * o Each (bus,lun) is a logical device in I2O. We keep a map + * table. We spoof failed selection for unmapped units + * o Request sense buffers can come back for free. + * o Scatter gather is a bit dynamic. We have to investigate at + * setup time. + * o Some of our resources are dynamically shared. The i2o core + * needs a message reservation protocol to avoid swap v net + * deadlocking. We need to back off queue requests. + * + * In general the firmware wants to help. Where its help isn't performance + * useful we just ignore the aid. Its not worth the code in truth. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" +#include "i2o_scsi.h" + +#define VERSION_STRING "Version 0.0.1" + +#define dprintk(x) + +#define MAXHOSTS 32 + +struct proc_dir_entry proc_scsi_i2o_scsi = { + PROC_SCSI_I2O, 8, "i2o_scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +struct i2o_scsi_host +{ + struct i2o_controller *controller; + s16 task[16][8]; /* Allow 16 devices for now */ + unsigned long tagclock[16][8]; /* Tag clock for queueing */ + s16 bus_task; /* The adapter TID */ +}; + +static int scsi_context; +static int lun_done; +static int i2o_scsi_hosts; + +static u32 *retry[32]; +static struct i2o_controller *retry_ctrl[32]; +static struct timer_list retry_timer; +static int retry_ct = 0; + +static atomic_t queue_depth; + +/* + * Retry congested frames. This actually needs pushing down into + * i2o core. We should only bother the OSM with this when we can't + * queue and retry the frame. Or perhaps we should call the OSM + * and its default handler should be this in the core, and this + * call a 2nd "I give up" handler in the OSM ? + */ + +static void i2o_retry_run(unsigned long f) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for(i=0;i>12)&0xFFF, + m[1]&0xFFF, + m[1]>>24); + printk("Failure Code %d.\n", m[4]>>24); + if(m[4]&(1<<16)) + printk("Format error.\n"); + if(m[4]&(1<<17)) + printk("Path error.\n"); + if(m[4]&(1<<18)) + printk("Path State.\n"); + if(m[4]&(1<<18)) + printk("Congestion.\n"); + + m=(u32 *)bus_to_virt(m[7]); + printk("Failing message is %p.\n", m); + + if((m[4]&(1<<18)) && retry_ct < 32) + { + retry_ctrl[retry_ct]=c; + retry[retry_ct]=m; + if(!retry_ct++) + { + retry_timer.expires=jiffies+1; + add_timer(&retry_timer); + } + } + else + { + /* Create a scsi error for this */ + current_command = (Scsi_Cmnd *)m[3]; + printk("Aborted %ld\n", current_command->serial_number); + + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + } + return; + } + + + /* Low byte is the adapter status, next is the device */ + as=(u8)m[4]; + ds=(u8)(m[4]>>8); + st=(u8)(m[4]>>24); + + dprintk(("i2o got a scsi reply %08X: ", m[0])); + dprintk(("m[2]=%08X: ", m[2])); + dprintk(("m[4]=%08X\n", m[4])); + + if(m[2]&0x80000000) + { + if(m[2]&0x40000000) + { + dprintk(("Lun event.\n")); + lun_done=1; + return; + } + printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); + return; + } + + current_command = (Scsi_Cmnd *)m[3]; + + /* + * Is this a control request coming back - eg an abort ? + */ + + if(current_command==NULL) + { + if(st) + printk("SCSI abort: %08X", m[4]); + printk("SCSI abort completed.\n"); + return; + } + + dprintk(("Completed %ld\n", current_command->serial_number)); + + atomic_dec(&queue_depth); + + if(st == 0x06) + { + if(m[5] < current_command->underflow) + { + int i; + printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", + m[5], current_command->underflow); + printk("Cmd: "); + for(i=0;i<15;i++) + printk("%02X ", current_command->cmnd[i]); + printk(".\n"); + } + else st=0; + } + + if(st) + { + /* An error has occured */ + + printk(KERN_DEBUG "SCSI error %08X", m[4]); + + if (ds == 0x0E) + { + /* SCSI Reset */ + current_command->result = DID_RESET << 16; + current_command->scsi_done(current_command); + return; + } + if (ds == 0x0F) + { + current_command->result = DID_PARITY << 16; + current_command->scsi_done(current_command); + return; + } + + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + /* + * It worked maybe ? + */ + current_command->result = DID_OK << 16 | ds; + current_command->scsi_done(current_command); +} + +struct i2o_handler i2o_scsi_handler= +{ + i2o_scsi_reply, + "I2O SCSI OSM", + 0 +}; + +static int i2o_find_lun(struct i2o_controller *c, int tid, int *target, int *lun) +{ + u8 reply[8]; + + if(i2o_query_scalar(c, tid, scsi_context|0x40000000, + 0, 4, reply, 8, &lun_done)<0) + return -1; + + *lun=reply[1]; + + if(i2o_query_scalar(c, tid, scsi_context|0x40000000, + 0, 3, reply, 8, &lun_done)<0) + return -1; + + *target=reply[3]; + + printk("SCSI (%d,%d)\n", *target, *lun); + return 0; +} + +static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct i2o_scsi_host *h) +{ + struct i2o_device *unit; + int lun; + int target; + + h->controller=c; + h->bus_task=d->id; + + for(target=0;target<16;target++) + for(lun=0;lun<8;lun++) + h->task[target][lun] = -1; + + for(unit=c->devices;unit!=NULL;unit=unit->next) + { + int class = unit->type&0xFFFF; + +// printk("Class %04X, parent %d, want %d.\n", +// class, unit->parent, d->id); + + /* Only look at scsi and fc devices */ + if(class != 0x1041 && class != 0x1051) + continue; + /* On our bus ? */ +// printk("Found a disk.\n"); + if(unit->parent==d->id || 1 || unit->parent == d->parent) + { +// printk("Its ours.\n"); + if(i2o_find_lun(c, unit->id, &target, &lun)==-1) + { + printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", d->id); + continue; + } + h->task[target][lun]=unit->id; + h->tagclock[target][lun]=jiffies; + } + } +} + +int i2o_scsi_detect(Scsi_Host_Template * tpnt) +{ + unsigned long flags; + struct Scsi_Host *shpnt = NULL; + int i; + int count; + + printk("i2o_scsi.c: %s\n", VERSION_STRING); + + if(i2o_install_handler(&i2o_scsi_handler)<0) + { + printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); + return 0; + } + + scsi_context = i2o_scsi_handler.context; + + init_timer(&retry_timer); + retry_timer.data = 0UL; + retry_timer.function = i2o_retry_run; + + printk("SCSI OSM at %d.\n", scsi_context); + + for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *c=i2o_find_controller(i); + struct i2o_device *d; + /* + * This controller doesn't exist. + */ + + if(c==NULL) + continue; + + /* + * Fixme - we need some altered device locking. This + * is racing with device addition in theory. Easy to fix. + */ + + for(d=c->devices;d!=NULL;d=d->next) + { + int class = d->type & 0xFFFF; + /* + * Scsi or fibrechannel busses only + */ + if(class!=0x1040 && class!=0x1050) + continue; + +// printk("Found a controller.\n"); + shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); + save_flags(flags); + cli(); + shpnt->unique_id = (u32)d; + shpnt->io_port = 0; + shpnt->n_io_port = 0; + shpnt->irq = 0; + shpnt->this_id = /* Good question */15; + restore_flags(flags); +// printk("Scanning I2O port %d.\n", d->id); + i2o_scsi_init(c, d, (struct i2o_scsi_host *) shpnt->hostdata); + count++; + } + } + if(count==0) + { + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + i2o_scsi_hosts = count; + return count; +} + +int i2o_scsi_release(struct Scsi_Host *host) +{ + if(--i2o_scsi_hosts==0) + { + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + return 0; +} + + +const char *i2o_scsi_info(struct Scsi_Host *SChost) +{ +// sprintf(info, "I2O SCSI driver"); +// return info; + return("foo"); +} + + +/* + * From the wd93 driver: + * Returns true if there will be a DATA_OUT phase with this command, + * false otherwise. + * (Thanks to Joerg Dorchain for the research and suggestion.) + * + */ +static int is_dir_out(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case 0xea: + return 1; + default: + return 0; + } +} + +int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +{ + int i; + int tid; + struct i2o_controller *c; + Scsi_Cmnd *current_command; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg, *mptr; + u32 m; + u32 *lenptr; + int direction; + int scsidir; + u32 len; + + static int max_qd = 1; + + /* + * The scsi layer should be handling this stuff + */ + + if(is_dir_out(SCpnt)) + { + direction=0x04000000; + scsidir=0x80000000; + } + else + { + scsidir=0x40000000; + direction=0x00000000; + } + + /* + * Do the incoming paperwork + */ + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + SCpnt->scsi_done = done; + + if(SCpnt->target > 15) + { + printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target); + return -1; + } + + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + + dprintk(("qcmd: Tid = %d\n", tid)); + + current_command = SCpnt; /* set current command */ + current_command->scsi_done = done; /* set ptr to done function */ + + /* We don't have such a device. Pretend we did the command + and that selection timed out */ + + if(tid == -1) + { +// printk("Unknown item - spoof completion\n"); + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + + dprintk(("Real scsi messages.\n")); + + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = *c->post_port; + } + while(m==0xFFFFFFFF); + msg = bus_to_virt(c->mem_offset + m); + + /* + * Put together a scsi execscb message + */ + + msg[1] = I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid; + msg[2] = scsi_context; /* So the I2O layer passes to us */ + /* Sorry 64bit folks. FIXME */ + msg[3] = (u32)SCpnt; /* We want the SCSI control block back */ + /* Direction, disconnect ok, no tagging (yet) */ + msg[4] = scsidir|(1<<29)|SCpnt->cmd_len; + + /* + * Attach tags to the devices + */ + if(SCpnt->device->tagged_supported) + { + /* + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. + */ + if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ)) + { + msg[4]|=(1<<23)|(1<<24); + hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies; + } + else switch(SCpnt->tag) + { + case SIMPLE_QUEUE_TAG: + msg[4]|=(1<<23); + break; + case HEAD_OF_QUEUE_TAG: + msg[4]|=(1<<24); + break; + case ORDERED_QUEUE_TAG: + msg[4]|=(1<<23)|(1<<24); + break; + default: + msg[4]|=(1<<23); + } + } + + mptr=msg+5; + + /* + * Write SCSI command into the message - always 16 byte block + */ + + memcpy(mptr, SCpnt->cmnd, 16); + mptr+=4; + lenptr=mptr++; /* Remember me - fill in when we know */ + + + /* + * Now fill in the SGList and command + * + * FIXME: we need to set the sglist limits according to the + * message size of the I2O controller. We might only have room + * for 6 or so worst case + */ + + if(SCpnt->use_sg) + { + struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + + len = 0; + + for(i = 0 ; i < SCpnt->use_sg; i++) + { + *mptr++=direction|0x10000000|sg->length; + len+=sg->length; + *mptr++=virt_to_bus(sg->address); + } + mptr[-2]|=0xC0000000; /* End of List and block */ + *lenptr=len; + if(len != SCpnt->underflow) + printk("Cmd len %08X Cmd underflow %08X\n", + len, SCpnt->underflow); + } + else + { + dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, + SCpnt->request_bufflen)); + *mptr++=0xD0000000|direction|SCpnt->request_bufflen; + *mptr++=virt_to_bus(SCpnt->request_buffer); + *lenptr = len = SCpnt->request_bufflen; + /* No transfer ? - fix up the request */ + if(len == 0) + msg[4]&=~0xC0000000; + } + + /* + * Stick the headers on + */ + + msg[0] = (mptr-msg)<<16 | SGL_OFFSET_10; + + /* Queue the message */ + i2o_post_message(c,m); + + atomic_inc(&queue_depth); + + if(atomic_read(&queue_depth)> max_qd) + { + max_qd=atomic_read(&queue_depth); + printk("Queue depth now %d.\n", max_qd); + } + + mb(); + dprintk(("Issued %ld\n", current_command->serial_number)); + + return 0; +} + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + SCpnt->SCp.Status++; +} + +int i2o_scsi_command(Scsi_Cmnd * SCpnt) +{ + i2o_scsi_queuecommand(SCpnt, internal_done); + SCpnt->SCp.Status = 0; + while (!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; +} + +int i2o_scsi_abort(Scsi_Cmnd * SCpnt) +{ + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg; + u32 m; + int tid; + + printk("i2o_scsi_abort\n"); + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + if(tid==-1) + { + printk(KERN_ERR "impossible command to abort.\n"); + return SCSI_ABORT_NOT_RUNNING; + } + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = *c->post_port; + } + while(m==0xFFFFFFFF); + msg = bus_to_virt(c->mem_offset + m); + + msg[0] = FIVE_WORD_MSG_SIZE; + msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid; + msg[2] = scsi_context; + msg[3] = 0; /* Not needed for an abort */ + msg[4] = (u32)SCpnt; + wmb(); + i2o_post_message(c,m); + wmb(); +// SCpnt->result = DID_RESET << 16; +// SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_PENDING; +} + +int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +{ + int tid; + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 m; + u32 *msg; + + printk("i2o_scsi_reset\n"); + + /* + * Find the TID for the bus + */ + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->bus_task; + c = hostdata->controller; + + /* + * Now send a SCSI reset request. Any remaining commands + * will be aborted by the IOP. We need to catch the reply + * possibly ? + */ + + m = *c->post_port; + + /* + * No free messages, try again next time - no big deal + */ + + if(m == 0xFFFFFFFF) + return SCSI_RESET_PUNT; + + msg = bus_to_virt(c->mem_offset + m); + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid; + msg[2] = scsi_context|0x80000000; + /* We use the top bit to split controller and unit transactions */ + /* Now store unit,tid so we can tie the completion back to a specific device */ + msg[3] = c->unit << 16 | tid; + i2o_post_message(c,m); + return SCSI_RESET_PENDING; +} + +/* + * This is anyones guess quite frankly. + */ + +int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +/* Loadable module support */ +#ifdef MODULE + +MODULE_AUTHOR("Red Hat Software"); + +Scsi_Host_Template driver_template = I2OSCSI; + +#include "../scsi/scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_scsi.h linux.ac/drivers/i2o/i2o_scsi.h --- linux.vanilla/drivers/i2o/i2o_scsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_scsi.h Wed Mar 24 17:25:54 1999 @@ -0,0 +1,46 @@ +#ifndef _I2O_SCSI_H +#define _I2O_SCSI_H + +#if !defined(LINUX_VERSION_CODE) +#include +#endif + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include + +#define I2O_SCSI_ID 15 + +extern struct proc_dir_entry proc_scsi_i2o_scsi; + +extern int i2o_scsi_detect(Scsi_Host_Template *); +extern const char *i2o_scsi_info(struct Scsi_Host *); +extern int i2o_scsi_command(Scsi_Cmnd *); +extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int i2o_scsi_abort(Scsi_Cmnd *); +extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); +extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); +extern void i2o_scsi_setup(char *str, int *ints); + +#define I2OSCSI { \ + next: NULL, \ + proc_dir: &proc_scsi_i2o_scsi, \ + name: "I2O SCSI Layer", \ + detect: i2o_scsi_detect, \ + release: i2o_scsi_release, \ + info: i2o_scsi_info, \ + command: i2o_scsi_command, \ + queuecommand: i2o_scsi_queuecommand, \ + abort: i2o_scsi_abort, \ + reset: i2o_scsi_reset, \ + bios_param: i2o_scsi_bios_param, \ + can_queue: 8, \ + this_id: I2O_SCSI_ID, \ + sg_tablesize: SG_NONE, \ + cmd_per_lun: 6, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ + } + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Config.in linux.ac/drivers/net/Config.in --- linux.vanilla/drivers/net/Config.in Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/net/Config.in Wed Mar 24 11:09:14 1999 @@ -2,6 +2,9 @@ # Network device configuration # +mainmenu_option next_comment +comment 'ARCnet devices' + tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH @@ -12,6 +15,8 @@ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi +endmenu + tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -22,6 +27,10 @@ # # Ethernet # + +mainmenu_option next_comment +comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then @@ -82,18 +91,15 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support' CONFIG_AT1700 + tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 tristate 'Cabletron E21xx support' CONFIG_E2100 tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 tristate 'EtherExpress 16 support' CONFIG_EEXPRESS - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - fi + tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN @@ -114,6 +120,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -144,6 +151,8 @@ fi fi +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -152,25 +161,20 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI if [ "$CONFIG_HIPPI" = "y" ]; then - bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI - bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS fi fi fi -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI -fi - # # AppleTalk # + if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK if [ "$CONFIG_COPS" != "n" ]; then @@ -182,6 +186,7 @@ bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi + endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then @@ -202,10 +207,13 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN fi +mainmenu_option next_comment +comment 'Token ring devices' + bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR @@ -213,12 +221,21 @@ tristate 'SysKonnect adapter support' CONFIG_SKTR fi +endmenu + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi + # # WAN drivers support # + +mainmenu_option next_comment +comment 'Wan interfaces' + + # There is no way to detect a comtrol sv11 - force it modular for now. # dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m @@ -226,8 +243,22 @@ # The COSA/SRP driver has not been tested as non-modular yet. # dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI # +# There is no way to detect a Sealevel board. Force it modular +# +dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + +tristate 'Frame relay DLCI support' CONFIG_DLCI +if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI +fi + +# +# Wan router core. +# + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then @@ -237,14 +268,20 @@ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC + bool ' WANPIPE BiSync Streaming API support' CONFIG_WANPIPE_BSTRM + bool ' WANPIPE HDLC (LAPB) API support' CONFIG_WANPIPE_HDLC fi fi fi + +endmenu + # # X.25 network drivers # if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" != "n" ]; then +if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/net/Makefile Sat Mar 20 22:59:15 1999 @@ -143,14 +143,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o CONFIG_8390_BUILTIN = y @@ -171,14 +163,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_NE2K_PCI),y) L_OBJS += ne2k-pci.o CONFIG_8390_BUILTIN = y @@ -438,6 +422,14 @@ endif endif +ifeq ($(CONFIG_SUNBMAC),y) +L_OBJS += sunbmac.o +else + ifeq ($(CONFIG_SUNBMAC),m) + M_OBJS += sunbmac.o + endif +endif + ifeq ($(CONFIG_MYRI_SBUS),y) L_OBJS += myri_sbus.o else @@ -772,6 +764,19 @@ endif endif +ifeq ($(CONFIG_SEALEVEL_4021),y) +L_OBJS += sealevel.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_SEALEVEL_4021),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += sealevel.o + endif +endif + + ifeq ($(CONFIG_COSA),y) L_OBJS += cosa.o CONFIG_SYNCPPP_BUILTIN = y @@ -1031,6 +1036,16 @@ ifeq ($(CONFIG_WANPIPE_PPP),y) L_OBJS += sdla_ppp.o endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + L_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + L_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + L_OBJS += sdla_hdlc.o + endif + endif ifeq ($(CONFIG_VENDOR_SANGOMA),m) @@ -1045,6 +1060,15 @@ endif ifeq ($(CONFIG_WANPIPE_PPP),y) WANPIPE_OBJS += sdla_ppp.o + endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + WANPIPE_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + WANPIPE_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + WANPIPE_OBJS += sdla_hdlc.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/baycom_epp.c linux.ac/drivers/net/hamradio/baycom_epp.c --- linux.vanilla/drivers/net/hamradio/baycom_epp.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/net/hamradio/baycom_epp.c Mon Mar 1 14:24:08 1999 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/myri_sbus.c linux.ac/drivers/net/myri_sbus.c --- linux.vanilla/drivers/net/myri_sbus.c Wed Mar 24 10:55:19 1999 +++ linux.ac/drivers/net/myri_sbus.c Sat Mar 20 22:59:58 1999 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/net_init.c linux.ac/drivers/net/net_init.c --- linux.vanilla/drivers/net/net_init.c Tue Dec 22 23:19:46 1998 +++ linux.ac/drivers/net/net_init.c Tue Mar 16 18:59:42 1999 @@ -252,6 +252,22 @@ return dev; } + +void unregister_hipdev(struct device *dev) +{ + int i; + rtnl_lock(); + unregister_netdevice(dev); + for (i = 0; i < MAX_HIP_CARDS; ++i) { + if (hipdev_index[i] == dev) { + hipdev_index[i] = NULL; + break; + } + } + rtnl_unlock(); +} + + static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p) { /* Never send broadcast/multicast ARP messages */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rrunner.c linux.ac/drivers/net/rrunner.c --- linux.vanilla/drivers/net/rrunner.c Tue Dec 22 23:19:47 1998 +++ linux.ac/drivers/net/rrunner.c Mon Mar 22 12:49:06 1999 @@ -59,15 +59,7 @@ * stack will need to know about I/O vectors or something similar. */ -static const char *version = "rrunner.c: v0.09 12/14/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; - -static unsigned int read_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length); -static u32 read_eeprom_word(struct rr_private *rrpriv, - void * offset); -static int rr_load_firmware(struct device *dev); +static const char __initdata *version = "rrunner.c: v0.17 03/09/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; /* @@ -78,44 +70,32 @@ extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; +static int probed __initdata = 0; + __initfunc(int rr_hippi_probe (struct device *dev)) { - static int i = 0; int boards_found = 0; int version_disp; /* was version info already displayed? */ - u8 pci_bus; /* PCI bus number (0-255) */ - u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ + struct pci_dev *pdev = NULL; + struct pci_dev *opdev = NULL; u8 pci_latency; - u16 command; /* PCI Configuration space Command register */ - unsigned int tmp; - u8 irq; struct rr_private *rrpriv; + if (probed) + return -ENODEV; + probed++; + if (!pci_present()) /* is PCI BIOS even present? */ return -ENODEV; version_disp = 0; - for (; i < 255; i++) + while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, + PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, + pdev))) { - if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL, - PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, - i, &pci_bus, &pci_dev_fun) != 0) - break; - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, &command); - - /* Enable mastering */ - - command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, command); - - if (!(command & PCI_COMMAND_MEMORY)){ - printk("shared mem not enabled - unable to configure RoadRunner\n"); - break; - } + if (pdev == opdev) + return 0; /* * So we found our HIPPI ... time to tell the system. @@ -123,31 +103,24 @@ dev = init_hippi_dev(dev, sizeof(struct rr_private)); - if (dev == NULL) + if (!dev) break; if (!dev->priv) dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); - rrpriv = (struct rr_private *)dev->priv; - - /* Read register base address from - PCI Configuration Space */ - - pcibios_read_config_dword(pci_bus, pci_dev_fun, - PCI_BASE_ADDRESS_0, &tmp); + if (!dev->priv) + return -ENOMEM; - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_INTERRUPT_LINE, &irq); + rrpriv = (struct rr_private *)dev->priv; + memset(rrpriv, 0, sizeof(*rrpriv)); - dev->irq = irq; - rrpriv->pci_bus = pci_bus; - rrpriv->pci_dev_fun = pci_dev_fun; - sprintf(rrpriv->name, "RoadRunner serial HIPPI"); #ifdef __SMP__ spin_lock_init(&rrpriv->lock); #endif + sprintf(rrpriv->name, "RoadRunner serial HIPPI"); + dev->irq = pdev->irq; dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; @@ -168,29 +141,30 @@ printk(version); } - printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n", - dev->name, tmp, dev->irq); - - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, &pci_latency); -#if 0 - if (pci_latency <= 48){ - printk(" PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 48); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency <= 0x58){ + pci_latency = 0x58; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + pci_latency); } -#else - if (pci_latency <= 0x58) - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 0x58); -#endif + + pci_set_master(pdev); + + printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " + "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, + pdev->base_address[0], dev->irq, pci_latency); + /* * Remap the regs into kernel space. */ - rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000); + rrpriv->regs = (struct rr_regs *) + ioremap(pdev->base_address[0], 0x1000); + if (!rrpriv->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i); + printk(KERN_ERR "%s: Unable to map I/O register, " + "RoadRunner %i will be disabled.\n", + dev->name, boards_found); break; } @@ -198,7 +172,7 @@ * Don't access any registes before this point! */ #ifdef __BIG_ENDIAN - regs->HostCtrl |= NO_SWAP; + writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); #endif /* * Need to add a case for little-endian 64-bit hosts here. @@ -209,6 +183,7 @@ boards_found++; dev->base_addr = 0; dev = NULL; + opdev = pdev; } /* @@ -217,12 +192,59 @@ * 1 or more boards. Otherwise, return failure (-ENODEV). */ +#ifdef MODULE + return boards_found; +#else if (boards_found > 0) return 0; else return -ENODEV; +#endif +} + +static struct device *root_dev = NULL; + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +#endif + + +int init_module(void) +{ + int cards; + + root_dev = NULL; + + cards = rr_hippi_probe(NULL); + return cards ? 0 : -ENODEV; } +void cleanup_module(void) +{ + struct rr_private *rr; + struct device *next; + + while (root_dev) { + next = ((struct rr_private *)root_dev->priv)->next; + rr = (struct rr_private *)root_dev->priv; + + if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ + printk(KERN_ERR "%s: trying to unload running NIC\n", + root_dev->name); + writel(HALT_NIC, &rr->regs->HostCtrl); + } + + iounmap(rr->regs); + unregister_hipdev(root_dev); + kfree(root_dev); + + root_dev = next; + } +} +#endif + /* * Commands are considered to be slow, thus there is no reason to @@ -238,21 +260,25 @@ * This is temporary - it will go away in the final version. * We probably also want to make this function inline. */ - if (regs->HostCtrl & NIC_HALTED){ - printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->HostCtrl) & NIC_HALTED){ + printk("issuing command for halted NIC, code 0x%x, " + "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); } idx = rrpriv->info->cmd_ctrl.pi; - regs->CmdRing[idx] = *(u32*)(cmd); + writel(*(u32*)(cmd), ®s->CmdRing[idx]); + mb(); idx = (idx - 1) % CMD_RING_ENTRIES; rrpriv->info->cmd_ctrl.pi = idx; + mb(); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->Mode) & FATAL_ERR) + printk("error code %02x\n", readl(®s->Fail1)); } @@ -273,85 +299,97 @@ rr_load_firmware(dev); - regs->TX_state = 0x01000000; - regs->RX_state = 0xff800000; - regs->AssistState = 0; - regs->LocalCtrl = CLEAR_INTA; - regs->BrkPt = 0x01; - regs->Timer = 0; - regs->TimerRef = 0; - regs->DmaReadState = RESET_DMA; - regs->DmaWriteState = RESET_DMA; - regs->DmaWriteHostHi = 0; - regs->DmaWriteHostLo = 0; - regs->DmaReadHostHi = 0; - regs->DmaReadHostLo = 0; - regs->DmaReadLen = 0; - regs->DmaWriteLen = 0; - regs->DmaWriteLcl = 0; - regs->DmaWriteIPchecksum = 0; - regs->DmaReadLcl = 0; - regs->DmaReadIPchecksum = 0; - regs->PciState = 0; /* 0x90 for GE? */ - regs->Mode = SWAP_DATA; + writel(0x01000000, ®s->TX_state); + writel(0xff800000, ®s->RX_state); + writel(0, ®s->AssistState); + writel(CLEAR_INTA, ®s->LocalCtrl); + writel(0x01, ®s->BrkPt); + writel(0, ®s->Timer); + writel(0, ®s->TimerRef); + writel(RESET_DMA, ®s->DmaReadState); + writel(RESET_DMA, ®s->DmaWriteState); + writel(0, ®s->DmaWriteHostHi); + writel(0, ®s->DmaWriteHostLo); + writel(0, ®s->DmaReadHostHi); + writel(0, ®s->DmaReadHostLo); + writel(0, ®s->DmaReadLen); + writel(0, ®s->DmaWriteLen); + writel(0, ®s->DmaWriteLcl); + writel(0, ®s->DmaWriteIPchecksum); + writel(0, ®s->DmaReadLcl); + writel(0, ®s->DmaReadIPchecksum); + writel(0, ®s->PciState); +#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN + writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); +#elif (BITS_PER_LONG == 64) + writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); +#else + writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->Mode); +#endif #if 0 /* * Don't worry, this is just black magic. */ - regs->RxBase = 0xdf000; - regs->RxPrd = 0xdf000; - regs->RxCon = 0xdf000; - regs->TxBase = 0xce000; - regs->TxPrd = 0xce000; - regs->TxCon = 0xce000; - regs->RxIndPro = 0; - regs->RxIndCon = 0; - regs->RxIndRef = 0; - regs->TxIndPro = 0; - regs->TxIndCon = 0; - regs->TxIndRef = 0; - regs->pad10[0] = 0xcc000; - regs->DrCmndPro = 0; - regs->DrCmndCon = 0; - regs->DwCmndPro = 0; - regs->DwCmndCon = 0; - regs->DwCmndRef = 0; - regs->DrDataPro = 0; - regs->DrDataCon = 0; - regs->DrDataRef = 0; - regs->DwDataPro = 0; - regs->DwDataCon = 0; - regs->DwDataRef = 0; + writel(0xdf000, ®s->RxBase); + writel(0xdf000, ®s->RxPrd); + writel(0xdf000, ®s->RxCon); + writel(0xce000, ®s->TxBase); + writel(0xce000, ®s->TxPrd); + writel(0xce000, ®s->TxCon); + writel(0, ®s->RxIndPro); + writel(0, ®s->RxIndCon); + writel(0, ®s->RxIndRef); + writel(0, ®s->TxIndPro); + writel(0, ®s->TxIndCon); + writel(0, ®s->TxIndRef); + writel(0xcc000, ®s->pad10[0]); + writel(0, ®s->DrCmndPro); + writel(0, ®s->DrCmndCon); + writel(0, ®s->DwCmndPro); + writel(0, ®s->DwCmndCon); + writel(0, ®s->DwCmndRef); + writel(0, ®s->DrDataPro); + writel(0, ®s->DrDataCon); + writel(0, ®s->DrDataRef); + writel(0, ®s->DwDataPro); + writel(0, ®s->DwDataCon); + writel(0, ®s->DwDataRef); #endif - regs->MbEvent = 0xffffffff; - regs->Event = 0; + writel(0xffffffff, ®s->MbEvent); + writel(0, ®s->Event); - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); rrpriv->info->evt_ctrl.pi = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); - regs->PciState = 0; +/* + * Why 32 ? is this not cache line size dependant? + */ + writel(WBURST_32, ®s->PciState); + mb(); - start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); + start_pc = rr_read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); #if (DEBUG > 1) printk("%s: Executing firmware at address 0x%06x\n", dev->name, start_pc); #endif - regs->Pc = start_pc + 0x800; + writel(start_pc + 0x800, ®s->Pc); + mb(); udelay(5); - regs->Pc = start_pc; + writel(start_pc, ®s->Pc); + mb(); return 0; } @@ -360,7 +398,7 @@ /* * Read a string from the EEPROM. */ -static unsigned int read_eeprom(struct rr_private *rrpriv, +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length) @@ -368,22 +406,25 @@ struct rr_regs *regs = rrpriv->regs; u32 misc, io, host, i; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = 0; - host = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); + host = readl(®s->HostCtrl); + writel(host | HALT_NIC, ®s->HostCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); - buf[i] = (regs->WinData >> 24) & 0xff; + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); + buf[i] = (readl(®s->WinData) >> 24) & 0xff; + mb(); } - regs->HostCtrl = host; - regs->LocalCtrl = misc; - regs->ExtIo = io; - + writel(host, ®s->HostCtrl); + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return i; } @@ -392,13 +433,13 @@ * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */ -static u32 read_eeprom_word(struct rr_private *rrpriv, +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset) { u32 word; - if ((read_eeprom(rrpriv, (unsigned long)offset, - (char *)&word, 4) == 4)) + if ((rr_read_eeprom(rrpriv, (unsigned long)offset, + (char *)&word, 4) == 4)) return be32_to_cpu(word); return 0; } @@ -410,38 +451,42 @@ * This is only called when the firmware is not running. */ static unsigned int write_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length) + unsigned long offset, + unsigned char *buf, + unsigned long length) { struct rr_regs *regs = rrpriv->regs; u32 misc, io, data, i, j, ready, error = 0; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = ENABLE_EEPROM_WRITE; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); data = buf[i] << 24; /* * Only try to write the data if it is not the same * value already. */ - if ((regs->WinData & 0xff000000) != data){ - regs->WinData = data; + if ((readl(®s->WinData) & 0xff000000) != data){ + writel(data, ®s->WinData); ready = 0; j = 0; mb(); while(!ready){ - udelay(1000); - if ((regs->WinData & 0xff000000) == data) + udelay(20); + if ((readl(®s->WinData) & 0xff000000) == + data) ready = 1; + mb(); if (j++ > 5000){ printk("data mismatch: %08x, " "WinData %08x\n", data, - regs->WinData); + readl(®s->WinData)); ready = 1; error = 1; } @@ -449,8 +494,9 @@ } } - regs->LocalCtrl = misc; - regs->ExtIo = io; + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return error; } @@ -465,7 +511,8 @@ rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - rev = regs->FwRev; + rev = readl(®s->FwRev); + rrpriv->fw_rev = rev; if (rev > 0x00020024) printk(" Firmware revision: %i.%i.%i\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); @@ -477,13 +524,13 @@ printk(" Firmware revision too old: %i.%i.%i, please " "upgrade to 2.0.37 or later.\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); - return -EFAULT; - } - printk(" Maximum receive rings %i\n", regs->MaxRxRng); +#if (DEBUG > 2) + printk(" Maximum receive rings %i\n", readl(®s->MaxRxRng)); +#endif - sram_size = read_eeprom_word(rrpriv, (void *)8); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); printk(" SRAM size 0x%06x\n", sram_size); if (sysctl_rmem_max < 262144){ @@ -498,6 +545,9 @@ sysctl_wmem_max = 262144; } + rrpriv->next = root_dev; + root_dev = dev; + return 0; } @@ -507,7 +557,7 @@ struct rr_private *rrpriv; struct rr_regs *regs; u32 hostctrl; - unsigned long myjif, flags, tmp_ptr; + unsigned long myjif, flags; struct cmd cmd; short i; @@ -516,8 +566,9 @@ spin_lock_irqsave(&rrpriv->lock, flags); - hostctrl = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + hostctrl = readl(®s->HostCtrl); + writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->HostCtrl); + mb(); if (hostctrl & PARITY_ERR){ printk("%s: Parity error halting NIC - this is serious!\n", @@ -526,31 +577,14 @@ return -EFAULT; } - - memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); - memset(rrpriv->info, 0, sizeof(struct rr_info)); - - tmp_ptr = virt_to_bus((void *)rrpriv->rx_ctrl); -#if (BITS_PER_LONG == 64) - regs->RxRingHi = (tmp_ptr >> 32); -#else - regs->RxRingHi = 0; -#endif - regs->RxRingLo = ((tmp_ptr) & 0xffffffff); - - tmp_ptr = virt_to_bus((void *)rrpriv->info); -#if (BITS_PER_LONG == 64) - regs->InfoPtrHi = (tmp_ptr >> 32); -#else - regs->InfoPtrHi = 0; -#endif - regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff); + set_rxaddr(regs, rrpriv->rx_ctrl); + set_infoaddr(regs, rrpriv->info); rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; rrpriv->info->evt_ctrl.mode = 0; rrpriv->info->evt_ctrl.pi = 0; - rrpriv->info->evt_ctrl.rngptr = virt_to_bus(rrpriv->evt_ring); + set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring); rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; @@ -558,20 +592,19 @@ rrpriv->info->cmd_ctrl.pi = 15; for (i = 0; i < CMD_RING_ENTRIES; i++) { - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); } for (i = 0; i < TX_RING_ENTRIES; i++) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); rrpriv->tx_skbuff[i] = 0; } - rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; rrpriv->info->tx_ctrl.mode = 0; rrpriv->info->tx_ctrl.pi = 0; - rrpriv->info->tx_ctrl.rngptr = virt_to_bus(rrpriv->tx_ring); + set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring); /* * Set dirty_tx before we start receiving interrupts, otherwise @@ -585,14 +618,20 @@ rr_reset(dev); - regs->IntrTmr = 0x60; - regs->WriteDmaThresh = 0x80 | 0x1f; - regs->ReadDmaThresh = 0x80 | 0x1f; + writel(0x60, ®s->IntrTmr); + /* + * These seem to have no real effect as the Firmware sets + * it's own default values + */ + writel(0x10, ®s->WriteDmaThresh); + writel(0x20, ®s->ReadDmaThresh); rrpriv->fw_running = 0; + mb(); hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR); - regs->HostCtrl = hostctrl; + writel(hostctrl, ®s->HostCtrl); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); @@ -626,10 +665,7 @@ if ((((unsigned long)skb->data) & 0xfff) > ~65320) printk("skb alloc error\n"); -#if (BITS_PER_LONG == 32) - rrpriv->rx_ring[i].zero = 0; -#endif - rrpriv->rx_ring[i].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->rx_ring[i].addr, skb->data); rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; } @@ -637,7 +673,8 @@ rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES; rrpriv->rx_ctrl[4].mode = 8; rrpriv->rx_ctrl[4].pi = 0; - rrpriv->rx_ctrl[4].rngptr = virt_to_bus(rrpriv->rx_ring); + mb(); + set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring); cmd.code = C_NEW_RNG; cmd.ring = 4; @@ -647,18 +684,15 @@ #if 0 { u32 tmp; - tmp = regs->ExtIo; - regs->ExtIo = 0x80; + tmp = readl(®s->ExtIo); + writel(0x80, ®s->ExtIo); i = jiffies + 1 * HZ; while (jiffies < i); - regs->ExtIo = tmp; + writel(tmp, ®s->ExtIo); } #endif dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; return 0; } @@ -669,24 +703,24 @@ * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler. */ -static u32 rr_handle_event(struct device *dev, u32 prodidx) +static u32 rr_handle_event(struct device *dev, u32 prodidx, u32 eidx) { struct rr_private *rrpriv; struct rr_regs *regs; - u32 tmp, eidx; + u32 tmp; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - eidx = rrpriv->info->evt_ctrl.pi; while (prodidx != eidx){ switch (rrpriv->evt_ring[eidx].code){ case E_NIC_UP: - tmp = regs->FwRev; + tmp = readl(®s->FwRev); printk("%s: Firmware revision %i.%i.%i up and running\n", dev->name, (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff)); rrpriv->fw_running = 1; + mb(); break; case E_LINK_ON: printk("%s: Optical link ON\n", dev->name); @@ -729,7 +763,7 @@ #if (DEBUG > 2) printk("%s: RX ring valid event\n", dev->name); #endif - regs->IpRxPi = RX_RING_ENTRIES - 1; + writel(RX_RING_ENTRIES - 1, ®s->IpRxPi); break; case E_INV_RNG: printk("%s: RX ring invalid event\n", dev->name); @@ -756,35 +790,24 @@ } rrpriv->info->evt_ctrl.pi = eidx; + mb(); return eidx; } -static int rx_int(struct device *dev, u32 rxlimit) +static void rx_int(struct device *dev, u32 rxlimit, u32 index) { struct rr_private *rrpriv = (struct rr_private *)dev->priv; - u32 index, pkt_len; + u32 pkt_len; struct rr_regs *regs = rrpriv->regs; - index = rrpriv->cur_rx; - - while(index != rxlimit){ + do { pkt_len = rrpriv->rx_ring[index].size; #if (DEBUG > 2) printk("index %i, rxlimit %i\n", index, rxlimit); printk("len %x, mode %x\n", pkt_len, rrpriv->rx_ring[index].mode); #endif -#if 0 -/* - * I have never seen this occur - */ - if(!(rrpriv->rx_skbuff[index])){ - printk("Trying to receive in empty skbuff\n"); - goto out; - } -#endif - if (pkt_len > 0){ struct sk_buff *skb; @@ -808,7 +831,7 @@ skb = rrpriv->rx_skbuff[index]; skb_put(skb, pkt_len); rrpriv->rx_skbuff[index] = newskb; - rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data); + set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data); }else{ printk("%s: Out of memory, deferring " "packet\n", dev->name); @@ -829,13 +852,13 @@ rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN; if ((index & 7) == 7) - regs->IpRxPi = index; + writel(index, ®s->IpRxPi); index = (index + 1) % RX_RING_ENTRIES; - } + } while(index != rxlimit); rrpriv->cur_rx = index; - return index; + mb(); } @@ -844,25 +867,18 @@ struct rr_private *rrpriv; struct rr_regs *regs; struct device *dev = (struct device *)dev_id; - u32 prodidx, eidx, txcsmr, rxlimit, txcon; + u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - if (!(regs->HostCtrl & RR_INT)) + if (!(readl(®s->HostCtrl) & RR_INT)) return; -#if 0 - if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) { - printk("%s: Re-entering the interrupt handler.\n", dev->name); - return; - } -#endif - spin_lock_irqsave(&rrpriv->lock, flags); - prodidx = regs->EvtPrd; + prodidx = readl(®s->EvtPrd); txcsmr = (prodidx >> 8) & 0xff; rxlimit = (prodidx >> 16) & 0xff; prodidx &= 0xff; @@ -872,6 +888,10 @@ prodidx, rrpriv->info->evt_ctrl.pi); #endif + rxindex = rrpriv->cur_rx; + if (rxindex != rxlimit) + rx_int(dev, rxlimit, rxindex); + txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { @@ -881,11 +901,12 @@ rrpriv->tx_skbuff[txcon] = NULL; rrpriv->tx_ring[txcon].size = 0; - rrpriv->tx_ring[txcon].addr = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); rrpriv->tx_ring[txcon].mode = 0; txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); + mb(); rrpriv->dirty_tx = txcon; if (rrpriv->tx_full && dev->tbusy && @@ -897,21 +918,15 @@ } } - rx_int(dev, rxlimit); - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx); + eidx = rr_handle_event(dev, prodidx, eidx); eidx |= ((txcsmr << 8) | (rxlimit << 16)); - regs->EvtCon = eidx; + writel(eidx, ®s->EvtCon); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); - -#if 0 - dev->interrupt = 0; -#endif } @@ -919,35 +934,64 @@ { struct rr_private *rrpriv; struct rr_regs *regs; + int ecode = 0; + unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; -#if 0 - regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT); -#endif + if (rrpriv->fw_rev < 0x00020000) { + printk(KERN_WARNING "%s: trying to configure device with " + "obsolete firmware\n", dev->name); + ecode = -EBUSY; + goto error; + } + + rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), + GFP_KERNEL | GFP_DMA); + if (!rrpriv->rx_ctrl) { + ecode = -ENOMEM; + goto error; + } + + rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); + if (!rrpriv->info){ + kfree(rrpriv->rx_ctrl); + ecode = -ENOMEM; + goto error; + } + memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); + memset(rrpriv->info, 0, sizeof(struct rr_info)); + mb(); + + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return -EAGAIN; + ecode = -EAGAIN; + goto error; } - rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), - GFP_KERNEL | GFP_DMA); - rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); - rr_init1(dev); dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; MOD_INC_USE_COUNT; return 0; + + error: + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + dev->tbusy = 1; + dev->start = 0; + return -ENOMEM; } @@ -965,12 +1009,13 @@ printk("%s: dumping NIC TX rings\n", dev->name); printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", - regs->RxPrd, regs->TxPrd, regs->EvtPrd, regs->TxPi, + readl(®s->RxPrd), readl(®s->TxPrd), + readl(®s->EvtPrd), readl(®s->TxPi), rrpriv->info->tx_ctrl.pi); - printk("Error code 0x%x\n", regs->Fail1); + printk("Error code 0x%x\n", readl(®s->Fail1)); - index = (((regs->EvtPrd >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; + index = (((readl(®s->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; cons = rrpriv->dirty_tx; printk("TX ring index %i, TX consumer %i\n", index, cons); @@ -989,12 +1034,12 @@ if (rrpriv->tx_skbuff[cons]){ len = min(0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); - printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08x), skbuff-addr %08x, truesize 0x%x\n", + printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, rrpriv->tx_ring[cons].size, - rrpriv->tx_ring[cons].addr, - (unsigned int)bus_to_virt(rrpriv->tx_ring[cons].addr), - (unsigned int)rrpriv->tx_skbuff[cons]->data, + rrpriv->tx_ring[cons].addr.addrlo, + (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo), + (unsigned long)rrpriv->tx_skbuff[cons]->data, (unsigned int)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ if (!(i & 7)) @@ -1009,7 +1054,7 @@ printk("mode 0x%x, size 0x%x, phys-addr %08x\n", rrpriv->tx_ring[i].mode, rrpriv->tx_ring[i].size, - rrpriv->tx_ring[i].addr); + rrpriv->tx_ring[i].addr.addrlo); } @@ -1033,24 +1078,26 @@ */ spin_lock(&rrpriv->lock); - tmp = regs->HostCtrl; + tmp = readl(®s->HostCtrl); if (tmp & NIC_HALTED){ printk("%s: NIC already halted\n", dev->name); rr_dump(dev); - }else - tmp |= HALT_NIC; - regs->HostCtrl = tmp; + }else{ + tmp |= HALT_NIC | RR_CLEAR_INT; + writel(tmp, ®s->HostCtrl); + mb(); + } rrpriv->fw_running = 0; - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); rrpriv->info->tx_ctrl.entries = 0; rrpriv->info->cmd_ctrl.pi = 0; @@ -1060,7 +1107,7 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { if (rrpriv->tx_skbuff[i]) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); dev_kfree_skb(rrpriv->tx_skbuff[i]); } } @@ -1068,7 +1115,7 @@ for (i = 0; i < RX_RING_ENTRIES; i++) { if (rrpriv->rx_skbuff[i]) { rrpriv->rx_ring[i].size = 0; - rrpriv->rx_ring[i].addr = 0; + set_rraddr(&rrpriv->rx_ring[i].addr, 0); dev_kfree_skb(rrpriv->rx_skbuff[i]); } } @@ -1094,6 +1141,10 @@ u32 *ifield; struct sk_buff *new_skb; + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); + /* * We probably need to deal with tbusy here to prevent overruns. */ @@ -1128,11 +1179,11 @@ index = txctrl->pi; rrpriv->tx_skbuff[index] = skb; - rrpriv->tx_ring[index].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->tx_ring[index].addr, skb->data); rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; txctrl->pi = (index + 1) % TX_RING_ENTRIES; - regs->TxPi = txctrl->pi; + writel(txctrl->pi, ®s->TxPi); if (txctrl->pi == rrpriv->dirty_tx){ rrpriv->tx_full = 1; @@ -1167,8 +1218,9 @@ { struct rr_private *rrpriv; struct rr_regs *regs; + unsigned long eptr, segptr; int i, j; - u32 localctrl, eptr, sptr, segptr, len, tmp; + u32 localctrl, sptr, len, tmp; u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; @@ -1178,40 +1230,44 @@ if (dev->flags & IFF_UP) return -EBUSY; - if (!(regs->HostCtrl & NIC_HALTED)){ + if (!(readl(®s->HostCtrl) & NIC_HALTED)){ printk("%s: Trying to load firmware to a running NIC.\n", dev->name); return -EBUSY; } - localctrl = regs->LocalCtrl; - regs->LocalCtrl = 0; + localctrl = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); - regs->EvtPrd = 0; - regs->RxPrd = 0; - regs->TxPrd = 0; + writel(0, ®s->EvtPrd); + writel(0, ®s->RxPrd); + writel(0, ®s->TxPrd); /* * First wipe the entire SRAM, otherwise we might run into all * kinds of trouble ... sigh, this took almost all afternoon * to track down ;-( */ - io = regs->ExtIo; - regs->ExtIo = 0; - sram_size = read_eeprom_word(rrpriv, (void *)8); + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); for (i = 200; i < sram_size / 4; i++){ - regs->WinBase = i * 4; - regs->WinData = 0; + writel(i * 4, ®s->WinBase); + mb(); + writel(0, ®s->WinData); + mb(); } - regs->ExtIo = io; + writel(io, ®s->ExtIo); + mb(); - eptr = read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs); + eptr = (unsigned long)rr_read_eeprom_word(rrpriv, + &hw->rncd_info.AddrRunCodeSegs); eptr = ((eptr & 0x1fffff) >> 3); - p2len = read_eeprom_word(rrpriv, (void *)(0x83*4)); + p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4)); p2len = (p2len << 2); - p2size = read_eeprom_word(rrpriv, (void *)(0x84*4)); + p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4)); p2size = ((p2size & 0x1fffff) >> 3); if ((eptr < p2size) || (eptr > (p2size + p2len))){ @@ -1219,7 +1275,7 @@ goto out; } - revision = read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); + revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); if (revision != 1){ printk("%s: invalid firmware format (%i)\n", @@ -1227,18 +1283,18 @@ goto out; } - nr_seg = read_eeprom_word(rrpriv, (void *)eptr); + nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr +=4; #if (DEBUG > 1) printk("%s: nr_seg %i\n", dev->name, nr_seg); #endif for (i = 0; i < nr_seg; i++){ - sptr = read_eeprom_word(rrpriv, (void *)eptr); + sptr = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - len = read_eeprom_word(rrpriv, (void *)eptr); + len = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - segptr = read_eeprom_word(rrpriv, (void *)eptr); + segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr); segptr = ((segptr & 0x1fffff) >> 3); eptr += 4; #if (DEBUG > 1) @@ -1246,16 +1302,19 @@ dev->name, i, sptr, len, segptr); #endif for (j = 0; j < len; j++){ - tmp = read_eeprom_word(rrpriv, (void *)segptr); - regs->WinBase = sptr; - regs->WinData = tmp; + tmp = rr_read_eeprom_word(rrpriv, (void *)segptr); + writel(sptr, ®s->WinBase); + mb(); + writel(tmp, ®s->WinData); + mb(); segptr += 4; sptr += 4; } } out: - regs->LocalCtrl = localctrl; + writel(localctrl, ®s->LocalCtrl); + mb(); return 0; } @@ -1291,7 +1350,7 @@ error = -ENOMEM; goto out; } - i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (i != EEPROM_BYTES){ kfree(image); printk(KERN_ERR "%s: Error reading EEPROM\n", @@ -1325,7 +1384,7 @@ } oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image){ + if (!oldimage){ printk(KERN_ERR "%s: Unable to allocate memory " "for old EEPROM image\n", dev->name); error = -ENOMEM; @@ -1343,7 +1402,7 @@ printk(KERN_ERR "%s: Error writing EEPROM\n", dev->name); - i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); if (i != EEPROM_BYTES) printk(KERN_ERR "%s: Error reading back EEPROM " "image\n", dev->name); @@ -1354,7 +1413,6 @@ dev->name); error = -EFAULT; } - kfree(image); kfree(oldimage); break; @@ -1374,6 +1432,6 @@ /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c" + * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rrunner.h linux.ac/drivers/net/rrunner.h --- linux.vanilla/drivers/net/rrunner.h Tue Dec 22 23:19:47 1998 +++ linux.ac/drivers/net/rrunner.h Tue Mar 16 18:59:42 1999 @@ -278,7 +278,6 @@ #define TRACE_ON_WHAT_BIT 0x00020000 /* Traces on */ #define ONEM_BUF_WHAT_BIT 0x00040000 /* 1Meg vs 256K */ #define CHAR_API_WHAT_BIT 0x00080000 /* Char API vs network only */ -#define MS_DOS_WHAT_BIT 0x00100000 /* MS_DOS */ #define CMD_EVT_WHAT_BIT 0x00200000 /* Command event */ #define LONG_TX_WHAT_BIT 0x00400000 #define LONG_RX_WHAT_BIT 0x00800000 @@ -486,6 +485,63 @@ #define SAME_IFIELD 0x80 +typedef struct { +#if (BITS_PER_LONG == 64) + u64 addrlo; +#else + u32 addrhi; + u32 addrlo; +#endif +} rraddr; + + +static inline void set_rraddr(rraddr *ra, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) + ra->addrlo = baddr; +#else + /* Don't bother setting zero every time */ + ra->addrlo = baddr; +#endif + mb(); +} + + +static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->RxRingHi); + writel(baddr >> 32, ®s->RxRingLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->RxRingHi); + writel(baddr & 0xffffffff, ®s->RxRingLo); +#else + writel(0, ®s->RxRingHi); + writel(baddr, ®s->RxRingLo); +#endif + mb(); +} + + +static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->InfoPtrHi); + writel(baddr >> 32, ®s->InfoPtrLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->InfoPtrHi); + writel(baddr & 0xffffffff, ®s->InfoPtrLo); +#else + writel(0, ®s->InfoPtrHi); + writel(baddr, ®s->InfoPtrLo); +#endif + mb(); +} + + /* * TX ring */ @@ -498,12 +554,7 @@ #define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) struct tx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -525,12 +576,7 @@ #define RX_RING_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) struct rx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -714,12 +760,7 @@ * This struct is shared with the NIC firmware. */ struct ring_ctrl { -#if (BITS_PER_LONG == 64) - u64 rngptr; -#else - u32 zero; - u32 rngptr; -#endif + rraddr rngptr; #ifdef __LITTLE_ENDIAN u16 entries; u8 pad; @@ -759,19 +800,19 @@ struct rx_desc rx_ring[RX_RING_ENTRIES]; struct tx_desc tx_ring[TX_RING_ENTRIES]; struct event evt_ring[EVT_RING_ENTRIES]; - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; + struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct rr_regs *regs; /* Register base */ struct ring_ctrl *rx_ctrl; /* Receive ring control */ struct rr_info *info; /* Shared info page */ + struct device *next; spinlock_t lock; struct timer_list timer; u32 cur_rx, cur_cmd, cur_evt; u32 dirty_rx, dirty_tx; u32 tx_full; + u32 fw_rev; short fw_running; - u8 pci_bus; /* PCI bus number */ - u8 pci_dev_fun; /* PCI device numbers */ char name[24]; /* The assigned name */ struct net_device_stats stats; }; @@ -789,5 +830,11 @@ static int rr_close(struct device *dev); static struct net_device_stats *rr_get_stats(struct device *dev); static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length); +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset); +static int rr_load_firmware(struct device *dev); #endif /* _RRUNNER_H_ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_bstrm.c linux.ac/drivers/net/sdla_bstrm.c --- linux.vanilla/drivers/net/sdla_bstrm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sdla_bstrm.c Thu Mar 11 13:09:05 1999 @@ -0,0 +1,1011 @@ +/**************************************************************************** +* sdla_bstrm.c Bisync Streaming API module. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Sep 24, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#define _GNUC_ +#include /* BSC Streaming firmware API definitions */ + + +#define MAX_RETRY 10 + +#define NOT_SET 0x00 +#define SC 0x01 +#define EC 0x02 + +/* + * Prototypes + */ + +static int update (wan_device_t *); +static int new_if (wan_device_t *, struct device *, wanif_conf_t *); +static int del_if (wan_device_t *, struct device *); + +static int bsc_exec (struct sdla * , void * , void *); +static void bsc_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void timer_intr(sdla_t *); + +static int if_init (struct device *); +static int if_open (struct device *); +static int if_close (struct device *); +static int if_header(struct sk_buff *, struct device *, unsigned short, void * , void *, unsigned); +static int if_rebuild_hdr (struct sk_buff *); +static int if_send (struct sk_buff *, struct device *); +static struct enet_statistics* if_stats (struct device *); + +static int bsc_code_version(sdla_t *, char *); +static int bsc_intr_mode (sdla_t *, unsigned, unsigned short); +static void bsc_poll_read (sdla_t * , pid_t , struct device *); + +static void send_result_packet(struct sk_buff *, unsigned short, struct device *, pid_t, MAILBOX_STRUCT *, unsigned char, int ); + +typedef struct bsc_private_area +{ + + sdla_t *card; /* card it belongs to */ + char name[WAN_IFNAME_SZ+1]; /* interface name */ + char usedby[USED_BY_FIELD]; /* interface used by */ + unsigned long tick_counter; /* busy counter */ + char status; /* for SK RX Q checks */ + char read_cmd; /* who is doing read */ + pid_t pid_number; /* pid for read cmd */ + struct sk_buff *saved_skb; /* ptr to new_skb */ + struct enet_statistics ifstats; /* statistics */ + +} bsc_private_area_t; + +extern int sangoma_check_sockets( struct sk_buff *); +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* + * BSC initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int bsc_init (sdla_t *card, wandev_conf_t *conf) +{ + char str[80]; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_BSC) { + + printk(KERN_INFO "invalid configuration ID!\n"); + } + + /* Initialize protocol-specific fields of adapter data space */ + switch (card->hw.fwid) { + + case SFID_BSC502: + card->mbox = (void*)(card->hw.dpmbase + + SEND_MB_OFF); + card->rxmb = (void*)(card->hw.dpmbase + + RECEIVE_MB_OFF); + card->flags = (void*)(card->hw.dpmbase + + INTERRUPT_REPORT_IB_OFF); + break; + + default: + return -EINVAL; + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (bsc_code_version(card, NULL) || bsc_code_version(card, str)) + return -EIO; + + printk(KERN_INFO "%s: running BiSync Streaming firmware v%s\n", + card->devname, str); + + card->exec = &bsc_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->isr = &bsc_isr; + + card->wandev.state = WAN_DISCONNECTED; + + card->wandev.api_status = NOT_SET; + + /* Set the read mode: Polling or Interrupt driven */ + card->wandev.read_mode = (conf->read_mode) ? conf->read_mode : WANOPT_INTR; + switch( card->wandev.read_mode ){ + case WANOPT_INTR: + printk(KERN_INFO "%s: Interrupt read mode\n", card->devname); + break; + case WANOPT_POLL: + printk(KERN_INFO "%s: Polling read mode\n", card->devname); + break; + default: + printk(KERN_INFO "%s: Unknown read mode\n", card->devname); + return -EIO; + + } + + return 0; +} + + +/* + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ + return 0; +} + +/* + * Create new network interface. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registeration. + * The register_net_device() is called after this routine. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t *wandev, struct device *dev, wanif_conf_t *conf){ + sdla_t *card = wandev->private; + bsc_private_area_t *bsc_data_area; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + bsc_data_area = kmalloc(sizeof(bsc_private_area_t), GFP_KERNEL); + + if( bsc_data_area == NULL ) + return -ENOMEM; + + memset(bsc_data_area, 0, sizeof(bsc_private_area_t)); + + bsc_data_area->card = card; + bsc_data_area->saved_skb = NULL; + bsc_data_area->status = NO_SK_RX_CHECK; + bsc_data_area->read_cmd = NO_READ_CMD; + bsc_data_area->pid_number = 0; + + /* copy the name of the interface initialize data */ + strcpy(bsc_data_area->name, conf->name); + + /* This interface is used for API or WANPIPE */ + strcpy(bsc_data_area->usedby, conf->usedby); + + /* prepare network device data space for registration */ + dev->name = bsc_data_area->name; + dev->init = &if_init; + dev->priv = bsc_data_area; + return 0; +} + + +/* + * Delete logical channel. + */ +static int del_if (wan_device_t *wandev, struct device *dev) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + sdla_t *card = bsc_data_area->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + if (!card->open_cnt) { + wanpipe_set_state(card, WAN_DISCONNECTED); + } + card->wandev.critical = 0; + + if (dev->priv) { + + + kfree(dev->priv); + dev->priv = NULL; + } + + return 0; +} + +/* + * Execute adapter interface command. + */ +static int bsc_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device *dev) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + sdla_t *card = bsc_data_area->card; + wan_device_t *wandev = &card->wandev; + int err = 0; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + //dev->family = AF_INET; /* address family */ + dev->type = 30; /* ARP h/w type */ + + /* This is done because for an API we do not want to call ifconfig + * which set these calls. + */ + if( strcmp(bsc_data_area->usedby, "API") == 0){ + dev->flags |= IFF_UP; + } + + /* Set to the Maximum size of the SEND & RECV MAILBOX */ + dev->mtu = 4096; + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; //10; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + if( strcmp(bsc_data_area->usedby, "API") == 0) + if_open( dev ); + + return err; +} + + +/* + * Open network interface. + * o if this is the first open, then enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ + +static int if_open (struct device *dev) +{ + bsc_private_area_t *ppp_data_area = dev->priv; + sdla_t *card = ppp_data_area->card; + int err = 0; + + + if (dev->start) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + if (!card->open_cnt) { + } + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + card->wandev.critical = 0; + return err; +} + + +/* + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ + +static int if_close (struct device *dev) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + sdla_t *card = bsc_data_area->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + card->wandev.critical = 0; + return 0; +} + +/* + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field + * of the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + printk(KERN_INFO "if_header\n"); + return 1; +} + +/* + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (struct sk_buff* skb) +{ + return 1; +} + + +/* + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + + if( bsc_data_area == NULL) + return NULL; + else + return &bsc_data_area->ifstats; +} + + +/* + * Receive a socket of type SOCK_PACKET. Process the socket which contains + * a command block to be executed on the board. Execute the command and + * then send the packet back up to the socket layer. SOCK_PACKET socket + * comes directly to the network send routine without any protocols in + * between. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + sdla_t *card = bsc_data_area->card; + MAILBOX_STRUCT *mbox = card->mbox; + BSC_INT_BYTES *bsc_flags = card->flags; + pid_t pid_number; + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + mark_bh(NET_BH); + return 0; + + } + + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then + * we will kick start the device by making dev->tbusy = 0. + * We expect that our device never stays busy more than 5 + * seconds. So this is only used as a last resort. + */ + + if ((jiffies - bsc_data_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + + /* unbusy all the interfaces on the card */ + for (dev = card->wandev.dev; dev; dev = dev->slave) + dev->tbusy = 0; + + } + + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "critical %02X\n", card->wandev.critical); + dev_kfree_skb(skb); + ++bsc_data_area->ifstats.tx_dropped; + enable_irq(card->hw.irq); + return 0; + + } + + + if(ntohs(skb->protocol) == 0x16 ){ + + struct sk_buff *new_skb; + CMDBLOCK_STRUCT *cmdblock; + MAILBOX_STRUCT *cmd_area; + unsigned short length; + int err; + + + ++bsc_data_area->ifstats.tx_packets; + + cmdblock = (CMDBLOCK_STRUCT *)skb->data; + cmd_area = (MAILBOX_STRUCT *)&cmdblock->cmdarea; + + /* Copy the pid number into the CMDBLOCK so that the user + * app knows for who the result is for. + */ + pid_number = cmdblock->pid_num; + + + switch( cmd_area->command ){ + + case ENABLE_COMMUNICATIONS: + + /* + * The enable communications command will + * perform the set interrupt triggers command. + * This is done so that the user application + * does a set configuration before calling + * enable communications. The receive interrupts + * are only made available if the user has set + * the read mode to interrupt mode. In polling + * mode there is only timer interrupt turned on. + */ + + if( card->wandev.read_mode == WANOPT_INTR ) { + bsc_intr_mode(card, + (INTERRUPT_ON_RX_BLOCK | + INTERRUPT_ON_TIMER),10); + } else { + bsc_intr_mode(card, (INTERRUPT_ON_TIMER) + , 10 ); + } + + /* No interrupts are allowed at this point */ + bsc_flags->int_allowed = NO_INTERRUPTS; + break; + + case BSC_READ: + + /* + * For an interrupt driven read, a read command + * is only done ONCE by the application. This + * is done so that the driver knows which + * interface to bind to the socket when a + * receive interrupt occurs. + */ + + if( card->wandev.read_mode == WANOPT_INTR){ + + /* + * Set the read_cmd flag so that we + * know which interface has requested + * the receive packets. On receive + * I will set the skb->dev to this + * interface. The pid number is + * also stored to prevent multiple + * interactions on the same interface. + * At this point RX interrupts are + * turned on. + */ + + bsc_data_area->read_cmd = READ_CMD; + bsc_data_area->pid_number = pid_number; + + /* send a reply back. It is not a + * board command so I will send it from + * here. + */ + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, mbox, BSC_READ, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + bsc_flags->int_allowed = + INTERRUPT_ON_RX_BLOCK; + goto send_done; + } else { + + /* For a polled read, the user + * application performs the BSC_READ + * command. The driver polls the board + * to see if there is any data available + */ + + bsc_poll_read( card, pid_number, dev ); + goto send_done; + } + break; + + default: + break; + } + + /* + * Prepare the send mailbox to execute the command on the + * board. + */ + + memset(mbox, 0, sizeof(MAILBOX_STRUCT)); + memcpy(mbox, cmd_area, sizeof(MAILBOX_STRUCT)); + + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + /* The result is known at this point. I have to check + * whether a SET_CONFIGURATION and ENABLE_COMMS command + * was done and whether or not it was successfull. + */ + if( mbox->return_code == COMMAND_SUCCESSFULL ) { + switch( mbox->command ){ + + case ENABLE_COMMUNICATIONS: + card->wandev.api_status |= EC; + break; + case SET_CONFIGURATION: + card->wandev.api_status |= SC; + break; + case DISABLE_COMMUNICATIONS: + card->wandev.api_status = NOT_SET; + break; + } + } + + /* + * Allocate a new socket buffer. Fill it with the result + * in send mailbox. Check if we can send the data up to + * the socket layer. + */ + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, mbox, 0, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + + } else + ++bsc_data_area->ifstats.tx_dropped; + +send_done: + if(!dev->tbusy) { + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; +} + + +int bsc_code_version(sdla_t* card, char* str) +{ + MAILBOX_STRUCT *mbox = card->mbox; + int retry = MAX_RETRY, err; + + do + { + memset(mbox, 0, sizeof(MAILBOX_STRUCT)); + mbox->command = READ_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + } while (err && retry--); + + if (!err && str) { + int len = mbox->buffer_length; + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} + +/* + * This routine polls the board to see if there is data on the board. + * It is responsible for making the result structure and filling it + * with the correct return code and data. + */ +void bsc_poll_read(sdla_t* card, pid_t pid_number, struct device *dev) +{ + MAILBOX_STRUCT *mbox = card->rxmb; + struct sk_buff *new_skb; + unsigned short length; + int retry=MAX_RETRY, data_avail = 0; + + + /* If EC flag is set then it means that the Enable communications has + * been performed successfully. + */ + if( (card->wandev.api_status & EC) ){ + do + { + if(mbox->opp_flag){ + data_avail = 1; + break; + } + } while (retry--); + } + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, mbox, BSC_READ, data_avail); + } else + printk(KERN_INFO "poll_read: out of mem\n"); + + if( data_avail ) + mbox->opp_flag = 0x00; +} + + + +int bsc_intr_mode(sdla_t* card, unsigned mode, unsigned short timer_val) +{ + MAILBOX_STRUCT *mbox = card->mbox; + int retry = MAX_RETRY; + int err; + + + do + { + memset(mbox, 0, sizeof(MAILBOX_STRUCT)); + mbox->command = SET_INTERRUPT_TRIGGERS; + mbox->buffer_length = 2; + mbox->data[0] = mode; + mbox->data[1] = 1; + if(timer_val) + memcpy(&mbox->data[1], &timer_val, sizeof(short)); + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + } while (err && retry--); + + return err; +} + +static void bsc_isr( sdla_t *card ) +{ + BSC_INT_BYTES *bsc_flags = card->flags; + + card->in_isr = 1; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname); card->in_isr = 0; + return; + + } + + card->wandev.critical = CRITICAL_IN_ISR; + + switch (bsc_flags->int_type) { + + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x20: + timer_intr(card); + break; + default: + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, bsc_flags->int_type); + } + + card->in_isr = 0; + bsc_flags->int_type = 0; + card->wandev.critical = 0; +} + + +void rx_intr( sdla_t *card ) +{ + struct device *dev = card->wandev.dev; + BSC_INT_BYTES *bsc_flags = card->flags; + MAILBOX_STRUCT *mbox = card->rxmb; + MAILBOX_STRUCT *cmd_area; + CMDBLOCK_STRUCT *cmdblock; + bsc_private_area_t *bsc_data_area = NULL; + struct sk_buff *new_skb; + unsigned short length; + int err, found = 0; + + if ( mbox->opp_flag != 0x01) { + + + printk(KERN_INFO + "%s: corrupted Rx buffer, flag = 0x%02X!\n", + card->devname, mbox->opp_flag); + + return; + + } + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + bsc_data_area = dev->priv; + if( bsc_data_area->read_cmd == READ_CMD ){ + found = 1; + break; + } + } + + if(!found){ + /* Turn off RX interrupts */ + bsc_flags->int_allowed &= ~INTERRUPT_ON_RX_BLOCK; + printk(KERN_INFO "%s: Turn off Rx Interrupts\n", card->devname); + mbox->opp_flag = 0x00; + ++bsc_data_area->ifstats.rx_dropped; + return; + } + + if (dev && dev->start) { + + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + skb_put(new_skb,length); + new_skb->dev = dev; + new_skb->len = length; + new_skb->protocol = htons(0x16); + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = bsc_data_area->pid_number; + cmd_area = &cmdblock->cmdarea; + + /* + * Prepare the mailbox to send it back to the process. + */ + memcpy(cmd_area, mbox, MAILBOX_SIZE + mbox->buffer_length); + + /* Set it to the 'BSC_READ' to let the user process know + * for which command the result is being passed up. + */ + cmd_area->command = BSC_READ; + cmd_area->return_code = COMMAND_SUCCESSFULL; + + /* Check and see if we can send the socket back up to + * the stack. Is there room on the socket queue ? + * If yes, then send the data up. If not, then + * enable timer interrupt on the board and send the + * packet when we there is room on the socket queue. + */ + err=sangoma_check_sockets(new_skb); + if( err >= 1){ + if(err == 1){ + printk(KERN_INFO "rx_intr: No memory for skb\n"); + /* Turn off receive interrupts because + * we cannot push any more data up. + */ + bsc_flags->int_allowed &= ~INTERRUPT_ON_RX_BLOCK; + bsc_flags->int_allowed |= INTERRUPT_ON_TIMER; + dev->tbusy = 1; + bsc_data_area->status = BTM_CHECK_SK_RX_Q; + bsc_data_area->saved_skb = new_skb; + } else if(err == 2){ + printk(KERN_INFO "rx_intr: No socket initialized\n"); + new_skb->sk = NULL; + //new_skb->free = 1; + ++bsc_data_area->ifstats.rx_dropped; + dev_kfree_skb(new_skb); + } + } else { + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++bsc_data_area->ifstats.rx_packets; + } + } else + printk(KERN_INFO "rx_intr: (new_skb) out of mem\n"); + + } else + ++bsc_data_area->ifstats.rx_dropped; + + /* We have read the data */ + + mbox->opp_flag = 0x00; + +} + + +void timer_intr( sdla_t *card ) +{ + struct device *dev = card->wandev.dev; + BSC_INT_BYTES *bsc_flags = card->flags; + bsc_private_area_t *bsc_data_area; + struct sk_buff *new_skb; + int err, found = 0; + + + /* check all the interfaces on the card to see if its status flag + * indicates CHECK_SK_RX_Q + */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + + bsc_data_area = dev->priv; + if( bsc_data_area->status == TOP_CHECK_SK_RX_Q || + bsc_data_area->status == BTM_CHECK_SK_RX_Q ){ + found = 1; + new_skb = bsc_data_area->saved_skb; + err=sangoma_check_sockets(new_skb); + if( err >= 1){ + if(err == 1) + printk(KERN_INFO "timer_intr: No memory for skb\n"); + else if(err == 2) { + printk(KERN_INFO "timer_intr: No socket initialized\n"); + dev->tbusy = 0; + new_skb->sk = NULL; + //new_skb->free = 1; + ++bsc_data_area->ifstats.rx_dropped; + dev_kfree_skb(new_skb); + if( bsc_data_area->status == BTM_CHECK_SK_RX_Q && ~(bsc_flags->int_allowed & INTERRUPT_ON_RX_BLOCK) ){ + bsc_flags->int_allowed |= INTERRUPT_ON_RX_BLOCK; + } + bsc_data_area->status = NO_SK_RX_CHECK; + } + } else { + dev->tbusy = 0; + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++bsc_data_area->ifstats.rx_packets; + if( bsc_data_area->status == BTM_CHECK_SK_RX_Q && ~(bsc_flags->int_allowed & INTERRUPT_ON_RX_BLOCK) ){ + bsc_flags->int_allowed |= INTERRUPT_ON_RX_BLOCK; + } + bsc_data_area->status = NO_SK_RX_CHECK; + } + } + } + if(!found) + bsc_flags->int_allowed &= ~INTERRUPT_ON_TIMER; +} + +void send_result_packet( struct sk_buff *new_skb, unsigned short length, struct device *dev, pid_t pid_number, MAILBOX_STRUCT *mbox, unsigned char cmd, int data_avail) +{ + bsc_private_area_t *bsc_data_area = dev->priv; + sdla_t *card = bsc_data_area->card; + BSC_INT_BYTES *bsc_flags = card->flags; + CMDBLOCK_STRUCT *cmdblock; + MAILBOX_STRUCT *cmd_area; + int err; + + + skb_put(new_skb,length); + new_skb->dev = dev; + new_skb->len = length; + new_skb->protocol = htons(0x16); + + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = pid_number; + cmd_area = (MAILBOX_STRUCT *)&cmdblock->cmdarea; + + memcpy(cmd_area, mbox, 16 + mbox->buffer_length); + + if(cmd == BSC_READ){ + cmd_area->command = BSC_READ; + cmd_area->return_code = COMMAND_SUCCESSFULL; + + if(card->wandev.read_mode == WANOPT_POLL){ + if( !data_avail ) + cmd_area->return_code = NO_DATA_AVAILABLE; + } + + if(!(card->wandev.api_status & EC) || + (card->wandev.api_status == NOT_SET)) { + cmd_area->return_code = COMMUNICATIONS_DISABLED; + } + + } + + /* + * Check and see if we can send the socket back + * up to the stack. Is there room on the socket + * queue ? If yes, then send the data up. If not, + * then enable timer interrupt on the board and + * send the packet when we there is room on the + * socket queue. + * sangoma_check_sockets() is our kernel level + * routine in dev.c (/net). This routine checks + * receive queue for any room. + */ + + err=sangoma_check_sockets(new_skb); + + if( err >= 1){ + + if(err == 1){ + + /* + * In this case there is no room on the + * socket queue for the skb. We will + * store the skb (new_skb) so that it is + * sent later on (through the timer + * routine). + */ + printk(KERN_INFO "No memory in socket queue for skb\n"); + dev->tbusy = 1; + bsc_data_area->tick_counter = jiffies; + bsc_data_area->status = TOP_CHECK_SK_RX_Q; + bsc_data_area->saved_skb = new_skb; + bsc_flags->int_allowed |= INTERRUPT_ON_TIMER; + } else if(err == 2) { + + /* + * In this case there is no socket + * created. The user app are not + * even created/initialized the socket. + * I have decided to discard the packets + * in the scenario. + */ + + printk(KERN_INFO "No socket initialized\n"); + new_skb->sk = NULL; + //new_skb->free = 1; + ++bsc_data_area->ifstats.rx_dropped; + dev_kfree_skb(new_skb); + } + } else { + /* There is room on the SK RX Q. */ + + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++bsc_data_area->ifstats.rx_packets; + } +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_chdlc.c linux.ac/drivers/net/sdla_chdlc.c --- linux.vanilla/drivers/net/sdla_chdlc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sdla_chdlc.c Thu Mar 11 13:09:05 1999 @@ -0,0 +1,3099 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Author: David Fong (Based on Code by Jaspreet Singh) +* +* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include +#include /* sockaddr_in */ +#include +#include +#include +#include /* htons(), etc. */ + +#define _GNUC_ +#include /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define CHDLC_MIN_DATA_LEN 300 /* minimum mtu */ +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_MAX_DATA_LEN 15354 /* maximum MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define MAX_RETRY 10 + +#define NOT_SET 0x00 +/* For determining whether Set Configuration and Enable Comms has been done. + */ +#define SC 0x01 /* Set global configuration */ +#define EC 0x02 /* Enabled HDLC Communications */ +#define STC 0x04 /* Set Trace configuration */ + +/* For determining whether HDLC_SEND_WAIT command has been issued and requires + * a transmit interrupt. + */ + +#define TX_WAIT 0x01 + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + +#define WANPIPE 0x00 +#define API 0x01 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char usedby; /* interface used by */ + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned char port_number; /* Port number on the board */ + unsigned char ttl; /* Time To Live for UDP security */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ + struct enet_statistics if_stats; /* interface statistics */ + + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + + char status; /* for SK RX Q checks */ + char tx_status; /* for wait tx */ + char read_cmd; /* who is doing read */ + pid_t tx_pid_number; /* pid for send cmd */ + pid_t rx_pid_number; /* pid for read cmd */ + struct sk_buff *saved_skb; /* ptr to new_skb */ + + + unsigned long router_start_time; + unsigned char route_status; + unsigned long tick_counter; /* For 5s timeout counter */ + + unsigned long router_up_time; +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ +static int num_of_interfaces_for_wanpipe[2]; +static int num_of_interfaces_on_port[2]; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); +extern int sangoma_check_sockets( struct sk_buff *); + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff *skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +static void send_result_packet(struct sk_buff *, unsigned short, struct device *, pid_t, CHDLC_MAILBOX_STRUCT *, unsigned char, int ); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char ); +static int chdlc_comm_enable (sdla_t* card, unsigned char); +static int chdlc_comm_disable (sdla_t* card, unsigned char); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char); +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char); +static void chdlc_poll_read (sdla_t * , pid_t , struct device *); + + +/* Miscellaneous CHDLC Functions */ +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ); +static int chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card, unsigned char); +static int process_global_exception(sdla_t *card, unsigned char); +static int chdlc_get_err_stats (sdla_t* card); +static int configure_ip (sdla_t* card, unsigned char); +static int unconfigure_ip (sdla_t* card, unsigned char); +static void process_route(sdla_t *card); +static void port_set_state (sdla_t *card, int, unsigned char); +static int read_chdlc_configuration( sdla_t *, unsigned char ); + + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card, unsigned char); +static void tx_intr_api( sdla_t *card, struct device *dev ); +static void timer_intr(sdla_t *, unsigned char); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card, struct device *dev ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ); +static unsigned int dec_to_uint (unsigned char* str, int len); + +static int Intr_test_counter; + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpc_init (sdla_t* card, wandev_conf_t* conf) + { + union + { + char str[80]; + } u; + + TRUE_CHDLC_MAILBOX_STRUCT* mb; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* There is one mailbox common between two ports */ + card->mbox = (void *)(card->hw.dpmbase); + + mb = card->mbox; + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO "%s: Initialization not completed by adapter. Please contact Sangoma representative.\n", card->devname); + return -EIO; + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + printk(KERN_INFO "%s: running Cisco HDLC firmware v%s\n", + card->devname, u.str); + + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + num_of_interfaces_for_wanpipe[0] = 0; + num_of_interfaces_for_wanpipe[1] = 0; + //num_of_interfaces_on_port[0] = 0; + //num_of_interfaces_on_port[1] = 0; + + /* This is for the ports link state */ + card->u.c.state[0] = WAN_DISCONNECTED; + card->u.c.state[1] = WAN_DISCONNECTED; + + /* This is for the API status for returning result code */ + card->u.c.api_status[0] = NOT_SET; + card->u.c.api_status[1] = NOT_SET; + + /* Set the flag pointers for both ports to NULL */ + card->u.c.flags[0] = NULL; + card->u.c.flags[1] = NULL; + + return 0; + } + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN; + + card = wandev->private; + + chdlc_get_err_stats(card); + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + unsigned char port_num; + int err; + + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if( chdlc_priv_area == NULL ) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(chdlc_priv_area->name, conf->name); + + /* This interface is used for API or WANPIPE */ + if( strcmp(conf->usedby, "WANPIPE") == 0){ + chdlc_priv_area->usedby = WANPIPE; + } else if( strcmp(conf->usedby, "API") == 0){ + chdlc_priv_area->usedby = API; + } + + /* Get the port number information */ + if (is_digit(conf->addr[0])) { + int port_number = dec_to_uint(conf->addr, 0); + + if (port_number == 0 || port_number == 1) { + chdlc_priv_area->port_number = port_number; + } else { + printk(KERN_ERR + "%s: invalid PORT NUMBER %u on interface %s!\n", + wandev->name, port_number, chdlc_priv_area->name); + return -EINVAL; + } + + } else { + + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chdlc_priv_area->name); + return -EINVAL; + } + + chdlc_priv_area->saved_skb = NULL; + chdlc_priv_area->status = NO_SK_RX_CHECK; + chdlc_priv_area->read_cmd = NO_READ_CMD; + chdlc_priv_area->tx_pid_number = 0; + chdlc_priv_area->rx_pid_number = 0; + chdlc_priv_area->tx_status = NOT_SET; + + + /* The following is only done when the interface is used for WANPIPE */ + if( chdlc_priv_area->usedby == WANPIPE){ + + if( num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number] > 1 ) + return -EEXIST; + + num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number]++; + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + + /* route_status here because we don't want it reset + when cpipemon flushes the statistics */ + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = chdlc_priv_area->port_number; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -EIO; + } + + + chdlc_priv_area->ttl = conf->ttl; + chdlc_priv_area->interface = conf->interface; + chdlc_priv_area->clocking = conf->clocking; + + /* For Port 0 */ + if(chdlc_priv_area->port_number == 0 ){ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P0_MAX_BAUD_RATE): P0_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P0_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + }else if(chdlc_priv_area->port_number == 1){ + /* For Port 1 */ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P1_MAX_BAUD_RATE): P1_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P1_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + } + + + port_num = chdlc_priv_area->port_number; + + card->u.c.flags[port_num] = (void *)( card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE ) ); /* mod to get offset within window */ + + + card->u.c.protocol_options[port_num] = 0; + if (conf->ignore_dcd == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_DCD_FOR_LINK_STAT; + + if (conf->ignore_cts == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_CTS_FOR_LINK_STAT; + + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options[port_num] |= IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx[port_num] = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx[port_num] = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err[port_num] = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + + card->u.c.kpalv_tx[port_num] = + (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx[port_num] = + (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err[port_num] = + (conf->keepalive_err_margin -MIN_KPALV_ERR_TOL) >=0 ? + min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } + + card->u.c.slarp_timer[port_num] = + (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + + } else if( chdlc_priv_area->usedby == API ) { + /* && + (num_of_interfaces_on_port[chdlc_priv_area->port_number] == 0) ){ + */ + num_of_interfaces_on_port[chdlc_priv_area->port_number]++; + if(read_chdlc_configuration(card, chdlc_priv_area->port_number)) + return -EIO; + + } + + + /* prepare network device data space for registration */ + dev->name = chdlc_priv_area->name; + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + + if( chdlc_priv_area->usedby == API){ + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + card->wandev.critical = 0; + + if (dev->priv) { + kfree(dev->priv); + dev->priv = NULL; + } + } + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTTOPOINT; + dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + dev->mtu = chdlc_priv_area->mtu; + dev->hard_header_len = CHDLC_HDR_LEN; + + /* This is done because for an API we do not want to call ifconfig + * which set these calls. + */ + if( chdlc_priv_area->usedby == API){ + dev->flags |= IFF_UP; + /* Set to the Maximum SEND or RECV mailbox */ + dev->mtu = 15384; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + if( chdlc_priv_area->usedby == API ) + if_open( dev ); + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags[port_num]; + struct timeval tv; + int err = 0; + + if (dev->start) return -EBUSY; /* only one open is allowed */ + + disable_irq(card->hw.irq); + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + enable_irq(card->hw.irq); + return -EAGAIN; + } + + if( chdlc_priv_area->usedby == WANPIPE ){ + /* + && + !(num_of_interfaces_on_port[port_num] == 1)){ + */ + num_of_interfaces_on_port[port_num]++; + if (config508(chdlc_priv_area, card)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + /* Interrupt Testing */ + Intr_test_counter = 0; + err = intr_test( card, dev ); + + if((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + printk("Please choose another interrupt\n"); + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff( card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + flags->interrupt_info_struct.interrupt_permission &= + ~TX_APP_INT_PEND; + /* Enable communications */ + if (chdlc_comm_enable(card, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + port_set_state(card,WAN_CONNECTING, port_num); + do_gettimeofday( &tv ); + chdlc_priv_area->router_start_time = tv.tv_sec; + dev->mtu = min(dev->mtu, chdlc_priv_area->mtu); + } + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + + if(chdlc_priv_area && (chdlc_priv_area->usedby == WANPIPE) ){ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + port_set_state(card, WAN_DISCONNECTED, port_num); + chdlc_set_intr_mode(card, 0, port_num); + chdlc_comm_disable(card, port_num); + card->wandev.critical = 0; + } + return 0; +} + +/*============================================================================ + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + skb->protocol = htons(type); + + return CHDLC_HDR_LEN; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (struct sk_buff *skb) +{ + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + struct in_device *in_dev; + CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + unsigned port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_MAILBOX_STRUCT *my_mbox= NULL; + pid_t pid_number; + unsigned char *sendpacket; + unsigned long check_braddr, check_mcaddr; + int err, udp_type = 0, retry = 0; + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + mark_bh(NET_BH); + return 0; + } + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chdlc_priv_area->if_stats.collisions; + + if ((jiffies - chdlc_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "Port%d: Transmit times out\n",port_num); + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } + sendpacket = skb->data; + + if(ntohs(skb->protocol) != 0x16 ){ + + udp_type = udp_pkt_type( skb, card ); + + in_dev = dev->ip_ptr; + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL) { + /*retreive source address in two forms: broadcast & + multicast */ + check_braddr = sendpacket[15]; + check_mcaddr = sendpacket[12]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[13]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[13]; + check_mcaddr |= sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[12]; + check_mcaddr |= sendpacket[15]; + + /* if the Source Address is a Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + /* if the Source Address is a Multicast address */ + if ((check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { + + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + } + } + } + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + /* If the critical flag is set due to an Interrupt + * then set enable transmit interrupt flag to enable + * transmit interrupt. (delay interrupt) + */ + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + printk(KERN_INFO "ENABLE TX\n"); + /* set the counter to see if we get the interrupt in + * 5 seconds. + */ + + chdlc_priv_area->tick_counter = jiffies; + + enable_irq(card->hw.irq); + return 1; + + } + + dev_kfree_skb(skb); + + enable_irq(card->hw.irq); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + if(ntohs(skb->protocol) == 0x16 ){ + + struct sk_buff *new_skb; + CMDBLOCK_STRUCT *cmdblock; + CHDLC_MAILBOX_STRUCT *cmd_area; + unsigned short length; + int err; + + + ++chdlc_priv_area->if_stats.tx_packets; + + + cmdblock = (CMDBLOCK_STRUCT *)skb->data; + cmd_area = (CHDLC_MAILBOX_STRUCT *)&cmdblock->cmdarea; + + /* Copy the pid number into the CMDBLOCK so that the user + * app knows for who the result is for. + */ + pid_number = cmdblock->pid_num; + cmd_area->port_number = port_num; + + switch( cmd_area->command ){ + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + + /* A user application cannot run the following commands because + * WANPIPE is being run on that port. + */ + + case SET_CHDLC_CONFIGURATION: + case DISABLE_CHDLC_COMMUNICATIONS: + if( num_of_interfaces_for_wanpipe[port_num] == 1) { + + my_mbox->buffer_length = 0; + my_mbox->command = cmd_area->command; + my_mbox->return_code = INVALID_CHDLC_COMMAND; + /* send a reply back. This command cannot be + * executed. + */ + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0, 0); + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + kfree(my_mbox); + + if(!dev->tbusy){ + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + } + break; + case ENABLE_CHDLC_COMMUNICATIONS: + + if( num_of_interfaces_for_wanpipe[port_num] == 1) { + + my_mbox->buffer_length = 0; + my_mbox->command = cmd_area->command; + my_mbox->return_code = INVALID_CHDLC_COMMAND; + /* send a reply back. This command cannot be + * executed. + */ + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0, 0); + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + kfree(my_mbox); + if(!dev->tbusy){ + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + } + + tx_status = (CHDLC_TX_STATUS_EL_CFG_STRUCT *) + card->u.c.tx_status[port_num]; + + rx_status = (CHDLC_RX_STATUS_EL_CFG_STRUCT *) + card->u.c.rx_status[port_num]; + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base[port_num] = (void *) + (card->hw.dpmbase + + (tx_status->base_addr_Tx_status_elements % + SDLA_WINDOWSIZE)); + + card->u.c.txbuf_last[port_num] = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base[port_num] + + (tx_status->number_Tx_status_elements - 1); + + + card->u.c.rxbuf_base[port_num] = (void *) + (card->hw.dpmbase + + (rx_status->base_addr_Rx_status_elements % + SDLA_WINDOWSIZE)); + + card->u.c.rxbuf_last[port_num] = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base[port_num] + + (rx_status->number_Rx_status_elements - 1); + + card->u.c.rx_base[port_num] = + rx_status->base_addr_Rx_buffer; + card->u.c.rx_top[port_num] = + rx_status->end_addr_Rx_buffer; + + /* Set up next pointer to be used */ + card->u.c.txbuf[port_num] = card->u.c.txbuf_base[port_num]; + card->u.c.rxmb[port_num] = card->u.c.rxbuf_base[port_num]; + /* + * The enable communications command will + * perform the set interrupt triggers command. + * This is done so that the user application + * does a set configuration before calling + * enable communications. + */ + + chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_TX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TIMER | + APP_INT_ON_CHDLC_EXCEP_COND, + port_num); + + /* No interrupts are allowed at this point only + * the HDLC and GLOBAL exceptions + */ + chdlc_int->interrupt_permission = + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND; + break; + + case CHDLC_SEND_WAIT: + case CHDLC_SEND_NO_WAIT: + + my_mbox = kmalloc( sizeof(CHDLC_MAILBOX_STRUCT), + GFP_ATOMIC); + + my_mbox->return_code = COMMAND_OK; + + /* Since CHDLC_SEND_NO_WAIT & CHDLC_SEND_WAIT are our + * command and not a board command, it is very important * that we provide return codes. + */ + if (card->u.c.state[port_num] != WAN_CONNECTED) { + my_mbox->return_code = LINK_DISCONNECTED; + } + if (chdlc_send(card, cmd_area->data, cmd_area->buffer_length, port_num)) { + my_mbox->return_code = NO_TX_BFRS_AVAIL; + if(cmd_area->command == CHDLC_SEND_WAIT){ + chdlc_priv_area->tx_pid_number = pid_number; + chdlc_int->interrupt_permission |= + APP_INT_ON_TX_FRAME; + + chdlc_priv_area->tx_status=TX_WAIT; + kfree(my_mbox); + + if(!dev->tbusy){ + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + } + + } + my_mbox->buffer_length = 0; + my_mbox->command = cmd_area->command; + + /* send a reply back. It is not a board + * command so I will send it from here. + */ + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0, 0); + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + kfree(my_mbox); + if(!dev->tbusy) { + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + + break; + + case CHDLC_READ_NO_WAIT: + case CHDLC_READ_WAIT: + + my_mbox = kmalloc(sizeof(CHDLC_MAILBOX_STRUCT), + GFP_ATOMIC); + + /* + * CHDLC_READ_NO_WAIT command reads the data(if present) * on the board. This is a poll method. + * + * CHDLC_READ_WAIT command is an interrupt driven cmd + * In this case the user will issue this command once + * to register the interface user wishes to use. + * This way the driver knows which interface to bind to + * the socket when a receive interrupt occurs. + */ + + if( cmd_area->command == CHDLC_READ_WAIT){ + /* + * Set the read_cmd flag so that we know which + * interface has requested the receive packets. + * On receive interrupt I will set the skb->dev + * to this interface. The pid number is also + * stored to prevent multiple interactions on + * the same interface. At this point RX + * interrupts are turned on. + */ + + chdlc_priv_area->read_cmd = READ_CMD; + chdlc_priv_area->rx_pid_number = pid_number; + + /* send a reply back. It is not a + * board command so I will send it from + * here. + */ + my_mbox->buffer_length = 0; + length = MAILBOX_SIZE + my_mbox->buffer_length; + my_mbox->command = CHDLC_READ_WAIT; + + if( card->u.c.state[port_num] != WAN_CONNECTED ) + { + my_mbox->return_code = LINK_DISCONNECTED; + } + if(!(card->u.c.api_status[port_num] & EC) + || (card->u.c.api_status[port_num] == NOT_SET)){ + + my_mbox->return_code = CHDLC_COMMS_DISABLED; + } else + my_mbox->return_code = COMMAND_OK; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + + /* Enable receive interrupt */ + chdlc_int->interrupt_permission |= + APP_INT_ON_RX_FRAME; + + } else { + + chdlc_int->interrupt_permission &= + ~APP_INT_ON_RX_FRAME; + /* For a polled read, the user + * application performs the CHDLC_READ_NO_WAIT + * command. The driver polls the board + * to see if there is any data available + */ + chdlc_poll_read( card, pid_number, dev ); + } + + kfree(my_mbox); + + if(!dev->tbusy) + dev_kfree_skb(skb); + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + break; + + default: + break; + } + + /* + * Prepare the send mailbox to execute the command on the + * board. + */ + + memset(mbox, 0, sizeof(TRUE_CHDLC_MAILBOX_STRUCT)); + memcpy(mbox, cmd_area, sizeof(TRUE_CHDLC_MAILBOX_STRUCT)); + + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + + /* + * Allocate a new socket buffer. Fill it with the result + * in send mailbox. Check if we can send the data up to + * the socket layer. + */ + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, mbox, 0, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + + + + /* The result is known at this point. I have to check + * whether a SET_CONFIGURATION and ENABLE_COMMS command + * was done and whether or not it was successfull. + */ + if( mbox->return_code == COMMAND_OK ) { + switch( mbox->command ){ + + case ENABLE_CHDLC_COMMUNICATIONS: + card->u.c.api_status[port_num] |= EC; + break; + case SET_CHDLC_CONFIGURATION: + card->u.c.api_status[port_num] |= SC; + break; + case DISABLE_CHDLC_COMMUNICATIONS: + card->u.c.api_status[port_num] = NOT_SET; + break; + } + } + + + } else { + + if (udp_type == UDP_CPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, chdlc_priv_area); + + } else if (card->u.c.state[port_num] != WAN_CONNECTED) { + ++chdlc_priv_area->if_stats.tx_dropped; + + } else if (!skb->protocol) { + ++chdlc_priv_area->if_stats.tx_errors; + + } else { + if (chdlc_send(card, skb->data, skb->len, port_num)) { + + retry = 1; + dev->tbusy = 1; + chdlc_priv_area->tick_counter = jiffies; + ++chdlc_priv_area->if_stats.tx_errors; + chdlc_int->interrupt_permission |= TX_APP_INT_PEND; + + } else { + ++chdlc_priv_area->if_stats.tx_packets; + } + } + } + + if (!dev->tbusy){ + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + +} + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, + udp_length, + temp, + i, + ip_length; + unsigned long sum; + + /* Set length of packet */ + len = mbox_len + 62; + + /* fill in UDP reply */ + data[36] = 0x02; + + /* fill in UDP length */ + udp_length = mbox_len + 42; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[24],&temp,2); + + /* swap UDP ports */ + memcpy(&temp,&data[20],2); + memcpy(&data[20],&data[22],2); + memcpy(&data[22],&temp,2); + + /* add UDP pseudo header */ + temp = 0x1100; + memcpy(&data[udp_length+20],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+22],&temp,2); + + /* calculate UDP checksum */ + data[26] = data[27] = 0; + sum = 0; + + for ( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[12+i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if ( temp == 0 ) + temp = 0xffff; + + memcpy(&data[26], &temp, 2); + + /* fill in IP length */ + ip_length = udp_length + 20; + temp = (ip_length<<8)|(ip_length>>8); + memcpy(&data[2], &temp, 2); + + /* swap IP addresses */ + memcpy(&temp, &data[12], 2); + memcpy(&data[12], &data[16], 2); + memcpy(&data[16], &temp, 2); + memcpy(&temp, &data[14], 2); + memcpy(&data[14], &data[18], 2); + memcpy(&data[18], &temp, 2); + + /* fill in IP checksum */ + data[10] = data[11] = 0; + sum = 0; + + for( i = 0; i < 20; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + memcpy(&data[10], &temp, 2); + + return len; + +} /* reply_udp */ + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + return &chdlc_priv_area->if_stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = 0; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + mailbox->port_number = port_num; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char port_num) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 0; + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int chdlc_comm_disable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ +static int chdlc_get_err_stats (sdla_t* card) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + COMMS_ERROR_STATS_STRUCT* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = stats->CRC_err_count; + card->wandev.stats.rx_missed_errors = stats->Rx_abort_count; + + } else { + chdlc_error(card,err,mb); + return err; + } + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + CHDLC_OPERATIONAL_STATS_STRUCT *stats = (void*)mb->data; + card->wandev.stats.rx_length_errors = + stats->Rx_Data_discard_short_count + + stats->Rx_Data_discard_long_count; + + card->wandev.stats.rx_frame_errors = + stats->Rx_frm_incomp_CHDLC_hdr_count + + stats->Rx_frms_too_long_count + + stats->Rx_invalid_CHDLC_addr_count + + stats->Rx_invalid_CHDLC_ctrl_count + + stats->Rx_invalid_CHDLC_type_count + + stats->Rx_SLARP_invalid_code_count + + stats->Rx_SLARP_Reply_bad_IP_addr + + stats->Rx_SLARP_Reply_bad_netmask; + + } else + chdlc_error(card,err,mb); + + + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char port_num) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf[port_num]; + + if (txbuf->opp_flag) return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf[port_num] = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last[port_num]) + card->u.c.txbuf[port_num] = card->u.c.txbuf_base[port_num]; + + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wpc_isr (sdla_t* card) +{ + struct device* dev = card->wandev.dev; + chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i, interrupt_serviced = 0; + int port_num; + + card->in_isr = 1; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + for (i=0; i<2; i++){ + flags = card->u.c.flags[i]; + printk(KERN_INFO "%s: Critical %X while in ISR port%d int type = 0x%02X\n",card->devname, card->wandev.critical,i,flags->interrupt_info_struct.interrupt_type); + } + card->in_isr = 0; + return; + } + card->wandev.critical = 0x61; + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + flags = card->u.c.flags[0]; + + /* Check both the ports to see on which port we have the interrupt. */ + //for (port_num=0; port_num<2; port_num++){ + /* check on port 0 first then port 1 */ + port_num = 0; + for( port_num=0; port_num<2; port_num++){ + + if( card->u.c.flags[port_num] != NULL ) { + flags = card->u.c.flags[port_num]; + + switch (flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + interrupt_serviced = 1; + +// test_timer = jiffies; +// while (1){ +// if ((jiffies - test_timer) > ((1/4)*HZ)) break; +// } + rx_intr(card, port_num); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + interrupt_serviced = 1; + flags->interrupt_info_struct. + interrupt_permission &= ~TX_APP_INT_PEND; + + for( dev=card->wandev.dev; dev; dev=dev->slave) { + chdlc_priv_area = dev->priv; + + if( chdlc_priv_area->usedby == API && + chdlc_priv_area->tx_status == TX_WAIT && + chdlc_priv_area->port_number == port_num ){ + tx_intr_api(card, dev); + break; + } else if(chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + dev->tbusy = 0; + mark_bh(NET_BH); + break; + } + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND: /* 0x04: cmd complete */ + interrupt_serviced = 1; + ++Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + interrupt_serviced = 1; + process_chdlc_exception(card, port_num); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + interrupt_serviced = 1; + process_global_exception(card, port_num); + break; + case TIMER_APP_INT_PEND: + interrupt_serviced = 1; + timer_intr(card, port_num); + break; + default: + break; + } + if(interrupt_serviced) + break; + } + } + if( !interrupt_serviced) { + + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + } + + + /* If the enable transmit interrupt flag is set then enable transmit + * interrupt on the board. This only goes through if if_send is called + * and the critical flag is set due to an Interrupt. + */ + if(card->wandev.enable_tx_int) { + flags->interrupt_info_struct. + interrupt_permission |= TX_APP_INT_PEND; + card->wandev.enable_tx_int = 0; + } + + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; + card->wandev.critical = 0; + +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card, unsigned char port_num) +{ + struct device *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb[port_num]; + struct sk_buff *skb, *new_skb; + unsigned len; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + return; + + } + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + break; + } else if( chdlc_priv_area->usedby == API && + chdlc_priv_area->read_cmd == READ_CMD && + chdlc_priv_area->port_number == port_num){ + break; + } + } + + if (dev && dev->start) { + + if( chdlc_priv_area->usedby == API ) { + CMDBLOCK_STRUCT *cmdblock; + CHDLC_MAILBOX_STRUCT *cmd_area; + int err; + + len = MAILBOX_SIZE + rxbuf->frame_length; + + if((new_skb = dev_alloc_skb(len)) != NULL) { + unsigned addr = rxbuf->ptr_data_bfr; + unsigned data_len = 0, tmp = 0; + + skb_put(new_skb,len); + new_skb->dev = dev; + new_skb->len = len; + new_skb->protocol = htons(0x16); + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = chdlc_priv_area->rx_pid_number; + cmd_area = &cmdblock->cmdarea; + /* + * Copy the data from ptr_data_bfr. This is a + * rotational buffer so we have to be carefull. + */ + data_len = rxbuf->frame_length; + cmd_area->buffer_length = data_len; + + if((addr + data_len) > card->u.c.rx_top[port_num] + 1) { + tmp = card->u.c.rx_top[port_num] - addr + 1; + sdla_peek(&card->hw, addr, cmd_area->data,tmp); + addr = card->u.c.rx_base[port_num]; + data_len -= tmp; + } + sdla_peek(&card->hw, addr, (&cmd_area->data[tmp]), data_len); + + + /* Set it to the 'CHDLC_READ_WAIT' to let the user + * process know for which command the result is being + * passed up. The return code is set to OK. The P_bit + * is copied to the mailbox PF_bit. (Poll & Final bit) + */ + + cmd_area->command = CHDLC_READ_WAIT; + cmd_area->return_code = COMMAND_OK; + + /* Check and see if we can send the socket back up to + * the stack. Is there room on the socket queue ? + * If yes, then send the data up. If not, then + * enable timer interrupt on the board and send the + * packet when there is room on the socket queue. + */ + + err=sangoma_check_sockets(new_skb); + + if( err >= 1){ + + if( err == 1 ) { + printk(KERN_INFO "rx_intr: No memory for skb\n"); + /* Turn off receive interrupts because + * we cannot push any more data up. + */ + chdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + /* Turn on timer interrupt to check the + * status of the socket RX queue. + */ + chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + dev->tbusy = 1; + chdlc_priv_area->status = BTM_CHECK_SK_RX_Q; + chdlc_priv_area->saved_skb = new_skb; + + } else if(err == 2) { + + /* + * In this case there is no socket + * created. The user app are not + * even created/initialized the socket. + * I have decided to discard the packets + * in the scenario. + */ + + printk(KERN_INFO "rx_intr: %s No socket initialized\n", dev->name); + chdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + new_skb->sk = NULL; + //new_skb->free = 1; + ++chdlc_priv_area->if_stats.rx_dropped; + dev_kfree_skb(new_skb); + return; + } + + } else { + /* + * The socket RX queue has room so I can send + * the data up. + */ + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++chdlc_priv_area->if_stats.rx_packets; + } + } else { + printk(KERN_INFO "rx_intr: (new_skb) out of mem\n"); + chdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + return; + } + + + } else if(chdlc_priv_area->usedby == WANPIPE ) { + len = rxbuf->frame_length; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb != NULL) { + /* Copy data to the socket buffer */ + unsigned addr = rxbuf->ptr_data_bfr; + + if ((addr + len) > card->u.c.rx_top[port_num] + 1) { + unsigned tmp = card->u.c.rx_top[port_num] - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base[port_num]; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + /* Decapsulate packet */ + skb->protocol = htons(ETH_P_IP); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_CPIPE_TYPE){ + process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area); + dev_kfree_skb(skb); + + } else { + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++chdlc_priv_area->if_stats.rx_packets; + } + + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++chdlc_priv_area->if_stats.rx_dropped; + } + } + } + + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb[port_num] = ++rxbuf; + + if ((void*)rxbuf > card->u.c.rxbuf_last[port_num]) + card->u.c.rxmb[port_num] = card->u.c.rxbuf_base[port_num]; +} + + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - config508 used to set configuration options on the board + static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) + +------------------------------------------------------------------------------*/ + +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) +{ + struct device * dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + unsigned char port_num = chdlc_priv_area->port_number; + CHDLC_CONFIGURATION_STRUCT cfg; + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if (chdlc_priv_area->clocking) cfg.baud_rate = chdlc_priv_area->bps; + + cfg.line_config_options = chdlc_priv_area->interface == WANOPT_RS232 ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.modem_status_timer = 100; + + cfg.CHDLC_protocol_options = card->u.c.protocol_options[port_num]; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = 0; + cfg.max_CHDLC_data_field_length = chdlc_priv_area->mtu; + cfg.transmit_keepalive_timer = card->u.c.kpalv_tx[port_num]; + cfg.receive_keepalive_timer = card->u.c.kpalv_rx[port_num]; + cfg.keepalive_error_tolerance = card->u.c.kpalv_err[port_num]; + cfg.SLARP_request_timer = card->u.c.slarp_timer[port_num]; + + if (cfg.SLARP_request_timer) { + cfg.IP_address = 0; + cfg.IP_netmask = 0; + } + else { + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa != NULL ) { + cfg.IP_address = ntohl(ifa->ifa_local); + cfg.IP_netmask = ntohl(ifa->ifa_mask); + } + } + } + + return chdlc_configure(card, &cfg, port_num); +} + + + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + mbox->port_number = port_num; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if( err != CMD_TIMEOUT ){ + + switch(mbox->return_code){ + case EXCEP_MODEM_STATUS_CHANGE: + if( (mbox->data[0] & 0x04) ){ + if( (mbox->data[0] & 0x08) ) + printk(KERN_INFO "Port %d: DCD is now high\n", port_num); + else + printk(KERN_INFO "Port %d: DCD is now low\n", port_num); + } + if( (mbox->data[0] & 0x10)){ + if( (mbox->data[0] & 0x20) ) + printk(KERN_INFO "Port %d: CTS is now high\n", port_num); + else + printk(KERN_INFO "Port %d: CTS is now low\n", port_num); + } + break; + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "Port %d: line trace disabled\n", port_num); + break; + default: + printk(KERN_INFO "Port %d: global exception %x\n", port_num, mbox->return_code); + break; + } + + + /* Send the result to all the interfaces */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + + chdlc_priv_area = dev->priv; + if(dev->start && chdlc_priv_area->usedby == API + && chdlc_priv_area->port_number == port_num){ + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, 0, mbox, 0, 0); + } else + printk(KERN_INFO "global_excep: out of mem\n"); + } + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if( err != CMD_TIMEOUT ) { + switch (err) { + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED, port_num); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: CTS and/or DCD down.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_LINK_INACTIVE_KPALV: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: Keepalive timer expired.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_IP_ADDRESS_DISCOVERED: + if (configure_ip(card, port_num)) return -1; + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "Port%d: Loopback Condition Detected.\n", port_num); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "Port%d: No exceptions reported.\n", + port_num); + break; + } + + /* Send the result to all the interfaces */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + + chdlc_priv_area = dev->priv; + if(dev->start && chdlc_priv_area->usedby == API + && chdlc_priv_area->port_number == port_num){ + length = MAILBOX_SIZE + mb->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, 0, mb, 0, 0); + } else + printk(KERN_INFO "chdlc_excep: out of mem\n"); + } + } + } + return 0; +} + + +/*============================================================================ + * Configure IP from SLARP negotiation + * This adds dynamic routes when SLARP has provided valid addresses + */ + +static int configure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + chdlc_private_area_t *chdlc_priv_area=NULL; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + char err; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + + if (card->u.c.slarp_timer[port_num]) { /* set to discover */ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_CONFIGURATION_STRUCT *cfg; + mm_segment_t fs = get_fs(); + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -1; + } + + /* According to Cisco HDLC, if the point-to-point address is + A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa, + ie 2 and 1 respectively */ + + cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; + + if ((cfg->IP_address & ~cfg->IP_netmask) > 2) { + printk(KERN_INFO "%s: Remote address incompatible to SLARP.\n",dev->name); + return -1; + } + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = (ntohl(cfg->IP_address) & ntohl(0xFFFFFF00)) + (~(ntohl(cfg->IP_address)) & ntohl(0x0003)); + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ntohl(cfg->IP_address); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } else + printk(KERN_INFO "%s: Dynamic route added.\n", + card->devname); + + } + else { /* not set to discover */ + if (htonl(in_dev->ifa_list->ifa_local & ~(in_dev->ifa_list->ifa_mask)) > 2) { + printk(KERN_INFO "%s: Local address incompatible to SLARP.\n", dev->name); + return -1; + } + + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = (in_dev->ifa_list->ifa_local & ntohl(0xFFFFFF00)) + (~(in_dev->ifa_list->ifa_local) & ntohl(0x0003)); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + } + + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; + + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + + return 0; +} + + +/*============================================================================ + * Un-Configure IP negotiated by SLARP + * This removes dynamic routes when the link becomes inactive. + */ + +static int unconfigure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area=NULL; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + if (chdlc_priv_area->route_status == ROUTE_ADDED) { + chdlc_priv_area->route_status = REMOVE_ROUTE; + + /* The idea here is to delete the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + } + return 0; +} + +/*============================================================================ + * Routine to add/remove routes + * Called like a polling routine when Routes are flagged to be added/removed. + */ + +static void process_route (sdla_t *card) + { + struct device *dev = card->wandev.dev; + struct ifreq if_info; + struct sockaddr_in *if_data1; + mm_segment_t fs; + int err; + + for(dev=card->wandev.dev; dev; dev=dev->slave){ + + switch (((chdlc_private_area_t *)dev->priv)->route_status) { + + case ADD_ROUTE: + + ((chdlc_private_area_t *)dev->priv)-> + route_status = ROUTE_ADDED; + break; + + case REMOVE_ROUTE: + + fs = get_fs(); + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Remove route failed.\n", + dev->name); + printk(KERN_INFO "Error code: %d\n",err); + } else { + ((chdlc_private_area_t *)dev->priv)-> + route_status = NO_ROUTE; + printk(KERN_INFO "%s: Dynamic route removed.\n", + dev->name); + } + break; + } + } + /* Once we've processed the route, stop polling */ + card->poll = NULL; +} + + +/*============================================================================= + * Process UDP call of type CPIPEAB. + */ + +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *sendpacket; + unsigned char *data; + unsigned char *buf; + unsigned char buf2[5]; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + TRUE_CHDLC_MAILBOX_STRUCT *mb = card->mbox; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + ip_packet_t *ip_packet; + struct timeval tv; + int err; + + sendpacket = skb->data; + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmd 0x%02X\n" + ,card->devname, ((ip_packet_t *)skb->data)->um_packet.cblock.command); + return 1; + } + + memcpy(data,sendpacket,skb->len); + ip_packet = (ip_packet_t *)data; + + switch(ip_packet->um_packet.cblock.command) { + + case FT1_MONITOR_STATUS_CTRL: + if(card->hw.fwid != SFID_CHDLC508) { + udp_mgmt_req_valid = 0; + break; + } + + case CPIPE_ENABLE_TRACING: + + case CPIPE_DISABLE_TRACING: + + case CPIPE_GET_TRACE_INFO: + + case SET_FT1_MODE: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + udp_mgmt_req_valid = 0; + } + break; + + default: + break; + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + ip_packet->um_packet.cblock.buffer_length = 0; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = 0xCD; + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(ip_packet->um_packet.cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Done in 2 steps now because WHAT to be trace will be + configurable in a future release */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> trace_config + |= TRACE_SLARP_FRAMES | TRACE_DATA_FRAMES | TRACE_CDP_FRAMES; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + mb->port_number = port_num; + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + + chdlc_priv_area->available_buffer_space = 2000 - sizeof(ip_packet_t); + } + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + ip_packet->um_packet.cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++) { + + frame_data_t *frame_data = (frame_data_t *) + &ip_packet->um_packet.data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + data_length = data_ptr ? + trace_element_struct.trace_length : 0; + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(frame_data_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + ip_packet->um_packet.ismoredata = 0x01; + break; + } + + frame_data->status = trace_element_struct.trace_type; + + frame_data->time_stamp = + trace_element_struct.trace_time_stamp; + + frame_data->real_length = + trace_element_struct.trace_length; + + + /* see if we can fit the frame into the user buffer */ + real_len = frame_data->real_length; + + if (data_ptr == 0) { + frame_data->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + frame_data->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1) { + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + frame_data->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &frame_data->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &buf2, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + /* update buffer length */ + if ( frame_data->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(frame_data_t); + + } /* For Loop */ + ip_packet->um_packet.num_frames = frames; + + /* set the data length */ + mb->buffer_length = buffer_length; + ip_packet->um_packet.cblock.buffer_length = buffer_length; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)ip_packet->um_packet.data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)ip_packet->um_packet.data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&ip_packet->um_packet.data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if( (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_STATUS) || (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ip_packet->um_packet.data[0] == 0) { + + if( --rCount != 0) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = ip_packet->um_packet.cblock.command; + mb->buffer_length = ip_packet->um_packet.cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) ip_packet-> + um_packet.data, mb->buffer_length); + } + mb->port_number = port_num; + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + + // chdlc_error(card, err, mb); + break; + } + + /* copy the result back to our buffer */ + memcpy(&ip_packet->um_packet.cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&ip_packet->um_packet.data, &mb->data, mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + ip_packet->ip_ttl = chdlc_priv_area->ttl; + + len = reply_udp( data, mb->buffer_length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + chdlc_send(card, data, len, port_num); + + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "no socket buffers available!\n"); + } + } + kfree(data); + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + unsigned char port_num; + char err; + + port_num = chdlc_priv_area->port_number; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base[port_num] = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last[port_num] = (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base[port_num] + (tx_config->number_Tx_status_elements-1); + + card->u.c.rxbuf_base[port_num] = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last[port_num] = (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base[port_num] + (rx_config->number_Rx_status_elements-1); + + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base[port_num] = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top[port_num] = rx_config->end_addr_Rx_buffer; + + /* Set up next pointer to be used */ + card->u.c.txbuf[port_num] = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb[port_num] = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + unsigned char port_num = chdlc_priv_area->port_number; + int err,i; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpp_isr is + * called it does not exit due to critical flag set. + */ + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + err = chdlc_set_intr_mode( card, APP_INT_ON_COMMAND_COMPLETE, port_num); + if ( err == CMD_OK ) { + + for (i=0; ibuffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + } + else { + disable_irq(card->hw.irq); + return err; + } + err = chdlc_set_intr_mode( card, 0, port_num ); + disable_irq(card->hw.irq); + if (err != CMD_OK) return err; + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + ip_packet_t *ip_packet = (ip_packet_t *)skb->data; + + if ( !strncmp(ip_packet->um_packet.signature,UDPMGMT_SIGNATURE,8) && + ip_packet->udp_dst_port == ntohs(card->wandev.udp_port) && + ip_packet->ip_protocol == UDPMGMT_UDP_PROTOCOL && + ip_packet->um_packet.request_reply == UDPMGMT_REQUEST ){ + + return UDP_CPIPE_TYPE; + } + + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state, unsigned char port_num) +{ + + if (card->u.c.state[port_num] != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "Port%d: link connected!\n", + port_num); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "Port%d: link connecting...\n", + port_num) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "Port%d: link disconnected!\n", + port_num) + ; + break; + } + card->u.c.state[port_num] = state; + } +} + +int read_chdlc_configuration( sdla_t *card, unsigned char port_num) +{ + + TRUE_CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + CHDLC_CONFIGURATION_STRUCT *conf_data; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_CHDLC_MAILBOX_STRUCT)); + mbox->command = READ_CHDLC_CONFIGURATION; + mbox->port_number = port_num; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + } while (err && retry--); + + if( !err ){ + conf_data = (CHDLC_CONFIGURATION_STRUCT *)mbox->data; + + card->u.c.flags[port_num] = (void*)(card->hw.dpmbase + + (conf_data->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + + tx_status = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.tx_status[port_num] = tx_status; + + rx_status = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.rx_status[port_num] = rx_status; + + } + return err; +} + +void send_result_packet( struct sk_buff *new_skb, unsigned short length, struct +device *dev, pid_t pid_number, CHDLC_MAILBOX_STRUCT *mbox, unsigned char cmd, int data_avail) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + SHARED_MEMORY_INFO_STRUCT *chdlc_info = card->u.c.flags[chdlc_priv_area->port_number]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &chdlc_info->interrupt_info_struct; + CMDBLOCK_STRUCT *cmdblock; + CHDLC_MAILBOX_STRUCT *cmd_area; + int err; + + + skb_put(new_skb,length); + new_skb->dev = dev; + new_skb->len = length; + new_skb->protocol = htons(0x16); + + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = pid_number; + cmd_area = (CHDLC_MAILBOX_STRUCT *)&cmdblock->cmdarea; + + memcpy(cmd_area, mbox, 16 + mbox->buffer_length); + + /* + * Check and see if we can send the socket back + * up to the stack. Is there room on the socket + * queue ? If yes, then send the data up. If not, + * then enable timer interrupt on the board and + * send the packet when we there is room on the + * socket queue. + * sangoma_check_sockets() is our kernel level + * routine in dev.c (/net). This routine checks + * receive queue for any room. + */ + + err=sangoma_check_sockets(new_skb); + + if( err >= 1){ + + if(err == 1){ + + /* + * In this case there is no room on the + * socket queue for the skb. We will + * store the skb (new_skb) so that it is + * sent later on (through the timer + * routine). + */ + printk(KERN_INFO "No memory in socket queue for skb\n"); dev->tbusy = 1; + chdlc_priv_area->tick_counter = jiffies; + chdlc_priv_area->status = TOP_CHECK_SK_RX_Q; + chdlc_priv_area->saved_skb = new_skb; + chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + + } else if(err == 2) { + + /* + * In this case there is no socket + * created. The user app are not + * even created/initialized the socket. + * I have decided to discard the packets + * in the scenario. + */ + printk(KERN_INFO "%s: No socket initialized\n", dev->name); + new_skb->sk = NULL; + //new_skb->free = 1; + ++chdlc_priv_area->if_stats.rx_dropped; + dev_kfree_skb(new_skb); + } + } else { + /* There is room on the SK RX Q. */ + + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++chdlc_priv_area->if_stats.rx_packets; + } +} + +void tx_intr_api( sdla_t *card, struct device *dev ) +{ + CHDLC_MAILBOX_STRUCT *my_mbox; + chdlc_private_area_t *chdlc_priv_area; + struct sk_buff *new_skb; + unsigned short length; + + + chdlc_priv_area = dev->priv; + + /* send a reply back. + */ + my_mbox = kmalloc(sizeof(CHDLC_MAILBOX_STRUCT), GFP_ATOMIC); + my_mbox->command = CHDLC_SEND_WAIT; + my_mbox->buffer_length = 0; + my_mbox->port_number = chdlc_priv_area->port_number; + my_mbox->return_code = NO_TX_BFRS_AVAIL; + length = MAILBOX_SIZE; + + if((new_skb = dev_alloc_skb( length )) != NULL) { + send_result_packet(new_skb, length, dev, chdlc_priv_area->tx_pid_number, my_mbox, 0, 0); + } else + printk(KERN_INFO "tx_intr: (new_skb) out of mem\n"); + + chdlc_priv_area->tx_status = NOT_SET; + kfree(my_mbox); + +} + +/* + * This routine polls the board to see if there is data on the board. + * It is responsible for making the result structure and filling it + * with the correct return code and data. + */ +void chdlc_poll_read(sdla_t* card, pid_t pid_number, struct device *dev) +{ + struct sk_buff *new_skb; + unsigned short length; + int retry=MAX_RETRY, data_avail = 0; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = NULL; + CHDLC_MAILBOX_STRUCT *my_mbox; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + unsigned char port_num = chdlc_priv_area->port_number; + unsigned long addr, data_len, tmp; + + /* If EC flag is set then it means that the Enable communications has + * been performed successfully. + */ + tmp = 0; + data_len = 0; + my_mbox = kmalloc(sizeof(CHDLC_MAILBOX_STRUCT), GFP_ATOMIC); + my_mbox->buffer_length = 0; + my_mbox->return_code = 0x99; + + if( (card->u.c.api_status[port_num] & EC) ){ + + rxbuf = card->u.c.rxmb[port_num]; + do + { + if(rxbuf->opp_flag){ + data_avail = 1; + data_len = rxbuf->frame_length; + my_mbox->buffer_length = data_len; + addr = rxbuf->ptr_data_bfr; + my_mbox->return_code = COMMAND_OK; + if ((addr + data_len) > card->u.c.rx_top[port_num] + 1) { + tmp = card->u.c.rx_top[port_num] - addr + 1; + sdla_peek(&card->hw, addr, my_mbox->data, tmp); + addr = card->u.c.rx_base[port_num]; + data_len -= tmp; + } + sdla_peek(&card->hw, addr, (&my_mbox->data[tmp]), data_len); + + /* Release buffer element and calculate a + * pointer to the next one + */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb[port_num] = ++rxbuf; + + if((void*)rxbuf >card->u.c.rxbuf_last[port_num]) + card->u.c.rxmb[port_num] = card->u.c.rxbuf_base[port_num]; + break; + } + } while (retry--); + } else { + my_mbox->buffer_length = 0; + my_mbox->return_code = CHDLC_COMMS_DISABLED; + } + + my_mbox->command = CHDLC_READ_NO_WAIT; + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0,0); + } else + printk(KERN_INFO "poll_read: out of mem\n"); + + kfree(my_mbox); + +} + +void timer_intr( sdla_t *card , unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + SHARED_MEMORY_INFO_STRUCT *chdlc_info = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &chdlc_info->interrupt_info_struct; + chdlc_private_area_t *chdlc_priv_area; + struct sk_buff *new_skb; + int err; + + + /* check all the interfaces on the card to see if its status flag + * indicates CHECK_SK_RX_Q + */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + chdlc_priv_area = dev->priv; + + if( chdlc_priv_area->port_number == port_num && + chdlc_priv_area->usedby == API && ( + chdlc_priv_area->status == TOP_CHECK_SK_RX_Q || + chdlc_priv_area->status == BTM_CHECK_SK_RX_Q) ){ + + new_skb = chdlc_priv_area->saved_skb; + err=sangoma_check_sockets(new_skb); + if( err >= 1){ + if(err == 1){ + printk(KERN_INFO "timer_intr: No memory for skb\n"); + } else if(err == 2) { + printk(KERN_INFO "timer_intr: %s No socket initialized\n", dev->name); + dev->tbusy = 0; + new_skb->sk = NULL; + //new_skb->free = 1; + ++chdlc_priv_area->if_stats.rx_dropped; + dev_kfree_skb(new_skb); + + //if( hdlc_data_area->status == BTM_CHECK_SK_RX_Q ){ + // hdlc_int->interrupt_permission |= APP_INT_ON_RX_FRAME; + //} + chdlc_priv_area->status= NO_SK_RX_CHECK; + chdlc_int->interrupt_permission &= ~APP_INT_ON_TIMER; + } + } else { + dev->tbusy = 0; + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++chdlc_priv_area->if_stats.rx_packets; + if( chdlc_priv_area->status == BTM_CHECK_SK_RX_Q +){ + chdlc_int->interrupt_permission |= APP_INT_ON_RX_FRAME; + } + chdlc_priv_area->status = NO_SK_RX_CHECK; + chdlc_int->interrupt_permission &= ~APP_INT_ON_TIMER; + } + } + } +} + + +/****** End ****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_fr.c linux.ac/drivers/net/sdla_fr.c --- linux.vanilla/drivers/net/sdla_fr.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_fr.c Thu Mar 11 13:08:32 1999 @@ -1,8 +1,7 @@ /***************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author(s): Gene Kozin -* Jaspreet Singh +* Author(s): Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -11,6 +10,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. +* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI +* status is received through an event interrupt. +* Jul 08, 1998 David Fong o Added inverse ARP support. +* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. +* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. +* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) +* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards * o Added Cli() to protect enabling of interrupts * while polling is called. @@ -53,7 +60,7 @@ * This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy) * forever. * The code got into this stage due to an -* interrupt occurring within the if clause for +* interrupt occuring within the if clause for * set_bit(0,dev->tbusy). Since an interrupt * disables furhter transmit interrupt and * makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause. @@ -93,72 +100,84 @@ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ #include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ +#include /* for do_gettimeofday */ +#include /* Dynamic Route Creation */ +#include /* sockaddr_in */ +#include /* in_ntoa(), etc... */ +#include +#include +#include #define _GNUC_ #include /* frame relay firmware API definitions */ -#include - /****** Defines & Macros ****************************************************/ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/* Q.922 frame types */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +/* Q.922 frame types */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* DLCI configured or not */ - #define DLCI_NOT_CONFIGURED 0x00 #define DLCI_CONFIG_PENDING 0x01 #define DLCI_CONFIGURED 0x02 /* CIR enabled or not */ - #define CIR_ENABLED 0x00 #define CIR_DISABLED 0x01 /* Interrupt mode for DLCI = 0 */ -#define BUFFER_INTR_MODE 0x00 -#define DLCI_LIST_INTR_MODE 0x01 - /* Transmit Interrupt Status */ - #define DISABLED 0x00 #define WAITING_TO_BE_ENABLED 0x01 -/* For handle_IPXWAN() */ +#define MAX_SEND_FAILS 50 +/* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci_configured; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_start_time;/* Router start time in seconds */ unsigned long tick_counter; /* counter for transmit time out */ char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ + char state; /* channel state */ + void *dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct net_device_stats ifstats; /* interface statistics */ + unsigned char enable_IPX; /* Enable/Disable the use of IPX */ + unsigned long network_number; /* Internal Network Number for IPX*/ + sdla_t *card; /* -> owner */ + unsigned route_flag; /* Add/Rem dest addr in route tables */ + unsigned inarp; /* Inverse Arp Request status */ + int inarp_interval; /* Time between InArp Requests */ + unsigned long inarp_tick; /* InArp jiffies tick counter */ + + struct net_device_stats ifstats; /* interface statistics */ + + /* This variable is used for discarding packets when consecutive + failures for an interface exceeds a limit */ + + unsigned long consecutive_send_fails; unsigned long if_send_entry; unsigned long if_send_skb_null; unsigned long if_send_broadcast; @@ -174,12 +193,14 @@ unsigned long if_send_no_bfrs; unsigned long if_send_adptr_bfrs_full; unsigned long if_send_bfrs_passed_to_adptr; + unsigned long rx_intr_no_socket; unsigned long rx_intr_dev_not_started; unsigned long rx_intr_FPIPE_request; unsigned long rx_intr_DRVSTATS_request; unsigned long rx_intr_bfr_not_passed_to_stack; unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_kmalloc_err; unsigned long UDP_FPIPE_mgmt_direction_err; unsigned long UDP_FPIPE_mgmt_adptr_type_err; @@ -201,32 +222,48 @@ unsigned long router_up_time; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; -typedef struct dlci_IB_mapping { - unsigned short dlci PACKED; - unsigned long addr_value PACKED; +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; } dlci_IB_mapping_t; /* This structure is used for DLCI list Tx interrupt mode. It is used to enable interrupt bit and set the packet length for transmission */ - -typedef struct fr_dlci_interface { - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; static unsigned short num_frames; static unsigned long curr_trace_addr; static unsigned long start_trace_addr; static unsigned short available_buffer_space; -static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */ + +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + +extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -238,67 +275,72 @@ /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct device *dev); + /* WANPIPE-specific entry points */ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); static int if_send(struct sk_buff *skb, struct device *dev); static struct net_device_stats *if_stats(struct device *dev); + /* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); -/* Background polling routines */ -static void wpf_poll(sdla_t * card); +static void fr508_isr(sdla_t *card); +static void fr508_rx_intr(sdla_t *card); +static void spur_intr(sdla_t *card); + /* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr_read_version(sdla_t *card, char *str); +static int fr_configure(sdla_t *card, fr_conf_t *conf); +static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); +static int fr_comm_enable(sdla_t *card); +static int fr_comm_disable(sdla_t *card); +static int fr_get_err_stats(sdla_t *card); +static int fr_get_stats(sdla_t *card); +static int fr_add_dlci(sdla_t *card, int dlci, int num); +static int fr_activate_dlci(sdla_t *card, int dlci, int num); +static int fr_issue_isf(sdla_t *card, int isf); +static int fr508_send(sdla_t *card, int dlci, int attr, int len, void *buf); + /* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); +static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); +static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); + /* Miscellaneous functions */ static int update_chan_state(struct device *dev); static void set_chan_state(struct device *dev, int state); -static struct device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card, fr_channel_t * chan); +static struct device *find_channel(sdla_t *card, unsigned dlci); +static int is_tx_ready(sdla_t *card, fr_channel_t *chan); static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int intr_test(sdla_t * card); -static void init_chan_statistics(fr_channel_t * chan); -static void init_global_statistics(sdla_t * card); -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); + +/* Inverse ARP and Dynamic routing functions */ +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device *dev); +int is_arp(void *buf); +int send_inarp_request(sdla_t *card, struct device *dev); + /* Udp management functions */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t *chan); +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t *chan); +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); - /****** Public Functions ****************************************************/ /*============================================================================ @@ -313,154 +355,183 @@ * Return: 0 o.k. * < 0 failure. */ -int wpf_init(sdla_t * card, wandev_conf_t * conf) +int wpf_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; fr_conf_t cfg; } u; int i; + /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) - { + if (conf->config_id != WANCONFIG_FR) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) - { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; + switch (card->hw.fwid) { + case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + card->mbox = (void*)(card->hw.dpmbase + + FR508_MBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + + FR508_FLAG_OFFS); card->isr = &fr508_isr; break; + default: return -EINVAL; } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) return -EIO; + printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); + card->devname, u.str); + /* Adjust configuration */ conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); conf->bps = min(conf->bps, 2048000); - /* Configure adapter firmware */ + + /* Initialze the configuration structure sent to the board to zero */ memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - if (conf->station == WANOPT_CPE) - { - u.cfg.options = 0x0080; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - } - else - { - u.cfg.options = 0x0081; - } - switch (conf->u.fr.signalling) - { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; + + /* Configure adapter firmware */ + + u.cfg.mtu = conf->mtu; + u.cfg.kbps = conf->bps / 1000; + + u.cfg.cir_fwd = u.cfg.cir_bwd = 16; + u.cfg.bc_fwd = u.cfg.bc_bwd = 16; + + u.cfg.options = 0x0000; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + + switch (conf->u.fr.signalling) { + + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; break; + + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; break; + + case WANOPT_NO: + u.cfg.options |= 0x0800; break; } - if (conf->station == WANOPT_CPE) - { + + if (conf->station == WANOPT_CPE) { + + u.cfg.station = 0; u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - } - else - { + card->u.f.dlci_num = 0; + + } else { + u.cfg.station = 1; /* switch emulation mode */ + /* For switch emulation we have to create a list of dlci(s) * that will be sent to be global SET_DLCI_CONFIGURATION * command in fr_configure() routine. */ - card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); - for (i = 0; i < card->u.f.dlci_num; i++) - { - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); + + for ( i = 0; i < card->u.f.dlci_num; i++) { + + card->u.f.node_dlci[i] = (unsigned short) + conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + } } + if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001; + if (conf->interface == WANOPT_RS232) u.cfg.port |= 0x0002; + if (conf->u.fr.t391) u.cfg.t391 = min(conf->u.fr.t391, 30); else u.cfg.t391 = 5; + if (conf->u.fr.t392) u.cfg.t392 = min(conf->u.fr.t392, 30); else u.cfg.t392 = 15; + if (conf->u.fr.n391) u.cfg.n391 = min(conf->u.fr.n391, 255); else u.cfg.n391 = 2; + if (conf->u.fr.n392) u.cfg.n392 = min(conf->u.fr.n392, 10); else - u.cfg.n392 = 3; + u.cfg.n392 = 3; + if (conf->u.fr.n393) u.cfg.n393 = min(conf->u.fr.n393, 10); else u.cfg.n393 = 4; + if (fr_configure(card, &u.cfg)) return -EIO; - if (card->hw.fwid == SFID_FR508) - { - fr_buf_info_t *buf_info = - (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); - card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * - sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase); + + if (card->hw.fwid == SFID_FR508) { + + fr_buf_info_t* buf_info = + (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); + + card->rxmb = + (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase); + card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; + card->u.f.rx_top = buf_info->buf_top; } - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = &wpf_poll; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; + + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->poll = NULL; //&wpf_poll; + card->exec = &wpf_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.ttl = conf->ttl; + card->wandev.udp_port = conf->udp_port; card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + /* Intialize global statistics for a card */ - init_global_statistics(card); - TracingEnabled = 0; - return 0; + init_global_statistics( card ); + + card->TracingEnabled = 0; + + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -468,17 +539,20 @@ /*============================================================================ * Update device status & statistics. */ - -static int update(wan_device_t * wandev) +static int update (wan_device_t* wandev) { - sdla_t *card; + sdla_t* card; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; fr_get_err_stats(card); fr_get_stats(card); @@ -498,85 +572,111 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { - sdla_t *card = wandev->private; - fr_channel_t *chan; + sdla_t* card = wandev->private; + fr_channel_t* chan; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; } + /* allocate and initialize private data */ chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); + if (chan == NULL) return -ENOMEM; + memset(chan, 0, sizeof(fr_channel_t)); strcpy(chan->name, conf->name); chan->card = card; + /* verify media address */ - if (is_digit(conf->addr[0])) - { + if (is_digit(conf->addr[0])) { + int dlci = dec_to_uint(conf->addr, 0); - if (dlci && (dlci <= 4095)) - { + + if (dlci && (dlci <= 4095)) { + chan->dlci = dlci; - } - else - { - printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); + + } else { + + printk(KERN_ERR + "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); err = -EINVAL; } - } - else - { - printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); + + } else { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + if (err) { + kfree(chan); return err; } + /* place cir,be,bc and other channel specific information into the * chan structure - */ - if (conf->cir) - { - chan->cir = max(1, min(conf->cir, 512)); - chan->cir_status = CIR_ENABLED; + */ + if (conf->cir) { + + chan->cir = max( 1, min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + if (conf->bc) - chan->bc = max(1, min(conf->bc, 512)); + chan->bc = max( 1, min( conf->bc, 512 ) ); if (conf->be) - chan->be = max(0, min(conf->be, 511)); - } - else + chan->be = max( 0, min( conf->be, 511) ); + + } else chan->cir_status = CIR_DISABLED; + chan->mc = conf->mc; - chan->dlci_configured = DLCI_NOT_CONFIGURED; - chan->tx_int_status = DISABLED; - init_chan_statistics(chan); + + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + chan->tx_int_status = DISABLED; + + chan->enable_IPX = conf->enable_IPX; + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; + + init_chan_statistics( chan ); + /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; dev->priv = chan; return 0; } + /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if (wan_device_t* wandev, struct device* dev) { - if (dev->priv) - { + if (dev->priv) { + kfree(dev->priv); dev->priv = NULL; } + return 0; } @@ -585,41 +685,46 @@ /*============================================================================ * Execute adapter interface command. */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, len; fr_cmd_t cmd; - if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd))) - return -EFAULT; + + if( copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ - do + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) + + if (cmd.length){ + if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) return -EFAULT; } + if (sdla_exec(mbox)) err = mbox->cmd.result; - else - return -EIO; - } - while (err && retry-- && fr_event(card, err, mbox)); - /* return result */ + else return -EIO; + + } while (err && retry-- && fr_event(card, err, mbox)); - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) + /* return result */ + if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) return -EFAULT; + len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; return 0; } /****** Network Device Interface ********************************************/ + /*============================================================================ * Initialize Linux network interface. * @@ -627,35 +732,43 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct device *dev) +static int if_init (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - wan_device_t *wandev = &card->wandev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->mtu = FR_CHANNEL_MTU; - dev->hard_header_len = FR_HEADER_LEN; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short *) dev->dev_addr = htons(chan->dlci); + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->mtu = FR_CHANNEL_MTU; + + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + /* Initialize socket buffers */ dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -667,102 +780,74 @@ * * Return 0 if O.k. or errno. */ - -static int if_open(struct device *dev) +static int if_open (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - struct device *dev2; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; int err = 0; - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; struct timeval tv; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if (!card->open_cnt) - { + + if (!card->open_cnt) { + Intr_test_counter = 0; card->intr_mode = INTR_TEST_MODE; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO - "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); + err = intr_test( card ); + + if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) { + + printk( + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); err = -EIO; card->wandev.critical = 0; return err; } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" - ,card->devname, Intr_test_counter); - /* The following allocates and intializes a circular - * link list of interfaces per card. - */ - card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); - if (card->devs_struct == NULL) - return -ENOMEM; - card->dev_to_devtint_next = card->devs_struct; - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - (card->devs_struct)->dev_ptr = dev2; - if (dev2->slave == NULL) - (card->devs_struct)->next = card->dev_to_devtint_next; - else { - (card->devs_struct)->next = kmalloc( - sizeof(load_sharing_t), GFP_KERNEL); - if ((card->devs_struct)->next == NULL) - return -ENOMEM; - card->devs_struct = (card->devs_struct)->next; - } - } - card->devs_struct = card->dev_to_devtint_next; - card->intr_mode = BUFFER_INTR_MODE; - /* - check all the interfaces for the device to see if CIR has - been enabled for any DLCI(s). If so then use the DLCI list - Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode - */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - if (((fr_channel_t *) dev2->priv)->cir_status - == CIR_ENABLED) { - card->intr_mode = DLCI_LIST_INTR_MODE; - break; - } - } + ,card->devname, Intr_test_counter); + + /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. - */ - if (card->intr_mode == BUFFER_INTR_MODE) { - if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: Global Buffering Tx Interrupt Mode\n" - ,card->devname); - } else if (card->intr_mode == DLCI_LIST_INTR_MODE) { - if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: DLCI list Tx Interrupt Mode\n", - card->devname); + If you enable comms and then set ints, you get a Tx int as you + perform the SET_INT_TRIGGERS command. So, we only set int + triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. + */ + if (fr_set_intr_mode(card, 0xB3, card->wandev.mtu, 100)) { + + err = -EIO; + card->wandev.critical = 0; + return err; } - flags->imask &= ~0x02; + + printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + + flags->imask &= ~0x22; + if (fr_comm_enable(card)) { + err = -EIO; card->wandev.critical = 0; return err; - } + } + wanpipe_set_state(card, WAN_CONNECTED); + if (card->wandev.station == WANOPT_CPE) { + /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); + } else { /* FR switch: activate DLCI(s) */ + /* For Switch emulation we have to ADD and ACTIVATE * the DLCI(s) that were configured with the SET_DLCI_ * CONFIGURATION command. Add and Activate will fail if @@ -770,23 +855,28 @@ * * Also If_open is called once for each interface. But * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add + * we have to pass the entire list of DLCI(s) to add * activate routines. - */ + */ + fr_add_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); + card->u.f.node_dlci[0], card->u.f.dlci_num); + fr_activate_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); + card->u.f.node_dlci[0], card->u.f.dlci_num); + } } + dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; wanpipe_open(card); update_chan_state(dev); - do_gettimeofday(&tv); + do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; + card->wandev.critical = 0; return err; } @@ -796,19 +886,21 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - -static int if_close(struct device *dev) +static int if_close (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); - if (!card->open_cnt) - { + + if (!card->open_cnt) { + wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0); + fr_set_intr_mode(card, 0, 0, 0); fr_comm_disable(card); } card->wandev.critical = 0; @@ -825,15 +917,15 @@ * * Return: media header length. */ - -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) { int hdr_len = 0; + skb->protocol = type; hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { + + if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } @@ -849,14 +941,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + struct device *dev = skb->dev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -864,6 +956,7 @@ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. + * o set critical flag when accessing board. * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. @@ -878,220 +971,239 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct device *dev) +static int if_send (struct sk_buff* skb, struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - int retry = 0, err; - unsigned char *sendpacket; - struct device *dev2; - unsigned long check_braddr, check_mcaddr; - fr508_flags_t *adptr_flags = card->flags; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int retry = 0, err; + unsigned char *sendpacket; + struct device* dev2; + unsigned long check_braddr, check_mcaddr; + fr508_flags_t* adptr_flags = card->flags; int udp_type, send_data; - fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; - unsigned long host_cpu_flags; - ++chan->if_send_entry; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + + ++chan->if_send_entry; - if (dev->tbusy) - { - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + if (skb == NULL){ + + /* if we get here, some higher layer thinks we've missed an + * tx-done interrupt. */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + ++chan->if_send_skb_null; + + mark_bh(NET_BH); + return 0; + } + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + */ + ++chan->if_send_busy; ++chan->ifstats.collisions; - if ((jiffies - chan->tick_counter) < (5 * HZ)) + + if ((jiffies - chan->tick_counter) < (5*HZ)) { return 1; + } printk(KERN_INFO "%s: Transmit timed out\n", chan->name); + ++chan->if_send_busy_timeout; + /* unbusy all the interfaces on the card */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) dev2->tbusy = 0; + } + + if (chan->consecutive_send_fails > MAX_SEND_FAILS ) { + chan->consecutive_send_fails = 0; + dev_kfree_skb(skb); + ++chan->ifstats.rx_dropped; + return 0; } + sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + ++chan->if_send_DRVSTATS_request; process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, chan); dev_kfree_skb(skb); return 0; } - else if (udp_type == UDP_FPIPE_TYPE) + else if (udp_type == UDP_FPIPE_TYPE) ++chan->if_send_FPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[17]; - check_mcaddr = sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[16]; - check_mcaddr |= sendpacket[15]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[15]; - check_mcaddr |= sendpacket[16]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[17]; - /* if the Source Address is a Multicast address */ - if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && - (check_mcaddr <= 0xFFFFFFFE)) - { - printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++chan->ifstats.tx_dropped; - ++chan->if_send_multicast; - return 0; + + + if (sendpacket[2] == 0x45 ) { + /* retreive source address in two forms:broadcast & multicast */ + check_braddr = sendpacket[17]; + check_mcaddr = sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[16]; + check_mcaddr |= sendpacket[15]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[15]; + check_mcaddr |= sendpacket[16]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[17]; + + /* if the Source Address is a Multicast address */ + if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && + (check_mcaddr <= 0xFFFFFFFE)){ + + printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chan->ifstats.tx_dropped; + ++ chan->if_send_multicast; + return 0; + } } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - if (card->wandev.critical == CRITICAL_IN_ISR) - { + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + ++chan->if_send_critical_ISR; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* The enable_tx_int flag is set here so that if - * the critical flag is set due to an interrupt - * then we want to enable transmit interrupts - * again. - */ - card->wandev.enable_tx_int = 1; - /* Setting this flag to WAITING_TO_BE_ENABLED - * specifies that interrupt bit has to be - * enabled for that particular interface. - * (delayed interrupt) - */ - chan->tx_int_status = WAITING_TO_BE_ENABLED; - /* This is used for enabling dynamic calculation - * of CIRs relative to the packet length. - */ - chan->pkt_length = skb->len; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - else - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + + /* The enable_tx_int flag is set here so that if + * the critical flag is set due to an interrupt + * then we want to enable transmit interrupts + * again. + */ + + card->wandev.enable_tx_int = 1; + + /* Setting this flag to WAITING_TO_BE_ENABLED + * specifies that interrupt bit has to be + * enabled for that particular interface. + * (delayed interrupt) + */ + + chan->tx_int_status = WAITING_TO_BE_ENABLED; + + /* This is used for enabling dynamic calculation + * of CIRs relative to the packet length. + */ + + chan->pkt_length = skb->len; + + + dev->tbusy = 1; + chan->tick_counter = jiffies; + enable_irq(card->hw.irq); return 1; } + ++chan->if_send_critical_non_ISR; ++chan->ifstats.tx_dropped; + printk(KERN_INFO "critical %02X\n", card->wandev.critical); dev_kfree_skb(skb); - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + enable_irq(card->hw.irq); return 0; } - card->wandev.critical = 0x21; - if (udp_type == UDP_FPIPE_TYPE) - { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, 0, chan); - } - else if (card->wandev.state != WAN_CONNECTED) - { + + if (udp_type == UDP_FPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, 0,chan); + + } else if (card->wandev.state != WAN_CONNECTED) { + ++chan->if_send_wan_disconnected; ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (chan->state != WAN_CONNECTED) - { + ++card->wandev.stats.tx_dropped; + + } else if (chan->state != WAN_CONNECTED) { + ++chan->if_send_dlci_disconnected; update_chan_state(dev); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (!is_tx_ready(card, chan)) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else if (!is_tx_ready(card, chan)) { + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length = skb->len; + dev->tbusy = 1; chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; - ++chan->if_send_no_bfrs; + ++ chan->if_send_no_bfrs; + ++ chan->ifstats.tx_errors; + ++chan->consecutive_send_fails; retry = 1; - } - else - { + } else { send_data = 1; /* If it's an IPX packet */ - if (sendpacket[1] == 0x00 && + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { - if (card->wandev.enable_IPX) - { - switch_net_numbers(sendpacket, - card->wandev.network_number, 0); - } - else - { - /* increment some statistic here! */ + sendpacket[7] == 0x37) { + + if( chan->enable_IPX ) { + switch_net_numbers(sendpacket, + chan->network_number, 0); + } else { + //increment some statistic here! send_data = 0; } } - if (send_data) - { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; + + if (send_data){ + err = + fr508_send(card, chan->dlci, 0, skb->len, skb->data); + + if (err) { + switch(err) { + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length =skb->len; + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + retry = 1; + ++ chan->if_send_adptr_bfrs_full; + ++ chan->ifstats.tx_errors; + ++ card->wandev.stats.tx_errors; + ++chan->consecutive_send_fails; + break; + default: + ++chan->if_send_dlci_disconnected; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - retry = 1; - ++chan->if_send_adptr_bfrs_full; - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; - } - else - { - ++chan->if_send_bfrs_passed_to_adptr; + } else { + chan->consecutive_send_fails = 0; + ++ chan->if_send_bfrs_passed_to_adptr; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; } } } - if (!retry) - dev_kfree_skb(skb); + if (!retry) { + dev_kfree_skb(skb); + } + card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + + enable_irq(card->hw.irq); return retry; } @@ -1099,54 +1211,72 @@ * Reply to UDP Management system. * Return nothing. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { - unsigned short len, udp_length, temp, i, ip_length; + unsigned short len, + udp_length, + temp, + i, + ip_length; unsigned long sum; + /* Set length of packet */ len = mbox_len + 62; + /* fill in UDP reply */ data[38] = 0x02; + /* fill in UDP length */ udp_length = mbox_len + 40; + /* put it on an even boundary */ - if (udp_length & 0x0001) - { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[26], &temp, 2); + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[26],&temp,2); + /* swap UDP ports */ - memcpy(&temp, &data[22], 2); - memcpy(&data[22], &data[24], 2); - memcpy(&data[24], &temp, 2); + memcpy(&temp,&data[22],2); + memcpy(&data[22],&data[24],2); + memcpy(&data[24],&temp,2); + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 22], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 24], &temp, 2); + memcpy(&data[udp_length+22],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+24],&temp,2); + /* calculate UDP checksum */ data[28] = data[29] = 0; sum = 0; - for (i = 0; i < udp_length + 12; i += 2) - { - memcpy(&temp, &data[14 + i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[14+i],2); + sum += (unsigned long)temp; + } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); + } - temp = (unsigned short) sum; + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[28], &temp, 2); + /* fill in IP length */ ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); + temp = (ip_length<<8)|(ip_length>>8); memcpy(&data[4], &temp, 2); + /* swap IP addresses */ memcpy(&temp, &data[14], 2); memcpy(&data[14], &data[18], 2); @@ -1154,600 +1284,499 @@ memcpy(&temp, &data[16], 2); memcpy(&data[16], &data[20], 2); memcpy(&data[20], &temp, 2); + /* fill in IP checksum */ data[12] = data[13] = 0; sum = 0; - for (i = 0; i < 20; i += 2) - { - memcpy(&temp, &data[2 + i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < 20; i+=2 ) { + + memcpy(&temp,&data[2+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); - temp = (unsigned short) sum; + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[12], &temp, 2); + return len; -} /* reply_udp */ +} /* reply_udp */ + /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); + + pnetwork_number = (unsigned long)((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + if (!incoming) { /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; } } else { /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) - { - sendpacket[14] = (unsigned char) (network_number >> 24); - sendpacket[15] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0) { + sendpacket[14] = (unsigned char)(network_number >> 24); + sendpacket[15] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - if (!incoming) { + + + pnetwork_number = (unsigned long)((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) - { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; } } else { /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[26] = (unsigned char) (network_number >> 24); - sendpacket[27] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0 ) { + sendpacket[26] = (unsigned char)(network_number >> 24); + sendpacket[27] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats *if_stats(struct device *dev) +static struct enet_statistics* if_stats (struct device* dev) { - fr_channel_t *chan = dev->priv; - if(chan==NULL) + fr_channel_t* chan = dev->priv; + + if(chan == NULL) return NULL; - + return &chan->ifstats; } /****** Interrupt Handlers **************************************************/ -/*============================================================================ - * S502 frame relay interrupt service routine. - */ -static void fr502_isr(sdla_t * card) -{ - fr502_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; - default: - spur_intr(card); - } - flags->iflag = 0; -} /*============================================================================ * S508 frame relay interrupt service routine. */ - -static void fr508_isr(sdla_t * card) +static void fr508_isr (sdla_t* card) { - fr508_flags_t *flags = card->flags; - fr_buf_ctl_t *bctl; + fr508_flags_t* flags = card->flags; + fr_buf_ctl_t* bctl; char *ptr = &flags->iflag; - struct device *dev = card->wandev.dev; - struct device *dev2; - int i; - unsigned long host_cpu_flags; - unsigned disable_tx_intr = 1; - fr_channel_t *chan; - fr_dlci_interface_t *dlci_interface; + struct device* dev = card->wandev.dev; + struct device* dev2; + int i,err; + unsigned disable_tx_intr; + fr_channel_t* chan; + fr_dlci_interface_t* dlci_interface; + fr_mbox_t* mbox = card->mbox; + /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. + * in sdlamain.c. */ card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); ++card->statistics.isr_already_critical; card->in_isr = 0; return; } - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ + + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ card->wandev.critical = CRITICAL_IN_ISR; - card->dlci_int_mode_unbusy = 0; - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - fr508_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); + + switch (flags->iflag) { + + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + fr508_rx_intr(card); + break; + + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); bctl->flag = 0xA0; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - dev->tbusy = 0; - /* This is used to perform devtint at the - * end of the isr - */ - card->dlci_int_mode_unbusy = 1; - /* check to see if any other interfaces are - * busy. If so then do not disable the tx - * interrupts - */ - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (dev2->tbusy == 1) - { + + /* Find the structure and make it unbusy */ + dev = find_channel( card, flags->dlci); + dev->tbusy = 0; + chan = dev->priv; + + mark_bh(NET_BH); + + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + if (!card->wandev.enable_tx_int) { + disable_tx_intr = 1; + for (dev2 = card->wandev.dev; dev2; dev2 = + dev2->slave){ + if ( dev2->tbusy == 1){ disable_tx_intr = 0; break; - } + } } + if (disable_tx_intr) flags->imask &= ~0x02; - } - else if (card->intr_mode == BUFFER_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (!dev2 || !dev2->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - if (dev2->tbusy) - { - card->buff_int_mode_unbusy = 1; - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; - dev2->tbusy = 0; - } - else - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; - } - flags->imask &= ~0x02; - } - break; + } + break; + case 0x08: - Intr_test_counter++; + Intr_test_counter++; ++card->statistics.isr_intr_test; + break; + + case 0x10: /* Event interrupt occured */ + + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err) + fr_event(card, err, mbox); + break; + + case 0x20: /* Timer interrupt */ + /* Used to send inarp request at given interval */ + + if (card->wandev.state == WAN_CONNECTED) { + int num_remaining = 0; + for (dev=card->wandev.dev;dev;dev=dev->slave) { + fr_channel_t *chan = dev->priv; + + if (chan->inarp == INARP_REQUEST && + chan->state == WAN_CONNECTED) { + num_remaining++; + + if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { + send_inarp_request(card,dev); + chan->inarp_tick = jiffies; + } + } + + } + if (!num_remaining) { /* no more to process */ + flags->imask &= ~0x20; + } + } + break; + default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + break; - } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if (card->wandev.enable_tx_int) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - chan = dev2->priv; - if (chan->tx_int_status == WAITING_TO_BE_ENABLED) - { - dlci_interface = chan->dlci_int_interface; - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = chan->pkt_length; - chan->tx_int_status = DISABLED; - } + } + + if (card->wandev.enable_tx_int) { + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; + if ( chan->tx_int_status == WAITING_TO_BE_ENABLED ) { + + dlci_interface = chan->dlci_int_interface; + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length = + chan->pkt_length; + chan->tx_int_status = DISABLED; } } card->wandev.enable_tx_int = 0; flags->imask |= 0x02; ++card->statistics.isr_enable_tx_int; - } - save_flags(host_cpu_flags); - cli(); + } card->in_isr = 0; - card->wandev.critical = 0xD1; flags->iflag = 0; card->wandev.critical = 0; - restore_flags(host_cpu_flags); - /* Device is now ready to send. The instant this is executed the If_Send - routine is called. That is why this is put at the bottom of the ISR - to prevent a endless loop condition caused by repeated Interrupts and - enable_tx_int flag. - */ - if (card->dlci_int_mode_unbusy) - mark_bh(NET_BH); - if (card->buff_int_mode_unbusy) - { - for (;;) - { - if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) - { - ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; - mark_bh(NET_BH); - } - if ((card->devs_struct)->next == card->dev_to_devtint_next) - break; - card->devs_struct = (card->devs_struct)->next; - } - card->devs_struct = (card->dev_to_devtint_next)->next; - card->dev_to_devtint_next = card->devs_struct; - } } -/*============================================================================ - * Receive interrupt handler. - */ -static void fr502_rx_intr(sdla_t * card) -{ - fr_mbox_t *mbox = card->rxmb; - struct sk_buff *skb; - struct device *dev; - fr_channel_t *chan; - unsigned dlci, len; - void *buf; - unsigned char *sendpacket; - unsigned char buf2[3]; - int udp_type; - sdla_mapmem(&card->hw, FR502_RX_VECTOR); - dlci = mbox->cmd.dlci; - len = mbox->cmd.length; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - chan = dev->priv; - if (!dev->start) - { - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Copy data to the socket buffer */ - buf = skb_put(skb, len); - memcpy(buf, mbox->data, len); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - /* Check if it's a UDP management packet */ - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - udp_type = udp_pkt_type(skb, card); - if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) - { - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else - { - ++chan->rx_intr_FPIPE_request; - process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - } - else - { - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } - } - sdla_mapmem(&card->hw, FR_MB_VECTOR); -} + + /*============================================================================ * Receive interrupt handler. - */ - -static void fr508_rx_intr(sdla_t * card) -{ - fr_buf_ctl_t *frbuf = card->rxmb; - struct sk_buff *skb; - struct device *dev; - fr_channel_t *chan; - unsigned dlci, len, offs; - void *buf; - unsigned rx_count = 0; - fr508_flags_t *flags = card->flags; + * When a receive interrupt occurs do the following: + * 1- Find the structure for the dlci that the interrupt occured on + * 2- If it doesn't exist then print appropriate msg and goto step 8. + * 3- If it exist then copy data to a skb. + * 4- If skb contains Sangoma UDP data then process them + * 5- If skb contains IPXWAN data then send IPXWAN reply packets + * 6- If skb contains Inverse Arp data then send Inv Arp replies + * 7- If skb contains any other data then decapsulate the packet and + * send it to the stack. + * 8- Release the receive element and update receive pointers on the board + */ +static void fr508_rx_intr (sdla_t* card) +{ + fr_buf_ctl_t* frbuf = card->rxmb; + fr508_flags_t* flags = card->flags; + fr_channel_t* chan; char *ptr = &flags->iflag; - int i, err, udp_type; - if (frbuf->flag != 0x01) - { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) frbuf, frbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + struct sk_buff* skb; + struct device* dev; + void* buf; + unsigned dlci, len, offs; + int i, err, udp_type; + + if (frbuf->flag != 0x01) { + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)frbuf, frbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; } - do - { - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + + if (dev == NULL) { + + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" + , card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + + } else { chan = dev->priv; - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" - ,card->devname, dlci); - ++card->statistics.rx_intr_on_orphaned_DLCI; - } - else - { - skb = dev_alloc_skb(len); - if (!dev->start || (skb == NULL)) - { - ++chan->ifstats.rx_dropped; - if (dev->start) - { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++chan->rx_intr_no_socket; - } else - ++chan->rx_intr_dev_not_started; - } - else - { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) - { - unsigned tmp = card->u.f.rx_top - offs + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; + + skb = dev_alloc_skb(len); + + if (!dev->start || (skb == NULL)) { + ++chan->ifstats.rx_dropped; + + if(dev->start) { + + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++chan->rx_intr_no_socket; + + } else + ++ chan->rx_intr_dev_not_started; + } else { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) { + unsigned tmp = card->u.f.rx_top - offs + 1; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + + ++chan->rx_intr_DRVSTATS_request; + process_udp_driver_call( UDP_PKT_FRM_NETWORK, + card, skb, dev, dlci, chan); + + } else if (udp_type == UDP_FPIPE_TYPE) { + + ++chan->rx_intr_FPIPE_request; + err = process_udp_mgmt_pkt( UDP_PKT_FRM_NETWORK, + card, skb, dev, dlci, chan); + + } else if (handle_IPXWAN(skb->data,chan->name, chan->enable_IPX, chan->network_number)) { + + if (chan->enable_IPX) { + fr508_send(card, dlci, 0, skb->len, skb->data); } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else if (udp_type == UDP_FPIPE_TYPE) - { - ++chan->rx_intr_FPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, dlci, chan); + dev_kfree_skb(skb); + + } else if (is_arp(skb->data)) { + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); } - else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) - { - if (card->wandev.enable_IPX) - fr508_send(card, dlci, 0, skb->len, skb->data); - } - else - { - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(skb, 1); - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan-> - rx_intr_bfr_not_passed_to_stack; - ++chan-> - ifstats.rx_errors; - ++card-> - wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } + dev_kfree_skb(skb); + + } else if ( skb->data[0] != 0x03) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); + dev_kfree_skb(skb); + + } else { + + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan->rx_intr_bfr_not_passed_to_stack; + ++ chan->ifstats.rx_errors; + ++ card->wandev.stats.rx_errors; + + } else { + netif_rx(skb); + ++ chan->rx_intr_bfr_passed_to_stack; + ++ chan->ifstats.rx_packets; + ++ card->wandev.stats.rx_packets; } - } - } - /* Release buffer element and calculate a pointer to the next - one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - /* The loop put in is temporary, that is why the break is - * placed here. (?????) - */ - break; - frbuf = card->rxmb; - } - while (frbuf->flag && ((++rx_count) < 4)); -} -/*============================================================================ - * Transmit interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void tx_intr(sdla_t * card) -{ - struct device *dev = card->wandev.dev; - if (card->intr_mode == BUFFER_INTR_MODE) - { - for (; dev; dev = dev->slave) - { - if (!dev || !dev->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - dev->tbusy = 0; - mark_bh(NET_BH); - } - } - else - { - dev->tbusy = 0; - mark_bh(NET_BH); - } + } + } + } + + /* Release buffer element and calculate a pointer to the next + one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + } + /*============================================================================ * Spurious interrupt handler. * o print a warning * o - * If number of spurious interrupts exceeded some limit, then ??? */ - -static void spur_intr(sdla_t * card) +static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/* - Return 0 for non-IPXWAN packet - 1 for IPXWAN packet or IPX is not enabled! - */ +/*=========================================================================== + * Return 0 for non-IPXWAN packet + * 1 for IPXWAN packet or IPX is not enabled! + */ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) { int i; - if (sendpacket[1] == 0x00 && + + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { + sendpacket[7] == 0x37) { + /* It's an IPX packet */ - if (!enable_IPX) { + if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } - } - else - { + } else { /* It's not IPX so return and pass it up the stack. */ return 0; } - if (sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) { /* It's IPXWAN */ - if (sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) + + if( sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) { /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 49; sendpacket[i] == 0x00; i += 5) + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 49; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) + if( sendpacket[i + 4] != 0x02) { sendpacket[i + 1] = 0; } } + /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) + if( sendpacket[i] == 0x04 ) + { i += 8; - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) + } + + /* We also want to turn off all header compression opt. + */ + for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } + /* Set the packet type to timer response */ sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); } - else if (sendpacket[42] == 0x02) + else if( sendpacket[42] == 0x02 ) { /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + /* Set the packet type to information response */ sendpacket[42] = 0x03; + /* Set the router name */ sendpacket[59] = 'F'; sendpacket[60] = 'P'; @@ -1756,465 +1785,540 @@ sendpacket[63] = 'E'; sendpacket[64] = '-'; sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for (i = 73; i < 107; i += 1) + for(i = 73; i < 107; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } + /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char) (network_number >> 24); - sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char) (network_number & 0x000000FF); + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + return 1; } - /* If we get here, its an IPX-data packet so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + + /* If we get here, its an IPX-data packet so it'll get passed up the + * stack. + * switch the network numbers + */ + switch_net_numbers(sendpacket, network_number ,1); return 0; } -/****** Background Polling Routines ****************************************/ - /*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thead' to allow for - * time-dependent housekeeping work. - * - * o fetch asynchronous network events. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ + * Process Route. + * This routine is called as a polling routine to dynamically add/delete routes + * negotiated by inverse ARP. It is in this "task" because we don't want routes + * to be added while in interrupt context. +*/ + +static void process_route (sdla_t* card) +{ + struct device* dev; + struct in_device *in_dev; + + /* Dynamic Route adding/removing */ + for (dev = card->wandev.dev; dev ; dev = dev->slave) { + if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE || + ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) { + struct rtentry route; + int err = 0; + mm_segment_t fs = get_fs(); + + in_dev = dev->ip_ptr; -static void wpf_poll(sdla_t * card) -{ -/* struct device* dev = card->wandev.dev; */ - fr508_flags_t *flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - if (((jiffies - card->state_tick) < HZ) || - (card->intr_mode == INTR_TEST_MODE)) - return; - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - ++card->statistics.poll_already_critical; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - card->wandev.critical = 0x11; - ++card->statistics.poll_processed; - /* This is to be changed later ??? */ - /* - if( dev && dev->tbusy && !(flags->imask & 0x02) ) { - printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask); - } - */ - if (flags->event) - { - fr_mbox_t *mbox = card->mbox; - int err; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - card->state_tick = jiffies; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=in_dev->ifa_list->ifa_address; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + + switch(((fr_channel_t*)dev->priv)->route_flag) { + + case ADD_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCADDRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + ((fr_channel_t*)dev->priv)->name, + in_ntoa(in_dev->ifa_list->ifa_address) ); + } + else { + ((fr_channel_t*)dev->priv)-> + route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCDELRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE; + } + break; + } /* Case Statement */ + } + } /* If ADD/DELETE ROUTE */ + } /* Device 'For' Loop */ + + card->poll = NULL; } + + /****** Frame Relay Firmware-Specific Functions *****************************/ /*============================================================================ * Read firmware code version. * o fill string str with firmware version info. */ - -static int fr_read_version(sdla_t * card, char *str) +static int fr_read_version (sdla_t* card, char* str) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_CODE_VERSION; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err && str) - { + if (!err && str) { + int len = mbox->cmd.length; + memcpy(str, mbox->data, len); - str[len] = '\0'; + str[len] = '\0'; } return err; } + /*============================================================================ * Set global configuration. */ - -static int fr_configure(sdla_t * card, fr_conf_t * conf) +static int fr_configure (sdla_t* card, fr_conf_t *conf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int dlci_num = card->u.f.dlci_num; int err, i; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; + + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); + sizeof(fr_conf_t) + dlci_num * sizeof(short); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Set DLCI configuration. */ -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci) +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.dlci = (unsigned short) dlci; mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = 0x0E; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry--); + + } while (err && retry--); + return err; } /*============================================================================ * Set interrupt mode. */ -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, unsigned short timeout) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; + fr508_intr_ctl_t* ictl = (void*)mbox->data; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - if (card->hw.fwid == SFID_FR502) - { - fr502_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr502_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - mbox->cmd.length = sizeof(fr502_intr_ctl_t); - } - else - { - fr508_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - } + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + + /* indicate timeout on timer */ + if (mode & 0x20) ictl->timeout = timeout; + + mbox->cmd.length = sizeof(fr508_intr_ctl_t); + mbox->cmd.command = FR_SET_INTR_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Enable communications. */ -static int fr_comm_enable(sdla_t * card) +static int fr_comm_enable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_ENABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Disable communications. */ -static int fr_comm_disable(sdla_t * card) +static int fr_comm_disable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_DISABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Get communications error statistics. */ -static int fr_get_err_stats(sdla_t * card) +static int fr_get_err_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_ERROR_STATS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_comm_stat_t *stats = (void *) mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_comm_stat_t* stats = (void*)mbox->data; + + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - } - return err; + + } return err; } + /*============================================================================ * Get statistics. */ -static int fr_get_stats(sdla_t * card) +static int fr_get_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_link_stat_t *stats = (void *) mbox->data; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_link_stat_t* stats = (void*)mbox->data; + card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2; + card->wandev.stats.rx_dropped = + stats->rx_dropped + stats->rx_dropped2; + } + return err; } + /*============================================================================ * Add DLCI(s) (Access Node only!). * This routine will perform the ADD_DLCIs command for the specified DLCI. */ -static int fr_add_dlci(sdla_t * card, int dlci, int num) +static int fr_add_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; - do + + do { - unsigned short *dlci_list = (void *) mbox->data; + unsigned short* dlci_list = (void*)mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ADD_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Activate DLCI(s) (Access Node only!). * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. */ -static int fr_activate_dlci(sdla_t * card, int dlci, int num) +static int fr_activate_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; + do { - unsigned short *dlci_list = (void *) mbox->data; + unsigned short* dlci_list = (void*)mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ACTIVATE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Issue in-channel signalling frame. */ -static int fr_issue_isf(sdla_t * card, int isf) +static int fr_issue_isf (sdla_t* card, int isf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->data[0] = isf; - mbox->cmd.length = 1; + mbox->cmd.length = 1; mbox->cmd.command = FR_ISSUE_IS_FRAME; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Send a frame (S502 version). - */ -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, buf, len); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Send a frame (S508 version). */ -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; mbox->cmd.command = FR_WRITE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_buf_ctl_t* frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + sdla_poke(&card->hw, frbuf->offset, buf, len); frbuf->flag = 0x01; } + return err; } /****** Firmware Asynchronous Event Handlers ********************************/ /*============================================================================ - * Main asynchronous event/error handler. + * Main asyncronous event/error handler. * This routine is called whenever firmware command returns non-zero * return code. * * Return zero if previous command has to be cancelled. */ - -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) +static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) { - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; int i; - switch (event) - { + + switch (event) { + case FRRES_MODEM_FAILURE: return fr_modem_failure(card, mbox); + case FRRES_CHANNEL_DOWN: + { + struct device *dev; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + } + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; + } + case FRRES_CHANNEL_UP: + { + struct device *dev; + int num_requests = 0; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if( chan->inarp == INARP_REQUEST ){ + num_requests++; + chan->inarp_tick = jiffies; + } + } + + /* Allow timer interrupts */ + if (num_requests) flags->imask |= 0x20; wanpipe_set_state(card, WAN_CONNECTED); return 1; + } + case FRRES_DLCI_CHANGE: return fr_dlci_change(card, mbox); + case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); + printk(KERN_INFO "%s: DLCI list mismatch!\n", + card->devname); return 1; + case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + break; + case FRRES_DLCI_INACTIVE: - printk(KERN_ERR "%s: DLCI %u is inactive!\n", - card->devname, mbox->cmd.dlci); break; + case FRRES_CIR_OVERFLOW: break; case FRRES_BUFFER_OVERFLOW: - break; + break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, mbox->cmd.command, event); + , card->devname, mbox->cmd.command, event); } + return 0; } @@ -2223,178 +2327,227 @@ * * Return zero if previous command has to be cancelled. */ -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) { printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - switch (mbox->cmd.command) - { + card->devname, mbox->data[0]); + + switch (mbox->cmd.command){ case FR_WRITE: + case FR_READ: return 0; } + return 1; } + /*============================================================================ * Handle DLCI status change. * * Return zero if previous command has to be cancelled. */ -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) { - dlci_status_t *status = (void *) mbox->data; + dlci_status_t* status = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); fr_dlc_conf_t cfg; fr_channel_t *chan; - struct device *dev2; - for (; cnt; --cnt, ++status) - { - unsigned short dlci = status->dlci; - struct device *dev = find_channel(card, dlci); - if (dev == NULL) - { - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - } - else - { - if (status->state & 0x01) - { + fr508_flags_t* flags = card->flags; + struct device* dev2; + + + for (; cnt; --cnt, ++status) { + + unsigned short dlci= status->dlci; + struct device* dev = find_channel(card, dlci); + + if (dev == NULL){ + printk(KERN_INFO + "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + }else{ + if (status->state == 0x00) { printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); + "%s: DLCI %u is inactive!\n", + card->devname, dlci); + if (dev && dev->start) set_chan_state(dev, WAN_DISCONNECTED); } - else if (status->state & 0x02) - { + + if (status->state & 0x01) { + printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); - chan = dev->priv; - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + + if (dev && dev->start) { + fr_channel_t *chan = dev->priv; + + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev, WAN_DISCONNECTED); + } + + } else if (status->state & 0x02) { + + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci); + + + chan = dev->priv; + + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ chan->dlci_configured = DLCI_CONFIG_PENDING; + if (dev && dev->start) set_chan_state(dev, WAN_CONNECTED); + } } } - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; - if (chan->dlci_configured == DLCI_CONFIG_PENDING) - { + + if (chan->dlci_configured == DLCI_CONFIG_PENDING) { memset(&cfg, 0, sizeof(cfg)); - if (chan->cir_status == CIR_DISABLED) - { - cfg.cir_fwd = cfg.cir_bwd = 16; + + if ( chan->cir_status == CIR_DISABLED) { + + cfg.cir_fwd = cfg.cir_bwd = 16; cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - printk(KERN_INFO "%s: CIR Disabled for %s\n", - card->devname, chan->name); + cfg.conf_flags = 0x0001; + printk(KERN_INFO "%s: CIR Disabled for %s\n", + card->devname, chan->name); + } else if (chan->cir_status == CIR_ENABLED) { + cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; cfg.conf_flags = 0x0000; printk(KERN_INFO "%s: CIR Enabled for %s\n", - card->devname, chan->name); + card->devname, chan->name); + //printk(KERN_INFO + //"%s: CIR Enabled for %s: CIR = %d, BC = %d, + //BE = %d\n",card->devname, chan->name, + //cfg.cir_fwd, cfg.bc_fwd, cfg.be_fwd); + } - if (fr_dlci_configure(card, &cfg, chan->dlci)) - { - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; + + if (fr_dlci_configure( card, &cfg , chan->dlci)){ + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; } + chan->dlci_configured = DLCI_CONFIGURED; + + /* Allow timer interrupts */ + if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { + chan->inarp_tick = jiffies; + flags->imask |= 0x20; + } + /* Read the interface byte mapping into the channel structure. */ - if (card->intr_mode == DLCI_LIST_INTR_MODE) - read_DLCI_IB_mapping(card, chan); + read_DLCI_IB_mapping( card, chan ); } + } return 1; } + /******* Miscellaneous ******************************************************/ /*============================================================================ * Update channel state. */ -static int update_chan_state(struct device *dev) +static int update_chan_state (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - fr_mbox_t *mbox = card->mbox; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - int dlci_found = 0; - do + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_LIST_ACTIVE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - unsigned short *list = (void *) mbox->data; + if (!err) { + + unsigned short* list = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) - { - if (*list == chan->dlci) - { - dlci_found = 1; - set_chan_state(dev, WAN_CONNECTED); + + for (; cnt; --cnt, ++list) { + + if (*list == chan->dlci) { + set_chan_state(dev, WAN_CONNECTED); break; } } - if (!dlci_found) - printk(KERN_INFO "%s: DLCI %u is inactive\n", - card->devname, chan->dlci); } - + return err; } + /*============================================================================ * Set channel state. */ -static void set_chan_state(struct device *dev, int state) +static void set_chan_state (struct device* dev, int state) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; unsigned long flags; - + save_flags(flags); cli(); - - if (chan->state != state) - { - switch (state) - { + + if (chan->state != state) { + + switch (state) { + case WAN_CONNECTED: printk(KERN_INFO "%s: interface %s connected!\n" - ,card->devname, dev->name); + , card->devname, dev->name); break; + case WAN_CONNECTING: - printk(KERN_INFO - "%s: interface %s connecting...\n", - card->devname, dev->name); + printk(KERN_INFO + "%s: interface %s connecting...\n", + card->devname, dev->name); break; + case WAN_DISCONNECTED: - printk(KERN_INFO - "%s: interface %s disconnected!\n", - card->devname, dev->name); + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); break; } + chan->state = state; } + chan->state_tick = jiffies; restore_flags(flags); } @@ -2402,14 +2555,18 @@ /*============================================================================ * Find network device by its channel number. */ -static struct device *find_channel(sdla_t * card, unsigned dlci) +static struct device* find_channel (sdla_t* card, unsigned dlci) { - struct device *dev; + struct device* dev; + for (dev = card->wandev.dev; dev; dev = dev->slave) - if (((fr_channel_t *) dev->priv)->dlci == dlci) + + if (((fr_channel_t*)dev->priv)->dlci == dlci) break; + return dev; } + /*============================================================================ * Check to see if a frame can be sent. If no transmit buffers available, * enable transmit interrupts. @@ -2417,22 +2574,13 @@ * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ - -static int is_tx_ready(sdla_t * card, fr_channel_t * chan) +static int is_tx_ready (sdla_t* card, fr_channel_t* chan) { - if (card->hw.fwid == SFID_FR508) - { - unsigned char sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - } - else - { - fr502_flags_t *flags = card->flags; - if (flags->tx_ready) - return 1; - flags->imask |= 0x02; - } + unsigned char sb = inb(card->hw.port); + + if (sb & 0x02) + return 1; + return 0; } @@ -2440,13 +2588,16 @@ * Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */ -static unsigned int dec_to_uint(unsigned char *str, int len) +static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned) '0'); + val = (val * 10) + (*str - (unsigned)'0'); + return val; } @@ -2454,371 +2605,624 @@ * Process UDP call of type FPIPE8ND */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan) { int c_retry = MAX_CMD_RETRY; unsigned char *data; unsigned char *buf; unsigned char buf2[5]; - unsigned int loops, frames, len; + unsigned char frames; + unsigned int loops, len; unsigned long data_ptr; unsigned short real_len, buffer_length; struct sk_buff *new_skb; unsigned char *sendpacket; - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int err; struct timeval tv; int udp_mgmt_req_valid = 1; + sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd 0x%02X", - card->devname, data[47]); + + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd 0x%02X", + card->devname, data[47]); ++chan->UDP_FPIPE_mgmt_kmalloc_err; - return 1; + return 1; } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { + + memcpy(data,sendpacket,skb->len); + + switch(data[47]) { + /* FPIPE_ENABLE_TRACE */ case 0x41: + /* FPIPE_DISABLE_TRACE */ - case 0x42: + case 0x42: + /* FPIPE_GET_TRACE_INFO */ case 0x43: + /* SET FT1 MODE */ case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - ++chan->UDP_FPIPE_mgmt_direction_err; + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->UDP_FPIPE_mgmt_direction_err; udp_mgmt_req_valid = 0; break; } + /* FPIPE_FT1_READ_STATUS */ case 0x44: + /* FT1 MONITOR STATUS */ case 0x80: - if (card->hw.fwid != SFID_FR508) - { + if(card->hw.fwid != SFID_FR508) { ++chan->UDP_FPIPE_mgmt_adptr_type_err; udp_mgmt_req_valid = 0; + break; } - break; default: break; - } - if (!udp_mgmt_req_valid) - { + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ data[48] = data[49] = 0; + /* set return code */ data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD; - } - else - { - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - if (!TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x37; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (err) - { - TracingEnabled = 0; - /* set the return code */ - data[50] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - /* get num_frames */ - sdla_peek(&card->hw, 0x9000, &num_frames, 2); - sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE - - * sizeof(UDP_MGMT_PACKET) - 41 */ - available_buffer_space = 1926; - /* set return code */ - data[50] = 0; - } - else - { - /* set return code to line trace already - enabled */ - data[50] = 1; - } - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* FPIPE_DISABLE_TRACE */ - case 0x42: - if (TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x36; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - } - /* set return code */ - data[50] = 0; - mbox->cmd.length = 0; - TracingEnabled = 0; - break; - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* Line trace cannot be performed on the 502 */ - if (!TracingEnabled) + + } else { + + switch (data[47]) { + + /* FPIPE_ENABLE_TRACE */ + case 0x41: + + if(!card->TracingEnabled) { + do { - /* set return code */ - data[50] = 1; + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x37; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, + mbox)); + + + if(err) { + + card->TracingEnabled = 0; + /* set the return code */ + data[50] = mbox->cmd.result; mbox->cmd.length = 0; break; } - buffer_length = 0; - loops = (num_frames < 20) ? num_frames : 20; - for (frames = 0; frames < loops; frames += 1) - { - sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /* 1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - buffer_length) < 9) - { - /* indicate we have more frames on board - and exit */ - data[62] |= 0x02; - break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4); - /* see if we can fit the frame into the user buffer */ - memcpy(&real_len, &data[64 + buffer_length], 2); - if (data_ptr == 0 || real_len + 8 > available_buffer_space) - { - data[63 + buffer_length] = 0x00; - } - else - { - /* we can take it next time */ - if (available_buffer_space - buffer_length < real_len + 8) - { - data[62] |= 0x02; - break; - } - /* ok, get the frame */ - data[63 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len); - /* zero the opp flag to show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, curr_trace_addr, &buf2, 1); - /* now move onto the next frame */ - curr_trace_addr += 16; - /* check if we passed the last address */ - if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) - curr_trace_addr = start_trace_addr; - /* update buffer length and make sure - its even */ - if (data[63 + buffer_length] == 0x01) - buffer_length += real_len - 1; - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } - } - /* ok now set the total number of frames passed in the - high 5 bits */ - data[62] = (frames << 3) | data[62]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[48], &buffer_length, 2); - data[50] = 0; - break; - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - sdla_peek(&card->hw, 0xF020, &data[62], 2); - data[48] = 2; - data[49] = 0; + + /* get num_frames */ + sdla_peek(&card->hw, 0x9000, &num_frames, 2); + sdla_peek(&card->hw, 0x9002, &curr_trace_addr, + 4); + start_trace_addr = curr_trace_addr; + + /* MAX_SEND_BUFFER_SIZE - 30 (IP header + frame + * header (2) ) - 32 (fpipemon CBLOCK) + */ + available_buffer_space = 1938; + /* set return code */ data[50] = 0; - mbox->cmd.length = 2; - break; - /* FPIPE_FLUSH_DRIVER_STATS */ - case 0x48: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - case 0x49: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *) &data[62] = chan->router_up_time; - mbox->cmd.length = 4; - break; - /* FPIPE_KILL_BOARD */ - case 0x50: - break; - /* FT1 MONITOR STATUS */ - case 0x80: - if (data[62] == 1) - { - if (rCount++ != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[62] == 0) - { - if (--rCount != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - if (!err) - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - { - memcpy(&data[62], &mbox->data,mbox->cmd.length); - } - } - else - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + } else { + /* set return code to line trace already + enabled */ + data[50] = 1; + } + + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + + /* FPIPE_DISABLE_TRACE */ + case 0x42: + + if(card->TracingEnabled) { + + do { + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x36; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + } + + /* set return code */ + data[50] = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 0; + break; + + + /* FPIPE_GET_TRACE_INFO */ + case 0x43: + + /* Line trace cannot be performed on the 502 */ + if(!card->TracingEnabled) { + + /* set return code */ + data[50] = 1; + mbox->cmd.length = 0; + break; + } + + buffer_length = 0; + loops = (num_frames < 20)?num_frames:20; + data[62] = 0x00; + for( frames = 0; frames < loops; frames += 1) { + + sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); /* no data on board so exit */ + if( buf2[0] == 0x00 ) + break; + + /* 1+sizeof(FRAME_DATA) = 9 */ + + if( (available_buffer_space - buffer_length) + < 9 ) { + /* indicate we have more frames on board and exit */ + data[62] |= 0x02; + break; + } + + /* get frame status */ + sdla_peek(&card->hw, curr_trace_addr + 0x05, + &data[62+buffer_length], 1); + /* get time stamp */ + sdla_peek(&card->hw, curr_trace_addr + 0x06, + &data[66+buffer_length], 2); + /* get frame length */ + sdla_peek(&card->hw, curr_trace_addr + 0x01, + &data[64+buffer_length], 2); + /* get pointer to real data */ + sdla_peek(&card->hw, curr_trace_addr + 0x0C, + &data_ptr, 4); + /* see if we can fit the frame into the user + buffer */ + memcpy(&real_len, &data[64+buffer_length], 2); + + if (( data_ptr == 0 )|| (( real_len + 8 ) > available_buffer_space - buffer_length )) { + data[63+buffer_length] = 0x00; + } else { + /* we can take it next time */ + if(( available_buffer_space - + buffer_length ) < ( real_len + 8)) { + + data[62] |= 0x02; + break; + } + + /* ok, get the frame */ + data[63+buffer_length] = 0x01; + + /* get the data */ + sdla_peek(&card->hw, data_ptr, + &data[68+buffer_length], real_len); } + /* zero the opp flag to show we got + the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, curr_trace_addr, + &buf2, 1); + + /* now move onto the next frame */ + curr_trace_addr += 16; + + /* check if we passed the last address*/ if( curr_trace_addr >= + (start_trace_addr + num_frames*16)) { + curr_trace_addr = start_trace_addr; + } + + /* update buffer length and make sure + its even */ + if( data[63+buffer_length] == 0x01 ) { + buffer_length += real_len - 1; + } + /* for the header */ + buffer_length += 8; + + if( buffer_length & 0x0001 ) + buffer_length += 1; + } + + /* ok now set the total number of frames passed in the + high 5 bits */ + data[62] = (frames << 3) | data[62]; + + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[48], &buffer_length,2); + data[50] = 0; + break; + + /* FPIPE_FT1_READ_STATUS */ + case 0x44: + sdla_peek(&card->hw, 0xF020, &data[62], 2); + data[48] = 2; + data[49] = 0; + data[50] = 0; + mbox->cmd.length = 2; + break; + + /* FPIPE_FLUSH_DRIVER_STATS */ + case 0x48: + init_chan_statistics( chan ); + init_global_statistics( card ); + mbox->cmd.length = 0; + break; + + case 0x49: + do_gettimeofday( &tv ); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(unsigned long*)&data[62] = chan->router_up_time; + mbox->cmd.length = 4; + break; + + /* FPIPE_KILL_BOARD */ + case 0x50: + break; + + + /* FT1 MONITOR STATUS */ + case 0x80: + if( data[62] == 1){ + + if( rCount++ != 0 ){ + + data[50] = 0; + mbox->cmd.length = 1; + break; + } } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { + + /* Disable FT1 MONITOR STATUS */ + if( data[62] == 0) { + + if( --rCount != 0) { + data[50] = 0; + mbox->cmd.length = 1; + break; + } + } + + default: + + do { + memcpy(&mbox->cmd, &sendpacket[47], + sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[62], + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : + CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + + if( !err ) { + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + + memcpy(&data[62],&mbox->data, + mbox->cmd.length); + } + } else { + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + } + } + } + + /* Fill UDP TTL */ + data[10] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + err = fr508_send(card, dlci, 0, len, data); - if (err) + if (err) ++chan->UDP_FPIPE_mgmt_adptr_send_passed; else ++chan->UDP_FPIPE_mgmt_adptr_send_failed; dev_kfree_skb(skb); - } - else - { + + } else { /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + if((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ buf = skb_put(new_skb, len); memcpy(buf, data, len); + /* Decapsulate packet and pass it up the protocol stack */ new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(new_skb, dev)) - { + buf = skb_pull(new_skb, 1); /* remove hardware header*/ + + if(!wanrouter_type_trans(new_skb, dev)) { + ++chan->UDP_FPIPE_mgmt_not_passed_to_stack; /* can't decapsulate packet */ dev_kfree_skb(new_skb); - } - else - { + } else { ++chan->UDP_FPIPE_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_FPIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } + +/*============================================================================== + * Send Inverse ARP Request + */ + +int send_inarp_request(sdla_t *card, struct device *dev) +{ + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + struct in_device *in_dev; + + in_dev = dev->ip_ptr; + + if(in_dev != NULL ) { + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + if(in_dev->ifa_list != NULL) + arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else + arphdr->ar_sip = 0; + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + fr508_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + kfree(ArpPacket); + } + return 1; +} + + +/*============================================================================== + * Check packet for ARP Type + */ + +int is_arp(void *buf) +{ + arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; + + if (arphdr->pad == 0x00 && + arphdr->NLPID == 0x80 && + arphdr->PID == 0x0608) + return 1; + else return 0; +} + +/*============================================================================== + * Process ARP Packet Type + */ + +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device* dev) +{ + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_buf_ctl_t* frbuf = card->rxmb; + struct in_device *in_dev; + + + in_dev = dev->ip_ptr; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); + printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; + + fr508_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_tip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + card->poll = &process_route; + + break; + + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_sip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + card->poll = &process_route; + + break; + default: // ARP's and RARP's -- Shouldn't happen. + } + } + + return 0; + +} + + /*============================================================================== * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ * TEST_COUNTER times. */ - -static int intr_test(sdla_t * card) +static int intr_test( sdla_t* card ) { - fr_mbox_t *mb = card->mbox; - int err, i; + fr_mbox_t* mb = card->mbox; + int err,i; + /* The critical flag is unset here because we want to get into the ISR without the flag already set. The If_open sets the flag. - */ + */ card->wandev.critical = 0; - err = fr_set_intr_mode(card, 0x08, card->wandev.mtu); - if (err == CMD_OK) - { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) - { - /* Run command READ_CODE_VERSION */ + + err = fr_set_intr_mode( card, 0x08, card->wandev.mtu, 0 ); + + if (err == CMD_OK) { + + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { + + /* Run command READ_CODE_VERSION */ memset(&mb->cmd, 0, sizeof(fr_cmd_t)); - mb->cmd.length = 0; + mb->cmd.length = 0; mb->cmd.command = 0x40; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) fr_event(card, err, mb); } - } - else - { - return err; + + } else { + return err; } - err = fr_set_intr_mode(card, 0, card->wandev.mtu); - if (err != CMD_OK) + + err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); + + if( err != CMD_OK ) return err; + card->wandev.critical = 1; return 0; } /*============================================================================ * Process UDP call of type DRVSTATS. */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan) + +static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan ) { int c_retry = MAX_CMD_RETRY; unsigned char *sendpacket; @@ -2826,151 +3230,222 @@ unsigned char *data; unsigned char *buf; unsigned int len; - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; struct sk_buff *new_skb; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" + ,card->devname, data[45]); + ++chan->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { + return 1; + } + + memcpy(data,sendpacket,skb->len); + + switch(data[47]) { + case 0x45: - *(unsigned long *) &data[62] = chan->if_send_entry; - *(unsigned long *) &data[66] = chan->if_send_skb_null; - *(unsigned long *) &data[70] = chan->if_send_broadcast; - *(unsigned long *) &data[74] = chan->if_send_multicast; - *(unsigned long *) &data[78] = chan->if_send_critical_ISR; - *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR; - *(unsigned long *) &data[86] = chan->if_send_busy; - *(unsigned long *) &data[90] = chan->if_send_busy_timeout; - *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request; - *(unsigned long *) &data[98] = chan->if_send_FPIPE_request; - *(unsigned long *) &data[102] = chan->if_send_wan_disconnected; - *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected; - *(unsigned long *) &data[110] = chan->if_send_no_bfrs; - *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full; - *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr; - *(unsigned long *) &data[120] = card->irq_dis_if_send_count; - mbox->cmd.length = 62; + *(unsigned long*)&data[62] = + chan->if_send_entry; + *(unsigned long*)&data[66] = + chan->if_send_skb_null; + *(unsigned long*)&data[70] = + chan->if_send_broadcast; + *(unsigned long*)&data[74] = + chan->if_send_multicast; + *(unsigned long*)&data[78] = + chan->if_send_critical_ISR; + *(unsigned long*)&data[82] = + chan->if_send_critical_non_ISR; + *(unsigned long*)&data[86] = + chan->if_send_busy; + *(unsigned long*)&data[90] = + chan->if_send_busy_timeout; + *(unsigned long*)&data[94] = + chan->if_send_DRVSTATS_request; + *(unsigned long*)&data[98] = + chan->if_send_FPIPE_request; + *(unsigned long*)&data[102] = + chan->if_send_wan_disconnected; + *(unsigned long*)&data[106] = + chan->if_send_dlci_disconnected; + *(unsigned long*)&data[110] = + chan->if_send_no_bfrs; + *(unsigned long*)&data[114] = + chan->if_send_adptr_bfrs_full; + *(unsigned long*)&data[118] = + chan->if_send_bfrs_passed_to_adptr; + *(unsigned long*)&data[122] = + chan->consecutive_send_fails; + mbox->cmd.length = 64; break; + case 0x46: - *(unsigned long *) &data[62] = card->statistics.isr_entry; - *(unsigned long *) &data[66] = card->statistics.isr_already_critical; - *(unsigned long *) &data[70] = card->statistics.isr_rx; - *(unsigned long *) &data[74] = card->statistics.isr_tx; - *(unsigned long *) &data[78] = card->statistics.isr_intr_test; - *(unsigned long *) &data[82] = card->statistics.isr_spurious; - *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started; - *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI; - *(unsigned long *) &data[102] = chan->rx_intr_no_socket; - *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started; - *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request; - *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack; - *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack; + *(unsigned long*)&data[62] = card->statistics.isr_entry; + *(unsigned long*)&data[66] = + card->statistics.isr_already_critical; + *(unsigned long*)&data[70] = card->statistics.isr_rx; + *(unsigned long*)&data[74] = card->statistics.isr_tx; + *(unsigned long*)&data[78] = + card->statistics.isr_intr_test; + *(unsigned long*)&data[82] = + card->statistics.isr_spurious; + *(unsigned long*)&data[86] = + card->statistics.isr_enable_tx_int; + *(unsigned long*)&data[90] = + card->statistics.tx_intr_dev_not_started; + *(unsigned long*)&data[94] = + card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long*)&data[98] = + card->statistics.rx_intr_on_orphaned_DLCI; + *(unsigned long*)&data[102] = + chan->rx_intr_no_socket; + *(unsigned long*)&data[106] = + chan->rx_intr_dev_not_started; + *(unsigned long*)&data[110] = + chan->rx_intr_DRVSTATS_request; + *(unsigned long*)&data[114] = + chan->rx_intr_FPIPE_request; + *(unsigned long*)&data[118] = + chan->rx_intr_bfr_not_passed_to_stack; + *(unsigned long*)&data[122] = + chan->rx_intr_bfr_passed_to_stack; + mbox->cmd.length = 64; break; + case 0x47: - *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err; - *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed; - *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed; - *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket; - *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack; - *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[134] = card->statistics.poll_entry; - *(unsigned long *) &data[138] = card->statistics.poll_already_critical; - *(unsigned long *) &data[142] = card->statistics.poll_processed; - *(unsigned long *) &data[144] = card->irq_dis_poll_count; - mbox->cmd.length = 86; + *(unsigned long*)&data[62] = + chan->UDP_FPIPE_mgmt_kmalloc_err; + *(unsigned long*)&data[66] = + chan->UDP_FPIPE_mgmt_adptr_type_err; + *(unsigned long*)&data[70] = + chan->UDP_FPIPE_mgmt_direction_err; + *(unsigned long*)&data[74] = + chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[78] = + chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[82] = + chan->UDP_FPIPE_mgmt_adptr_send_passed; + *(unsigned long*)&data[86] = + chan->UDP_FPIPE_mgmt_adptr_send_failed; + *(unsigned long*)&data[90] = + chan->UDP_FPIPE_mgmt_no_socket; + *(unsigned long*)&data[94] = + chan->UDP_FPIPE_mgmt_not_passed_to_stack; + *(unsigned long*)&data[98] = + chan->UDP_FPIPE_mgmt_passed_to_stack; + *(unsigned long*)&data[102] = + chan->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long*)&data[106] = + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[110] = + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[114] = + chan->UDP_DRVSTATS_mgmt_adptr_send_passed; + *(unsigned long*)&data[118] = + chan->UDP_DRVSTATS_mgmt_adptr_send_failed; + *(unsigned long*)&data[122] = + chan->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long*)&data[126] = + chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; + *(unsigned long*)&data[130] = + chan->UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long*)&data[134] = + card->statistics.poll_entry; + *(unsigned long*)&data[138] = + card->statistics.poll_already_critical; + *(unsigned long*)&data[142] = + card->statistics.poll_processed; + *(unsigned long*)&data[146] = 0; + mbox->cmd.length = 86; break; + default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (!err) - { + do { + memcpy(&mbox->cmd, &sendpacket[47], + sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[62], + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : + CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + + if( !err ) { ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&data[62], &mbox->data, mbox->cmd.length); - } - else - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - } - } + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + + memcpy(&data[62],&mbox->data, + mbox->cmd.length); + } + }else { + ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + } + } + /* Fill UDP TTL */ data[10] = card->wandev.ttl; len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + err = fr508_send(card, dlci, 0, len, data); - if (err) + + if (err) ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; else ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; dev_kfree_skb(skb); - } - else - { + + } else { + /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + if((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ buf = skb_put(new_skb, len); memcpy(buf, data, len); + /* Decapsulate packet and pass it up the protocol stack */ + new_skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(new_skb, 1); - if (!wanrouter_type_trans(new_skb, dev)) - { + + /* remove hardware header*/ + buf = skb_pull(new_skb, 1); + + if(!wanrouter_type_trans(new_skb, dev)) { + /* can't decapsulate packet */ ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; dev_kfree_skb(new_skb); - } - else - { + } else { ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } @@ -2978,52 +3453,57 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) { - unsigned char *sendpacket; - unsigned char buf2[5]; + unsigned char* sendpacket; + unsigned char buf2[5]; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[2] == 0x45 && /* IP packet */ - sendpacket[11] == 0x11 && /* UDP packet */ - sendpacket[24] == buf2[1] && /* UDP Port */ - sendpacket[25] == buf2[0] && - sendpacket[38] == 0x01) - { - if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ - sendpacket[31] == 0x50 && - sendpacket[32] == 0x49 && - sendpacket[33] == 0x50 && - sendpacket[34] == 0x45 && - sendpacket[35] == 0x38 && - sendpacket[36] == 0x4E && - sendpacket[37] == 0x44) - { + + if( sendpacket[2] == 0x45 && /* IP packet */ + sendpacket[11] == 0x11 && /* UDP packet */ + sendpacket[24] == buf2[1] && /* UDP Port */ + sendpacket[25] == buf2[0] && + sendpacket[38] == 0x01 ) { + + if ( sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ + sendpacket[31] == 0x50 && + sendpacket[32] == 0x49 && + sendpacket[33] == 0x50 && + sendpacket[34] == 0x45 && + sendpacket[35] == 0x38 && + sendpacket[36] == 0x4E && + sendpacket[37] == 0x44 ){ + return UDP_FPIPE_TYPE; - } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[31] == 0x52 && - sendpacket[32] == 0x56 && - sendpacket[33] == 0x53 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x41 && - sendpacket[36] == 0x54 && - sendpacket[37] == 0x53) - { + + } else if(sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[31] == 0x52 && + sendpacket[32] == 0x56 && + sendpacket[33] == 0x53 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x41 && + sendpacket[36] == 0x54 && + sendpacket[37] == 0x53 ){ + return UDP_DRVSTATS_TYPE; - } - else + + } else return UDP_INVALID_TYPE; - } - else + + } else return UDP_INVALID_TYPE; + } + /*============================================================================== * Initializes the Statistics values in the fr_channel structure. */ - -void init_chan_statistics(fr_channel_t * chan) +void init_chan_statistics( fr_channel_t* chan) { + chan->route_flag = NO_ROUTE; chan->if_send_entry = 0; chan->if_send_skb_null = 0; chan->if_send_broadcast = 0; @@ -3039,12 +3519,16 @@ chan->if_send_no_bfrs = 0; chan->if_send_adptr_bfrs_full = 0; chan->if_send_bfrs_passed_to_adptr = 0; + + chan->consecutive_send_fails = 0; + chan->rx_intr_no_socket = 0; chan->rx_intr_dev_not_started = 0; chan->rx_intr_FPIPE_request = 0; chan->rx_intr_DRVSTATS_request = 0; - chan->rx_intr_bfr_not_passed_to_stack = 0; + chan-> rx_intr_bfr_not_passed_to_stack = 0; chan->rx_intr_bfr_passed_to_stack = 0; + chan->UDP_FPIPE_mgmt_kmalloc_err = 0; chan->UDP_FPIPE_mgmt_direction_err = 0; chan->UDP_FPIPE_mgmt_adptr_type_err = 0; @@ -3064,64 +3548,66 @@ chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0; chan->UDP_DRVSTATS_mgmt_no_socket = 0; } + /*============================================================================== * Initializes the Statistics values in the Sdla_t structure. */ - -void init_global_statistics(sdla_t * card) +void init_global_statistics( sdla_t* card ) { /* Intialize global statistics for a card */ - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; card->statistics.rx_intr_on_orphaned_DLCI = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; } -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan) +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) { - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t *result; - int err, counter, found; - do - { + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (mbox->cmd.result != 0) - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name); + } while (err && retry-- && fr_event(card, err, mbox)); + + if( mbox->cmd.result != 0) + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *) mbox->data; + result = (void *)mbox->data; + found = 0; - for (; counter; --counter, ++result) - { - if (result->dlci == chan->dlci) - { - printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" - ,card->devname, result->dlci, result->addr_value ,chan->name); + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { + printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" + ,card->devname,result->dlci, result->addr_value + ,chan->name); chan->IB_addr = result->addr_value; - chan->dlci_int_interface = (void *) (card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); + chan->dlci_int_interface = (void*)(card->hw.dpmbase + + ( chan->IB_addr & 0x00001FFF)); found = 1; - break; - } + break; + } } if (!found) - printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); } /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_hdlc.c linux.ac/drivers/net/sdla_hdlc.c --- linux.vanilla/drivers/net/sdla_hdlc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sdla_hdlc.c Wed Mar 24 18:13:32 1999 @@ -0,0 +1,1639 @@ +/**************************************************************************** +* sdla_hdlc.c HDLC API module. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Oct 14, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#define _GNUC_ +#include /* HDLC firmware API definitions */ + + +#define MAX_RETRY 10 + +#define NOT_SET 0x00 +/* For determining whether Set Configuration and Enable Comms has been done. + */ +#define SC 0x01 /* Set global configuration */ +#define EC 0x02 /* Enabled HDLC Communications */ +#define STC 0x04 /* Set Trace configuration */ + +/* For determining whether HDLC_SEND_WAIT command has been issued and requires + * a transmit interrupt. + */ + +#define TX_WAIT 0x01 + +/* + * Prototypes + */ + +static int update (wan_device_t *); +static int new_if (wan_device_t *, struct device *, wanif_conf_t *); +static int del_if (wan_device_t *, struct device *); + +static int hdlc_exec (struct sdla * , void * , void *); +static void hdlc_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void tx_intr (sdla_t *); +static void timer_intr(sdla_t *); + +static int if_init (struct device *); +static int if_open (struct device *); +static int if_close (struct device *); +static int if_header(struct sk_buff *, struct device *, unsigned short, void * , void *, unsigned); +static int if_rebuild_hdr (struct sk_buff *); +static int if_send (struct sk_buff *, struct device *); +static struct enet_statistics* if_stats (struct device *); + +static int hdlc_code_version(sdla_t *, char *); +static void hdlc_intr_mode (sdla_t *, unsigned, unsigned short); +static void hdlc_poll_read (sdla_t * , pid_t , struct device *); +static void read_trace_data (sdla_t * , pid_t , struct device *); +static int read_hdlc_configuration( sdla_t *); +static int read_hdlc_trace_configuration( sdla_t *); +static void hdlc_read_global_exception( sdla_t *); +static void hdlc_read_hdlc_exception( sdla_t *); +static int hdlc_send( sdla_t *, unsigned char, void *, unsigned short ); + +static void send_result_packet(struct sk_buff *, unsigned short, struct device *, pid_t, HDLC_MAILBOX_STRUCT *, unsigned char, int ); + +typedef struct hdlc_private_area +{ + + sdla_t *card; /* card it belongs to */ + char name[WAN_IFNAME_SZ+1]; /* interface name */ + char usedby[USED_BY_FIELD]; /* interface used by */ + unsigned long tick_counter; /* busy counter */ + char status; /* for SK RX Q checks */ + char tx_status; /* for wait tx */ + char read_cmd; /* who is doing read */ + pid_t tx_pid_number; /* pid for send cmd */ + pid_t rx_pid_number; /* pid for read cmd */ + struct sk_buff *saved_skb; /* ptr to new_skb */ + struct enet_statistics ifstats; /* statistics */ + +} hdlc_private_area_t; + +extern int sangoma_check_sockets( struct sk_buff *); +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* + * HDLC initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int hdlc_init (sdla_t *card, wandev_conf_t *conf) +{ + char str[80]; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_HDLC) { + + printk(KERN_INFO "invalid configuration ID!\n"); + } + + /* Initialize protocol-specific fields of adapter data space */ + switch (card->hw.fwid) { + + case SFID_HDLC508: + card->mbox = (void*)(card->hw.dpmbase + + HDLC_MB_STRUCT_OFFSET); + /* This value will be set later on when ENABLE_HDLC_ + * COMMS command is done. + */ + card->rxmb = NULL; + card->u.h.trace_status = NULL; + break; + + default: + return -EINVAL; + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (hdlc_code_version(card, NULL) || hdlc_code_version(card, str)) + return -EIO; + + printk(KERN_INFO "%s: running HDLC firmware v%s\n", + card->devname, str); + + /* + * Get shared memory information structure and set the card->flags + * pointer to that structure. Also store the pointers to Transmit + * and receive status element configuration structures. + */ + if (read_hdlc_configuration( card )) + return -EIO; + + + card->exec = &hdlc_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->isr = &hdlc_isr; + + card->wandev.state = WAN_DISCONNECTED; + + card->wandev.api_status = NOT_SET; + + return 0; +} + + +/* + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ + return 0; +} + +/* + * Create new network interface. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registeration. + * The register_net_device() is called after this routine. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t *wandev, struct device *dev, wanif_conf_t *conf){ + sdla_t *card = wandev->private; + hdlc_private_area_t *hdlc_data_area; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + hdlc_data_area = kmalloc(sizeof(hdlc_private_area_t), GFP_KERNEL); + + if( hdlc_data_area == NULL ) + return -ENOMEM; + + memset(hdlc_data_area, 0, sizeof(hdlc_private_area_t)); + + hdlc_data_area->card = card; + hdlc_data_area->saved_skb = NULL; + hdlc_data_area->status = NO_SK_RX_CHECK; + hdlc_data_area->read_cmd = NO_READ_CMD; + hdlc_data_area->tx_pid_number = 0; + hdlc_data_area->rx_pid_number = 0; + hdlc_data_area->tx_status = NOT_SET; + + /* copy the name of the interface initialize data */ + strcpy(hdlc_data_area->name, conf->name); + + /* This interface is used for API or WANPIPE */ + strcpy(hdlc_data_area->usedby, conf->usedby); + + /* prepare network device data space for registration */ + dev->name = hdlc_data_area->name; + dev->init = &if_init; + dev->priv = hdlc_data_area; + return 0; +} + + +/* + * Delete logical channel. + */ +static int del_if (wan_device_t *wandev, struct device *dev) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + if (!card->open_cnt) { + wanpipe_set_state(card, WAN_DISCONNECTED); + } + card->wandev.critical = 0; + + if (dev->priv) { + + + kfree(dev->priv); + dev->priv = NULL; + } + + return 0; +} + +/* + * Execute adapter interface command. + */ +static int hdlc_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device *dev) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + wan_device_t *wandev = &card->wandev; + int err = 0; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + //dev->family = AF_INET; /* address family */ + dev->type = 30; /* ARP h/w type */ + + /* This is done because for an API we do not want to call ifconfig + * which set these calls. + */ + if( strcmp(hdlc_data_area->usedby, "API") == 0){ + dev->flags |= IFF_UP; + } + + /* Set to the Maximum size of the SEND & RECV MAILBOX */ + dev->mtu = 4129; + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; //10; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + if( strcmp(hdlc_data_area->usedby, "API") == 0) + if_open( dev ); + + return err; +} + + +/* + * Open network interface. + * o if this is the first open, then enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ + +static int if_open (struct device *dev) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + int err = 0; + + + if (dev->start) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + if (!card->open_cnt) { + } + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + card->wandev.critical = 0; + return err; +} + + +/* + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ + +static int if_close (struct device *dev) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + card->wandev.critical = 0; + return 0; +} + +/* + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field + * of the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + printk(KERN_INFO "if_header\n"); + return 1; +} + +/* + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (struct sk_buff* skb) +{ + return 1; +} + + +/* + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + + if( hdlc_data_area == NULL) + return NULL; + else + return &hdlc_data_area->ifstats; +} + + +/* + * Receive a socket of type SOCK_PACKET. Process the socket which contains + * a command block to be executed on the board. Execute the command and + * then send the packet back up to the socket layer. SOCK_PACKET socket + * comes directly to the network send routine without any protocols in + * between. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + HDLC_SHARED_MEMORY_INFO_STRUCT *hdlc_info = card->flags; + HDLC_INTERRUPT_INFO_STRUCT *hdlc_int = &hdlc_info->HDLC_interrupt_info; + HDLC_MAILBOX_STRUCT *my_mbox= NULL; + pid_t pid_number; + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. + */ + + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + mark_bh(NET_BH); + return 0; + + } + + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then + * we will kick start the device by making dev->tbusy = 0. + * We expect that our device never stays busy more than 5 + * seconds. So this is only used as a last resort. + */ + + if ((jiffies - hdlc_data_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + + /* unbusy all the interfaces on the card */ + for (dev = card->wandev.dev; dev; dev = dev->slave) + dev->tbusy = 0; + } + + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "critical %02X\n", card->wandev.critical); + dev_kfree_skb(skb); + ++hdlc_data_area->ifstats.tx_dropped; + enable_irq(card->hw.irq); + return 0; + + } + + + if(ntohs(skb->protocol) == 0x16 ){ + + struct sk_buff *new_skb; + CMDBLOCK_STRUCT *cmdblock; + HDLC_MAILBOX_STRUCT *cmd_area; + unsigned short length; + int err; + + + ++hdlc_data_area->ifstats.tx_packets; + + + cmdblock = (CMDBLOCK_STRUCT *)skb->data; + cmd_area = (HDLC_MAILBOX_STRUCT *)&cmdblock->cmdarea; + + /* Copy the pid number into the CMDBLOCK so that the user + * app knows for who the result is for. + */ + pid_number = cmdblock->pid_num; + + switch( cmd_area->command ){ + HDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + HDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + TRACE_STATUS_EL_CFG_STRUCT *trace_status; + + case ENABLE_HDLC_COMMUNICATIONS: + + tx_status = (HDLC_TX_STATUS_EL_CFG_STRUCT *) + card->u.h.tx_status; + + rx_status = (HDLC_RX_STATUS_EL_CFG_STRUCT *) + card->u.h.rx_status; + + /* Setup Head and Tails for buffers */ + card->u.h.txbuf_base = (void *)(card->hw.dpmbase + + (tx_status->base_addr_Tx_status_elements % + SDLA_WINDOWSIZE)); + + card->u.h.txbuf_last = ( HDLC_I_FRM_TX_STATUS_EL_STRUCT *)card->u.h.txbuf_base + (tx_status->number_Tx_status_elements - 1); + + + card->u.h.rxbuf_base = (void *)(card->hw.dpmbase + + (rx_status->base_addr_Rx_status_elements % + SDLA_WINDOWSIZE)); + + card->u.h.rxbuf_last = ( HDLC_I_FRM_RX_STATUS_EL_STRUCT +*)card->u.h.rxbuf_base + (rx_status->number_Rx_status_elements - 1); + + card->u.h.rx_base = rx_status->base_addr_Rx_buffer; + card->u.h.rx_end = rx_status->end_addr_Rx_buffer; + + /* Set up next pointer to be used */ + card->u.h.txbuf = card->u.h.txbuf_base; + card->rxmb = card->u.h.rxbuf_base; + + if(!read_hdlc_trace_configuration(card)){ + /* Set up the trace buffers */ + trace_status = (TRACE_STATUS_EL_CFG_STRUCT *)card->u.h.trace_status; + card->u.h.tracebuf_base = (void *)(card->hw.dpmbase + (trace_status->base_addr_trace_status_elements % SDLA_WINDOWSIZE)); + card->u.h.tracebuf_last = (TRACE_STATUS_ELEMENT_STRUCT *)card->u.h.tracebuf_base + (trace_status->number_trace_status_elements - 1); + card->u.h.tracebuf = card->u.h.tracebuf_base; + card->u.h.trace_base = trace_status->base_addr_trace_buffer; + card->u.h.trace_end = trace_status->end_addr_trace_buffer; + } + + /* + * The enable communications command will + * perform the set interrupt triggers command. + * This is done so that the user application + * does a set configuration before calling + * enable communications. + */ + + hdlc_intr_mode(card, ( APP_INT_ON_RX_FRAME | + APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_HDLC_EXCEP_COND),10); + + /* No interrupts are allowed at this point only + * the HDLC and GLOBAL exceptions + */ + hdlc_int->interrupt_permission = + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_HDLC_EXCEP_COND; + break; + + case HDLC_SEND_NO_WAIT: + case HDLC_SEND_WAIT: + + my_mbox=kmalloc(sizeof(HDLC_MAILBOX_STRUCT),GFP_ATOMIC); + /* Since HDLC_SEND_NO_WAIT & HDLC_SEND_WAIT are our + * command and not a board command, it is very important + * that we provide return codes. The return codes + * involved are link status and whether comms were + * enabled. + */ + if( card->wandev.state != WAN_CONNECTED ){ + + my_mbox->return_code =HDLC_LINK_NOT_IN_ABM; + + } else if(!(card->wandev.api_status & EC) || + (card->wandev.api_status == NOT_SET)){ + + my_mbox->return_code = HDLC_COMMS_DISABLED; + + } else { + if ( hdlc_send( card, cmd_area->PF_bit, + cmd_area->data, cmd_area->buffer_length )){ + /* data was not sent */ + my_mbox->return_code= NO_TX_BFRS_AVAILABLE; + + if(cmd_area->command == HDLC_SEND_WAIT){ + hdlc_data_area->tx_pid_number = pid_number; + hdlc_int->interrupt_permission |= + APP_INT_ON_TX_FRAME; + + hdlc_data_area->tx_status=TX_WAIT; + + kfree(my_mbox); + + if(!dev->tbusy){ + dev_kfree_skb(skb); + } + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + } + + } else { + /* data was sent */ + my_mbox->return_code = OK; + } + } + my_mbox->buffer_length = 0; + my_mbox->command = cmd_area->command; + + /* send a reply back. It is not a board + * command so I will send it from here. + */ + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + kfree(my_mbox); + + if(!dev->tbusy) { + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + break; + case HDLC_READ_NO_WAIT: + case HDLC_READ_WAIT: + + my_mbox=kmalloc(sizeof(HDLC_MAILBOX_STRUCT),GFP_ATOMIC); + /* + * HDLC_READ_NO_WAIT command reads the data (if present) + * on the board. This is a poll method. + * + * HDLC_READ_WAIT command is an interrupt driven command + * In this case the user will issue this command once + * to register the interface user wishes to use. + * This way the driver knows which interface to bind to + * the socket when a receive interrupt occurs. + */ + + if( cmd_area->command == HDLC_READ_WAIT){ + /* + * Set the read_cmd flag so that we know which + * interface has requested the receive packets. + * On receive interrupt I will set the skb->dev + * to this interface. The pid number is also + * stored to prevent multiple interactions on + * the same interface. At this point RX + * interrupts are turned on. + */ + + hdlc_data_area->read_cmd = READ_CMD; + hdlc_data_area->rx_pid_number = pid_number; + + /* send a reply back. It is not a + * board command so I will send it from + * here. + */ + my_mbox->buffer_length = 0; + length = MAILBOX_SIZE + my_mbox->buffer_length; + my_mbox->command = HDLC_READ_WAIT; + + if( card->wandev.state != WAN_CONNECTED ){ + + my_mbox->return_code = HDLC_LINK_NOT_IN_ABM; + + } else if(!(card->wandev.api_status & EC) || + (card->wandev.api_status == NOT_SET)){ + + my_mbox->return_code=HDLC_COMMS_DISABLED; + + } else + my_mbox->return_code = OK; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, my_mbox, HDLC_READ_WAIT, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + + /* Enable receive interrupt */ + + hdlc_int->interrupt_permission |= + APP_INT_ON_RX_FRAME; + + } else { + + hdlc_int->interrupt_permission &= + ~APP_INT_ON_RX_FRAME; + /* For a polled read, the user + * application performs the HDLC_READ_NO_WAIT + * command. The driver polls the board + * to see if there is any data available */ + + hdlc_poll_read( card, pid_number, dev ); + } + + kfree(my_mbox); + + if(!dev->tbusy) + dev_kfree_skb(skb); + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + break; + + case HDLC_READ_TRACE_DATA: + + read_trace_data( card, pid_number, dev ); + + if(!dev->tbusy) + dev_kfree_skb(skb); + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + break; + + default: + break; + } + /* + * Prepare the send mailbox to execute the command on the + * board. + * The True Board Mailbox size is smaller than the Mailbox + * I have defined (HDLC_MAILBOX_STRUCT). This was done + * so that only one mailbox was used for API purposes. The + * API send and receive calls require a larger data area + * in the mailbox. + */ + + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + memcpy(mbox, cmd_area, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + /* The result is known at this point. I have to check + * whether a SET_CONFIGURATION and ENABLE_COMMS command + * was done and whether or not it was successfull. + */ + if( mbox->return_code == OK ) { + switch( mbox->command ){ + + case ENABLE_HDLC_COMMUNICATIONS: + card->wandev.api_status |= EC; + break; + case SET_HDLC_CONFIGURATION: + card->wandev.api_status |= SC; + break; + case DISABLE_HDLC_COMMUNICATIONS: + card->wandev.api_status = NOT_SET; + break; + case SET_TRACE_CONFIGURATION: + card->wandev.api_status |= STC; + break; + } + } + + /* + * Allocate a new socket buffer. Fill it with the result + * in send mailbox. Check if we can send the data up to + * the socket layer. + */ + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, mbox, 0, 0); + + } else + printk(KERN_INFO "if_send: (new_skb) out of mem\n"); + + } else + ++hdlc_data_area->ifstats.tx_dropped; + + if(!dev->tbusy) { + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; +} + +int hdlc_code_version(sdla_t* card, char* str) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + int retry = MAX_RETRY, err; + + do + { + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = READ_HDLC_CODE_VERSION; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + } while (err && retry--); + + if (!err && str) { + int len = mbox->buffer_length; + memcpy(str, mbox->data, len); + str[len] = '\0'; + } + return err; +} + + +int read_hdlc_configuration( sdla_t *card ) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + HDLC_CONFIGURATION_STRUCT *conf_data=NULL; + HDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + HDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = READ_HDLC_CONFIGURATION; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + } while (err && retry--); + + if( !err ){ + conf_data = (HDLC_CONFIGURATION_STRUCT *)mbox->data; + card->flags = (void*)(card->hw.dpmbase + + (conf_data->ptr_shared_mem_info_struct + % SDLA_WINDOWSIZE)); + + tx_status = (HDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_HDLC_Tx_stat_el_cfg_struct % + SDLA_WINDOWSIZE)); + + card->u.h.tx_status = tx_status; + + rx_status = (HDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_HDLC_Rx_stat_el_cfg_struct % + SDLA_WINDOWSIZE)); + + card->u.h.rx_status = rx_status; + + } + + return err; +} + + +int read_hdlc_trace_configuration( sdla_t *card ) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + LINE_TRACE_CONFIG_STRUCT *conf_data=NULL; + TRACE_STATUS_EL_CFG_STRUCT *trace_status; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = READ_TRACE_CONFIGURATION; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + } while (err && retry--); + + if( !err ){ + conf_data = (LINE_TRACE_CONFIG_STRUCT *)mbox->data; + trace_status = (TRACE_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_trace_stat_el_cfg_struct % + SDLA_WINDOWSIZE)); + card->u.h.trace_status = trace_status; + } + + return err; +} + + + +void hdlc_intr_mode( sdla_t* card, unsigned mode, unsigned short timer_val ) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + HDLC_INT_TRIGGERS_STRUCT *conf_data = NULL; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = SET_HDLC_INTERRUPT_TRIGGERS; + mbox->buffer_length = sizeof(HDLC_INT_TRIGGERS_STRUCT); + conf_data = (HDLC_INT_TRIGGERS_STRUCT *)mbox->data; + conf_data->HDLC_interrupt_triggers = mode; + conf_data->IRQ = card->hw.irq; + conf_data->interrupt_timer = 0; + if(timer_val) + conf_data->interrupt_timer = timer_val; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + } while (err && retry--); + return; +} + + + +void hdlc_isr( sdla_t *card ) +{ + HDLC_SHARED_MEMORY_INFO_STRUCT *hdlc_info = card->flags; + HDLC_INTERRUPT_INFO_STRUCT *hdlc_int = &hdlc_info->HDLC_interrupt_info; + HDLC_INFORMATION_STRUCT *hdlc_status = &hdlc_info->HDLC_info; + + card->in_isr = 1; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname); card->in_isr = 0; + return; + + } + + card->wandev.critical = CRITICAL_IN_ISR; + + switch (hdlc_int->interrupt_type) { + + case RX_APP_INT_PEND: /* receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: + hdlc_int->interrupt_permission &= ~APP_INT_ON_TX_FRAME; + tx_intr(card); + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + hdlc_read_global_exception( card ); + break; + + case HDLC_EXCEP_COND_APP_INT_PEND: + hdlc_read_hdlc_exception( card ); + if( !(hdlc_status->HDLC_status & 1) ) + wanpipe_set_state(card, WAN_DISCONNECTED); + else + wanpipe_set_state(card, WAN_CONNECTED); + break; + default: + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, hdlc_int->interrupt_type); + } + + card->in_isr = 0; + hdlc_int->interrupt_type = 0; + card->wandev.critical = 0; + + +} + +/* This routine executes the READ_GLOBAL_EXCEPTION_CONDITION to find out the + * details of that exception condition. + */ +void hdlc_read_global_exception( sdla_t *card ) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + struct device *dev; + hdlc_private_area_t *hdlc_data_area = NULL; + struct sk_buff *new_skb; + int err; + unsigned short length = 0; + + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if(err != CMD_TIMEOUT) { + switch(mbox->return_code){ + case EXCEP_MODEM_STATUS_CHANGE: + if( (mbox->data[0] & 0x04) ){ + if( (mbox->data[0] & 0x08) ) + printk(KERN_INFO "DCD is now high\n"); + else + printk(KERN_INFO "DCD is now low\n"); + } + if( (mbox->data[0] & 0x10)){ + if( (mbox->data[0] & 0x20) ) + printk(KERN_INFO "CTS is now high\n"); + else + printk(KERN_INFO "CTS is now low\n"); + } + printk(KERN_INFO "Modem status changed\n"); + break; + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "line trace disabled\n"); + break; + default: + printk(KERN_INFO "global %x\n", mbox->return_code); + break; + } + + /* Send the result to all the interfaces */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + + if (dev && dev->start) { + hdlc_data_area = dev->priv; + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, 0, mbox, 0, 0); + } else + printk(KERN_INFO "global_excep: out of mem\n"); + } + } + + } + return; +} + + +/* This routine executes the READ_HDLC_EXCEPTION_CONDITION to find out the + * details of that exception condition. + */ +void hdlc_read_hdlc_exception( sdla_t *card ) +{ + HDLC_MAILBOX_STRUCT *mbox = card->mbox; + hdlc_private_area_t *hdlc_data_area = NULL; + struct device *dev; + struct sk_buff *new_skb; + int err; + unsigned short length = 0; + + memset(mbox, 0, sizeof(TRUE_HDLC_MAILBOX_STRUCT)); + mbox->command = READ_HDLC_EXCEPTION_CONDITION; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + + if(err != CMD_TIMEOUT) { + /* Send the result to all the interfaces */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + if (dev && dev->start) { + hdlc_data_area = dev->priv; + + length = MAILBOX_SIZE + mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, 0, mbox, 0, 0); + } else + printk(KERN_INFO "hdlc_excep: out of mem\n"); + } + } + } + return; +} + +/* This routine is used for transmitting information frames */ +int hdlc_send( sdla_t *card, unsigned char p_bit, void *data, unsigned short len ) +{ + HDLC_I_FRM_TX_STATUS_EL_STRUCT *tx_buf = card->u.h.txbuf; + + if( tx_buf->opp_flag ){ + return 1; + } + + sdla_poke(&card->hw, tx_buf->ptr_data_bfr, data, len); + tx_buf->I_frame_length = len; + tx_buf->P_bit = p_bit; + tx_buf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.h.txbuf = ++tx_buf; + + if ((void*)tx_buf > card->u.h.txbuf_last) + card->u.h.txbuf = card->u.h.txbuf_base; + + return 0; +} + + +void send_result_packet( struct sk_buff *new_skb, unsigned short length, struct +device *dev, pid_t pid_number, HDLC_MAILBOX_STRUCT *mbox, unsigned char cmd, int data_avail) +{ + hdlc_private_area_t *hdlc_data_area = dev->priv; + sdla_t *card = hdlc_data_area->card; + HDLC_SHARED_MEMORY_INFO_STRUCT *hdlc_info = card->flags; + HDLC_INTERRUPT_INFO_STRUCT *hdlc_int = &hdlc_info->HDLC_interrupt_info; + CMDBLOCK_STRUCT *cmdblock; + HDLC_MAILBOX_STRUCT *cmd_area; + int err; + + + skb_put(new_skb,length); + new_skb->dev = dev; + new_skb->len = length; + new_skb->protocol = htons(0x16); + + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = pid_number; + cmd_area = (HDLC_MAILBOX_STRUCT *)&cmdblock->cmdarea; + + memcpy(cmd_area, mbox, 26 + mbox->buffer_length); + + if(cmd == HDLC_READ_NO_WAIT || cmd == HDLC_READ_WAIT){ + cmd_area->command = cmd; + cmd_area->return_code = OK; + + if(cmd == HDLC_READ_NO_WAIT){ + if( !data_avail ) + cmd_area->return_code = NO_TX_BFRS_AVAILABLE; + } + + if(!(card->wandev.api_status & EC) || + (card->wandev.api_status == NOT_SET)) { + cmd_area->return_code = HDLC_COMMS_DISABLED; + } + + } + /* + * Check and see if we can send the socket back + * up to the stack. Is there room on the socket + * queue ? If yes, then send the data up. If not, + * then enable timer interrupt on the board and + * send the packet when we there is room on the + * socket queue. + * sangoma_check_sockets() is our kernel level + * routine in dev.c (/net). This routine checks + * receive queue for any room. + */ + + err=sangoma_check_sockets(new_skb); + + if( err >= 1){ + + if(err == 1){ + + /* + * In this case there is no room on the + * socket queue for the skb. We will + * store the skb (new_skb) so that it is + * sent later on (through the timer + * routine). + */ + printk(KERN_INFO "No memory in socket queue for skb\n"); dev->tbusy = 1; + hdlc_data_area->tick_counter = jiffies; + hdlc_data_area->status = TOP_CHECK_SK_RX_Q; + hdlc_data_area->saved_skb = new_skb; + hdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + + } else if(err == 2) { + + /* + * In this case there is no socket + * created. The user app are not + * even created/initialized the socket. + * I have decided to discard the packets + * in the scenario. + */ + + printk(KERN_INFO "%s: No socket initialized\n", dev->name); + new_skb->sk = NULL; + //new_skb->free = 1; + ++hdlc_data_area->ifstats.rx_dropped; + dev_kfree_skb(new_skb); + } + } else { + /* There is room on the SK RX Q. */ + + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++hdlc_data_area->ifstats.rx_packets; + } +} + +void timer_intr( sdla_t *card ) +{ + struct device *dev = card->wandev.dev; + HDLC_SHARED_MEMORY_INFO_STRUCT *hdlc_info = card->flags; + HDLC_INTERRUPT_INFO_STRUCT *hdlc_int = &hdlc_info->HDLC_interrupt_info; + hdlc_private_area_t *hdlc_data_area; + struct sk_buff *new_skb; + int err; + + + /* check all the interfaces on the card to see if its status flag + * indicates CHECK_SK_RX_Q + */ + for (dev = card->wandev.dev; dev; dev = dev->slave){ + hdlc_data_area = dev->priv; + + if( hdlc_data_area->status == TOP_CHECK_SK_RX_Q || + hdlc_data_area->status == BTM_CHECK_SK_RX_Q ){ + + new_skb = hdlc_data_area->saved_skb; + err=sangoma_check_sockets(new_skb); + if( err >= 1){ + if(err == 1){ + printk(KERN_INFO "timer_intr: No memory for skb\n"); + } else if(err == 2) { + printk(KERN_INFO "timer_intr: %s No socket initialized\n", dev->name); + dev->tbusy = 0; + new_skb->sk = NULL; + //new_skb->free = 1; + ++hdlc_data_area->ifstats.rx_dropped; + dev_kfree_skb(new_skb); + + //if( hdlc_data_area->status == BTM_CHECK_SK_RX_Q ){ + // hdlc_int->interrupt_permission |= APP_INT_ON_RX_FRAME; + //} + hdlc_data_area->status = NO_SK_RX_CHECK; + hdlc_int->interrupt_permission &= ~APP_INT_ON_TIMER; + } + } else { + dev->tbusy = 0; + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++hdlc_data_area->ifstats.rx_packets; + if( hdlc_data_area->status == BTM_CHECK_SK_RX_Q ){ + hdlc_int->interrupt_permission |= APP_INT_ON_RX_FRAME; + } + hdlc_data_area->status = NO_SK_RX_CHECK; + hdlc_int->interrupt_permission &= ~APP_INT_ON_TIMER; + } + } + } +} + + + + +/* This routine handles the transmit interrupt. It is responsible for + * sending a packet up to the stack. A process has sent a packet with HDLC_ + * SEND_WAIT command, the command failed due to buffer constraints, a result + * is given only when a transmit interrupt occurs which tells the user that + * next send command will (most likely) have buffer(s) available. + */ +void tx_intr( sdla_t *card ) +{ + struct device *dev = card->wandev.dev; + HDLC_MAILBOX_STRUCT *my_mbox; + hdlc_private_area_t *hdlc_data_area; + struct sk_buff *new_skb; + unsigned short length; + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + + hdlc_data_area = dev->priv; + + if( hdlc_data_area->tx_status == TX_WAIT ){ + + /* send a reply back. + */ + my_mbox = kmalloc(sizeof(HDLC_MAILBOX_STRUCT), GFP_ATOMIC); + my_mbox->command = HDLC_SEND_WAIT; + my_mbox->buffer_length = 0; + my_mbox->return_code =NO_TX_BFRS_AVAILABLE; + length = MAILBOX_SIZE; + + if((new_skb = dev_alloc_skb( length )) != NULL) { + send_result_packet(new_skb, length, dev, hdlc_data_area->tx_pid_number, my_mbox, 0, 0); + + } else + printk(KERN_INFO "tx_intr: (new_skb) out of mem\n"); + hdlc_data_area->tx_status = NOT_SET; + kfree(my_mbox); + break; + } + } + +} + + +/* + * This routine polls the board to see if there is data on the board. + * It is responsible for making the result structure and filling it + * with the correct return code and data. + */ +void hdlc_poll_read(sdla_t* card, pid_t pid_number, struct device *dev) +{ + struct sk_buff *new_skb; + unsigned short length; + int retry=MAX_RETRY, data_avail = 0; + HDLC_I_FRM_RX_STATUS_EL_STRUCT *rxbuf = NULL; + HDLC_MAILBOX_STRUCT *my_mbox; + unsigned long addr, data_len, tmp; + + /* If EC flag is set then it means that the Enable communications has + * been performed successfully. + */ + tmp = 0; + data_len = 0; + my_mbox = kmalloc(sizeof(HDLC_MAILBOX_STRUCT), GFP_ATOMIC); + my_mbox->buffer_length = 0; + if( (card->wandev.api_status & EC) ){ + + rxbuf = card->rxmb; + do + { + if(rxbuf->opp_flag){ + data_avail = 1; + data_len = rxbuf->I_frame_length; + my_mbox->buffer_length = data_len; + addr = rxbuf->ptr_data_bfr; + + if ((addr + data_len) > card->u.h.rx_end + 1) { + tmp = card->u.h.rx_end - addr + 1; + sdla_peek(&card->hw, addr, my_mbox->data, tmp); + addr = card->u.h.rx_base; + data_len -= tmp; + } + sdla_peek(&card->hw, addr, (&my_mbox->data[tmp]), data_len); + my_mbox->PF_bit = rxbuf->P_bit; + break; + } + } while (retry--); + } else { + my_mbox->buffer_length = 0; + + } + + my_mbox->command = HDLC_READ_NO_WAIT; + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, my_mbox, HDLC_READ_NO_WAIT, data_avail); + } else + printk(KERN_INFO "poll_read: out of mem\n"); + + kfree(my_mbox); + + if( (card->wandev.api_status & EC) && data_avail ){ + /* Release buffer element and calculate a pointer to the next + * one + */ + + rxbuf->opp_flag = 0x00; + card->rxmb = ++rxbuf; + + if ((void*)rxbuf > card->u.h.rxbuf_last) + card->rxmb = card->u.h.rxbuf_base; + } + +} + + +/* + * This routine polls the board to see if there is any trace data on the + * board. It is responsible for making the result structure and filling it + * with the correct return code and data. + */ +void read_trace_data(sdla_t* card, pid_t pid_number, struct device *dev) +{ + struct sk_buff *new_skb; + unsigned short length; + int retry=MAX_RETRY; + TRACE_STATUS_ELEMENT_STRUCT *tracebuf = NULL; + HDLC_MAILBOX_STRUCT *my_mbox; + unsigned long addr, data_len, tmp; + + /* If EC flag is set then it means that the Enable communications has + * been performed successfully. + */ + tmp = 0; + data_len = 0; + my_mbox = kmalloc(sizeof(HDLC_MAILBOX_STRUCT), GFP_ATOMIC); + my_mbox->buffer_length = 0; + my_mbox->return_code = 0x00; + + if( (card->wandev.api_status & EC) && + (card->wandev.api_status & STC) && + (card->wandev.state == WAN_CONNECTED) ){ + + tracebuf = card->u.h.tracebuf; + if(tracebuf == NULL){ + printk(KERN_INFO "NULL\n"); + return; + } + my_mbox->return_code = NO_TRACE_BUFFERS; + do + { + /* There is data available */ + if(tracebuf->opp_flag){ + + /* In the mailbox data area we will fill it + * with trace_type, trace_time_stamp, + * trace_length and the actual trace data. + */ + my_mbox->buffer_length = 5; + memcpy(my_mbox->data, &tracebuf->trace_type, sizeof(unsigned char)); + memcpy(&my_mbox->data[1], &tracebuf->trace_time_stamp, sizeof(unsigned short)); + memcpy(&my_mbox->data[3], &tracebuf->trace_length, sizeof(unsigned short)); + data_len = tracebuf->trace_length; + my_mbox->buffer_length += data_len; + + /* Copy the trace buffer into the data */ + addr = tracebuf->ptr_data_bfr; + if( my_mbox->buffer_length > MAX_NO_DATA_BYTES_IN_I_FRAME ){ + my_mbox->return_code = TRACE_BUFFER_TOO_BIG; + break; + } + + if (addr == 0x00 ) + /* The trace data could not be stored + * due to buffer limitations. + */ + my_mbox->return_code = TRACE_BUFFER_NOT_STORED; + else { + + if ((addr + data_len) > card->u.h.trace_end + 1) { + tmp = card->u.h.trace_end - addr + 1; + sdla_peek(&card->hw, addr, &my_mbox->data[5], tmp); + addr = card->u.h.trace_base; + data_len -= tmp; + } + sdla_peek(&card->hw, addr, (&my_mbox->data[tmp + 5]), data_len); + my_mbox->return_code = OK; + } + + /* Release buffer element and calculate a + * pointer to the next one + */ + + tracebuf->opp_flag = 0x00; + card->u.h.tracebuf = ++tracebuf; + + if ((void*)tracebuf > card->u.h.tracebuf_last) + card->u.h.tracebuf = card->u.h.tracebuf_base; + + break; + } + } while (retry--); + } else { + my_mbox->return_code = HDLC_COMMS_DISABLED; + if(card->wandev.state != WAN_CONNECTED) + my_mbox->return_code = HDLC_LINK_NOT_IN_ABM; + if(!(card->wandev.api_status & STC)) + my_mbox->return_code = SET_TRACE_CFG; + my_mbox->buffer_length = 0; + } + + my_mbox->command = HDLC_READ_TRACE_DATA; + + length = MAILBOX_SIZE + my_mbox->buffer_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + send_result_packet(new_skb, length, dev, pid_number, my_mbox, 0,0); + } else + printk(KERN_INFO "poll_read: out of mem\n"); + + kfree(my_mbox); + + +} + + +/* Handle the receive interrupt */ +void rx_intr( sdla_t *card ) +{ + struct device *dev = card->wandev.dev; + HDLC_SHARED_MEMORY_INFO_STRUCT *hdlc_info = card->flags; + HDLC_INTERRUPT_INFO_STRUCT *hdlc_int = &hdlc_info->HDLC_interrupt_info; + HDLC_I_FRM_RX_STATUS_EL_STRUCT *rxbuf = card->rxmb; + HDLC_MAILBOX_STRUCT *cmd_area; + CMDBLOCK_STRUCT *cmdblock; + hdlc_private_area_t *hdlc_data_area = NULL; + struct sk_buff *new_skb; + unsigned short length; + int err, found = 0; + unsigned data_len, addr, tmp = 0; + + if ( rxbuf->opp_flag != 0x01) { + + printk(KERN_INFO + "%s: corrupted Rx buffer, flag = 0x%02X!\n", + card->devname, rxbuf->opp_flag); + return; + } + + /* + * Find which interface to pass up the receive data. + */ + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + hdlc_data_area = dev->priv; + if( hdlc_data_area->read_cmd == READ_CMD ){ + found = 1; + break; + } + } + + /* + * No interface was found to pass the data up to. + */ + if(!found){ + /* Turn off RX interrupts */ + hdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + printk(KERN_INFO "%s: Turn off Rx Interrupts\n", card->devname); + ++hdlc_data_area->ifstats.rx_dropped; + return; + } + + if (dev && dev->start) { + + length = MAILBOX_SIZE + rxbuf->I_frame_length; + + if((new_skb = dev_alloc_skb(length)) != NULL) { + + skb_put(new_skb,length); + new_skb->dev = dev; + new_skb->len = length; + new_skb->protocol = htons(0x16); + cmdblock = (CMDBLOCK_STRUCT *)new_skb->data; + cmdblock->pid_num = hdlc_data_area->rx_pid_number; + cmd_area = &cmdblock->cmdarea; + + + /* + * Copy the data from ptr_data_bfr. This is a + * rotational buffer so we have to be carefull. + */ + data_len = rxbuf->I_frame_length; + cmd_area->buffer_length = data_len; + addr = rxbuf->ptr_data_bfr; + + if ((addr + data_len) > card->u.h.rx_end + 1) { + tmp = card->u.h.rx_end - addr + 1; + sdla_peek(&card->hw, addr, cmd_area->data,tmp); + addr = card->u.h.rx_base; + data_len -= tmp; + } + sdla_peek(&card->hw, addr, (&cmd_area->data[tmp]), data_len); + /* Set it to the 'HDLC_READ_WAIT' to let the user + * process know for which command the result is being + * passed up. The return code is set to OK. The P_bit + * is copied to the mailbox PF_bit. (Poll & Final bit) + */ + + cmd_area->command = HDLC_READ_WAIT; + cmd_area->return_code = OK; + cmd_area->PF_bit = rxbuf->P_bit; + + + /* Check and see if we can send the socket back up to + * the stack. Is there room on the socket queue ? + * If yes, then send the data up. If not, then + * enable timer interrupt on the board and send the + * packet when there is room on the socket queue. + */ + + err=sangoma_check_sockets(new_skb); + + if( err >= 1){ + + if( err == 1 ) { + printk(KERN_INFO "rx_intr: No memory for skb\n"); + /* Turn off receive interrupts because + * we cannot push any more data up. + */ + hdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + /* Turn on timer interrupt to check the + * status of the socket RX queue. + */ + hdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + dev->tbusy = 1; + hdlc_data_area->status = BTM_CHECK_SK_RX_Q; + hdlc_data_area->saved_skb = new_skb; + + } else if(err == 2) { + + /* + * In this case there is no socket + * created. The user app are not + * even created/initialized the socket. + * I have decided to discard the packets + * in the scenario. + */ + + printk(KERN_INFO "rx_intr: %s No socket initialized\n", dev->name); + hdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + return; + } + + } else { + /* + * The socket RX queue has room so I can send + * the data up. + */ + new_skb->pkt_type = PACKET_HOST; + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + ++hdlc_data_area->ifstats.rx_packets; + } + } else { + printk(KERN_INFO "rx_intr: (new_skb) out of mem\n"); + hdlc_int->interrupt_permission &= ~APP_INT_ON_RX_FRAME; + return; + } + } else + ++hdlc_data_area->ifstats.rx_dropped; + + /* We have read the data */ + + rxbuf->opp_flag = 0x00; + card->rxmb = ++rxbuf; + + if ((void*)rxbuf > card->u.h.rxbuf_last) + card->rxmb = card->u.h.rxbuf_base; + +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_ppp.c linux.ac/drivers/net/sdla_ppp.c --- linux.vanilla/drivers/net/sdla_ppp.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_ppp.c Wed Mar 24 18:13:32 1999 @@ -10,7 +10,15 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. +* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. +* Jun 22, 1998 David Fong o Added remote IP address assignment +* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. +* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. +* o Implemented new routines like +* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), +* tokenize() and strstrip(). * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * while they have been disabled. * Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by @@ -65,10 +73,13 @@ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ -#include /* copyto/from user */ +#include +#include /* sockaddr_in */ +#include /* in_aton(), in_ntoa() prototypes */ +#include +#include #define _GNUC_ -#include /* PPP firmware API definitions */ - +#include /* PPP firmware API definitions */ /****** Defines & Macros ****************************************************/ #ifdef _DEBUG_ @@ -76,27 +87,37 @@ #else #define STATIC static #endif -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ + +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ /* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - + /******Data Structures*****************************************************/ + /* This structure is placed in the private data area of the device structure. * The card structure used to occupy the private area but now the following * structure will incorporate the card structure along with PPP specific data */ - -typedef struct ppp_private_area + +typedef struct ppp_private_area { - sdla_t *card; + sdla_t* card; unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter */ - unsigned mc; /*multicast support on or off */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + unsigned char enable_IPX; + unsigned long network_number; + unsigned char pap; + unsigned char chap; + unsigned char sysname[31]; /* system name for in-bnd auth*/ + unsigned char userid[511]; /* list of user ids */ + unsigned char passwd[511]; /* list of passwords */ /* PPP specific statistics */ unsigned long if_send_entry; unsigned long if_send_skb_null; @@ -113,11 +134,13 @@ unsigned long if_send_protocol_error; unsigned long if_send_tx_int_enabled; unsigned long if_send_bfr_passed_to_adptr; + unsigned long rx_intr_no_socket; unsigned long rx_intr_DRVSTATS_request; unsigned long rx_intr_PTPIPE_request; unsigned long rx_intr_bfr_not_passed_to_stack; unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_PTPIPE_mgmt_kmalloc_err; unsigned long UDP_PTPIPE_mgmt_adptr_type_err; unsigned long UDP_PTPIPE_mgmt_direction_err; @@ -125,7 +148,8 @@ unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; unsigned long UDP_PTPIPE_mgmt_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_no_socket; + unsigned long UDP_PTPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; unsigned long UDP_DRVSTATS_mgmt_direction_err; @@ -133,74 +157,85 @@ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; - unsigned long router_up_time; -} ppp_private_area_t; + unsigned long UDP_DRVSTATS_mgmt_no_socket; -/* variable for keeping track of enabling/disabling FT1 monitor status */ + unsigned long router_up_time; + +}ppp_private_area_t; +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct device *dev); + /* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); static int if_send(struct sk_buff *skb, struct device *dev); static struct enet_statistics *if_stats(struct device *dev); + + /* PPP firmware interface functions */ -static int ppp_read_version(sdla_t * card, char *str); -static int ppp_configure(sdla_t * card, void *data); -static int ppp_set_intr_mode(sdla_t * card, unsigned mode); -static int ppp_comm_enable(sdla_t * card); -static int ppp_comm_disable(sdla_t * card); -static int ppp_get_err_stats(sdla_t * card); -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); +static int ppp_read_version(sdla_t *card, char *str); +static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_configure(sdla_t *card, void *data); +static int ppp_set_intr_mode(sdla_t *card, unsigned mode); +static int ppp_comm_enable(sdla_t *card); +static int ppp_comm_disable(sdla_t *card); +static int ppp_get_err_stats(sdla_t *card); +static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); + /* Interrupt handlers */ -STATIC void wpp_isr(sdla_t * card); -static void rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); +STATIC void wpp_isr(sdla_t *card); +static void rx_intr(sdla_t *card); + /* Background polling routines */ -static void wpp_poll(sdla_t * card); -static void poll_active(sdla_t * card); -static void poll_connecting(sdla_t * card); -static void poll_disconnected(sdla_t * card); +static void wpp_poll(sdla_t *card); +static void poll_active(sdla_t *card); +static void poll_connecting(sdla_t *card); +static void poll_disconnected(sdla_t *card); + /* Miscellaneous functions */ -static int config502(sdla_t * card); -static int config508(sdla_t * card); +static int read_info( sdla_t *card ); +static int remove_route( sdla_t *card ); +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card); static void show_disc_cause(sdla_t * card, unsigned cause); -static unsigned char bps_to_speed_code(unsigned long bps); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area); -static void init_ppp_tx_rx_buff(sdla_t * card); -static int intr_test(sdla_t * card); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area); -static void init_global_statistics(sdla_t * card); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area); +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area); +static void init_ppp_tx_rx_buff( sdla_t *card ); +static int intr_test( sdla_t *card ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); +static void init_global_statistics( sdla_t *card ); +static int tokenize(char *str, char **tokens); +static char* strstrip(char *str, char *s); + +static int Read_connection_info; static int Intr_test_counter; -static char TracingEnabled; static unsigned long curr_trace_addr; static unsigned long start_trace_addr; static unsigned short available_buffer_space; + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); - +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, unsigned long network_number, unsigned short proto); /****** Public Functions ****************************************************/ /*============================================================================ @@ -215,30 +250,40 @@ * Return: 0 o.k. * < 0 failure. */ -int wpp_init(sdla_t * card, wandev_conf_t * conf) +int wpp_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; } u; + /* Verify configuration ID */ if (conf->config_id != WANCONFIG_PPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields */ switch (card->hw.fwid) { - case SFID_PPP502: - card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); - break; - case SFID_PPP508: - card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); - break; - default: - return -EINVAL; + + case SFID_PPP502: + card->mbox =(void*)(card->hw.dpmbase + PPP502_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP502_FLG_OFFS); + break; + + case SFID_PPP508: + card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); + break; + + default: + return -EINVAL; + } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work @@ -246,33 +291,36 @@ */ if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) return -EIO; - printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str); + + printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); /* Adjust configuration and set defaults */ card->wandev.mtu = (conf->mtu) ? - min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = &wpp_poll; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = &wpp_poll; + card->exec = &wpp_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - TracingEnabled = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + card->irq_dis_poll_count = 0; + card->u.p.authenticator = conf->u.ppp.authenticator; + card->u.p.ip_mode = conf->u.ppp.ip_mode ? + conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; + card->TracingEnabled = 0; + Read_connection_info = 1; + /* initialize global statistics */ - init_global_statistics(card); + init_global_statistics( card ); + return 0; } @@ -281,17 +329,22 @@ /*============================================================================ * Update device status & statistics. */ -static int update(wan_device_t * wandev) +static int update(wan_device_t *wandev) { sdla_t *card; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; + ppp_get_err_stats(card); wandev->critical = 0; return 0; @@ -309,29 +362,70 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf) { sdla_t *card = wandev->private; ppp_private_area_t *ppp_priv_area; + if (wandev->ndev) return -EEXIST; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; + } + /* allocate and initialize private data */ ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - if (ppp_priv_area == NULL) - return -ENOMEM; + + if( ppp_priv_area == NULL ) + return -ENOMEM; + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - ppp_priv_area->card = card; + + ppp_priv_area->card = card; + /* initialize data */ strcpy(card->u.p.if_name, conf->name); + /* initialize data in ppp_private_area structure */ - init_ppp_priv_struct(ppp_priv_area); + + init_ppp_priv_struct( ppp_priv_area ); + ppp_priv_area->mc = conf->mc; + ppp_priv_area->pap = conf->pap; + ppp_priv_area->chap = conf->chap; + + /* If no user ids are specified */ + if(!strlen(conf->userid) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + /* If no passwords are specified */ + if(!strlen(conf->passwd) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + if(strlen(conf->sysname) > 31) + return -EINVAL; + + /* If no system name is specified */ + if(!strlen(conf->sysname) && (card->u.p.authenticator)) + return -EINVAL; + + /* copy the data into the ppp private structure */ + memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); + memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); + memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); + + + ppp_priv_area->enable_IPX = conf->enable_IPX; + if (conf->network_number) + ppp_priv_area->network_number = conf->network_number; + else + ppp_priv_area->network_number = 0xDEADBEEF; + /* prepare network device data space for registration */ dev->name = card->u.p.if_name; dev->init = &if_init; @@ -342,13 +436,14 @@ /*============================================================================ * Delete logical channel. */ - -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if(wan_device_t *wandev, struct device *dev) { if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + + kfree(dev->priv); + dev->priv = NULL; + } + return 0; } @@ -357,27 +452,35 @@ /*============================================================================ * Execute adapter interface command. */ - static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) { ppp_mbox_t *mbox = card->mbox; int len; - if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) + + if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) return -EFAULT; + len = mbox->cmd.length; + if (len) { - if(copy_from_user((void *) &mbox->data, u_data, len)) + + if( copy_from_user((void*)&mbox->data, u_data, len)) return -EFAULT; + } + /* execute command */ if (!sdla_exec(mbox)) return -EIO; + /* return result */ - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t))) + if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) return -EFAULT; len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; + return 0; } @@ -390,7 +493,6 @@ * interface registration. Returning anything but zero will fail interface * registration. */ - static int if_init(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -398,26 +500,33 @@ wan_device_t *wandev = &card->wandev; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ dev_init_buffers(dev); + return 0; } @@ -428,7 +537,6 @@ * * Return 0 if O.k. or errno. */ - static int if_open(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -436,48 +544,91 @@ ppp_flags_t *flags = card->flags; struct timeval tv; int err = 0; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { + + if (config508(ppp_priv_area, card)){ + err = -EIO; card->wandev.critical = 0; return err; } + Intr_test_counter = 0; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); + err = intr_test( card ); + + if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); err = -EIO; card->wandev.critical = 0; return err; + } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff(card); + init_ppp_tx_rx_buff( card ); + if (ppp_set_intr_mode(card, 0x03)) { + err = -EIO; card->wandev.critical = 0; return err; + } + flags->imask &= ~0x02; + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + if (ppp_comm_enable(card)) { + err = -EIO; card->wandev.critical = 0; return err; + } + + wanpipe_set_state(card, WAN_CONNECTING); wanpipe_open(card); dev->mtu = min(dev->mtu, card->wandev.mtu); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - do_gettimeofday(&tv); + do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; card->wandev.critical = 0; + return err; } @@ -486,13 +637,14 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - static int if_close(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); wanpipe_set_state(card, WAN_DISCONNECTED); @@ -511,19 +663,21 @@ * * Return: media header length. */ - static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, void *daddr, void *saddr, unsigned len) { - switch (type) + switch (type) { case ETH_P_IP: + case ETH_P_IPX: - skb->protocol = type; + skb->protocol = htons(type); break; + default: skb->protocol = 0; } + return PPP_HDR_LEN; } @@ -533,14 +687,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff *skb) { - struct device *dev=skb->dev; + struct device *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -561,133 +715,198 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct device *dev) +static int if_send (struct sk_buff *skb, struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + struct in_device *in_dev; unsigned char *sendpacket; unsigned long check_braddr, check_mcaddr; unsigned long host_cpu_flags; ppp_flags_t *flags = card->flags; int retry = 0; int err, udp_type; + + ++ppp_priv_area->if_send_entry; + if (skb == NULL) { + /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); + card->devname, dev->name); + ++ppp_priv_area->if_send_skb_null; + mark_bh(NET_BH); return 0; + } + if (dev->tbusy) { + /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ + ++ppp_priv_area->if_send_busy; - ++card->wandev.stats.collisions; - if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) { + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { return 1; } - printk(KERN_INFO "%s: Transmit times out\n", card->devname); + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + ++ppp_priv_area->if_send_busy_timeout; - /* unbusy the card (because only one interface per card) */ + + /* unbusy the card (because only one interface per card)*/ dev->tbusy = 0; - } + } sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + ++ppp_priv_area->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, + process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, ppp_priv_area); + dev_kfree_skb(skb); return 0; - } else if (udp_type == UDP_PTPIPE_TYPE) + } + else if (udp_type == UDP_PTPIPE_TYPE) ++ppp_priv_area->if_send_PTPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[15]; - check_mcaddr = sendpacket[12]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[13]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[13]; - check_mcaddr |= sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[12]; - check_mcaddr |= sendpacket[15]; - /* if the Source Address is a Multicast address */ - if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) - && (check_mcaddr <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_multicast; - ++card->wandev.stats.tx_dropped; - return 0; + + + in_dev = dev->ip_ptr; + + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL){ + /* retreive source address in two forms: broadcast & + * multicast + */ + check_braddr = sendpacket[15]; + check_mcaddr = sendpacket[12]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[13]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[13]; + check_mcaddr |= sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[12]; + check_mcaddr |= sendpacket[15]; + + + /* if the Source Address is a Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_broadcast; + ++card->wandev.stats.tx_dropped; + return 0; + + } + + /* if the Source Address is a Multicast address */ + if ( (ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { + + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_multicast; + ++card->wandev.stats.tx_dropped; + return 0; + + } + } } disable_irq(card->hw.irq); ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - if (card->wandev.critical == CRITICAL_IN_ISR) { + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + /* If the critical flag is set due to an Interrupt * then set enable transmit interrupt flag to enable * transmit interrupt. (delay interrupt) */ card->wandev.enable_tx_int = 1; - dev->tbusy = 1; + dev->tbusy = 1; + /* set the counter to see if we get the interrupt in * 5 seconds. */ ppp_priv_area->tick_counter = jiffies; - ++ppp_priv_area->if_send_critical_ISR; + ++ppp_priv_area->if_send_critical_ISR; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; + } - dev_kfree_skb(skb); + + dev_kfree_skb(skb); ++ppp_priv_area->if_send_critical_non_ISR; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; } - if (udp_type == UDP_PTPIPE_TYPE) { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, ppp_priv_area); + + + + if (udp_type == UDP_PTPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, ppp_priv_area); + } else if (card->wandev.state != WAN_CONNECTED) { + ++ppp_priv_area->if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - } else if (!skb->protocol) { + ++card->wandev.stats.tx_dropped; + + } else if (!skb->protocol) { ++ppp_priv_area->if_send_protocol_error; - ++card->wandev.stats.tx_errors; + ++card->wandev.stats.tx_errors; + } else { - /*If it's IPX change the network numbers to 0 if they're ours. */ - if (skb->protocol == ETH_P_IPX) { - if (card->wandev.enable_IPX) { - switch_net_numbers(skb->data, - card->wandev.network_number, 0); + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == htons(ETH_P_IPX) ) { + if(ppp_priv_area->enable_IPX) { + switch_net_numbers( skb->data, + ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; goto tx_done; } } + if (ppp_send(card, skb->data, skb->len, skb->protocol)) { + retry = 1; dev->tbusy = 1; ++ppp_priv_area->if_send_adptr_bfrs_full; @@ -695,22 +914,26 @@ ppp_priv_area->tick_counter = jiffies; ++card->wandev.stats.tx_errors; flags->imask |= 0x02; /* unmask Tx interrupts */ + } else { ++ppp_priv_area->if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; } - } -tx_done: - if (!retry) { + } + +tx_done: + if (!retry){ dev_kfree_skb(skb); } + card->wandev.critical = 0; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return retry; } @@ -718,52 +941,72 @@ * Reply to UDP Management system. * Return length of reply. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) -{ - unsigned short len, udp_length, temp, i, ip_length; +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { + unsigned short len, + udp_length, + temp, + i, + ip_length; unsigned long sum; + /* Set length of packet */ len = mbox_len + 60; + /* fill in UDP reply */ data[36] = 0x02; + /* fill in UDP length */ udp_length = mbox_len + 40; + /* put it on an even boundary */ - if (udp_length & 0x0001) { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[24], &temp, 2); + } + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[24],&temp,2); + /* swap UDP ports */ - memcpy(&temp, &data[20], 2); - memcpy(&data[20], &data[22], 2); - memcpy(&data[22], &temp, 2); + memcpy(&temp,&data[20],2); + memcpy(&data[20],&data[22],2); + memcpy(&data[22],&temp,2); + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 20], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 22], &temp, 2); + memcpy(&data[udp_length+20],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+22],&temp,2); + /* calculate UDP checksum */ data[26] = data[27] = 0; sum = 0; - for (i = 0; i < udp_length + 12; i += 2) { - memcpy(&temp, &data[12 + i], 2); - sum += (unsigned long) temp; + + for ( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[12+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; + + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if ( temp == 0 ) temp = 0xffff; + memcpy(&data[26], &temp, 2); + /* fill in IP length */ ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); + temp = (ip_length<<8)|(ip_length>>8); memcpy(&data[2], &temp, 2); + /* swap IP addresses */ memcpy(&temp, &data[12], 2); memcpy(&data[12], &data[16], 2); @@ -771,93 +1014,101 @@ memcpy(&temp, &data[14], 2); memcpy(&data[14], &data[18], 2); memcpy(&data[18], &temp, 2); + /* fill in IP checksum */ data[10] = data[11] = 0; sum = 0; - for (i = 0; i < 20; i += 2) { - memcpy(&temp, &data[i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < 20; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); } - temp = (unsigned short) sum; + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[10], &temp, 2); + return len; -} /* reply_udp */ + +} /* reply_udp */ /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; + //If the destination network number is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; } } else { - /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[6] = (unsigned char) (network_number >> 24); - sendpacket[7] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char) (network_number & - 0x000000FF); + //If the incoming network is 0, make it ours + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - if (!incoming) { - /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + //If the source network is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; } } else { - /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[18] = (unsigned char) (network_number >> 24); - sendpacket[19] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char) (network_number & - 0x000000FF); + //If the source network is 0, make it ours + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. + * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ - static struct enet_statistics *if_stats(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card; + sdla_t* card; - /* - * Device is down:No statistics - */ - - if(ppp_priv_area==NULL) + if( ppp_priv_area == NULL ) return NULL; - + card = ppp_priv_area->card; return &card->wandev.stats; } @@ -868,122 +1119,260 @@ * Read firmware code version. * Put code version as ASCII string in str. */ - -static int ppp_read_version(sdla_t * card, char *str) +static int ppp_read_version(sdla_t *card, char *str) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_CODE_VERSION; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { + int len = mb->cmd.length; + memcpy(str, mb->data, len); str[len] = '\0'; + } + return err; } - -/*============================================================================ - * Configure PPP firmware. - */ - -static int ppp_configure(sdla_t * card, void *data) +/*=========================================================================== + * Set Out-Bound Authentication. +*/ +static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { ppp_mbox_t *mb = card->mbox; - int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; + memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ) ); + memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); + memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), + ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); + + mb->cmd.length = strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ; + + mb->cmd.command = PPP_SET_OUTBOUND_AUTH; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } -/*============================================================================ - * Set interrupt mode. - */ - -static int ppp_set_intr_mode(sdla_t * card, unsigned mode) +/*=========================================================================== + * Set In-Bound Authentication. +*/ +static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { ppp_mbox_t *mb = card->mbox; - int err; + int err, i; + char* user_tokens[32]; + char* pass_tokens[32]; + int userids, passwds; + int add_ptr; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->data, 0, 1008); + memcpy(mb->data, ppp_priv_area->sysname, + strlen(ppp_priv_area->sysname)); + + /* Parse the userid string and the password string and build a string + to copy it to the data area of the command structure. The string + will look like "SYS_NAMEUSER1PASS1USER2PASS2 + .... " + */ + userids = tokenize( ppp_priv_area->userid, user_tokens); + passwds = tokenize( ppp_priv_area->passwd, pass_tokens); + + if (userids != passwds){ + printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); + return 1; + } + + add_ptr = strlen(ppp_priv_area->sysname) + 1; + for (i=0; idata + add_ptr), user_tokens[i], + strlen(user_tokens[i])); + memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), + pass_tokens[i], strlen(pass_tokens[i])); + add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + + strlen(pass_tokens[i]) + 1; + } + + mb->cmd.length = add_ptr + 1; + mb->cmd.command = PPP_SET_INBOUND_AUTH; + + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + + +/*============================================================================ + * Tokenize string. + * Parse a string of the following syntax: + * ,,... + * and fill array of tokens with pointers to string elements. + * + */ +static int tokenize (char *str, char **tokens) +{ + int cnt = 0; + + tokens[0] = strtok(str, "/"); + while (tokens[cnt] && (cnt < 32 - 1)) + { + tokens[cnt] = strstrip(tokens[cnt], " \t"); + tokens[++cnt] = strtok(NULL, "/"); + } + return cnt; +} + +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +static char* strstrip (char *str, char* s) +{ + char *eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str /* strip leading spaces */ + ; + while ((eos > str) && strchr(s, *(eos - 1))) + --eos /* strip trailing spaces */ + ; + *eos = '\0'; + return str; +} +/*============================================================================ + * Configure PPP firmware. + */ +static int ppp_configure(sdla_t *card, void *data) +{ + ppp_mbox_t *mb = card->mbox; + int data_len = (card->hw.fwid == SFID_PPP502) ? + sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memcpy(mb->data, data, data_len); + mb->cmd.length = data_len; + mb->cmd.command = PPP_SET_CONFIG; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int ppp_set_intr_mode(sdla_t *card, unsigned mode) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->data[0] = mode; - switch (card->hw.fwid) { - case SFID_PPP502: - mb->cmd.length = 1; - break; - case SFID_PPP508: - default: - mb->data[1] = card->hw.irq; - mb->cmd.length = 2; + + switch (card->hw.fwid) + { + case SFID_PPP502: + mb->cmd.length = 1; + break; + + case SFID_PPP508: + + default: + mb->data[1] = card->hw.irq; + mb->cmd.length = 2; } + mb->cmd.command = PPP_SET_INTR_FLAGS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Enable communications. */ - -static int ppp_comm_enable(sdla_t * card) +static int ppp_comm_enable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_ENABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Disable communications. */ - -static int ppp_comm_disable(sdla_t * card) +static int ppp_comm_disable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_DISABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Get communications error statistics. */ - -static int ppp_get_err_stats(sdla_t * card) +static int ppp_get_err_stats(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_ERROR_STATS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err == CMD_OK) { - ppp_err_stats_t *stats = (void *) mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; + + ppp_err_stats_t* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } else + + } else ppp_error(card, err, mb); + return err; } @@ -992,27 +1381,41 @@ * Return: 0 - o.k. * 1 - no transmit buffers available */ - -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) +static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) { ppp_buf_ctl_t *txbuf = card->u.p.txbuf; unsigned long addr; + if (txbuf->flag) - return 1 - ; + return 1 + ; + if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else + + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; + + else + addr = txbuf->buf.ptr; + + sdla_poke(&card->hw, addr, data, len); - txbuf->length = len; /* frame length */ - if (proto == ETH_P_IPX) + + txbuf->length = len; /* frame length */ + + if (proto == htons(ETH_P_IPX)) txbuf->proto = 0x01; /* protocol ID */ - txbuf->flag = 1; /* start transmission */ + else + txbuf->proto = 0x00; /* protocol ID */ + + txbuf->flag = 1; /* start transmission */ + /* Update transmit buffer control fields */ card->u.p.txbuf = ++txbuf; - if ((void *) txbuf > card->u.p.txbuf_last) + + if ((void*)txbuf > card->u.p.txbuf_last) card->u.p.txbuf = card->u.p.txbuf_base; + return 0; } @@ -1025,19 +1428,22 @@ * * Return zero if previous command has to be cancelled. */ - -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) { unsigned cmd = mb->cmd.command; + switch (err) { - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, cmd, err); + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); } + return 0; } @@ -1046,65 +1452,82 @@ /*============================================================================ * PPP interrupt service routine. */ - -STATIC void wpp_isr(sdla_t * card) +STATIC void wpp_isr(sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; unsigned long host_cpu_flags; struct device *dev = card->wandev.dev; int i; + card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + card->force_enable_irq = 0; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; - printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname); + printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname); card->in_isr = 0; return; + } + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ card->wandev.critical = CRITICAL_IN_ISR; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - flags->imask &= ~0x02; - dev->tbusy = 0; - card->buff_int_mode_unbusy = 1; - break; - case 0x08: - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + flags->imask &= ~0x02; + dev->tbusy = 0; + card->buff_int_mode_unbusy = 1; + break; + + case 0x08: + ++Intr_test_counter; + ++card->statistics.isr_intr_test; + break; + + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); } + /* The critical flag is set to CRITICAL_INTR_HANDLED to let the * if_send call know that the interrupt is handled so that * transmit interrupts are not enabled again. - */ + */ + card->wandev.critical = CRITICAL_INTR_HANDLED; + /* If the enable transmit interrupt flag is set then enable transmit * interrupt on the board. This only goes through if if_send is called * and the critical flag is set due to an Interrupt. */ - if (card->wandev.enable_tx_int) { + if(card->wandev.enable_tx_int) { + flags->imask |= 0x02; card->wandev.enable_tx_int = 0; ++card->statistics.isr_enable_tx_int; + } save_flags(host_cpu_flags); cli(); @@ -1112,15 +1535,16 @@ flags->iflag = 0; card->wandev.critical = 0; restore_flags(host_cpu_flags); - if (card->buff_int_mode_unbusy) + + if(card->buff_int_mode_unbusy) mark_bh(NET_BH); + } /*============================================================================ * Receive interrupt handler. */ - -static void rx_intr(sdla_t * card) +static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; struct device *dev = card->wandev.dev; @@ -1129,159 +1553,198 @@ unsigned len; void *buf; int i, err; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; + ppp_flags_t *flags = card->flags; + char *ptr = &flags->iflag; int udp_type; + + if (rxbuf->flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) rxbuf, rxbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; + } + + if (dev && dev->start) { - len = rxbuf->length; + + len = rxbuf->length; ppp_priv_area = dev->priv; + /* Allocate socket buffer */ skb = dev_alloc_skb(len); + if (skb != NULL) { + /* Copy data to the socket buffer */ if (card->hw.fwid == SFID_PPP502) { - unsigned addr = (rxbuf->buf.o_p[1] << 8) + - rxbuf->buf.o_p[0]; + + unsigned addr = (rxbuf->buf.o_p[1] << 8) + + rxbuf->buf.o_p[0]; buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); + } else { + unsigned addr = rxbuf->buf.ptr; + if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr - + 1; + + unsigned tmp = card->u.p.rx_top - addr + + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, addr, buf, tmp); addr = card->u.p.rx_base; len -= tmp; + } + buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); } + /* Decapsulate packet */ - switch (rxbuf->proto) { - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; + switch (rxbuf->proto) { + + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; } - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->rx_intr_DRVSTATS_request; + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE){ + + ++ppp_priv_area->rx_intr_DRVSTATS_request; process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (udp_type == UDP_PTPIPE_TYPE) { + UDP_PKT_FRM_NETWORK, card, skb, + dev, ppp_priv_area); + dev_kfree_skb(skb); + + } else if (udp_type == UDP_PTPIPE_TYPE){ ++ppp_priv_area->rx_intr_PTPIPE_request; err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, ppp_priv_area); + UDP_PKT_FRM_NETWORK, card, + skb, dev, ppp_priv_area); dev_kfree_skb(skb); - } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { - if (card->wandev.enable_IPX) { - ppp_send(card, skb->data, skb->len, ETH_P_IPX); - dev_kfree_skb(skb); + + } else if (handle_IPXWAN(skb->data,card->devname, ppp_priv_area->enable_IPX, ppp_priv_area->network_number, skb->protocol)) { + + if( ppp_priv_area->enable_IPX) { + ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); + dev_kfree_skb(skb); + } else { ++card->wandev.stats.rx_dropped; } } else { /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_bfr_passed_to_stack; + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + ++ppp_priv_area->rx_intr_bfr_passed_to_stack; } + } else { + printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + card->devname); ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_no_socket; + } + } else ++card->statistics.rx_intr_dev_not_started; + /* Release buffer element and calculate a pointer to the next one */ rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; card->rxmb = ++rxbuf; - if ((void *) rxbuf > card->u.p.rxbuf_last) + + if ((void*)rxbuf > card->u.p.rxbuf_last) card->rxmb = card->u.p.rxbuf_base; } -/*============================================================================ - * Transmit interrupt handler. - */ - -static void tx_intr(sdla_t * card) -{ - struct device *dev = card->wandev.dev; - if (!dev || !dev->start) { - ++card->statistics.tx_intr_dev_not_started; - return; - } - dev->tbusy = 0; - mark_bh(NET_BH); -} - static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) { int i; - if (proto == htons(ETH_P_IPX)) { - /* It's an IPX packet */ - if (!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ + + if( proto == htons(ETH_P_IPX) ) { + //It's an IPX packet + if(!enable_IPX) { + //Return 1 so we don't pass it up the stack. return 1; } } else { - /* It's not IPX so pass it up the stack. */ + //It's not IPX so pass it up the stack. return 0; } - if (sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) { - /* It's IPXWAN */ - if (sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 41; sendpacket[i] == 0x00; i += 5) { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) { + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + //It's IPXWAN + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + //It's a timer request packet + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + //Go through the routing options and answer no to every + //option except Unnumbered RIP/SAP + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + //0x02 is the option for Unnumbered RIP/SAP + if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; } } - /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) { + + //Skip over the extended Node ID option + if( sendpacket[i] == 0x04 ) + { i += 8; } - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) { + + //We also want to turn off all header compression opt. + for(; sendpacket[i] == 0x80 ;) + { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } - /* Set the packet type to timer response */ + + //Set the packet type to timer response sendpacket[34] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); - } else if (sendpacket[34] == 0x02) { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); - /* Set the packet type to information response */ + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + //This is an information request packet + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + //Set the packet type to information response sendpacket[34] = 0x03; - /* Set the router name */ + + //Set the router name sendpacket[51] = 'P'; sendpacket[52] = 'T'; sendpacket[53] = 'P'; @@ -1290,30 +1753,38 @@ sendpacket[56] = 'E'; sendpacket[57] = '-'; sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for (i = 66; i < 99; i += 1) + for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); - } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char) (network_number >> 24); - sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char) (network_number & 0x000000FF); + + //Set the WNodeID to our network address + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + return 1; } else { - /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + //If we get here's its an IPX-data packet, so it'll get passed up the stack. + + //switch the network numbers + switch_net_numbers(sendpacket, network_number, 1); return 0; } } @@ -1329,80 +1800,141 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ - -static void wpp_poll(sdla_t * card) +static void wpp_poll(sdla_t *card) { struct device *dev = card->wandev.dev; ppp_flags_t *adptr_flags = card->flags; unsigned long host_cpu_flags; + ++card->statistics.poll_entry; + /* The wpp_poll is called continously by the WANPIPE thread to allow * for line state housekeeping. However if we are in a connected state * then we do not need to go through all the checks everytime. When in * connected state execute wpp_poll once every second. */ - if (card->wandev.state == WAN_CONNECTED) { - if ((jiffies - card->state_tick) < HZ) - return; + + if (card->wandev.state == WAN_CONNECTED) { + + if ((jiffies - card->state_tick) < HZ ) + return; + } - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (test_and_set_bit(0, (void *)&card->wandev.critical)) { + ++card->statistics.poll_already_critical; - printk(KERN_INFO "%s: critical inside wpp_poll\n", - card->devname); + printk(KERN_INFO "%s: critical inside wpp_poll\n", + card->devname); save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_poll_count)) && + !(card->irq_dis_if_send_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return; } - ++card->statistics.poll_processed; - if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { + + ++card->statistics.poll_processed; + + + /* check whether interrupts are turned on on the board and + * someone has done a disable_irq() and the code hasn't recovered + */ + if (adptr_flags->iflag) { + ++card->force_enable_irq; + if(card->force_enable_irq > 2){ + card->wandev.critical = 0; + card->irq_dis_poll_count = 0; + card->irq_dis_if_send_count = 0; + enable_irq(card->hw.irq); + return ; + + } + } + + if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { + ++card->statistics.poll_tbusy_bad_status; printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" - ,card->devname, adptr_flags->imask); - } - switch (card->wandev.state) { - case WAN_CONNECTED: - card->state_tick = jiffies; - poll_active(card); - break; - case WAN_CONNECTING: - poll_connecting(card); - break; - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - default: - printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", - card->devname, card->wandev.state); - break; + , card->devname, adptr_flags->imask); + } + + + switch(card->wandev.state){ + + case WAN_CONNECTED: + card->state_tick = jiffies; + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + + default: + printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", + card->devname, card->wandev.state); + break; } + card->wandev.critical = 0; + save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ( !(--card->irq_dis_poll_count) && !(card->irq_dis_if_send_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + } /*============================================================================ * Monitor active link phase. */ - -static void poll_active(sdla_t * card) +static void poll_active(sdla_t *card) { ppp_flags_t *flags = card->flags; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + + if (in_dev != NULL ) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER && + Read_connection_info && flags->ip_state == 0x9) { + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO "%s: An error occurred in IP assignment.\n", card->devname); + } else { + struct in_ifaddr *ifa = in_dev->ifa_list; + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_local) ); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_address) ); + } + Read_connection_info = 0; + } + } + /* We check the lcp_state to see if we are in DISCONNECTED state. * We are considered to be connected for lcp states 0x06, 0x07, 0x08 * and 0x09. */ if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + Read_connection_info = 1; + remove_route (card); + } wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); + } } @@ -1410,13 +1942,15 @@ * Monitor link establishment phase. * o if connection timed out, disconnect the link. */ - -static void poll_connecting(sdla_t * card) +static void poll_connecting(sdla_t *card) { ppp_flags_t *flags = card->flags; + if (flags->lcp_state == 0x09) { wanpipe_set_state(card, WAN_CONNECTED); + } else if (flags->disc_cause & 0x03) { + wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); } @@ -1427,171 +1961,154 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ - -static void poll_disconnected(sdla_t * card) +static void poll_disconnected(sdla_t *card) { struct device *dev = card->wandev.dev; + if (dev && dev->start && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { + wanpipe_set_state(card, WAN_CONNECTING); - if (ppp_comm_enable(card) == CMD_OK) - init_ppp_tx_rx_buff(card); + + if(ppp_comm_enable(card) == CMD_OK) + init_ppp_tx_rx_buff( card ); } } /****** Miscellaneous Functions *********************************************/ /*============================================================================ - * Configure S502 adapter. - */ - -static int config502(sdla_t * card) -{ - ppp502_conf_t cfg; - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp502_conf_t)); - if (card->wandev.clocking) - cfg.line_speed = bps_to_speed_code(card->wandev.bps); - cfg.txbuf_num = 4; - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; - cfg.conf_flags |= 0x0E; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ - return ppp_configure(card, &cfg); -} - -/*============================================================================ * Configure S508 adapter. */ - -static int config508(sdla_t * card) +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) { ppp508_conf_t cfg; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + /* Prepare PPP configuration structure */ memset(&cfg, 0, sizeof(ppp508_conf_t)); + if (card->wandev.clocking) cfg.line_speed = card->wandev.bps; + if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= 0x0020; - cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ - cfg.txbuf_percent = 60; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 100; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ + + cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/ + cfg.txbuf_percent = 60; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 100; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + + if( !card->u.p.authenticator ) { + printk(KERN_INFO "%s: Device is not configured as an authenticator\n", card->devname); + cfg.auth_options = 0x00; + }else{ + printk(KERN_INFO "%s: Device is configured as an authenticator\n", card->devname); + cfg.auth_options = 0x80; + } + if( ppp_priv_area->pap == WANOPT_YES){ + cfg.auth_options |= 0x01; + printk(KERN_INFO "%s: Pap enabled\n", card->devname); + } + if( ppp_priv_area->chap == WANOPT_YES){ + cfg.auth_options |= 0x02; + printk(KERN_INFO "%s: Chap enabled\n", card->devname); + } + + cfg.ipx_options = 0xA0; + + switch (card->u.p.ip_mode) { + + case WANOPT_PPP_STATIC: + cfg.ip_options = 0x80; + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; + break; + + case WANOPT_PPP_PEER: + cfg.ip_options = 0x8A; + cfg.ip_local = 0x00; + cfg.ip_remote = 0x00; + break; + + } return ppp_configure(card, &cfg); } /*============================================================================ * Show disconnection cause. */ - -static void show_disc_cause(sdla_t * card, unsigned cause) +static void show_disc_cause(sdla_t *card, unsigned cause) { - if (cause & 0x0002) - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - else if (cause & 0x0004) - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - else if (cause & 0x0008) + if (cause & 0x0002) + + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + + else if (cause & 0x0004) + + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + + else if (cause & 0x0008) + printk(KERN_INFO "%s: authentication failed\n", card->devname); - else if (cause & 0x0010) - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - else if (cause & 0x0020) + + else if (cause & 0x0010) + + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + + else if (cause & 0x0020) + printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - else if (cause & 0x0040) - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - else if (cause & 0x0080) - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - else if (cause & 0x0100) + "%s: peer's request for authentication rejected\n", + card->devname); + + else if (cause & 0x0040) + + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); + + else if (cause & 0x0080) + + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); + + else if (cause & 0x0100) + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - else if (cause & 0x0200) + card->devname); + + else if (cause & 0x0200) + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - ,card->devname); - else if (cause & 0x0400) - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} + , card->devname); -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ + else if (cause & 0x0400) -static unsigned char bps_to_speed_code(unsigned long bps) -{ - unsigned char number; - if (bps <= 1200) - number = 0x01; - else if (bps <= 2400) - number = 0x02; - else if (bps <= 4800) - number = 0x03; - else if (bps <= 9600) - number = 0x04; - else if (bps <= 19200) - number = 0x05; - else if (bps <= 38400) - number = 0x06; - else if (bps <= 45000) - number = 0x07; - else if (bps <= 56000) - number = 0x08; - else if (bps <= 64000) - number = 0x09; - else if (bps <= 74000) - number = 0x0A; - else if (bps <= 112000) - number = 0x0B; - else if (bps <= 128000) - number = 0x0C; - else - number = 0x0D; - return number; + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); } /*============================================================================ * Process UDP call of type DRVSTATS. */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area) +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1601,183 +2118,211 @@ ppp_mbox_t *mbox = card->mbox; struct sk_buff *new_skb; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmd 0x%02X" + ,card->devname, data[45]); + ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* PPIPE_DRIVER_STATISTICS */ - case 0x26: - *(unsigned long *) &data[60] = - ppp_priv_area->if_send_entry; - *(unsigned long *) &data[64] = - ppp_priv_area->if_send_skb_null; - *(unsigned long *) &data[68] = - ppp_priv_area->if_send_broadcast; - *(unsigned long *) &data[72] = - ppp_priv_area->if_send_multicast; - *(unsigned long *) &data[76] = - ppp_priv_area->if_send_critical_ISR; - *(unsigned long *) &data[80] = - ppp_priv_area->if_send_critical_non_ISR; - *(unsigned long *) &data[84] = - ppp_priv_area->if_send_busy; - *(unsigned long *) &data[88] = - ppp_priv_area->if_send_busy_timeout; - *(unsigned long *) &data[92] = - ppp_priv_area->if_send_DRVSTATS_request; - *(unsigned long *) &data[96] = - ppp_priv_area->if_send_PTPIPE_request; - *(unsigned long *) &data[100] = - ppp_priv_area->if_send_wan_disconnected; - *(unsigned long *) &data[104] = - ppp_priv_area->if_send_adptr_bfrs_full; - *(unsigned long *) &data[108] = - ppp_priv_area->if_send_protocol_error; - *(unsigned long *) &data[112] = - ppp_priv_area->if_send_tx_int_enabled; - *(unsigned long *) &data[116] = - ppp_priv_area->if_send_bfr_passed_to_adptr; - *(unsigned long *) &data[118] = - card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x27: - *(unsigned long *) &data[60] = card->statistics.isr_entry; - *(unsigned long *) &data[64] = - card->statistics.isr_already_critical; - *(unsigned long *) &data[68] = card->statistics.isr_rx; - *(unsigned long *) &data[72] = card->statistics.isr_tx; - *(unsigned long *) &data[76] = - card->statistics.isr_intr_test; - *(unsigned long *) &data[80] = - card->statistics.isr_spurious; - *(unsigned long *) &data[84] = - card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[88] = - card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[92] = - ppp_priv_area->rx_intr_no_socket; - *(unsigned long *) &data[96] = - ppp_priv_area->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[100] = - ppp_priv_area->rx_intr_PTPIPE_request; - *(unsigned long *) &data[104] = - ppp_priv_area->rx_intr_bfr_passed_to_stack; - *(unsigned long *) &data[108] = - card->statistics.rx_intr_dev_not_started; - *(unsigned long *) &data[112] = - card->statistics.tx_intr_dev_not_started; - mbox->cmd.length = 56; - break; - case 0x28: - *(unsigned long *) &data[60] = - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[64] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[68] = - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - *(unsigned long *) &data[72] = - ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[76] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[80] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - *(unsigned long *) &data[84] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[88] = - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; - *(unsigned long *) &data[92] = - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[96] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[100] = - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[104] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_adptr; - *(unsigned long *) &data[108] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[112] = - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[116] = - card->statistics.poll_entry; - *(unsigned long *) &data[120] = - card->statistics.poll_already_critical; - *(unsigned long *) &data[124] = - card->statistics.poll_processed; - *(unsigned long *) &data[126] = - card->irq_dis_poll_count; - mbox->cmd.length = 70; - break; - default: - /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + return 1; + } + + memcpy(data,sendpacket,skb->len); + + switch(data[45]) { + + /* PPIPE_DRIVER_STATISTICS */ + case 0x26: + *(unsigned long*)&data[60] = + ppp_priv_area->if_send_entry; + *(unsigned long*)&data[64] = + ppp_priv_area->if_send_skb_null; + *(unsigned long*)&data[68] = + ppp_priv_area->if_send_broadcast; + *(unsigned long*)&data[72] = + ppp_priv_area->if_send_multicast; + *(unsigned long*)&data[76] = + ppp_priv_area->if_send_critical_ISR; + *(unsigned long*)&data[80] = + ppp_priv_area->if_send_critical_non_ISR; + *(unsigned long*)&data[84] = + ppp_priv_area->if_send_busy; + *(unsigned long*)&data[88] = + ppp_priv_area->if_send_busy_timeout; + *(unsigned long*)&data[92] = + ppp_priv_area->if_send_DRVSTATS_request; + *(unsigned long*)&data[96] = + ppp_priv_area->if_send_PTPIPE_request; + *(unsigned long*)&data[100] = + ppp_priv_area->if_send_wan_disconnected; + *(unsigned long*)&data[104] = + ppp_priv_area->if_send_adptr_bfrs_full; + *(unsigned long*)&data[108] = + ppp_priv_area->if_send_protocol_error; + *(unsigned long*)&data[112] = + ppp_priv_area->if_send_tx_int_enabled; + *(unsigned long*)&data[116] = + ppp_priv_area->if_send_bfr_passed_to_adptr; + *(unsigned long*)&data[120] = + card->irq_dis_if_send_count; + mbox->cmd.length = 62; break; - } - ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } + + case 0x27: + *(unsigned long*)&data[60] = card->statistics.isr_entry; + *(unsigned long*)&data[64] = + card->statistics.isr_already_critical; + *(unsigned long*)&data[68] = card->statistics.isr_rx; + *(unsigned long*)&data[72] = card->statistics.isr_tx; + *(unsigned long*)&data[76] = + card->statistics.isr_intr_test; + *(unsigned long*)&data[80] = + card->statistics.isr_spurious; + *(unsigned long*)&data[84] = + card->statistics.isr_enable_tx_int; + *(unsigned long*)&data[88] = + card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long*)&data[92] = + ppp_priv_area->rx_intr_no_socket; + *(unsigned long*)&data[96] = + ppp_priv_area->rx_intr_DRVSTATS_request; + *(unsigned long*)&data[100] = + ppp_priv_area->rx_intr_PTPIPE_request; + *(unsigned long*)&data[104] = + ppp_priv_area->rx_intr_bfr_passed_to_stack; + *(unsigned long*)&data[108] = + card->statistics.rx_intr_dev_not_started; + *(unsigned long*)&data[112] = + card->statistics.tx_intr_dev_not_started; + mbox->cmd.length = 56; + break; + + case 0x28: + *(unsigned long*)&data[60] = + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + *(unsigned long*)&data[64] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; + *(unsigned long*)&data[68] = + ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; + *(unsigned long*)&data[72] = + ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[76] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[80] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; + *(unsigned long*)&data[84] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + *(unsigned long*)&data[88] = + ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; + *(unsigned long*)&data[92] = + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long*)&data[96] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[100] = + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[104] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_adptr; + *(unsigned long*)&data[108] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long*)&data[112] = + ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long*)&data[116] = + card->statistics.poll_entry; + *(unsigned long*)&data[120] = + card->statistics.poll_already_critical; + *(unsigned long*)&data[124] = + card->statistics.poll_processed; + *(unsigned long*)&data[128] = + card->irq_dis_poll_count; + mbox->cmd.length = 70; + break; + + + default: + /* it's a board command */ + memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + + /* run the command on the board */ + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + break; + } + + ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + + /* copy the result back to our buffer */ + //memcpy(data,sendpacket,skb->len); + memcpy(&data[45],&mbox->cmd, sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&data[60],&mbox->data, mbox->cmd.length); + } + } - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp( data, mbox->cmd.length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr; ppp_send(card, data, len, skb->protocol); - } else { + + + } else { + /* Pass it up the stack - Allocate socket buffer */ + Allocate socket buffer */ if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); + } + } + kfree(data); return 0; } /*============================================================================= * Process UDP call of type PTPIPEAB. */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, - struct sk_buff *skb, struct device *dev, - ppp_private_area_t * ppp_priv_area) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1791,210 +2336,293 @@ ppp_mbox_t *mbox = card->mbox; struct timeval tv; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_PPP508) { + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd0x%02X" + ,card->devname, data[45]); + + ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + return 1; + } + memcpy(data,sendpacket,skb->len); + + switch(data[45]) { + + /* FT1 MONITOR STATUS */ + case 0x80: + if(card->hw.fwid != SFID_PPP508) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; udp_mgmt_req_valid = 0; - break; - } - /* PPIPE_ENABLE_TRACING */ + break; + } + + /* PPIPE_ENABLE_TRACING */ case 0x20: - /* PPIPE_DISABLE_TRACING */ - case 0x21: - /* PPIPE_GET_TRACE_INFO */ - case 0x22: - /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + /* PPIPE_DISABLE_TRACING */ + case 0x21: + + /* PPIPE_GET_TRACE_INFO */ + case 0x22: + + /* SET FT1 MODE */ + case 0x81: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; udp_mgmt_req_valid = 0; - } - break; + } + break; + default: - break; - } - if (!udp_mgmt_req_valid) { + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ - data[46] = data[47] = 0; - /* set return code */ - data[48] = 0xCD; - } else { + data[46] = data[47] = 0; + + /* set return code */ + data[48] = 0xCD; + + } else { + switch (data[45]) { - /* PPIPE_ENABLE_TRACING */ - case 0x20: - if (!TracingEnabled) { + + /* PPIPE_ENABLE_TRACING */ + case 0x20: + if (!card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x03; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x03; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mbox); - TracingEnabled = 0; + card->TracingEnabled = 0; + /* set the return code */ - data[48] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - if (card->hw.fwid == SFID_PPP502) { + + data[48] = mbox->cmd.result; + mbox->cmd.length = 0; + break; + } + + if (card->hw.fwid == SFID_PPP502) { + sdla_peek(&card->hw, 0x9000, &buf2, 2); + } else { + sdla_peek(&card->hw, 0xC000, &buf2, 2); - } + } + curr_trace_addr = 0; - memcpy(&curr_trace_addr, &buf2, 2); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET) - - 41 */ - available_buffer_space = 1926; - } - data[48] = 0; - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* PPIPE_DISABLE_TRACING */ + memcpy(&curr_trace_addr, &buf2, 2); + start_trace_addr = curr_trace_addr; + + /* MAX_SEND_BUFFER_SIZE - 28 (IP header) + - 32 (ppipemon CBLOCK) */ + available_buffer_space = 1940; + } + data[48] = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + /* PPIPE_DISABLE_TRACING */ case 0x21: - if (TracingEnabled) { + + if(card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x3; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - /*set return code */ + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x00; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + } + + /*set return code*/ data[48] = 0; mbox->cmd.length = 0; - TracingEnabled = 0; + card->TracingEnabled = 0; break; - /* PPIPE_GET_TRACE_INFO */ + + /* PPIPE_GET_TRACE_INFO */ case 0x22: - if (TracingEnabled) { + + if(card->TracingEnabled) { + buffer_length = 0; - /* frames < NUM_TRACE_FRAMES */ - for (frames = 0; frames < 62; frames += 1) { - sdla_peek(&card->hw, curr_trace_addr, - &buf2, 1); + + /* frames < 62, where 62 is the number of trace + information elements. There is in total 496 + bytes of space and each trace information + element is 8 bytes. + */ + for ( frames = 0; frames < 62; frames += 1) { + + sdla_peek(&card->hw, curr_trace_addr, + &buf2, 1); + /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /*1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - - buffer_length) < 9) { + if( buf2[0] == 0x00 ) + break; + + /*1+sizeof(FRAME_DATA) = 9*/ + if ((available_buffer_space - + buffer_length) < 9){ + /*indicate we have more frames - on board and exit */ - data[60] |= 0x02; - break; - } + on board and exit */ + data[60] |= 0x02; + break; + } + /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + - 0x01, &data[60 + buffer_length], 1); + sdla_peek(&card->hw, curr_trace_addr + + 0x01,&data[60+buffer_length],1); + /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + - 0x06, &data[64 + buffer_length], 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x06,&data[64+buffer_length],2); + /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + - 0x02, &data[62 + buffer_length], 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x02,&data[62+buffer_length],2); + /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + - 0x04, &buf2, 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x04, &buf2, 2); + data_ptr = 0; - memcpy(&data_ptr, &buf2, 2); + memcpy(&data_ptr, &buf2, 2); + /* see if we can fit the frame into the - user buffer */ - memcpy(&real_len, - &data[62 + buffer_length], 2); - if ((data_ptr == 0) || - ((real_len + 8) > - available_buffer_space)) { - data[61 + buffer_length] = 0x00; + user buffer */ + memcpy(&real_len, + &data[62+buffer_length], 2); + + /* Initialize the passed length field */ + data[61+buffer_length] = 0x00; + if( data_ptr == 0 ) { + + data[61+buffer_length] = 0x00; + } else { + /* we can take it next time */ - if ((available_buffer_space - - buffer_length) < - (real_len + 8)) { + + if(( available_buffer_space - + buffer_length ) < + ( real_len + 8 )) { + data[60] |= 0x02; - break; - } - /* ok, get the frame */ - data[61 + buffer_length] = 0x01; + break; + } + + /* ok, get the frame */ + data[61+buffer_length] = 0x01; + /* get the data */ - sdla_peek(&card->hw, data_ptr, - &data[66 + buffer_length], - real_len); - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, - curr_trace_addr, &buf2, 1); - /* now move onto the next - frame */ - curr_trace_addr += 8; - /* check if we passed the last - address */ - if (curr_trace_addr >= - start_trace_addr + 0x1F0) { - curr_trace_addr = - start_trace_addr; - } - /* update buffer length and make sure its even */ - if (data[61 + buffer_length] - == 0x01) { - buffer_length += - real_len - 1; - } - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } + sdla_peek(&card->hw, data_ptr, + &data[66+buffer_length], + real_len); + } + /* zero the opp flag to + show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, + curr_trace_addr, &buf2, 1); + + /* now move onto the next + frame */ + curr_trace_addr += 8; + + /* check if we passed the last + address */ + if ( curr_trace_addr >= + start_trace_addr + 0x1F0) { + + curr_trace_addr = + start_trace_addr; + } + + /* update buffer length and make sure its even */ + + if ( data[61+buffer_length] + == 0x01 ) { + + buffer_length += + real_len - 1; + } + + /* for the header */ + buffer_length += 8; + + if( buffer_length & 0x0001 ) + buffer_length += 1; } - /* ok now set the total number of frames passed + + /* ok now set the total number of frames passed in the high 5 bits */ - data[60] = (frames << 2) | data[60]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[46], &buffer_length, 2); - /* set return code */ - data[48] = 0; - } else { + data[60] = (frames << 2) | data[60]; + + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[46], &buffer_length,2); + + /* set return code */ + data[48] = 0; + + } else { + /* set return code */ - data[48] = 1; - mbox->cmd.length = 0; - } - break; - /* PPIPE_GET_IBA_DATA */ + data[48] = 1; + mbox->cmd.length = 0; + } + break; + + /* PPIPE_GET_IBA_DATA */ case 0x23: + mbox->cmd.length = 0x09; + if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0xA003, &data[60], - mbox->cmd.length); + + sdla_peek(&card->hw, 0xA003, &data[60], + mbox->cmd.length); } else { - sdla_peek(&card->hw, 0xF003, &data[60], - mbox->cmd.length); + sdla_peek(&card->hw, 0xF003, &data[60], + mbox->cmd.length); } + /* set the length of the data */ data[46] = 0x09; + /* set return code */ data[48] = 0x00; + break; - /* PPIPE_KILL_BOARD */ + + /* PPIPE_KILL_BOARD */ case 0x24: break; - /* PPIPE_FT1_READ_STATUS */ + + /* PPIPE_FT1_READ_STATUS */ case 0x25: sdla_peek(&card->hw, 0xF020, &data[60], 2); data[46] = 2; @@ -2002,96 +2630,125 @@ data[48] = 0; mbox->cmd.length = 2; break; + case 0x29: - init_ppp_priv_struct(ppp_priv_area); - init_global_statistics(card); + init_ppp_priv_struct( ppp_priv_area ); + init_global_statistics( card ); mbox->cmd.length = 0; break; + case 0x30: - do_gettimeofday(&tv); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *) &data[60] = - ppp_priv_area->router_up_time; + + do_gettimeofday( &tv ); + ppp_priv_area->router_up_time = tv.tv_sec - + ppp_priv_area->router_start_time; + *(unsigned long*)&data[60] = + ppp_priv_area->router_up_time; mbox->cmd.length = 4; break; - /* FT1 MONITOR STATUS */ - case 0x80: + + /* FT1 MONITOR STATUS */ + case 0x80: + /* Enable FT1 MONITOR STATUS */ - if (data[60] == 1) { - if (rCount++ != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[60] == 0) { - if (--rCount != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } + if( data[60] == 1) { + + if( rCount++ != 0 ) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( data[60] == 0) { + + if( --rCount != 0) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + default: + /* it's a board command */ memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + /* run the command on the board */ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; break; } - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } /* end of switch */ - } /* end of else */ - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + memcpy(data,sendpacket,skb->len); + memcpy(&data[45],&mbox->cmd, sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&data[60],&mbox->data, mbox->cmd.length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp( data, mbox->cmd.length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; ppp_send(card, data, len, skb->protocol); - } else { + + } else { + /* Pass it up the stack - Allocate socket buffer */ + Allocate socket buffer */ if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); + } + } + kfree(data); return 0; } /*============================================================================= * Initial the ppp_private_area structure. */ - -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) { + ppp_priv_area->if_send_entry = 0; ppp_priv_area->if_send_skb_null = 0; ppp_priv_area->if_send_broadcast = 0; @@ -2104,12 +2761,15 @@ ppp_priv_area->if_send_PTPIPE_request = 0; ppp_priv_area->if_send_wan_disconnected = 0; ppp_priv_area->if_send_adptr_bfrs_full = 0; + ppp_priv_area->if_send_protocol_error = 0; + ppp_priv_area->if_send_tx_int_enabled = 0; ppp_priv_area->if_send_bfr_passed_to_adptr = 0; + ppp_priv_area->rx_intr_no_socket = 0; ppp_priv_area->rx_intr_DRVSTATS_request = 0; ppp_priv_area->rx_intr_PTPIPE_request = 0; - ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; @@ -2118,103 +2778,220 @@ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; + } /*============================================================================ * Initialize Global Statistics */ - -static void init_global_statistics(sdla_t * card) +static void init_global_statistics( sdla_t *card ) { - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_dev_not_started = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; - card->statistics.poll_tbusy_bad_status = 0; + card->statistics.rx_intr_dev_not_started= 0; + card->statistics.tx_intr_dev_not_started= 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; + card->statistics.poll_tbusy_bad_status = 0; + } /*============================================================================ * Initialize Receive and Transmit Buffers. */ - -static void init_ppp_tx_rx_buff(sdla_t * card) +static void init_ppp_tx_rx_buff( sdla_t *card ) { + if (card->hw.fwid == SFID_PPP502) { - ppp502_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); - card->u.p.txbuf_base = - (void *) (card->hw.dpmbase + info->txb_offs); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = - (void *) (card->hw.dpmbase + info->rxb_offs); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); + + ppp502_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP502_BUF_OFFS); + + card->u.p.txbuf_base = + (void*)(card->hw.dpmbase + info->txb_offs); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = + (void*)(card->hw.dpmbase + info->rxb_offs); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + } else { - ppp508_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); + + ppp508_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; + card->u.p.rx_top = info->rxb_end; } + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; + +} + +/*============================================================================= + * Read Connection Information (ie for Remote IP address assginment). + * Called when ppp interface connected. + */ +static int read_info( sdla_t *card ) +{ + ppp_mbox_t *mb = card->mbox; + struct device *dev = card->wandev.dev; + int err; + ppp508_connect_info_t *ppp508_connect_info; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + + /* Read Connection Information */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = PPP_GET_CONNECTION_INFO; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mb); + } + else { + mm_segment_t fs = get_fs(); + ppp508_connect_info = (ppp508_connect_info_t *)mb->data; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = ppp508_connect_info->ip_local; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ppp508_connect_info->ip_remote; + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } + } + return err; +} + +/*============================================================================= + * Remove Dynamic Route. + * Called when ppp interface disconnected. + */ + +static int remove_route( sdla_t *card ) +{ + mm_segment_t fs = get_fs(); + struct ifreq if_info; + struct sockaddr_in *if_data1; + struct device *dev = card->wandev.dev; + int err; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", + card->devname, err); + return err; + } + + return 0; } /*============================================================================= * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ - -static int intr_test(sdla_t * card) +static int intr_test( sdla_t *card ) { ppp_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset because during initialization (if_open) + int err,i; + + /* The critical flag is unset because during intialization (if_open) * we want the interrupts to be enabled so that when the wpp_isr is * called it does not exit due to critical flag set. - */ + */ + card->wandev.critical = 0; - err = ppp_set_intr_mode(card, 0x08); - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) { + + err = ppp_set_intr_mode( card, 0x08 ); + + if ( err == CMD_OK ) { + + for (i=0; icmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; + mb->cmd.length = 0; mb->cmd.command = 0x10; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); } - } else - return err; - err = ppp_set_intr_mode(card, 0); - if (err != CMD_OK) + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) return err; + card->wandev.critical = 1; return 0; } @@ -2222,40 +2999,49 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) { unsigned char *sendpacket; - unsigned char buf2[5]; + unsigned char buf2[5]; + sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[0] == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01) { - if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42) { + + if( sendpacket[0] == 0x45 && /* IP packet */ + sendpacket[9] == 0x11 && /* UDP packet */ + sendpacket[22] == buf2[1] && /* UDP Port */ + sendpacket[23] == buf2[0] && + sendpacket[36] == 0x01 ) { + + if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ + sendpacket[29] == 0x54 && + sendpacket[30] == 0x50 && + sendpacket[31] == 0x49 && + sendpacket[32] == 0x50 && + sendpacket[33] == 0x45 && + sendpacket[34] == 0x41 && + sendpacket[35] == 0x42 ){ + return UDP_PTPIPE_TYPE; - } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53) { + + } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[29] == 0x52 && + sendpacket[30] == 0x56 && + sendpacket[31] == 0x53 && + sendpacket[32] == 0x54 && + sendpacket[33] == 0x41 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x53 ){ + return UDP_DRVSTATS_TYPE; + } else return UDP_INVALID_TYPE; + } else return UDP_INVALID_TYPE; + } + /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_x25.c linux.ac/drivers/net/sdla_x25.c --- linux.vanilla/drivers/net/sdla_x25.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_x25.c Thu Mar 11 13:08:32 1999 @@ -1,16 +1,18 @@ /***************************************************************************** * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. * -* Author: Gene Kozin +* Author: Jaspreet Singh * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * 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. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.x porting +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * when they are disabled. * Nov 17, 1997 Farhan Thawar o Added IPX support @@ -38,7 +40,6 @@ * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ - #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -48,11 +49,14 @@ #include /* WANPIPE common user API definitions */ #include /* htons(), etc. */ #include - +#include +#include #define _GNUC_ #include /* X.25 firmware API definitions */ -/****** Defines & Macros ****************************************************/ +/* + * Defines & Macros + */ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ @@ -65,10 +69,14 @@ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -/* For IPXWAN */ +/* + * For IPXWAN + */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) -/****** Data Structures *****************************************************/ +/* + * Data Structures + */ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of X.25 channel-specific data. @@ -93,7 +101,9 @@ struct sk_buff* tx_skb; /* transmit socket buffer */ sdla_t* card; /* -> owner */ int ch_idx; - struct net_device_stats ifstats; /* interface statistics */ + unsigned char enable_IPX; + unsigned long network_number; + struct enet_statistics ifstats; /* interface statistics */ } x25_channel_t; typedef struct x25_call_info @@ -110,18 +120,28 @@ } facil[64]; /* facilities */ } x25_call_info_t; -/****** Function Prototypes *************************************************/ +/* + * Function Prototypes + */ -/* WAN link driver entry points. These are called by the WAN router module. */ +/* + * WAN link driver entry points. These are called by the WAN router module. + */ static int update (wan_device_t* wandev); static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); -/* WANPIPE-specific entry points */ +/* + * WANPIPE-specific entry points + */ + static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -/* Network device interface */ +/* + * Network device interface + */ + static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); @@ -129,9 +149,12 @@ unsigned short type, void* daddr, void* saddr, unsigned len); static int if_rebuild_hdr (struct sk_buff* skb); static int if_send (struct sk_buff* skb, struct device* dev); -static struct net_device_stats * if_stats (struct device* dev); +static struct net_device_stats *if_stats (struct device* dev); + +/* + * Interrupt handlers + */ -/* Interrupt handlers */ static void wpx_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void tx_intr (sdla_t* card); @@ -139,13 +162,19 @@ static void event_intr (sdla_t* card); static void spur_intr (sdla_t* card); -/* Background polling routines */ +/* + * Background polling routines + */ + static void wpx_poll (sdla_t* card); static void poll_disconnected (sdla_t* card); static void poll_connecting (sdla_t* card); static void poll_active (sdla_t* card); -/* X.25 firmware interface functions */ +/* + * X.25 firmware interface functions + */ + static int x25_get_version (sdla_t* card, char* str); static int x25_configure (sdla_t* card, TX25Config* conf); static int x25_get_err_stats (sdla_t* card); @@ -163,14 +192,20 @@ static int x25_fetch_events (sdla_t* card); static int x25_error (sdla_t* card, int err, int cmd, int lcn); -/* X.25 asynchronous event handlers */ +/* + * X.25 asynchronous event handlers + */ + static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -/* Miscellaneous functions */ +/* + * Miscellaneous functions + */ + static int connect (sdla_t* card); static int disconnect (sdla_t* card); static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); @@ -183,29 +218,30 @@ static unsigned int hex_to_uint (unsigned char* str, int len); static void parse_call_info (unsigned char* str, x25_call_info_t* info); -/* IPX functions */ +/* + * IPX functions + */ + static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! +/* + * Public Functions */ -/****** Public Functions ****************************************************/ - -/*============================================================================ - * X.25 Protocol Initialization routine. +/* + * X.25 Protocol Initialization routine. * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. * - * Return: 0 o.k. + * Return: 0 o.k. * < 0 failure. */ int wpx_init (sdla_t* card, wandev_conf_t* conf) @@ -349,20 +385,17 @@ card->wandev.enable_tx_int = 0; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; return 0; } -/******* WAN Device Driver Entry Points *************************************/ +/* + * WAN Device Driver Entry Points + */ -/*============================================================================ - * Update device status & statistics. +/* + * Update device status & statistics. */ + static int update (wan_device_t* wandev) { sdla_t* card; @@ -382,18 +415,19 @@ return 0; } -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. +/* + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. * - * Return: 0 o.k. + * Return: 0 o.k. * < 0 failure (channel will not be created) */ + static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; @@ -441,8 +475,7 @@ { printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; + wandev->name, lcn, chan->name); err = -EINVAL; } } @@ -450,8 +483,7 @@ { printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + wandev->name, chan->name); err = -EINVAL; } if (err) @@ -459,6 +491,14 @@ kfree(chan); return err; } + + chan->enable_IPX = conf->enable_IPX; + if (chan->enable_IPX) + chan->protocol = ETH_P_IPX; + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; /* prepare network device data space for registration */ dev->name = chan->name; @@ -467,8 +507,8 @@ return 0; } -/*============================================================================ - * Delete logical channel. +/* + * Delete logical channel. */ static int del_if (wan_device_t* wandev, struct device* dev) { @@ -480,10 +520,12 @@ return 0; } -/****** WANPIPE-specific entry points ***************************************/ +/* + * WANPIPE-specific entry points + */ -/*============================================================================ - * Execute adapter interface command. +/* + * Execute adapter interface command. */ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) @@ -495,20 +537,19 @@ if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; - - /* execute command */ + /* execute command */ + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { + if (cmd.length) { if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; + return -EFAULT; } if (sdla_exec(mbox)) - err = mbox->cmd.result - ; + err = mbox->cmd.result; + else return -EIO; } while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); @@ -517,20 +558,24 @@ if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) return -EFAULT; len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len) ) return -EFAULT; + return 0; } -/****** Network Device Interface ********************************************/ +/* + * Network Device Interface + */ -/*============================================================================ - * Initialize Linux network interface. +/* + * Initialize Linux network interface. * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. + * This routine is called only once for each interface, during Linux + * network interface registration. Returning anything but zero will fail + * interface registration. */ + static int if_init (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -546,7 +591,8 @@ dev->get_stats = &if_stats; /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ + dev->type = ARPHRD_X25; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; dev->mtu = X25_CHAN_MTU; dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ @@ -558,25 +604,26 @@ dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_end + wandev->msize - 1; + dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; /* Initialize socket buffers */ - - dev_init_buffers(dev); + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection +/* + * Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection * - * Return 0 if O.k. or errno. + * Return 0 if O.k. or errno. */ + static int if_open (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -600,11 +647,12 @@ return 0; } -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. +/* + * Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. */ + static int if_close (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -612,37 +660,38 @@ if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - + dev->start = 0; if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) chan_disc(dev); - + wanpipe_close(card); /* If this is the last close, disconnect physical link */ if (!card->open_cnt) disconnect(card); - + card->wandev.critical = 0; return 0; } -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. +/* + * Build media header. + * o encapsulate packet according to encapsulation type. * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. + * The trick here is to put packet type (Ethertype) into 'protocol' field + * of the socket buffer, so that we don't forget it. If encapsulation + * fails, set skb->protocol to 0 and discard packet later. * - * Return: media header length. + * Return: media header length. */ + static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; - + skb->protocol = type; if (!chan->protocol) { @@ -656,16 +705,16 @@ return hdr_len; } -/*============================================================================ - * Re-build media header. +/* + * Re-build media header. * - * Return: 1 physical address resolved. - * 0 physical address not resolved + * Return: 1 physical address resolved. + * 0 physical address not resolved */ - + static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; + struct device *dev = skb->dev; x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -674,22 +723,22 @@ return 1; } -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer +/* + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. */ static int if_send (struct sk_buff* skb, struct device* dev) @@ -700,6 +749,7 @@ TX25Status* status = card->flags; unsigned long host_cpu_flags; + if (dev->tbusy) { ++chan->ifstats.rx_dropped; @@ -749,94 +799,95 @@ return dev->tbusy; } - /* Below is only until we have per-channel IPX going.... */ - if(!(chan->svc)) - chan->protocol = skb->protocol; if (card->wandev.state != WAN_CONNECTED) ++chan->ifstats.tx_dropped; - - /* Below is only until we have per-channel IPX going.... */ - else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) + + else if ( chan->protocol && (chan->protocol != skb->protocol)) { printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); + chan->name, skb->protocol, dev->name) + ; + + printk(KERN_INFO "PROTO %Xn", chan->protocol); ++chan->ifstats.tx_errors; } else switch (chan->state) { - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan_connect(dev) != 0) - { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - /* fall through */ + case WAN_DISCONNECTED: + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + if (chan_connect(dev) != 0) + { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + /* fall through */ - case WAN_CONNECTED: - if( skb->protocol == ETH_P_IPX ) - { - if(card->wandev.enable_IPX) - { - switch_net_numbers( skb->data, - card->wandev.network_number, 0); - } - else - { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - goto tx_done; - } - } - dev->trans_start = jiffies; - if(chan_send(dev, skb)) - { - dev->tbusy = 1; - status->imask |= 0x2; + case WAN_CONNECTED: + if( skb->protocol == ETH_P_IPX ) { + if(chan->enable_IPX) { + switch_net_numbers( skb->data, + chan->network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + goto tx_done; } - break; + } + dev->trans_start = jiffies; + if(chan_send(dev, skb)) + { + dev->tbusy = 1; + status->imask |= 0x2; + } + break; - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; } + tx_done: if (!dev->tbusy) + { dev_kfree_skb(skb); - + } card->wandev.critical = 0; save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + return dev->tbusy; } -/*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats +/* + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats* if_stats (struct device* dev) +static struct net_device_stats *if_stats (struct device* dev) { - x25_channel_t* chan = dev->priv; - if(chan==NULL) + x25_channel_t *chan = dev->priv; + + if(chan == NULL) return NULL; + return &chan->ifstats; } -/****** Interrupt Handlers **************************************************/ +/* + * Interrupt Handlers + */ -/*============================================================================ +/* * X.25 Interrupt Service Routine. */ - + static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; @@ -846,8 +897,7 @@ card->in_isr = 1; card->buff_int_mode_unbusy = 0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; @@ -862,27 +912,28 @@ switch (status->iflags) { - case 0x01: /* receive interrupt */ - rx_intr(card); - break; - - case 0x02: /* transmit interrupt */ - tx_intr(card); - card->buff_int_mode_unbusy = 1; - status->imask &= ~0x2; - break; + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + tx_intr(card); + card->buff_int_mode_unbusy = 1; + status->imask &= ~0x2; + break; + + case 0x04: /* modem status interrupt */ + status_intr(card); + break; + + case 0x10: /* network event interrupt */ + event_intr(card); + break; - case 0x04: /* modem status interrupt */ - status_intr(card); - break; - - case 0x10: /* network event interrupt */ - event_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); + default: /* unwanted interrupt */ + spur_intr(card); } + card->wandev.critical = CRITICAL_INTR_HANDLED; if( card->wandev.enable_tx_int) { @@ -909,21 +960,21 @@ } } -/*============================================================================ - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * comming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. */ static void rx_intr (sdla_t* card) @@ -991,7 +1042,7 @@ bufptr = skb_put(skb, len); memcpy(bufptr, rxmb->data, len); - if (qdm & 0x01) + if (qdm & 0x01) return; /* more data is comming */ dev->last_rx = jiffies; /* timestamp */ @@ -1006,9 +1057,9 @@ } else { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) + if( handle_IPXWAN(skb->data, chan->name, chan->enable_IPX, chan->network_number, skb->protocol)) { - if( card->wandev.enable_IPX ) + if( chan->enable_IPX ) { if(chan_send(dev, skb)) { @@ -1021,29 +1072,30 @@ } else { - /* FIXME: increment IPX packet dropped statistic */ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; } } else { + skb->mac.raw = skb->data; netif_rx(skb); ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; } } } -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag +/* + * Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag */ static void tx_intr (sdla_t* card) { struct device *dev; - /* unbusy all devices and then dev_tint(); */ + /* unbusy all devices and then dev_tint() */ for(dev = card->wandev.dev; dev; dev = dev->slave) { ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; @@ -1052,41 +1104,43 @@ } -/*============================================================================ - * Modem status interrupt handler. +/* + * Modem status interrupt handler. */ static void status_intr (sdla_t* card) { } -/*============================================================================ - * Network event interrupt handler. +/* + * Network event interrupt handler. */ static void event_intr (sdla_t* card) { } -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? +/* + * Spurious interrupt handler. + * o print a warning + * o */ + static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/****** Background Polling Routines ****************************************/ +/* + * Background Polling Routines + */ -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. +/* + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! */ static void wpx_poll (sdla_t* card) @@ -1096,15 +1150,17 @@ disable_irq(card->hw.irq); ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "%s: critical in polling!\n",card->devname); + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: critical in polling!\n",card->devname); + save_flags(host_cpu_flags); cli(); if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + return; } @@ -1121,18 +1177,22 @@ case WAN_DISCONNECTED: poll_disconnected(card); } + card->wandev.critical = 0; + save_flags(host_cpu_flags); cli(); if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + } -/*============================================================================ - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. +/* + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. */ + static void poll_connecting (sdla_t* card) { TX25Status* status = card->flags; @@ -1147,22 +1207,24 @@ disconnect(card); } -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. +/* + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. */ + static void poll_disconnected (sdla_t* card) { if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) connect(card); } -/*============================================================================ - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. +/* + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. */ + static void poll_active (sdla_t* card) { struct device* dev; @@ -1202,20 +1264,22 @@ } } -/****** SDLA Firmware-Specific Functions ************************************* - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be dealt with - * immediately. To tackle with this problem we execute each interface command - * in a loop until good return code is received or maximum number of retries - * is reached. Each interface command returns non-zero return code, an - * asynchronous event/error handler x25_error() is called. +/* + * SDLA Firmware-Specific Functions + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. */ -/*============================================================================ - * Read X.25 firmware version. - * Put code version as ASCII string in str. +/* + * Read X.25 firmware version. + * Put code version as ASCII string in str. */ + static int x25_get_version (sdla_t* card, char* str) { TX25Mbox* mbox = card->mbox; @@ -1233,14 +1297,15 @@ if (!err && str) { int len = mbox->cmd.length; + memcpy(str, mbox->data, len); str[len] = '\0'; } return err; } -/*============================================================================ - * Configure adapter. +/* + * Configure adapter. */ static int x25_configure (sdla_t* card, TX25Config* conf) @@ -1275,7 +1340,7 @@ mbox->cmd.command = X25_HDLC_READ_COMM_ERR; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - + if (!err) { THdlcCommErr* stats = (void*)mbox->data; @@ -1288,9 +1353,10 @@ return err; } -/*============================================================================ - * Get protocol statistics. +/* + * Get protocol statistics. */ + static int x25_get_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1302,7 +1368,7 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; if (!err) { @@ -1314,9 +1380,10 @@ return err; } -/*============================================================================ - * Close HDLC link. +/* + * Close HDLC link. */ + static int x25_close_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1329,13 +1396,14 @@ mbox->cmd.command = X25_HDLC_LINK_CLOSE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - + return err; } -/*============================================================================ - * Open HDLC link. +/* + * Open HDLC link. */ + static int x25_open_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1348,7 +1416,7 @@ mbox->cmd.command = X25_HDLC_LINK_OPEN; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - + return err; } @@ -1371,9 +1439,10 @@ return err; } -/*============================================================================ - * Set (raise/drop) DTR. +/* + * Set (raise/drop) DTR. */ + static int x25_set_dtr (sdla_t* card, int dtr) { TX25Mbox* mbox = card->mbox; @@ -1390,13 +1459,14 @@ mbox->cmd.command = X25_SET_GLOBAL_VARS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - + return err; } -/*============================================================================ - * Set interrupt mode. +/* + * Set interrupt mode. */ + static int x25_set_intr_mode (sdla_t* card, int mode) { TX25Mbox* mbox = card->mbox; @@ -1415,13 +1485,15 @@ else mbox->cmd.length = 1; mbox->cmd.command = X25_SET_INTERRUPT_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); + return err; } -/*============================================================================ - * Read X.25 channel configuration. +/* + * Read X.25 channel configuration. */ + static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) { TX25Mbox* mbox = card->mbox; @@ -1450,11 +1522,11 @@ switch (mbox->data[0] && 0x1F) { - case 0x01: + case 0x01: offset = status->pvc_map; break; - case 0x03: + case 0x03: offset = status->icc_map; break; - case 0x07: + case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; @@ -1467,26 +1539,26 @@ /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { - case 0x00: - chan->tx_pkt_size = 16; + case 0x00: + chan->tx_pkt_size = 16; break; - case 0x08: - chan->tx_pkt_size = 32; + case 0x08: + chan->tx_pkt_size = 32; break; - case 0x10: - chan->tx_pkt_size = 64; + case 0x10: + chan->tx_pkt_size = 64; break; - case 0x18: - chan->tx_pkt_size = 128; + case 0x18: + chan->tx_pkt_size = 128; break; - case 0x20: - chan->tx_pkt_size = 256; + case 0x20: + chan->tx_pkt_size = 256; break; - case 0x28: - chan->tx_pkt_size = 512; + case 0x28: + chan->tx_pkt_size = 512; break; - case 0x30: - chan->tx_pkt_size = 1024; + case 0x30: + chan->tx_pkt_size = 1024; break; } printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", @@ -1495,8 +1567,8 @@ return err; } -/*============================================================================ - * Place X.25 call. +/* + * Place X.25 call. */ static int x25_place_call (sdla_t* card, x25_channel_t* chan) @@ -1506,7 +1578,11 @@ int err; char str[64]; - sprintf(str, "-d%s -uCC", chan->addr); + + if (chan->protocol == ETH_P_IP) + sprintf(str, "-d%s -uCC", chan->addr); + if (chan->protocol == ETH_P_IPX) + sprintf(str, "-d%s -u800000008137", chan->addr); do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); @@ -1519,13 +1595,12 @@ if (!err) { chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; } return err; } -/*============================================================================ - * Accept X.25 call. +/* + * Accept X.25 call. */ static int x25_accept_call (sdla_t* card, int lcn, int qdm) @@ -1542,13 +1617,14 @@ mbox->cmd.command = X25_ACCEPT_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - + return err; } -/*============================================================================ - * Clear X.25 call. +/* + * Clear X.25 call. */ + static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) { TX25Mbox* mbox = card->mbox; @@ -1564,13 +1640,14 @@ mbox->cmd.command = X25_CLEAR_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - + return err; } -/*============================================================================ - * Send X.25 data packet. +/* + * Send X.25 data packet. */ + static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) { TX25Mbox* mbox = card->mbox; @@ -1590,9 +1667,10 @@ return err; } -/*============================================================================ - * Fetch X.25 asynchronous events. +/* + * Fetch X.25 asynchronous events. */ + static int x25_fetch_events (sdla_t* card) { TX25Status* status = card->flags; @@ -1604,25 +1682,26 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_IS_DATA_AVAILABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); } return err; } -/*============================================================================ - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns non-zero - * return code to handle X.25 asynchronous events and common errors. - * Return non-zero to repeat command or zero to cancel it. +/* + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. */ + static int x25_error (sdla_t* card, int err, int cmd, int lcn) { int retry = 1; @@ -1639,106 +1718,116 @@ memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); switch (err) { - case 0x40: /* X.25 asynchronous packet was received */ - mb->data[dlen] = '\0'; - switch (mb->cmd.pktType & 0x7F) - { - case 0x30: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case 0x31: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case 0x02: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case 0x04: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - break; - - case 0x08: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } + case 0x40: /* X.25 asynchronous packet was received */ + mb->data[dlen] = '\0'; + switch (mb->cmd.pktType & 0x7F) + { + case 0x30: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); break; - case 0x41: /* X.25 protocol violation indication */ - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + case 0x31: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); break; - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); + case 0x02: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); break; - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); + case 0x04: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn) + ; break; - case 0x08: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); + case 0x08: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - break; + default: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn) + ; + } + break; - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - break; + case 0x41: /* X.25 protocol violation indication */ + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn) + ; + break; - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ - break; + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) + ; + break; + + case 0x08: /* modem failure */ + printk(KERN_INFO "%s: modem failure!\n", card->devname); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname) + ; + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]) + ; + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + retry = 0; /* abort command */ + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err) + ; + retry = 0; /* abort command */ } kfree(mb); return retry; } -/****** X.25 Asynchronous Event Handlers ************************************* - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. +/* + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. */ -/*============================================================================ - * Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation. - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when - * clearing a call because protocol encapsulation is not supported. - * 4. If an incoming call is received while a call request is pending - * (i.e. call collision has occurred), the incoming call shall be - * rejected and call request shall be retried. +/* + * Handle X.25 incoming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. */ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1749,13 +1838,14 @@ x25_channel_t* chan = NULL; int accept = 0; /* set to '1' if o.k. to accept call */ x25_call_info_t* info; - + /* Make sure there is no call collision */ if (dev != NULL) { printk(KERN_INFO "%s: X.25 incoming call collision on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } @@ -1766,6 +1856,7 @@ printk(KERN_INFO "%s: X.25 incoming call on LCN %d with D-bit set!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } @@ -1780,7 +1871,9 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + parse_call_info(mb->data, info); + printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", card->devname, new_lcn, mb->data); @@ -1790,18 +1883,31 @@ chan = dev->priv; if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + continue + ; + if (info->user[0] == NLPID_IP && chan->protocol != ETH_P_IP){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", chan->protocol, info->user[0]); + continue; + } + + if (info->user[0] == NLPID_SNAP && chan->protocol != ETH_P_IPX){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", chan->protocol); continue; + } if (strcmp(info->src, chan->addr) == 0) - break; + break + ; /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) - break; + break + ; } if (dev == NULL) { printk(KERN_INFO "%s: no channels available!\n", - card->devname); + card->devname) + ; x25_clear_call(card, new_lcn, 0, 0); } @@ -1810,7 +1916,8 @@ { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); + card->devname, new_lcn) + ; x25_clear_call(card, new_lcn, 0, 0); } else switch (info->user[0]) @@ -1821,35 +1928,34 @@ break; case NLPID_IP: /* IP datagrams */ - chan->protocol = ETH_P_IP; accept = 1; break; case NLPID_SNAP: /* IPX datagrams */ - chan->protocol = ETH_P_IPX; accept = 1; break; + default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incoming call " "on LCN %d!\n", card->devname, info->user[0], new_lcn); x25_clear_call(card, new_lcn, 0, 249); } - + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) { chan->lcn = new_lcn; if (x25_get_chan_conf(card, chan) == CMD_OK) set_chan_state(dev, WAN_CONNECTED); - else + else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1; } -/*============================================================================ - * Handle accepted call. +/* + * Handle accepted call. */ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1880,8 +1986,8 @@ return 1; } -/*============================================================================ - * Handle cleared call. +/* + * Handle cleared call. */ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1892,16 +1998,19 @@ printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " "Diagn:0x%02X\n", card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - if (dev == NULL) + + if (dev == NULL) return 1; + set_chan_state(dev, WAN_DISCONNECTED); + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; } -/*============================================================================ - * Handle X.25 restart event. +/* + * Handle X.25 restart event. */ - + static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; @@ -1914,12 +2023,14 @@ /* down all logical channels */ for (dev = wandev->dev; dev; dev = dev->slave) set_chan_state(dev, WAN_DISCONNECTED); + return (cmd == X25_WRITE) ? 0 : 1; } -/*============================================================================ +/* * Handle timeout event. */ + static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; @@ -1930,7 +2041,8 @@ printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); - if (dev) + + if (dev) set_chan_state(dev, WAN_DISCONNECTED); } else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", @@ -1938,32 +2050,37 @@ return 1; } -/******* Miscellaneous ******************************************************/ +/* + * Miscellaneous + */ -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR +/* + * Establish physical connection. + * o open HDLC and raise DTR * - * Return: 0 connection established - * 1 connection is in progress - * <0 error + * Return: 0 connection established + * 1 connection is in progress + * <0 error */ + static int connect (sdla_t* card) { if (x25_open_hdlc(card) || x25_setup_hdlc(card)) return -EIO; + wanpipe_set_state(card, WAN_CONNECTING); return 1; } -/*============================================================================ - * Tear down physical connection. - * o close HDLC link - * o drop DTR +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR * - * Return: 0 - * <0 error + * Return: 0 + * <0 error */ + static int disconnect (sdla_t* card) { wanpipe_set_state(card, WAN_DISCONNECTED); @@ -1973,28 +2090,30 @@ return 0; } -/*============================================================================ +/* * Find network device by its channel number. */ + static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { struct device* dev; for (dev = wandev->dev; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) + if (((x25_channel_t*)dev->priv)->lcn == lcn) break; return dev; } -/*============================================================================ - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call +/* + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call * - * Return: 0 connected - * >0 connection in progress - * <0 failure + * Return: 0 connected + * >0 connection in progress + * <0 failure */ + static int chan_connect (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -2004,10 +2123,13 @@ { if (!chan->addr[0]) return -EINVAL; /* no destination address */ + printk(KERN_INFO "%s: placing X.25 call to %s ...\n", card->devname, chan->addr); + if (x25_place_call(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTING); return 1; } @@ -2015,28 +2137,31 @@ { if (x25_get_chan_conf(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTED); } return 0; } -/*============================================================================ - * Disconnect logical channel. - * o if SVC then clear X.25 call +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call */ + static int chan_disc (struct device* dev) { x25_channel_t* chan = dev->priv; - if (chan->svc) + if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Set logical channel state. +/* + * Set logical channel state. */ + static void set_chan_state (struct device* dev, int state) { x25_channel_t* chan = dev->priv; @@ -2050,22 +2175,18 @@ switch (state) { case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); + printk (KERN_INFO "%s: interface %s connected!\n", card->devname, dev->name); *(unsigned short*)dev->dev_addr = htons(chan->lcn); chan->i_timeout_sofar = jiffies; break; case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); + printk (KERN_INFO "%s: interface %s connecting...\n", card->devname, dev->name); break; case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - if (chan->svc) - { + printk (KERN_INFO "%s: interface %s disconnected!\n", card->devname, dev->name); + if (chan->svc) { *(unsigned short*)dev->dev_addr = 0; chan->lcn = 0; } @@ -2077,21 +2198,22 @@ restore_flags(flags); } -/*============================================================================ - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. * - * Return: 0 - transmission complete - * 1 - busy + * Return: 0 - transmission complete + * 1 - busy * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. */ + static int chan_send (struct device* dev, struct sk_buff* skb) { x25_channel_t* chan = dev->priv; @@ -2123,7 +2245,6 @@ return 1; } ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ @@ -2131,13 +2252,12 @@ default: /* failure */ ++chan->ifstats.tx_errors; -/* return 1; */ } return 0; } -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. +/* + * Parse X.25 call request data and fill x25_call_info_t structure. */ static void parse_call_info (unsigned char* str, x25_call_info_t* info) @@ -2154,18 +2274,16 @@ for (i = 0; i < 16; ++i) { ch = str[2+i]; - if (!is_digit(ch)) - break; + if (!is_digit(ch)) break; info->dest[i] = ch; } break; - + case 's': /* source address */ for (i = 0; i < 16; ++i) { ch = str[2+i]; - if (!is_digit(ch)) - break; + if (!is_digit(ch)) break; info->src[i] = ch; } break; @@ -2185,15 +2303,13 @@ for (i = 0; i < 64; ++i) { ch = str[2+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); + info->facil[i].code = hex_to_uint(&str[2+4*i], 2); ch = str[4+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); + info->facil[i].parm = hex_to_uint(&str[4+4*i], 2); } info->nfacil = i; break; @@ -2201,14 +2317,15 @@ } } -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. +/* + * Convert line speed in bps to a number used by S502 code. */ + static unsigned char bps_to_speed_code (unsigned long bps) { unsigned char number; - if (bps <= 1200) number = 0x01 ; + if (bps <= 1200) number = 0x01; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; @@ -2225,29 +2342,36 @@ return number; } -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. +/* + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. */ + static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); + return val; } -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. +/* + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. */ + static unsigned int hex_to_uint (unsigned char* str, int len) { unsigned val, ch; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len; ++str, --len) { ch = *str; @@ -2255,8 +2379,7 @@ val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; + else break; } return val; } @@ -2273,14 +2396,14 @@ return 1; } } else { - /* It's not IPX so pass it up the stack. */ + /* It's not IPX so pass it up the stack.*/ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { - /* It's IPXWAN */ + /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) @@ -2289,19 +2412,24 @@ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP */ + * option except Unnumbered RIP/SAP + */ for(i = 41; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; + } } /* Skip over the extended Node ID option */ if( sendpacket[i] == 0x04 ) + { i += 8; + } - /* We also want to turn off all header compression opt. */ + /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; @@ -2338,7 +2466,9 @@ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; + } printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } @@ -2356,18 +2486,18 @@ return 1; } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ switch_net_numbers(sendpacket, network_number, 1); return 0; } } /* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { @@ -2376,21 +2506,17 @@ pnetwork_number = (unsigned long)((sendpacket[6] << 24) + (sendpacket[7] << 16) + (sendpacket[8] << 8) + sendpacket[9]); + - if (!incoming) - { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { sendpacket[6] = sendpacket[7] = sendpacket[8] = sendpacket[9] = 0x00; } - } - else - { + } else { /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { + if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2405,21 +2531,17 @@ pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); - - if( !incoming ) - { + + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = sendpacket[21] = 0x00; } - } - else - { + } else { /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { + if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdladrv.c linux.ac/drivers/net/sdladrv.c --- linux.vanilla/drivers/net/sdladrv.c Sat Jan 9 21:50:42 1999 +++ linux.ac/drivers/net/sdladrv.c Thu Mar 11 13:06:36 1999 @@ -13,6 +13,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels * Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. * Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. * Jun 12, 1996 Gene Kozin Added support for S503 card. @@ -179,7 +180,7 @@ /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static unsigned exec_idle; /* Hardware configuration options. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdlamain.c linux.ac/drivers/net/sdlamain.c --- linux.vanilla/drivers/net/sdlamain.c Mon Dec 28 23:09:43 1998 +++ linux.ac/drivers/net/sdlamain.c Thu Mar 11 13:07:55 1999 @@ -11,6 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel * Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 * Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); * Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 @@ -52,8 +53,8 @@ #define STATIC static #endif -#define DRV_VERSION 4 /* version number */ -#define DRV_RELEASE 1 /* release (minor version) number */ +#define DRV_VERSION 5 /* version number */ +#define DRV_RELEASE 0 /* release (minor version) number */ #define MAX_CARDS 8 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ @@ -90,7 +91,7 @@ /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static int ncards = CONFIG_WANPIPE_CARDS; static int active = 0; /* number of active cards */ static sdla_t* card_array = NULL; /* adapter data space */ @@ -322,6 +323,24 @@ break; #endif +#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: + err = wpc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_BSTRM + case SFID_BSC502: + err = bsc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_HDLC + case SFID_HDLC508: + err = hdlc_init(card, conf); + break; +#endif + default: printk(KERN_ERR "%s: this firmware is not supported!\n", wandev->name) @@ -335,9 +354,7 @@ return err; } /* Reserve I/O region and schedule background task */ -/* printk(KERN_INFO "about to request\n");*/ request_region(card->hw.port, card->hw.io_range, wandev->name); -/* printk(KERN_INFO "request done\n");*/ if (++active == 1) queue_task(&sdla_tq, &tq_scheduler); @@ -374,17 +391,10 @@ if (--active == 0) schedule(); /* stop background thread */ -/* printk(KERN_INFO "active now %d\n", active); - printk(KERN_INFO "About to call sdla_down\n");*/ sdla_down(&card->hw); -/* printk(KERN_INFO "sdla_down done\n"); - printk(KERN_INFO "About to call free_irq\n");*/ free_irq(wandev->irq, card); -/* printk(KERN_INFO "free_irq done\n"); - printk(KERN_INFO "About to call release_region\n");*/ release_region(card->hw.port, card->hw.io_range); -/* printk(KERN_INFO "release_region done\n");*/ wandev->critical = 0; return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sealevel.c linux.ac/drivers/net/sealevel.c --- linux.vanilla/drivers/net/sealevel.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sealevel.c Thu Feb 18 19:10:37 1999 @@ -0,0 +1,471 @@ +#define LINUX_21 + +/* + * Sealevel Systems 4021 driver. + * + * 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. + * + * (c) Copyright 1999 Building Number Three Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + + +struct slvl_device +{ + struct z8530_channel *chan; + struct ppp_device netdev; + char name[16]; + int channel; +}; + + +struct slvl_board +{ + struct slvl_device dev[2]; + struct z8530_dev board; + int iobase; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int sealevel_open(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int err = -1; + int unit = slvl->channel; + + /* + * Link layer up. + */ + + switch(unit) + { + case 0: + err=z8530_sync_dma_open(d, slvl->chan); + break; + case 1: + err=z8530_sync_open(d, slvl->chan); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + return err; + } + + slvl->chan->rx_function=sealevel_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int sealevel_close(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int unit = slvl->channel; + + /* + * Discard new frames + */ + + slvl->chan->rx_function=z8530_null_rx; + + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd) +{ + /* struct slvl_device *slvl=d->priv; + z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *sealevel_get_stats(struct device *d) +{ + struct slvl_device *slvl=d->priv; + if(slvl) + return z8530_get_stats(slvl->chan); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d) +{ + struct slvl_device *slvl=d->priv; + return z8530_queue_xmit(slvl->chan, skb); +} + +#ifdef LINUX_21 +static int sealevel_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = sealevel_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) +{ + struct z8530_dev *dev; + struct slvl_device *sv; + struct slvl_board *b; + + int i; + unsigned long flags; + int u; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Sealevel 4021"); + + b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); + if(!b) + goto fail3; + + memset(b, 0, sizeof(*sv)); + + b->dev[0].chan = &b->board.chanA; + b->dev[1].chan = &b->board.chanB; + + dev=&b->board; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + b->iobase = iobase; + + /* + * Select 8530 delays for the old board + */ + + if(slow) + iobase |= Z8530_PORT_SLEEP; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase; + dev->chanB.ctrlio=iobase+3; + dev->chanB.dataio=iobase+2; + + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + /* + * Assert DTR enable DMA + */ + + outb(3|(1<<7), b->iobase+4); + + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) + { + printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=&b->dev[0]; + dev->chanB.private=&b->dev[1]; + dev->chanA.netdevice=&b->dev[0].netdev.dev; + dev->chanB.netdevice=&b->dev[1].netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=b->dev[0].name; + + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) + goto fail; + + if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) + goto dmafail; + + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + if(dev->type==Z85C30) + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); + } + else + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); + } + + /* + * Now we can take the IRQ + */ + + restore_flags(flags); + + for(u=0; u<2; u++) + { + sv=&b->dev[u]; + sv->channel = u; + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==NULL) + { + struct device *d=sv->chan->netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = sealevel_open; + d->stop = sealevel_close; + d->hard_start_xmit = sealevel_queue_xmit; + d->get_stats = sealevel_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = sealevel_ioctl; +#ifdef LINUX_21 + d->neigh_setup = sealevel_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail_unit; + } + + break; + } + } + } + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return b; + +fail_unit: + if(u==1) + unregister_netdev(b->dev[0].chan->netdevice); + +dmafail2: + free_dma(dev->chanA.rxdma); +dmafail: + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(b); +fail3: + release_region(iobase,8); + return NULL; +} + +static void slvl_shutdown(struct slvl_board *b) +{ + int u; + + z8530_shutdown(&b->board); + + for(u=0; u<2; u++) + { + sppp_detach(&b->dev[u].netdev.dev); + unregister_netdev(&b->dev[u].netdev.dev); + } + + free_irq(b->board.irq, &b->board); + free_dma(b->board.chanA.rxdma); + free_dma(b->board.chanA.txdma); + /* DMA off on the card, drop DTR */ + outb(0, b->iobase); + release_region(b->iobase, 8); +} + +#ifdef MODULE + +static int io=0x238; +static int txdma=1; +static int rxdma=3; +static int irq=5; +static int slow=0; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); +MODULE_PARM(txdma,"i"); +MODULE_PARM_DESC(txdma, "Transmit DMA channel"); +MODULE_PARM(rxdma,"i"); +MODULE_PARM_DESC(rxdma, "Receive DMA channel"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); +MODULE_PARM(slow,"i"); +MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); +#endif + +static struct slvl_board *slvl_unit; + +int init_module(void) +{ + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(slvl_unit) + slvl_shutdown(slvl_unit); +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/oldproc.c linux.ac/drivers/pci/oldproc.c --- linux.vanilla/drivers/pci/oldproc.c Wed Mar 24 10:55:20 1999 +++ linux.ac/drivers/pci/oldproc.c Sat Mar 20 23:01:46 1999 @@ -300,6 +300,8 @@ DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), @@ -453,6 +455,7 @@ DEVICE( SATSAGEM, SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"), DEVICE( HUGHES, HUGHES_DIRECPC, "DirecPC"), DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), + DEVICE( ENSONIQ, ENSONIQ_ES1371, "ES1371"), DEVICE( ALTEON, ALTEON_ACENIC, "AceNIC"), DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), DEVICE( NVIDIA_SGS, NVIDIA_SGS_RIVA128, "Riva 128"), @@ -544,6 +547,7 @@ DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"), DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"), DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"), + DEVICE( ADAPTEC2, ADAPTEC2_2930U2,"AHA-2930U2"), DEVICE( ADAPTEC2, ADAPTEC2_78902, "AIC-7890/1"), DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"), DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"), diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/sbus.c linux.ac/drivers/sbus/sbus.c --- linux.vanilla/drivers/sbus/sbus.c Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/sbus/sbus.c Sat Mar 20 23:02:01 1999 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7,8xx.c linux.ac/drivers/scsi/53c7,8xx.c --- linux.vanilla/drivers/scsi/53c7,8xx.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/53c7,8xx.c Sun Nov 8 14:35:40 1998 @@ -1901,7 +1901,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies,timeout)) barrier(); failed = 1; @@ -1986,7 +1987,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7xx.c linux.ac/drivers/scsi/53c7xx.c --- linux.vanilla/drivers/scsi/53c7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/53c7xx.c Thu Dec 17 01:56:08 1998 @@ -298,6 +298,10 @@ */ #undef inb #undef outb +#undef inw +#undef outw +#undef inl +#undef outl #define inb(x) 1 #define inw(x) 1 #define inl(x) 1 @@ -1612,7 +1616,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); failed = 1; @@ -1698,7 +1703,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); @@ -1899,7 +1905,7 @@ if (left < 0) printk("scsi%d: loop detected in ncr reconncect list\n", host->host_no); - else if (ncr_search) + else if (ncr_search) { if (found) printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n", host->host_no, c->pid); @@ -1910,6 +1916,7 @@ /* If we're at the tail end of the issue queue, update that pointer too. */ found = 1; } + } /* * Traverse the host running list until we find this command or discover @@ -2960,14 +2967,14 @@ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM); else NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl); -#if 0 - /* Following disables snooping - run with caches disabled at first */ + /* Following disables snooping - snooping is not required, as non- + * cached pages are used for shared data, and appropriate use is + * made of cache_push/cache_clear. Indeed, for 68060 + * enabling snooping causes disk corruption of ext2fs free block + * bitmaps and the like. If you have a 68060 with snooping hardwared + * on, then you need to enable CONFIG_060_WRITETHROUGH. + */ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD); -#else - /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating - * cache lines. */ - NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0); -#endif /* Actually burst of eight, according to my 53c710 databook */ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2); NCR53c7x0_write8(SCID_REG, 1 << host->this_id); @@ -5947,11 +5954,12 @@ } } } - if (!(istat & (ISTAT_SIP|ISTAT_DIP))) + if (!(istat & (ISTAT_SIP|ISTAT_DIP))) { if (stage == 0) ++stage; else if (stage == 3) break; + } } hostdata->state = STATE_HALTED; restore_flags(flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/Config.in linux.ac/drivers/scsi/Config.in --- linux.vanilla/drivers/scsi/Config.in Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/scsi/Config.in Mon Mar 1 00:28:38 1999 @@ -25,10 +25,8 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N - if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then - int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24 - fi + bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/README.aic7xxx linux.ac/drivers/scsi/README.aic7xxx --- linux.vanilla/drivers/scsi/README.aic7xxx Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/scsi/README.aic7xxx Mon Mar 1 00:28:48 1999 @@ -17,6 +17,10 @@ AHA-274xT AHA-2842 AHA-2910B + AHA-2920C + AHA-2930 + AHA-2930U + AHA-2930U2 AHA-2940 AHA-2940W AHA-2940U @@ -77,8 +81,8 @@ Adaptec Cards ---------------------------- AHA-2920 (Only the cards that use the Future Domain chipset are not - supported, any 2920 cards based on Adaptec AIC chipsets are - supported) + supported, any 2920 cards based on Adaptec AIC chipsets, + such as the 2920C, are supported) AAA-13x Raid Adapters AAA-113x Raid Port Card @@ -108,7 +112,7 @@ Jess Johnson jester@frenzy.com (AIC7xxx FAQ author) Doug Ledford dledford@redhat.com - (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer) + (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original author of the driver. John has since retired from the project. Thanks @@ -325,11 +329,12 @@ list and someone can help you out. "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable - tagged queueing on specific devices. As of driver version 5.1.8, we - now globally enable tagged queueing by default. In order to - disable tagged queueing for certian devices at boot time, a user may - use this boot param. The driver will then parse this message out - and disable the specific device entries that are present based upon + or enable Tagged Command Queueing (TCQ) on specific devices. As of + driver version 5.1.11, TCQ is now either on or off by default + according to the setting you choose during the make config process. + In order to en/disable TCQ for certian devices at boot time, a user + may use this boot param. The driver will then parse this message out + and en/disable the specific device entries that are present based upon the value given. The param line is parsed in the following manner: { - first instance indicates the start of this parameter values @@ -419,10 +424,10 @@ see this documentation, you need to use one of the advanced configuration programs (menuconfig and xconfig). If you are using the "make menuconfig" method of configuring your kernel, then you would simply highlight the - option in question and hit the F1 key. If you are using the "make xconfig" - method of configuring your kernel, then simply click on the help button next - to the option you have questions about. The help information from the - Configure.help file will then get automatically displayed. + option in question and hit the ? key. If you are using the "make xconfig" + method of configuring your kernel, then simply click on the help button + next to the option you have questions about. The help information from + the Configure.help file will then get automatically displayed. /proc support ------------------------------ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx.c linux.ac/drivers/scsi/aic7xxx.c --- linux.vanilla/drivers/scsi/aic7xxx.c Tue Jan 19 02:57:30 1999 +++ linux.ac/drivers/scsi/aic7xxx.c Mon Mar 1 00:32:08 1999 @@ -354,7 +354,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.10" +#define AIC7XXX_C_VERSION "5.1.12" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -447,10 +447,10 @@ * You can try raising me if tagged queueing is enabled, or lowering * me if you only have 4 SCBs. */ -#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN -#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE #else -#define AIC7XXX_CMDS_PER_LUN 24 +#define AIC7XXX_CMDS_PER_DEVICE 8 #endif /* Set this to the delay in seconds after SCSI bus reset. */ @@ -495,7 +495,7 @@ * * *** Determining commands per LUN *** * - * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its + * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its * own algorithm to determine the commands/LUN. If SCB paging is * enabled, which is always now, the default is 8 commands per lun * that indicates it supports tagged queueing. All non-tagged devices @@ -513,8 +513,13 @@ * Make a define that will tell the driver not to use tagged queueing * by default. */ +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT +#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, 0, 0, 0} +#else #define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\ 255, 255, 255, 255, 255, 255, 255, 255} +#endif /* * Modify this as you see fit for your system. By setting tag_commands @@ -553,6 +558,27 @@ }; */ +static adapter_tag_info_t aic7xxx_tag_info[] = +{ + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS} +}; + + /* * Define an array of board names that can be indexed by aha_type. * Don't forget to change this when changing the types! @@ -579,6 +605,7 @@ "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ + "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ @@ -1410,35 +1437,6 @@ #endif -/* - * See the comments earlier in the file for what this item is all about - * If you have more than 4 controllers, you will need to increase the - * the number of items in the array below. Additionally, if you don't - * want to have lilo pass a humongous config line to the aic7xxx driver, - * then you can get in and manually adjust these instead of leaving them - * at the default. Pay attention to the comments earlier in this file - * concerning this array if you are going to hand modify these values. - */ -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS} -}; - #define VERBOSE_NORMAL 0x0000 #define VERBOSE_NEGOTIATION 0x0001 #define VERBOSE_SEQINT 0x0002 @@ -2796,6 +2794,7 @@ Scsi_Cmnd *cmd; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned int cpu_flags = 0; +#endif DRIVER_LOCK while (p->completeq.head != NULL) @@ -2803,20 +2802,9 @@ cmd = p->completeq.head; p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; cmd->host_scribble = NULL; - sti(); cmd->scsi_done(cmd); - cli(); } DRIVER_UNLOCK -#else - while (p->completeq.head != NULL) - { - cmd = p->completeq.head; - p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } -#endif } /*+F************************************************************************* @@ -3625,7 +3613,7 @@ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) printk(INFO_LEAD "Cleaning disconnected scbs " "list.\n", p->host_no, channel, target, lun); - if (p->features & AHC_PAGESCBS) + if (p->flags & AHC_PAGESCBS) { unsigned char next, prev, scb_index; @@ -3677,7 +3665,7 @@ * Walk the free list making sure no entries on the free list have * a valid SCB_TAG value or SCB_CONTROL byte. */ - if (p->features & AHC_PAGESCBS) + if (p->flags & AHC_PAGESCBS) { unsigned char next; @@ -6368,7 +6356,7 @@ * Determines the queue depth for a given device. There are two ways * a queue depth can be obtained for a tagged queueing device. One * way is the default queue depth which is determined by whether - * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used + * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used * as the default queue depth. Otherwise, we use either 4 or 8 as the * default queue depth (dependent on the number of hardware SCBs). * The other way we determine queue depth is through the use of the @@ -6396,7 +6384,7 @@ { int tag_enabled = TRUE; - default_depth = AIC7XXX_CMDS_PER_LUN; + default_depth = AIC7XXX_CMDS_PER_DEVICE; if (!(p->discenable & target_mask)) { @@ -7840,6 +7828,11 @@ */ aic7xxx_loadseq(p); + /* + * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register + */ + aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) { aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ @@ -8184,14 +8177,16 @@ { printk("aic7xxx: Using leftover BIOS values.\n"); } - if ( *sxfrctl1 & STPWEN ) + if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) { p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; sc->adapter_control &= ~CFAUTOTERM; sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; } if (aic7xxx_extended) - p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B; + p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); + else + p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); } else { @@ -8279,7 +8274,7 @@ mask = (0x01 << i); if (!have_seeprom) { - if(aic_inb(p, SCSISEQ) != 0) + if (aic_inb(p, SCSISEQ) != 0) { /* * OK...the BIOS set things up and left behind the settings we need. @@ -8339,20 +8334,30 @@ } if (p->flags & AHC_NEWEEPROM_FMT) { - if (sc->device_flags[i] & CFSYNCHISULTRA) - { - p->ultraenb |= mask; - } - else if (sc->device_flags[i] & CFNEWULTRAFORMAT) + if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && + !(p->features & AHC_ULTRA2) ) { - if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) && - !(p->features & AHC_ULTRA2) ) + /* + * I know of two different Ultra BIOSes that do this differently. + * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to + * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s + * while on the IBM Netfinity 5000 they want the same thing + * to be something else, while flags[i] & CFXFER == 0x03 and + * SYNCISULTRA false should be 40MByte/s. So, we set both to + * 40MByte/s and the lower speeds be damned. People will have + * to select around the conversely mapped lower speeds in order + * to select lower speeds on these boards. + */ + if ((sc->device_flags[i] & (CFXFER)) == 0x03) { sc->device_flags[i] &= ~CFXFER; sc->device_flags[i] |= CFSYNCHISULTRA; - p->ultraenb |= mask; } } + if (sc->device_flags[i] & CFSYNCHISULTRA) + { + p->ultraenb |= mask; + } } else if (sc->adapter_control & CFULTRAEN) { @@ -8837,25 +8842,29 @@ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7890_FE, 20, 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7890_FE, 21, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 22, + 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 22, + AHC_AIC7896_FE, 23, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 23, + AHC_AIC7896_FE, 24, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, + AHC_AIC7896_FE, 25, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 25, + AHC_AIC7860_FE, 26, 32, C46 }, }; @@ -9212,48 +9221,23 @@ aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | CACHETHEN | MPARCKEN | USCBSIZE32 | CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); - /* FALLTHROUGH */ - default: - /* - * We attempt to read a SEEPROM on *everything*. If we fail, - * then we fail, but this covers things like 2910c cards that - * now have SEEPROMs with their 7856 chipset that we would - * otherwise ignore. They still don't have a BIOS, but they - * have a SEEPROM that the SCSISelect utility on the Adaptec - * diskettes can configure. - */ aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; - case AHC_AIC7850: - case AHC_AIC7860: + default: /* * Set the DSCOMMAND0 register on these cards different from * on the 789x cards. Also, read the SEEPROM as well. - */ aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | CACHETHEN | MPARCKEN) & ~DPARCKEN, DSCOMMAND0); aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; - case AHC_AIC7880: - /* - * Only set the DSCOMMAND0 register if this is a Rev B. - * chipset. For those, we also enable Ultra mode by - * force due to brain-damage on the part of some BIOSes - * We overload the devconfig variable here since we can. + case AHC_AIC7870: + case AHC_AIC7895: */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); -#else - pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, - &devconfig); -#endif - if ((devconfig & 0xff) >= 1) - { - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - } + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + MPARCKEN) & ~(DPARCKEN | CACHETHEN), + DSCOMMAND0); aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; } @@ -11034,16 +11018,21 @@ int aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) { - int heads, sectors, cylinders; + int heads, sectors, cylinders, ret; struct aic7xxx_host *p; + struct buffer_head *bh; p = (struct aic7xxx_host *) disk->device->host->hostdata; + bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024); - /* - * XXX - if I could portably find the card's configuration - * information, then this could be autodetected instead - * of left to a boot-time switch. - */ + if ( bh ) + { + ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]); + brelse(bh); + if ( ret != -1 ) + return(ret); + } + heads = 64; sectors = 32; cylinders = disk->capacity / (heads * sectors); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_proc.c linux.ac/drivers/scsi/aic7xxx_proc.c --- linux.vanilla/drivers/scsi/aic7xxx_proc.c Wed Jan 6 23:02:23 1999 +++ linux.ac/drivers/scsi/aic7xxx_proc.c Sun Mar 7 17:07:40 1999 @@ -29,6 +29,8 @@ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ *-M*************************************************************************/ +#include + #define BLS (&aic7xxx_buffer[size]) #define HDRB \ " < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" @@ -160,21 +162,17 @@ size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); -#ifdef AIC7XXX_RESET_DELAY - size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); +#else + size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); #endif - size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n"); - size += sprintf(BLS, " Check below to see " - "which\n" - " devices use tagged " - "queueing\n"); - size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled (This is no longer " - "an option)\n"); #ifdef AIC7XXX_PROC_STATS size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); #else size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); #endif + size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Adapter Configuration:\n"); size += sprintf(BLS, " SCSI Adapter: %s\n", @@ -250,11 +248,7 @@ } size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); -#ifdef AIC7XXX_CMDS_PER_LUN - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN); -#else - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8); -#endif + size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " "instance %d:\n", p->instance); size += sprintf(BLS, " {"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/amiga7xx.c linux.ac/drivers/scsi/amiga7xx.c --- linux.vanilla/drivers/scsi/amiga7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/amiga7xx.c Thu Dec 17 01:56:25 1998 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -33,9 +34,9 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, - u32 base, int io_port, int irq, int dma, - long long options, int clock); +extern int ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, + u32 base, int io_port, int irq, int dma, + long long options, int clock); int amiga7xx_detect(Scsi_Host_Template *tpnt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_NCR5380.c linux.ac/drivers/scsi/atari_NCR5380.c --- linux.vanilla/drivers/scsi/atari_NCR5380.c Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/atari_NCR5380.c Sun Nov 8 14:35:42 1998 @@ -1459,9 +1459,9 @@ unsigned long timeout = jiffies + 2*NCR_TIMEOUT; while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout && !hostdata->connected) + && time_before(jiffies, timeout) && !hostdata->connected) ; - if (jiffies >= timeout) + if (time_after_eq(jiffies, timeout)) { printk("scsi : arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1616,7 +1616,7 @@ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) */ - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == @@ -1629,7 +1629,7 @@ return -1; } #else - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); #endif /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_scsi.c linux.ac/drivers/scsi/atari_scsi.c --- linux.vanilla/drivers/scsi/atari_scsi.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/atari_scsi.c Thu Dec 17 01:56:31 1998 @@ -132,51 +132,51 @@ } while(0) #define SCSI_DMA_READ_P(elt) \ - (((unsigned long)tt_scsi_dma.elt##_hi << 24) | \ - ((unsigned long)tt_scsi_dma.elt##_hmd << 16) | \ - ((unsigned long)tt_scsi_dma.elt##_lmd << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lo) - - -#define SCSI_DMA_SETADR(adr) \ - do { \ - unsigned long __adr = (adr); \ - st_dma.dma_lo = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_md = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_hi = (unsigned char)__adr; \ - MFPDELAY(); \ - } while(0) - -#define SCSI_DMA_GETADR() ({ \ - unsigned long __adr; \ - __adr = st_dma.dma_lo; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_md & 0xff) << 8; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_hi & 0xff) << 16; \ - MFPDELAY(); \ - __adr; \ -}) - -#define ENABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_enable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_enable_irq( IRQ_MFP_FSCSI ); \ - } while(0) - -#define DISABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_disable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_disable_irq( IRQ_MFP_FSCSI ); \ - } while(0) + (((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \ + (unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lo) + + +static inline void SCSI_DMA_SETADR(unsigned long adr) +{ + st_dma.dma_lo = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_md = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_hi = (unsigned char)adr; + MFPDELAY(); +} + +static inline unsigned long SCSI_DMA_GETADR(void) +{ + unsigned long adr; + adr = st_dma.dma_lo; + MFPDELAY(); + adr |= (st_dma.dma_md & 0xff) << 8; + MFPDELAY(); + adr |= (st_dma.dma_hi & 0xff) << 16; + MFPDELAY(); + return adr; +} + +static inline void ENABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_enable_irq(IRQ_TT_MFP_SCSI); + else + atari_enable_irq(IRQ_MFP_FSCSI); +} + +static inline void DISABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_disable_irq(IRQ_TT_MFP_SCSI); + else + atari_disable_irq(IRQ_MFP_FSCSI); +} #define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ @@ -480,16 +480,17 @@ /* fetch rest bytes in the DMA register */ dst = (char *)SCSI_DMA_READ_P( dma_addr ); - if ((nr = ((long)dst & 3))) { + nr = ((long)dst & 3); + if (nr) { /* there are 'nr' bytes left for the last long address before the DMA pointer */ - dst = (char *)( (unsigned long)dst & ~3 ); + dst = (char *)((unsigned long)dst ^ nr); DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", nr, (long)dst); dst = (char *)PTOV(dst); /* The content of the DMA pointer * is a physical address! */ DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst); - for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr ) + for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) *dst++ = *src++; } } @@ -764,7 +765,7 @@ } #endif -__initfunc(void atari_scsi_setup( char *str, int *ints )) +void __init atari_scsi_setup(char *str, int *ints) { /* Format of atascsi parameter is: * atascsi=,,,, @@ -772,23 +773,6 @@ * Negative values mean don't change. */ - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ - - int i = ints[0]+1, fact; - - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; - } - ints[0] = i-1; - if (ints[0] < 1) { printk( "atari_scsi_setup: no arguments!\n" ); return; @@ -869,7 +853,7 @@ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -__initfunc(static void atari_scsi_reset_boot( void )) +static void __init atari_scsi_reset_boot(void) { unsigned long end; @@ -892,7 +876,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies,end); ) barrier(); printk( " done\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.ac/drivers/scsi/gdth_proc.c --- linux.vanilla/drivers/scsi/gdth_proc.c Thu Jan 14 01:25:25 1999 +++ linux.ac/drivers/scsi/gdth_proc.c Sat Jan 16 21:35:28 1999 @@ -3,6 +3,7 @@ */ #include "gdth_ioctl.h" +#include int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.ac/drivers/scsi/ide-scsi.c --- linux.vanilla/drivers/scsi/ide-scsi.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/ide-scsi.c Tue Feb 16 17:21:46 1999 @@ -606,6 +606,8 @@ host = scsi_register(host_template, 0); for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); host->max_id = id; + host->max_lun = 1; /* We should query the drive for multilun + support ? */ host->can_queue = host->cmd_per_lun * id; return 1; } @@ -729,6 +731,9 @@ if (!drive) { printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); + goto abort; + } + if (cmd->lun != 0) { /* Only respond to LUN 0. Drop others */ goto abort; } scsi = drive->driver_data; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.c linux.ac/drivers/scsi/megaraid.c --- linux.vanilla/drivers/scsi/megaraid.c Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/scsi/megaraid.c Mon Mar 1 14:24:09 1999 @@ -82,7 +82,6 @@ #define CRLFSTR "\n" -#include #include #ifdef MODULE @@ -111,10 +110,7 @@ #include #include -#include #include -#include /* for kmalloc() */ -#include /* for CONFIG_PCI */ #if LINUX_VERSION_CODE < 0x20100 #include #else diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.ac/drivers/scsi/ncr53c8xx.c --- linux.vanilla/drivers/scsi/ncr53c8xx.c Wed Mar 10 21:13:05 1999 +++ linux.ac/drivers/scsi/ncr53c8xx.c Mon Mar 8 14:14:55 1999 @@ -4990,7 +4990,7 @@ ** Force ordered tag if necessary to avoid timeouts ** and to preserve interactivity. */ - if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp && time_before_eq(lp->tags_stime + 3*HZ, jiffies)) { if (lp->tags_smap) { order = M_ORDERED_TAG; if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ @@ -9824,7 +9824,8 @@ /* PCI_CACHE_LINE_SIZE value is in 32-bit words. */ cache_line_size = 64 / sizeof(u_int32); if (initverbose >= 2) - printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size); + printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", + cache_line_size); pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size); pcibios_read_config_byte(bus, device_fn, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/pci2000.c linux.ac/drivers/scsi/pci2000.c --- linux.vanilla/drivers/scsi/pci2000.c Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/scsi/pci2000.c Wed Mar 24 12:45:56 1999 @@ -34,10 +34,8 @@ #include #include -#include #include #include -#include #include #include #include @@ -523,6 +521,16 @@ OpDone (SCpnt, rc << 16); return 0; } + +static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) + { + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + Irq_Handler(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); + } + /**************************************************************** * Name: internal_done :LOCAL * @@ -570,26 +578,20 @@ ****************************************************************/ int Pci2000_Detect (Scsi_Host_Template *tpnt) { - int pci_index = 0; - struct Scsi_Host *pshost; - PADAPTER2000 padapter; - int z, zz; - int setirq; + int pci_index = 0; + struct Scsi_Host *pshost; + PADAPTER2000 padapter; + int z; + int setirq; + struct pci_dev *pdev = NULL; - if ( pcibios_present () ) - { - for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index ) + if ( pci_present () ) + while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_ROY_1, pdev))) { - UCHAR pci_bus, pci_device_fn; - - if ( pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, pci_index, &pci_bus, &pci_device_fn) != 0 ) - break; - pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); padapter = HOSTDATA(pshost); - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); - padapter->basePort &= 0xFFFE; + padapter->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; @@ -606,40 +608,35 @@ if ( WaitReady (padapter) ) goto unregister; - pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); + pshost->irq = pdev->irq; setirq = 1; - for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts + for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts { - if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses + if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses setirq = 0; } - if ( setirq ) // if not shared, posses + if ( setirq ) // if not shared, posses { - if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) ) + if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) ) { printk ("Unable to allocate IRQ for PSI-2000 controller.\n"); goto unregister; } } - PsiHost[pci_index] = pshost; // save SCSI_HOST pointer + PsiHost[pci_index] = pshost; // save SCSI_HOST pointer pshost->unique_id = padapter->basePort; pshost->max_id = 16; pshost->max_channel = 1; - for ( zz = 0; zz < MAX_BUS; zz++ ) - for ( z = 0; z < MAX_UNITS; z++ ) - padapter->dev[zz][z].tag = 0; - - printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); - printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__); + printk("\nPSI-2000 EIDE CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); + printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); + NumAdapters++; continue; unregister:; scsi_unregister (pshost); } - } - NumAdapters = pci_index; - return pci_index; + return NumAdapters; } /**************************************************************** * Name: Pci2220i_Abort @@ -713,7 +710,7 @@ #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PCI2220I; +Scsi_Host_Template driver_template = PCI2000; #include "scsi_module.c" #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/pci2000.h linux.ac/drivers/scsi/pci2000.h --- linux.vanilla/drivers/scsi/pci2000.h Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/scsi/pci2000.h Wed Mar 24 12:42:11 1999 @@ -202,25 +202,18 @@ extern struct proc_dir_entry Proc_Scsi_Pci2000; -#define PCI2000 { NULL, NULL, \ - &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ - NULL, \ - "PCI-2000 SCSI Intelligent Disk Controller",\ - Pci2000_Detect, \ - NULL, \ - NULL, \ - Pci2000_Command, \ - Pci2000_QueueCommand, \ - Pci2000_Abort, \ - Pci2000_Reset, \ - NULL, \ - Pci2000_BiosParam, \ - 16, \ - -1, \ - 16, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } +#define PCI2000 { proc_dir: &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ + name: "PCI-2000 SCSI Intelligent Disk Controller",\ + detect: Pci2000_Detect, \ + command: Pci2000_Command, \ + queuecommand: Pci2000_QueueCommand, \ + abort: Pci2000_Abort, \ + reset: Pci2000_Reset, \ + bios_param: Pci2000_BiosParam, \ + can_queue: 16, \ + this_id: -1, \ + sg_tablesize: 16, \ + cmd_per_lun: 1, \ + use_clustering: DISABLE_CLUSTERING } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/pci2220i.c linux.ac/drivers/scsi/pci2220i.c --- linux.vanilla/drivers/scsi/pci2220i.c Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/scsi/pci2220i.c Wed Mar 24 12:57:25 1999 @@ -1,7 +1,7 @@ /*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-22220I device driver proc support for Linux. + * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. * - * Copyright (c) 1999 Perceptive Solutions, Inc. + * Copyright (c) 1997 Perceptive Solutions, Inc. * * 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 @@ -25,51 +25,56 @@ *-M*************************************************************************/ #include + #include -#include #include #include -#include #include #include #include #include #include -#include -#include -#include -#include #include #include +#include #include +#include #include "scsi.h" #include "hosts.h" -#include "pci2220i.h" -#define PCI2220I_VERSION "1.10" -//#define READ_CMD IDE_COMMAND_READ -//#define WRITE_CMD IDE_COMMAND_WRITE -//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master -#define READ_CMD IDE_CMD_READ_MULTIPLE -#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE -#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master +#include "pci2220i.h" +#include "psi_dale.h" +#include struct proc_dir_entry Proc_Scsi_Pci2220i = - { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; + { PROC_SCSI_PCI2220I, 7, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; //#define DEBUG 1 #ifdef DEBUG #define DEB(x) x -#define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}} +#define STOP_HERE {int st;for(st=0;st<100;st++){st=1;}} #else #define DEB(x) -#define STOP_HERE() +#define STOP_HERE #endif -#define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more. +#define MAXADAPTER 4 /* Increase this and the sizes of the arrays below, if you need more. */ + +#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master for (1024 bytes) +#define PORT_DATA 0 +#define PORT_ERROR 1 +#define PORT_SECTOR_COUNT 2 +#define PORT_LBA_0 3 +#define PORT_LBA_8 4 +#define PORT_LBA_16 5 +#define PORT_LBA_24 6 +#define PORT_STAT_CMD 7 +#define PORT_STAT_SEL 8 +#define PORT_FAIL 9 +#define PORT_ALT_STAT 10 typedef struct { @@ -82,245 +87,44 @@ USHORT cylinders; // number of cylinders for this device USHORT spareword; // placeholder ULONG blocks; // number of blocks on device - DISK_MIRROR DiskMirror[2]; // RAID status and control - ULONG lastsectorlba[2]; // last addressable sector on the drive - USHORT raid; // RAID active flag - USHORT mirrorRecon; - UCHAR hotRecon; - USHORT reconCount; - } OUR_DEVICE, *POUR_DEVICE; + } OUR_DEVICE, *POUR_DEVICE; typedef struct { - USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer - USHORT regDmaCmdStat; // Byte #1 of DMA command status register - USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA - USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA - USHORT regDmaCount; // 32 bit register for DMA transfer count - USHORT regDmaMode; // 32 bit register for DMA mode control - USHORT regRemap; // 32 bit local space remap - USHORT regDesc; // 32 bit local region descriptor - USHORT regRange; // 32 bit local range - USHORT regIrqControl; // 16 bit Interrupt enable/disable and status - USHORT regScratchPad; // scratch pad I/O base address - USHORT regBase; // Base I/O register for data space - USHORT regData; // data register I/O address - USHORT regError; // error register I/O address - USHORT regSectCount; // sector count register I/O address - USHORT regLba0; // least significant byte of LBA - USHORT regLba8; // next least significant byte of LBA - USHORT regLba16; // next most significan byte of LBA - USHORT regLba24; // head and most 4 significant bits of LBA - USHORT regStatCmd; // status on read and command on write register - USHORT regStatSel; // board status on read and spigot select on write register - USHORT regFail; // fail bits control register - USHORT regAltStat; // alternate status and drive control register - USHORT basePort; // PLX base I/O port - USHORT timingMode; // timing mode currently set for adapter - USHORT timingPIO; // TRUE if PIO timing is active - ULONG timingAddress; // address to use on adapter for current timing mode - OUR_DEVICE device[DALE_MAXDRIVES]; - DISK_MIRROR *raidData[8]; + USHORT ports[12]; + USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer + USHORT regDmaCmdStat; // Byte #1 of DMA command status register + USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA + USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA + USHORT regDmaCount; // 32 bit register for DMA transfer count + USHORT regDmaMode; // 32 bit register for DMA mode control + USHORT regRemap; // 32 bit local space remap + USHORT regDesc; // 32 bit local region descriptor + USHORT regRange; // 32 bit local range + USHORT regIrqControl; // 16 bit Interrupt enable/disable and status + USHORT regScratchPad; // scratch pad I/O base address + USHORT regBase; // Base I/O register for data space + USHORT basePort; // PLX base I/O port + USHORT timingMode; // timing mode currently set for adapter + ULONG timingAddress; // address to use on adapter for current timing mode + OUR_DEVICE device[4]; + IDE_STRUCT ide; ULONG startSector; USHORT sectorCount; - UCHAR cmd; Scsi_Cmnd *SCpnt; VOID *buffer; - POUR_DEVICE pdev; // current device opearating on USHORT expectingIRQ; - USHORT reconIsStarting; // indicate hot reconstruct is starting - USHORT reconOn; // Hot reconstruct is to be done. - USHORT reconPhase; // Hot reconstruct operation is in progress. - ULONG reconSize; - USHORT demoFail; // flag for RAID failure demonstration - USHORT survivor; - USHORT failinprog; - USHORT timeoutReconRetry; - struct timer_list reconTimer; - struct timer_list timer; + USHORT readPhase; } ADAPTER2220I, *PADAPTER2220I; #define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata) -#define RECON_PHASE_READY 0x01 -#define RECON_PHASE_COPY 0x02 -#define RECON_PHASE_UPDATE 0x03 -#define RECON_PHASE_LAST 0x04 -#define RECON_PHASE_END 0x07 -#define RECON_PHASE_MARKING 0x80 -#define RECON_PHASE_FAILOVER 0xFF static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter static int NumAdapters = 0; +static IDENTIFY_DATA identifyData; static SETUP DaleSetup; -static DISK_MIRROR DiskMirror[2]; -static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P}; -static UCHAR Buffer[SECTORSXFER * BYTES_PER_SECTOR]; - -static void ReconTimerExpiry (unsigned long data); - -/**************************************************************** - * Name: MuteAlarm :LOCAL - * - * Description: Mute the audible alarm. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static void MuteAlarm (PADAPTER2220I padapter) - { - UCHAR old; - - old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83); - outb_p (old | 0x40, padapter->regFail); - } -/**************************************************************** - * Name: WaitReady :LOCAL - * - * Description: Wait for device ready. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WaitReady (PADAPTER2220I padapter) - { - ULONG z; - UCHAR status; - - for ( z = 0; z < (TIMEOUT_READY * 4); z++ ) - { - status = inb_p (padapter->regStatCmd); - if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) - return 0; - udelay (250); - } - return status; - } -/**************************************************************** - * Name: WaitReadyReset :LOCAL - * - * Description: Wait for device ready. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WaitReadyReset (PADAPTER2220I padapter) - { - ULONG z; - UCHAR status; - - for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second - { - status = inb_p (padapter->regStatCmd); - if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) - { - DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4)); - return 0; - } - udelay (250); - } - DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure")); - return status; - } -/**************************************************************** - * Name: WaitDrq :LOCAL - * - * Description: Wait for device ready for data transfer. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WaitDrq (PADAPTER2220I padapter) - { - ULONG z; - UCHAR status; - for ( z = 0; z < (TIMEOUT_DRQ * 4); z++ ) - { - status = inb_p (padapter->regStatCmd); - if ( status & IDE_STATUS_DRQ ) - return 0; - udelay (250); - } - return status; - } -/**************************************************************** - * Name: HardReset :LOCAL - * - * Description: Wait for device ready for data transfer. - * - * Parameters: padapter - Pointer adapter data structure. - * pdev - Pointer to device. - * spigot - Spigot number. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot) - { - SelectSpigot (padapter, spigot | 0x80); - - outb_p (0x0E, padapter->regAltStat); // reset the suvivor - udelay (100); // wait a little - outb_p (0x08, padapter->regAltStat); // clear the reset - udelay (100); - outb_p (0xA0, padapter->regLba24); //Specify drive - - outb_p (pdev->byte6, padapter->regLba24); // select the drive - if ( WaitReadyReset (padapter) ) - return TRUE; - outb_p (SECTORSXFER, padapter->regSectCount); - WriteCommand (padapter, IDE_CMD_SET_MULTIPLE); - if ( WaitReady (padapter) ) - return TRUE; - return FALSE; - } -/**************************************************************** - * Name: BusMaster :LOCAL - * - * Description: Do a bus master I/O. - * - * Parameters: padapter - Pointer adapter data structure. - * datain - TRUE if data read. - * irq - TRUE if bus master interrupt expected. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq) - { - ULONG zl; - - outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - padapter->sectorCount -= zl; - zl *= (ULONG)BYTES_PER_SECTOR; - padapter->buffer += zl; - outl (zl, padapter->regDmaCount); - if ( datain ) - { - outb_p (8, padapter->regDmaDesc); // read operation - if ( irq && !padapter->sectorCount ) - outb_p (5, padapter->regDmaMode); // interrupt on - else - outb_p (1, padapter->regDmaMode); // no interrupt - } - else - { - outb_p (0, padapter->regDmaDesc); // write operation - outb_p (1, padapter->regDmaMode); // no interrupt - } - outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear - } /**************************************************************** * Name: WriteData :LOCAL * @@ -333,224 +137,114 @@ ****************************************************************/ static int WriteData (PADAPTER2220I padapter) { - ULONG zl; - - if ( !WaitDrq (padapter) ) - { - if ( padapter->timingPIO ) - { - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); - padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; - } - else - BusMaster (padapter, 0, 0); - return 0; - } - padapter->cmd = 0; // null out the command byte - return 1; - } -/**************************************************************** - * Name: WriteDataBoth :LOCAL - * - * Description: Write data to device. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WriteDataBoth (PADAPTER2220I padapter) - { - ULONG zl; - UCHAR status0, status1; + ULONG timer; + USHORT *pports = padapter->ports; - SelectSpigot (padapter, 1); - status0 = WaitDrq (padapter); - if ( !status0 ) - { - SelectSpigot (padapter, 2); - status1 = WaitDrq (padapter); - if ( !status1 ) - { - SelectSpigot (padapter, 3); - if ( padapter->timingPIO ) - { - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); - padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; - } - else - BusMaster (padapter, 0, 0); + timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value + do { + if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ ) + { + outb_p (0, padapter->regDmaDesc); // write operation + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); + outl ((ULONG)padapter->ide.ide.ide[2] * (ULONG)512, padapter->regDmaCount); + outb_p (1, padapter->regDmaMode); // interrupts off + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear return 0; } - } - padapter->cmd = 0; // null out the command byte - if ( status0 ) - return 1; - return 2; + } while ( timer > jiffies ); // test for timeout + + padapter->ide.ide.ides.cmd = 0; // null out the command byte + return 1; } /**************************************************************** * Name: IdeCmd :LOCAL * - * Description: Process an IDE command. + * Description: Process a queued command from the SCSI manager. * * Parameters: padapter - Pointer adapter data structure. - * pdev - Pointer to device. * * Returns: Zero if no error or status register contents on error. * ****************************************************************/ -static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev) +static UCHAR IdeCmd (PADAPTER2220I padapter) { + ULONG timer; + USHORT *pports = padapter->ports; UCHAR status; - SelectSpigot (padapter, pdev->spigot); // select the spigot - outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive - status = WaitReady (padapter); - if ( !status ) - { - outb_p (padapter->sectorCount, padapter->regSectCount); - outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0); - outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8); - outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16); - padapter->expectingIRQ = TRUE; - WriteCommand (padapter, padapter->cmd); - return 0; - } - - padapter->cmd = 0; // null out the command byte - return status; - } -/**************************************************************** - * Name: IdeCmdBoth :LOCAL - * - * Description: Process an IDE command to both drivers. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: Zero if no error or spigot of error. - * - ****************************************************************/ -static UCHAR IdeCmdBoth (PADAPTER2220I padapter) - { - UCHAR status0; - UCHAR status1; + outb_p (padapter->ide.ide.ides.spigot, pports[PORT_STAT_SEL]); // select the spigot + outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive + timer = jiffies + TIMEOUT_READY; // calculate the timeout value + DEB(printk ("\npci2220i Issueing new command: 0x%X",padapter->ide.ide.ides.cmd)); + do { + status = inb_p (padapter->ports[PORT_STAT_CMD]); + if ( status & IDE_STATUS_DRDY ) + { + outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]); + outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]); + outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]); + outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]); + padapter->expectingIRQ = 1; + outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]); - SelectSpigot (padapter, 3); // select the spigots - outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive - SelectSpigot (padapter, 1); - status0 = WaitReady (padapter); - if ( !status0 ) - { - SelectSpigot (padapter, 2); - status1 = WaitReady (padapter); - if ( !status1 ) - { - SelectSpigot (padapter, 3); - outb_p (padapter->sectorCount, padapter->regSectCount); - outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0); - outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8); - outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16); - padapter->expectingIRQ = TRUE; - WriteCommand (padapter, padapter->cmd); + if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) + return (WriteData (padapter)); return 0; } - } - padapter->cmd = 0; // null out the command byte - if ( status0 ) - return 1; - return 2; + } while ( timer > jiffies ); // test for timeout + + padapter->ide.ide.ides.cmd = 0; // null out the command byte + return status; } /**************************************************************** - * Name: OpDone :LOCAL + * Name: SetupTransfer :LOCAL * - * Description: Complete an operatoin done sequence. + * Description: Setup a data transfer command. * - * Parameters: padapter - Pointer to host data block. - * spigot - Spigot select code. - * device - Device byte code. + * Parameters: padapter - Pointer adapter data structure. + * drive - Drive/head register upper nibble only. * - * Returns: Nothing. + * Returns: TRUE if no data to transfer. * ****************************************************************/ -static void OpDone (PADAPTER2220I padapter, ULONG result) +static int SetupTransfer (PADAPTER2220I padapter, UCHAR drive) { - Scsi_Cmnd *SCpnt = padapter->SCpnt; - - if ( padapter->reconPhase ) + if ( padapter->sectorCount ) { - padapter->reconPhase = 0; - if ( padapter->SCpnt ) - { - Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done); - } - else - { - if ( padapter->reconOn ) - { - ReconTimerExpiry ((unsigned long)padapter); - } - } + *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector; + padapter->ide.ide.ide[6] |= drive; +// padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount; + padapter->ide.ide.ides.sectors = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer + padapter->startSector += padapter->ide.ide.ides.sectors; + return 0; } else { - padapter->cmd = 0; - padapter->SCpnt = NULL; - SCpnt->result = result; - SCpnt->scsi_done (SCpnt); - if ( padapter->reconOn && !padapter->reconTimer.data ) - { - padapter->reconTimer.expires = jiffies + (HZ / 4); // start in 1/4 second - padapter->reconTimer.data = (unsigned long)padapter; - add_timer (&padapter->reconTimer); - } + padapter->ide.ide.ides.cmd = 0; // null out the command byte + padapter->SCpnt = NULL; + return 1; } } /**************************************************************** - * Name: InlineIdentify :LOCAL - * - * Description: Do an intline inquiry on a drive. - * - * Parameters: padapter - Pointer to host data block. - * spigot - Spigot select code. - * device - Device byte code. - * - * Returns: Last addressable sector or zero if none. - * - ****************************************************************/ -static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device) - { - PIDENTIFY_DATA pid = (PIDENTIFY_DATA)Buffer; - - SelectSpigot (padapter, spigot | 0x80); // select the spigot - outb_p (device << 4, padapter->regLba24); // select the drive - if ( WaitReady (padapter) ) - return 0; - WriteCommand (padapter, IDE_COMMAND_IDENTIFY); - if ( WaitDrq (padapter) ) - return 0; - insw (padapter->regData, Buffer, sizeof (IDENTIFY_DATA) >> 1); - return (pid->LBATotalSectors - 1); - } -/**************************************************************** * Name: DecodeError :LOCAL * * Description: Decode and process device errors. * - * Parameters: padapter - Pointer to adapter data. + * Parameters: pshost - Pointer to host data block. * status - Status register code. * * Returns: The driver status code. * ****************************************************************/ -static ULONG DecodeError (PADAPTER2220I padapter, UCHAR status) +static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) { + PADAPTER2220I padapter = HOSTDATA(pshost); UCHAR error; padapter->expectingIRQ = 0; + padapter->SCpnt = NULL; if ( status & IDE_STATUS_WRITE_FAULT ) { return DID_PARITY << 16; @@ -558,7 +252,7 @@ if ( status & IDE_STATUS_BUSY ) return DID_BUS_BUSY << 16; - error = inb_p (padapter->regError); + error = inb_p (padapter->ports[PORT_ERROR]); DEB(printk ("\npci2220i error register: %x", error)); switch ( error ) { @@ -574,483 +268,6 @@ return DID_ERROR << 16; } /**************************************************************** - * Name: StartTimer :LOCAL - * - * Description: Start the timer. - * - * Parameters: ipadapter - Pointer adapter data structure. - * - * Returns: Nothing. - * - ****************************************************************/ -static void StartTimer (PADAPTER2220I padapter) - { - padapter->timer.expires = jiffies + TIMEOUT_DATA; - add_timer (&padapter->timer); - } -/**************************************************************** - * Name: WriteSignature :LOCAL - * - * Description: Start the timer. - * - * Parameters: padapter - Pointer adapter data structure. - * pdev - Pointer to our device. - * spigot - Selected spigot. - * index - index of mirror signature on device. - * - * Returns: TRUE on any error. - * - ****************************************************************/ -static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot, int index) - { - ULONG zl; - - SelectSpigot (padapter, spigot); - zl = pdev->lastsectorlba[index]; - outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24); - outb_p (((UCHAR *)&zl)[2], padapter->regLba16); - outb_p (((UCHAR *)&zl)[1], padapter->regLba8); - outb_p (((UCHAR *)&zl)[0], padapter->regLba0); - outb_p (1, padapter->regSectCount); - - WriteCommand (padapter, IDE_COMMAND_WRITE); - if ( WaitDrq (padapter) ) - return TRUE; - StartTimer (padapter); - padapter->expectingIRQ = TRUE; - - outsw (padapter->regData, Buffer, DISK_MIRROR_POSITION / 2); - outsw (padapter->regData, &pdev->DiskMirror[index], sizeof (DISK_MIRROR) / 2); - outsw (padapter->regData, Buffer, ((512 - (DISK_MIRROR_POSITION + sizeof (DISK_MIRROR))) / 2)); - return FALSE; - } -/******************************************************************************************************* - * Name: InitFailover - * - * Description: This is the beginning of the failover routine - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * padapter - Pointer adapter data structure. - * pdev - Pointer to our device. - * - * Returns: TRUE on error. - * - ******************************************************************************************************/ -static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev) - { - UCHAR spigot; - - DEB (printk ("\npci2000i: Initialize failover process - survivor = %d", padapter->survivor)); - pdev->raid = FALSE; //initializes system for non raid mode - pdev->hotRecon = 0; - padapter->reconOn = FALSE; - spigot = (padapter->survivor) ? 2 : 1; - - if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD ) - return (TRUE); - - if ( HardReset (padapter, pdev, spigot) ) - return TRUE; - - outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light - pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status - - if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) ) - return TRUE; - padapter->failinprog = TRUE; - return FALSE; - } -/**************************************************************** - * Name: TimerExpiry :LOCAL - * - * Description: Timer expiry routine. - * - * Parameters: data - Pointer adapter data structure. - * - * Returns: Nothing. - * - ****************************************************************/ -static void TimerExpiry (unsigned long data) - { - PADAPTER2220I padapter = (PADAPTER2220I)data; - POUR_DEVICE pdev = padapter->pdev; - ULONG flags; - UCHAR status = IDE_STATUS_BUSY; - UCHAR temp, temp1; - - DEB (printk ("\nPCI2220I: Timeout expired ")); - save_flags (flags); - cli (); - - if ( padapter->failinprog ) - { - DEB (printk ("in failover process")); - restore_flags (flags); - OpDone (padapter, DecodeError (padapter, inb_p (padapter->regStatCmd))); - return; - } - - while ( padapter->reconPhase ) - { - DEB (printk ("in recon phase %X", padapter->reconPhase)); - if ( --padapter->timeoutReconRetry ) - { - StartTimer (padapter); - return; - } - switch ( padapter->reconPhase ) - { - case RECON_PHASE_MARKING: - case RECON_PHASE_LAST: - padapter->survivor = (pdev->spigot ^ 3) >> 1; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 1")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DID_ERROR << 16); - return; - - case RECON_PHASE_READY: - OpDone (padapter, DID_ERROR << 16); - return; - - case RECON_PHASE_COPY: - padapter->survivor = (pdev->spigot) >> 1; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 2")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DID_ERROR << 16); - return; - - case RECON_PHASE_UPDATE: - padapter->survivor = (pdev->spigot) >> 1; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 3")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DID_ERROR << 16); - return; - - case RECON_PHASE_END: - padapter->survivor = (pdev->spigot) >> 1; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 4")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DID_ERROR << 16); - return; - - default: - return; - } - } - - while ( padapter->cmd ) - { - outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine - if ( pdev->raid ) - { - if ( padapter->cmd == WRITE_CMD ) - { - DEB (printk ("in RAID write operation")); - if ( inb_p (padapter->regStatSel) & 1 ) - { - SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select - temp = inb_p (padapter->regStatCmd); - } - else - temp = IDE_STATUS_BUSY; - - if ( inb (padapter->regStatSel) & 2 ) - { - SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select - temp1 = inb_p (padapter->regStatCmd); - } - else - temp1 = IDE_STATUS_BUSY; - - if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) ) - { - if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) ) - { - status = temp; - break; - } - else - { - if (temp & IDE_STATUS_BUSY) - padapter->survivor = 1; - else - padapter->survivor = 0; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 5")); - if ( InitFailover (padapter, pdev) ) - { - status = inb_p (padapter->regStatCmd); - break; - } - return; - } - } - } - else - { - DEB (printk ("in RAID read operation")); - padapter->survivor = (pdev->spigot ^ 3) >> 1; - restore_flags (flags); - DEB (printk ("\npci2220i: FAILURE 6")); - if ( InitFailover (padapter, pdev) ) - { - status = inb_p (padapter->regStatCmd); - break; - } - return; - } - } - else - { - DEB (printk ("in I/O operation")); - status = inb_p (padapter->regStatCmd); - } - break; - } - - restore_flags (flags); - OpDone (padapter, DecodeError (padapter, status)); - } -/**************************************************************** - * Name: SetReconstruct :LOCAL - * - * Description: Set the reconstruct up. - * - * Parameters: pdev - Pointer to device structure. - * index - Mirror index number. - * - * Returns: Number of sectors on new disk required. - * - ****************************************************************/ -static LONG SetReconstruct (POUR_DEVICE pdev, int index) - { - pdev->DiskMirror[index].status = UCBF_MIRRORED; // setup the flags - pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD; - pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct - pdev->reconCount = 1990; // mark target drive early - pdev->hotRecon = 1 >> index; - return pdev->DiskMirror[index].reconstructPoint; - } -/**************************************************************** - * Name: ReconTimerExpiry :LOCAL - * - * Description: Reconstruct timer expiry routine. - * - * Parameters: data - Pointer adapter data structure. - * - * Returns: Nothing. - * - ****************************************************************/ -static void ReconTimerExpiry (unsigned long data) - { - PADAPTER2220I padapter; - POUR_DEVICE pdev; - ULONG testsize = 0; - PIDENTIFY_DATA pid; - USHORT minmode; - ULONG zl; - UCHAR zc; - - padapter = (PADAPTER2220I)data; - if ( padapter->SCpnt ) - return; - - pdev = padapter->device; - pid = (PIDENTIFY_DATA)Buffer; - padapter->reconTimer.data = 0; - padapter->timeoutReconRetry = 2; - padapter->pdev = pdev; - if ( padapter->reconIsStarting ) - { - padapter->reconIsStarting = FALSE; - padapter->reconOn = FALSE; - pdev->hotRecon = FALSE; - - if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) && - (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) ) - { - if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) ) - { - return; - } - - if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor? - testsize = SetReconstruct (pdev, 0); - else - if ( pdev->DiskMirror[1].status & UCBF_SURVIVOR ) // is second drive survivor? - testsize = SetReconstruct (pdev, 1); - - if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) ) - { - if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) - { - pdev->hotRecon = 1; - pdev->mirrorRecon = 0; - } - else - { - pdev->hotRecon = 2; - pdev->mirrorRecon = 1; - } - } - } - - if ( !pdev->hotRecon ) - return; - - zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm - outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail); - - while ( 1 ) - { - if ( HardReset (padapter, pdev, pdev->hotRecon) ) - { - DEB (printk ("\npci2220i: sub 1")); - break; - } - - pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0); - - if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize ) - { - DEB (printk ("\npci2220i: sub 2 %ld %ld", pdev->lastsectorlba[pdev->mirrorRecon], testsize)); - break; - } - - // test LBA and multiper sector transfer compatability - if (!pid->SupportLBA || (pid->NumSectorsPerInt < SECTORSXFER) || !pid->Valid_64_70 ) - { - DEB (printk ("\npci2220i: sub 3")); - break; - } - - // test PIO/bus matering mode compatability - if ( (pid->MinPIOCycleWithoutFlow > 240) && !pid->SupportIORDYDisable && !padapter->timingPIO ) - { - DEB (printk ("\npci2220i: sub 4")); - break; - } - - if ( pid->MinPIOCycleWithoutFlow <= 120 ) // setup timing mode of drive - minmode = 5; - else - { - if ( pid->MinPIOCylceWithFlow <= 150 ) - minmode = 4; - else - { - if ( pid->MinPIOCylceWithFlow <= 180 ) - minmode = 3; - else - { - if ( pid->MinPIOCylceWithFlow <= 240 ) - minmode = 2; - else - { - DEB (printk ("\npci2220i: sub 5")); - break; - } - } - } - } - - if ( padapter->timingMode > minmode ) // set minimum timing mode - padapter->timingMode = minmode; - if ( padapter->timingMode >= 2 ) - padapter->timingAddress = ModeArray[padapter->timingMode - 2]; - else - padapter->timingPIO = TRUE; - - padapter->reconOn = TRUE; - break; - } - - if ( !padapter->reconOn ) - { - pdev->hotRecon = FALSE; - padapter->survivor = pdev->mirrorRecon ^ 1; - padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 7")); - InitFailover (padapter, pdev); - return; - } - - pdev->raid = TRUE; - - if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) ) - return; - padapter->reconPhase = RECON_PHASE_MARKING; - return; - } - - //********************************** - // reconstruct copy starts here - //********************************** - if ( pdev->reconCount++ > 2000 ) - { - pdev->reconCount = 0; - if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) - { - padapter->survivor = pdev->mirrorRecon ^ 1; - padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 8")); - InitFailover (padapter, pdev); - return; - } - padapter->reconPhase = RECON_PHASE_UPDATE; - return; - } - - zl = pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint; - padapter->reconSize = pdev->DiskMirror[pdev->mirrorRecon ^ 1].reconstructPoint - zl; - if ( padapter->reconSize > MAX_BUS_MASTER_BLOCKS ) - padapter->reconSize = MAX_BUS_MASTER_BLOCKS; - - if ( padapter->reconSize ) - { - SelectSpigot (padapter, 3); // select the spigots - outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive - SelectSpigot (padapter, pdev->spigot); - if ( WaitReady (padapter) ) - return; - - SelectSpigot (padapter, pdev->hotRecon); - if ( WaitReady (padapter) ) - { - padapter->survivor = pdev->mirrorRecon ^ 1; - padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 9")); - InitFailover (padapter, pdev); - return; - } - - SelectSpigot (padapter, 3); - outb_p (padapter->reconSize & 0xFF, padapter->regSectCount); - outb_p (((UCHAR *)(&zl))[0], padapter->regLba0); - outb_p (((UCHAR *)(&zl))[1], padapter->regLba8); - outb_p (((UCHAR *)(&zl))[2], padapter->regLba16); - padapter->expectingIRQ = TRUE; - padapter->reconPhase = RECON_PHASE_READY; - SelectSpigot (padapter, pdev->hotRecon); - WriteCommand (padapter, WRITE_CMD); - StartTimer (padapter); - SelectSpigot (padapter, pdev->spigot); - WriteCommand (padapter, READ_CMD); - return; - } - - pdev->DiskMirror[pdev->mirrorRecon].status = UCBF_MIRRORED | UCBF_MATCHED; - pdev->DiskMirror[pdev->mirrorRecon ^ 1].status = UCBF_MIRRORED | UCBF_MATCHED; - if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) ) - return; - padapter->reconPhase = RECON_PHASE_LAST; - return; - } -/**************************************************************** * Name: Irq_Handler :LOCAL * * Description: Interrupt handler. @@ -1066,14 +283,12 @@ { struct Scsi_Host *shost = NULL; // Pointer to host data block PADAPTER2220I padapter; // Pointer to adapter control structure - POUR_DEVICE pdev; + USHORT *pports; // I/O port array Scsi_Cmnd *SCpnt; UCHAR status; - UCHAR status1; int z; - ULONG zl; -// DEB (printk ("\npci2220i recieved interrupt\n")); +// DEB(printk ("\npci2220i recieved interrupt\n")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process { @@ -1094,264 +309,82 @@ } padapter = HOSTDATA(shost); - pdev = padapter->pdev; + pports = padapter->ports; SCpnt = padapter->SCpnt; - if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) ) + if ( !padapter->expectingIRQ ) { DEB(printk ("\npci2220i Unsolicited interrupt\n")); - STOP_HERE (); return; } padapter->expectingIRQ = 0; - outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine - - if ( padapter->failinprog ) - { - DEB (printk ("\npci2220i interrupt failover complete")); - padapter->failinprog = FALSE; - status = inb_p (padapter->regStatCmd); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - DEB (printk ("\npci2220i: interrupt failover error from drive %X", status)); - padapter->cmd = 0; - } - else - { - DEB (printk ("\npci2220i: restarting failed opertation.")); - pdev->spigot = (padapter->survivor) ? 2 : 1; - del_timer (&padapter->timer); - if ( padapter->reconPhase ) - OpDone (padapter, DID_OK << 16); - else - Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done); - return; - } - } - - if ( padapter->reconPhase ) - { - switch ( padapter->reconPhase ) - { - case RECON_PHASE_MARKING: - case RECON_PHASE_LAST: - status = inb_p (padapter->regStatCmd); // read the device status - del_timer (&padapter->timer); - if ( padapter->reconPhase == RECON_PHASE_LAST ) - { - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - padapter->survivor = (pdev->spigot ^ 3) >> 1; - DEB (printk ("\npci2220i: FAILURE 10")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DecodeError (padapter, status)); - return; - } - if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) - { - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 11")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DecodeError (padapter, status)); - return; - } - padapter->reconPhase = RECON_PHASE_END; - return; - } - OpDone (padapter, DID_OK << 16); - return; - - case RECON_PHASE_READY: - status = inb_p (padapter->regStatCmd); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - del_timer (&padapter->timer); - OpDone (padapter, DecodeError (padapter, status)); - return; - } - SelectSpigot (padapter, pdev->hotRecon); - if ( WaitDrq (padapter) ) - { - del_timer (&padapter->timer); - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 12")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DecodeError (padapter, status)); - return; - } - SelectSpigot (padapter, pdev->spigot | 0x40); - padapter->reconPhase = RECON_PHASE_COPY; - padapter->expectingIRQ = TRUE; - if ( padapter->timingPIO ) - { - insw (padapter->regData, Buffer, padapter->reconSize * (BYTES_PER_SECTOR / 2)); - } - else - { - outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (Buffer), padapter->regDmaAddrPci); - outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount); - outb_p (8, padapter->regDmaDesc); // read operation - outb_p (1, padapter->regDmaMode); // no interrupt - outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear - } - return; - - case RECON_PHASE_COPY: - pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize; - case RECON_PHASE_UPDATE: - SelectSpigot (padapter, pdev->hotRecon | 0x80); - status = inb_p (padapter->regStatCmd); // read the device status - del_timer (&padapter->timer); - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 13")); - DEB (printk (" status = %X error = %X", status, inb_p (padapter->regError))); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DecodeError (padapter, status)); + status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + goto irqerror; + + switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt + { + case IDE_CMD_READ_MULTIPLE: + if ( padapter->readPhase == 1 ) // is this a bus master channel complete? + { + DEB(printk ("\npci2220i processing read interrupt cleanup")); + outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine + padapter->buffer += padapter->ide.ide.ides.sectors * 512; + if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) + { + SCpnt->result = DID_OK << 16; + padapter->SCpnt = NULL; + SCpnt->scsi_done (SCpnt); return; } - OpDone (padapter, DID_OK << 16); - return; - - case RECON_PHASE_END: - status = inb_p (padapter->regStatCmd); // read the device status - del_timer (&padapter->timer); - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + padapter->readPhase = 0; + if ( !(status = IdeCmd (padapter)) ) { - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 14")); - if ( InitFailover (padapter, pdev) ) - OpDone (padapter, DecodeError (padapter, status)); + DEB (printk ("\npci2220i interrupt complete, waiting for another")); return; } - padapter->reconOn = FALSE; - pdev->hotRecon = 0; - OpDone (padapter, DID_OK << 16); - return; - - default: - return; - } - } - - switch ( padapter->cmd ) // decide how to handle the interrupt - { - case READ_CMD: - if ( padapter->sectorCount ) + } + if ( status & IDE_STATUS_DRQ ) { - status = inb_p (padapter->regStatCmd); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - if ( pdev->raid ) - { - padapter->survivor = (pdev->spigot ^ 3) >> 1; - del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 15")); - if ( !InitFailover (padapter, pdev) ) - return; - } - break; - } - if ( padapter->timingPIO ) - { - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); - padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; - if ( !padapter->sectorCount ) - { - status = 0; - break; - } - } - else - BusMaster (padapter, 1, 1); - padapter->expectingIRQ = TRUE; + DEB(printk ("\npci2220i processing read interrupt start bus master cycle")); + outb_p (8, padapter->regDmaDesc); // read operation + padapter->readPhase = 1; + padapter->expectingIRQ = 1; + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); + outl ((ULONG)padapter->ide.ide.ides.sectors * (ULONG)512, padapter->regDmaCount); + outb_p (5, padapter->regDmaMode); // interrupt enable/disable + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear return; } - status = 0; break; - case WRITE_CMD: - SelectSpigot (padapter, pdev->spigot | 0x80); - status = inb_p (padapter->regStatCmd); // read the device status - if ( pdev->raid ) + case IDE_CMD_WRITE_MULTIPLE: + DEB(printk ("\npci2220i processing write interrupt cleanup")); + padapter->buffer += padapter->ide.ide.ides.sectors * 512; + if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) { - SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80); - status1 = inb_p (padapter->regStatCmd); // read the device status - } - else - status1 = 0; - - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) ) - { - padapter->survivor = (pdev->spigot ^ 3) >> 1; - del_timer (&padapter->timer); - SelectSpigot (padapter, pdev->spigot | 0x80); - DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError))); - if ( !InitFailover (padapter, pdev) ) - return; - } - break; + SCpnt->result = DID_OK << 16; + padapter->SCpnt = NULL; + SCpnt->scsi_done (SCpnt); + return; } - if ( pdev->raid ) + if ( !(status = IdeCmd (padapter)) ) { - if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - { - padapter->survivor = pdev->spigot >> 1; - del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError))); - if ( !InitFailover (padapter, pdev) ) - return; - status = status1; - break; - } - if ( padapter->sectorCount ) - { - status = WriteDataBoth (padapter); - if ( status ) - { - padapter->survivor = (status ^ 3) >> 1; - del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 18")); - if ( !InitFailover (padapter, pdev) ) - return; - SelectSpigot (padapter, status | 0x80); - status = inb_p (padapter->regStatCmd); // read the device status - break; - } - padapter->expectingIRQ = TRUE; - return; - } - status = 0; - break; - } - if ( padapter->sectorCount ) - { - SelectSpigot (padapter, pdev->spigot); - status = WriteData (padapter); - if ( status ) - break; - padapter->expectingIRQ = TRUE; + DEB (printk ("\npci2220i interrupt complete, waiting for another")); return; } - status = 0; break; case IDE_COMMAND_IDENTIFY: { PINQUIRYDATA pinquiryData = SCpnt->request_buffer; - PIDENTIFY_DATA pid = (PIDENTIFY_DATA)Buffer; - status = inb_p (padapter->regStatCmd); + DEB(printk ("\npci2220i processing verify interrupt cleanup")); if ( status & IDE_STATUS_DRQ ) { - insw (padapter->regData, pid, sizeof (IDENTIFY_DATA) >> 1); + insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1); memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure. pinquiryData->DeviceType = 0; @@ -1361,8 +394,8 @@ // Fill in vendor identification fields. for ( z = 0; z < 20; z += 2 ) { - pinquiryData->VendorId[z] = ((UCHAR *)pid->ModelNumber)[z + 1]; - pinquiryData->VendorId[z + 1] = ((UCHAR *)pid->ModelNumber)[z]; + pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1]; + pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z]; } // Initialize unused portion of product id. @@ -1373,32 +406,38 @@ // product revision in INQUIRY data. for ( z = 0; z < 4; z += 2 ) { - pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)pid->FirmwareRevision)[z + 1]; - pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)pid->FirmwareRevision)[z]; + pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1]; + pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z]; } - if ( pdev == padapter->device ) - *((USHORT *)(&pinquiryData->VendorSpecific)) = DEVICE_DALE_1; - - status = 0; + + SCpnt->result = DID_OK << 16; + padapter->SCpnt = NULL; + SCpnt->scsi_done (SCpnt); + return; } break; } default: - status = 0; - break; - } - - del_timer (&padapter->timer); - if ( status ) - { - DEB (printk ("\npci2220i Interupt hanlder return error")); - zl = DecodeError (padapter, status); + DEB(printk ("\npci2220i no real process here!")); + SCpnt->result = DID_OK << 16; + padapter->SCpnt = NULL; + SCpnt->scsi_done (SCpnt); + return; } - else - zl = DID_OK << 16; - OpDone (padapter, zl); +irqerror:; + DEB(printk ("\npci2220i error Device Status: %X\n", status)); + SCpnt->result = DecodeError (shost, status); + SCpnt->scsi_done (SCpnt); + } +static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) + { + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + Irq_Handler(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); } /**************************************************************** * Name: Pci2220i_QueueCommand @@ -1417,182 +456,121 @@ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information UCHAR rc; // command return code - int z; - PDEVICE_RAID1 pdr; SCpnt->scsi_done = done; + padapter->ide.ide.ides.spigot = pdev->spigot; padapter->buffer = SCpnt->request_buffer; - padapter->SCpnt = SCpnt; // Save this command data - if ( !done ) - { - printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb); - return 0; - } - - if ( padapter->reconPhase ) - return 0; - if ( padapter->reconTimer.data ) + if (done) { - del_timer (&padapter->reconTimer); - padapter->reconTimer.data = 0; + if ( !pdev->device ) + { + SCpnt->result = DID_BAD_TARGET << 16; + done (SCpnt); + return 0; + } } - - if ( !pdev->device || SCpnt->lun ) + else { - OpDone (padapter, DID_BAD_TARGET << 16); + printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb); return 0; } - + DEB (if(*cdb) printk ("\nCDB: %X- %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9])); switch ( *cdb ) { case SCSIOP_INQUIRY: // inquiry CDB { - if ( cdb[2] == SC_MY_RAID ) - { - switch ( cdb[3] ) - { - case MY_SCSI_REBUILD: - padapter->reconOn = padapter->reconIsStarting = TRUE; - OpDone (padapter, DID_OK << 16); - break; - case MY_SCSI_ALARMMUTE: - MuteAlarm (padapter); - OpDone (padapter, DID_OK << 16); - break; - case MY_SCSI_DEMOFAIL: - padapter->demoFail = TRUE; - OpDone (padapter, DID_OK << 16); - break; - default: - z = cdb[5]; // get index - pdr = (PDEVICE_RAID1)SCpnt->request_buffer; - if ( padapter->raidData[z] ) - { - memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR)); - pdr->TotalSectors = padapter->device[0].blocks; - } - else - memset (pdr, 0, sizeof (DEVICE_RAID1)); - OpDone (padapter, DID_OK << 16); - break; - } - return 0; - } - padapter->cmd = IDE_COMMAND_IDENTIFY; + padapter->ide.ide.ide[6] = pdev->byte6; + padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY; break; } case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - OpDone (padapter, DID_OK << 16); + SCpnt->result = DID_OK << 16; + done (SCpnt); return 0; + case SCSIOP_READ_CAPACITY: // read capctiy CDB { PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer; pdata->blksiz = 0x20000; XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks); - OpDone (padapter, DID_OK << 16); + SCpnt->result = DID_OK << 16; + done (SCpnt); return 0; } + case SCSIOP_VERIFY: // verify CDB - padapter->startSector = XSCSI2LONG (&cdb[2]); - padapter->sectorCount = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); - padapter->cmd = IDE_COMMAND_VERIFY; + *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]); + padapter->ide.ide.ide[6] |= pdev->byte6; + padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); + padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY; break; + case SCSIOP_READ: // read10 CDB padapter->startSector = XSCSI2LONG (&cdb[2]); padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - padapter->cmd = READ_CMD; + SetupTransfer (padapter, pdev->byte6); + padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; + padapter->readPhase = 0; break; + case SCSIOP_READ6: // read6 CDB padapter->startSector = SCSI2LONG (&cdb[1]); padapter->sectorCount = cdb[4]; - padapter->cmd = READ_CMD; + SetupTransfer (padapter, pdev->byte6); + padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; + padapter->readPhase = 0; break; + case SCSIOP_WRITE: // write10 CDB padapter->startSector = XSCSI2LONG (&cdb[2]); padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - padapter->cmd = WRITE_CMD; + SetupTransfer (padapter, pdev->byte6); + padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; break; case SCSIOP_WRITE6: // write6 CDB padapter->startSector = SCSI2LONG (&cdb[1]); padapter->sectorCount = cdb[4]; - padapter->cmd = WRITE_CMD; + SetupTransfer (padapter, pdev->byte6); + padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; break; + default: DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb)); - OpDone (padapter, DID_ERROR << 16); + SCpnt->result = DID_ERROR << 16; + done (SCpnt); return 0; } - if ( padapter->reconPhase ) - return 0; - - padapter->pdev = pdev; + padapter->SCpnt = SCpnt; // Save this command data - while ( padapter->demoFail ) + rc = IdeCmd (padapter); + if ( rc ) { - padapter->demoFail = FALSE; - if ( !pdev->raid || - (pdev->DiskMirror[0].status & UCBF_SURVIVOR) || - (pdev->DiskMirror[1].status & UCBF_SURVIVOR) ) - { - break; - } - if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) - padapter->survivor = 1; - else - padapter->survivor = 0; - DEB (printk ("\npci2220i: FAILURE 19")); - if ( InitFailover (padapter, pdev ) ) - break; + padapter->expectingIRQ = 0; + DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd)); + SCpnt->result = DID_ERROR << 16; + done (SCpnt); return 0; } - - StartTimer (padapter); - if ( pdev->raid && (padapter->cmd == WRITE_CMD) ) - { - rc = IdeCmdBoth (padapter); - if ( !rc ) - rc = WriteDataBoth (padapter); - if ( rc ) - { - del_timer (&padapter->timer); - padapter->expectingIRQ = 0; - padapter->survivor = (rc ^ 3) >> 1; - DEB (printk ("\npci2220i: FAILURE 20")); - if ( InitFailover (padapter, pdev) ) - { - OpDone (padapter, DID_ERROR << 16); - return 0; - } - } - } - else + if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) { - rc = IdeCmd (padapter, pdev); - if ( (padapter->cmd == WRITE_CMD) && !rc ) - rc = WriteData (padapter); - if ( rc ) + if ( WriteData (padapter) ) { - del_timer (&padapter->timer); padapter->expectingIRQ = 0; - if ( pdev->raid ) - { - padapter->survivor = (pdev->spigot ^ 3) >> 1; - DEB (printk ("\npci2220i: FAILURE 21")); - if ( !InitFailover (padapter, pdev) ) - return 0; - } - OpDone (padapter, DID_ERROR << 16); + DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to accept data\n", *cdb, padapter->ide.ide.ides.cmd)); + SCpnt->result = DID_ERROR << 16; + done (SCpnt); return 0; } } + DEB (printk(" now waiting for initial interrupt ")); return 0; } -static void internal_done(Scsi_Cmnd *SCpnt) +static void internal_done(Scsi_Cmnd * SCpnt) { SCpnt->SCp.Status++; } @@ -1608,7 +586,10 @@ ****************************************************************/ int Pci2220i_Command (Scsi_Cmnd *SCpnt) { + DEB(printk("pci2220i_command: ..calling pci2220i_queuecommand\n")); + Pci2220i_QueueCommand (SCpnt, internal_done); + SCpnt->SCp.Status = 0; while (!SCpnt->SCp.Status) barrier (); @@ -1619,7 +600,7 @@ * * Description: Read information from controller Flash memory. * - * Parameters: padapter - Pointer to host interface data structure. + * Parameters: hostdata - Pointer to host interface data structure. * pdata - Pointer to data structures. * base - base address in Flash. * length - lenght of data space in bytes. @@ -1627,24 +608,25 @@ * Returns: Nothing. * ****************************************************************/ -VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length) +VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length) { ULONG oldremap; UCHAR olddesc; ULONG z; UCHAR *pd = (UCHAR *)pdata; - oldremap = inl (padapter->regRemap); // save values to restore later - olddesc = inb_p (padapter->regDesc); + oldremap = inl (hostdata->regRemap); // save values to restore later + olddesc = inb_p (hostdata->regDesc); - outl (base | 1, padapter->regRemap); // remap to Flash space as specified - outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit + outl (base | 1, hostdata->regRemap); // remap to Flash space as specified + outb_p (0x40, hostdata->regDesc); // describe remap region as 8 bit for ( z = 0; z < length; z++) // get "length" data count - *pd++ = inb_p (padapter->regBase + z); // read in the data + *pd++ = inb_p (hostdata->regBase + z); // read in the data - outl (oldremap, padapter->regRemap); // restore remap register values - outb_p (olddesc, padapter->regDesc); + outl (oldremap, hostdata->regRemap); // restore remap register values + outb_p (olddesc, hostdata->regDesc); } + /**************************************************************** * Name: Pci2220i_Detect * @@ -1657,183 +639,109 @@ ****************************************************************/ int Pci2220i_Detect (Scsi_Host_Template *tpnt) { - int pci_index = 0; + struct pci_dev *pdev = NULL; struct Scsi_Host *pshost; - PADAPTER2220I padapter; + PADAPTER2220I hostdata; + ULONG modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P}; int unit; int z; - USHORT zs; - USHORT raidon = FALSE; int setirq; - UCHAR spigot1 = FALSE; - UCHAR spigot2 = FALSE; - if ( pcibios_present () ) - { - for ( pci_index = 0; pci_index <= MAXADAPTER; ++pci_index ) + if ( pci_present () ) + while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_DALE_1, pdev))) { - UCHAR pci_bus, pci_device_fn; - - if ( pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, pci_index, &pci_bus, &pci_device_fn) != 0 ) - break; - pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); - padapter = HOSTDATA(pshost); - memset (padapter, 0, sizeof (ADAPTER2220I)); + hostdata = HOSTDATA(pshost); - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zs); - zs &= 0xFFFE; - padapter->basePort = zs; - padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap - padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor - padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range - padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status - padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address - - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zs); - zs &= 0xFFFE; - padapter->regBase = zs; - padapter->regData = zs + REG_DATA; // data register I/O address - padapter->regError = zs + REG_ERROR; // error register I/O address - padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address - padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA - padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA - padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA - padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA - padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register - padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register - padapter->regFail = zs + REG_FAIL; - padapter->regAltStat = zs + REG_ALT_STAT; - - padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer - padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register - padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA - padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA - padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count - padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control + hostdata->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + DEB (printk ("\nBase Regs = %#04X", hostdata->basePort)); + hostdata->regRemap = hostdata->basePort + RTR_LOCAL_REMAP; // 32 bit local space remap + DEB (printk (" %#04X", hostdata->regRemap)); + hostdata->regDesc = hostdata->basePort + RTR_REGIONS; // 32 bit local region descriptor + DEB (printk (" %#04X", hostdata->regDesc)); + hostdata->regRange = hostdata->basePort + RTR_LOCAL_RANGE; // 32 bit local range + DEB (printk (" %#04X", hostdata->regRange)); + hostdata->regIrqControl = hostdata->basePort + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status + DEB (printk (" %#04X", hostdata->regIrqControl)); + hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX; // 16 byte scratchpad I/O base address + DEB (printk (" %#04X", hostdata->regScratchPad)); + + hostdata->regBase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; + for ( z = 0; z < 9; z++ ) // build regester address array + hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4); + hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL; + hostdata->ports[PORT_ALT_STAT] = hostdata->regBase + REG_ALT_STAT; + DEB (printk ("\nPorts =")); + DEB (for (z=0;z<11;z++) printk(" %#04X", hostdata->ports[z]);); + + hostdata->regDmaDesc = hostdata->regBase + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer + DEB (printk ("\nDMA Regs = %#04X", hostdata->regDmaDesc)); + hostdata->regDmaCmdStat = hostdata->regBase + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register + DEB (printk (" %#04X", hostdata->regDmaCmdStat)); + hostdata->regDmaAddrPci = hostdata->regBase + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA + DEB (printk (" %#04X", hostdata->regDmaAddrPci)); + hostdata->regDmaAddrLoc = hostdata->regBase + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA + DEB (printk (" %#04X", hostdata->regDmaAddrLoc)); + hostdata->regDmaCount = hostdata->regBase + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count + DEB (printk (" %#04X", hostdata->regDmaCount)); + hostdata->regDmaMode = hostdata->regBase + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control + DEB (printk (" %#04X", hostdata->regDmaMode)); - if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board + if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board goto unregister; - pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); + pshost->irq = pdev->irq; setirq = 1; - for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts + for ( z = 0; z < NumAdapters; z++ ) // scan for shared interrupts { - if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses + if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses setirq = 0; } - if ( setirq ) // if not shared, posses + if ( setirq ) // if not shared, posses { - if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) ) + if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) ) { printk ("Unable to allocate IRQ for PSI-2220I controller.\n"); goto unregister; } } - PsiHost[pci_index] = pshost; // save SCSI_HOST pointer + PsiHost[NumAdapters] = pshost; // save SCSI_HOST pointer - pshost->unique_id = padapter->regBase; + pshost->unique_id = hostdata->regBase; pshost->max_id = 4; - outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it - - padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE); - if ( padapter->timingMode >= 2 ) - padapter->timingAddress = ModeArray[padapter->timingMode - 2]; - else - padapter->timingPIO = TRUE; - - ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); - for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z ) - { - unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F; - padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit); - padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); - padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1)); - padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors; - padapter->device[z].heads = DaleSetup.setupDevice[unit].heads; - padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders; - padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks; + outb_p (0x01, hostdata->regRange); // fix our range register because other drivers want to tromp on it - if ( !z ) - { - ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror)); - DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS); - DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS); - if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) && - (DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) ) - { - raidon = TRUE; - } - - memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror)); - padapter->raidData[0] = &padapter->device[z].DiskMirror[0]; - padapter->raidData[2] = &padapter->device[z].DiskMirror[1]; - - if ( raidon ) - { - padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0); - padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0); - - if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] ) - spigot1 = TRUE; - if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] ) - spigot2 = TRUE; - if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR ) - spigot1 = TRUE; - - if ( spigot1 && spigot2 ) - { - padapter->device[z].raid = 1; - if ( DiskMirror[0].status & UCBF_REBUILD ) - padapter->device[z].spigot = 2; - else - padapter->device[z].spigot = 1; - if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) ) - { - padapter->reconOn = padapter->reconIsStarting = TRUE; - } - } - else - { - if ( spigot1 ) - { - if ( DiskMirror[0].status & UCBF_REBUILD ) - goto unregister; - DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR; - padapter->device[z].spigot = 1; - } - else - { - if ( DiskMirror[1].status & UCBF_REBUILD ) - goto unregister; - DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR; - padapter->device[z].spigot = 2; - } - if ( DaleSetup.rebootRebuil ) - padapter->reconOn = padapter->reconIsStarting = TRUE; - } - - break; - } - } + hostdata->timingMode = inb_p (hostdata->regScratchPad + DALE_TIMING_MODE); + hostdata->timingAddress = modearray[hostdata->timingMode - 2]; + ReadFlash (hostdata, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); + + for ( z = 0; z < inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES); ++z ) + { + unit = inb_p (hostdata->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F; + hostdata->device[unit].device = inb_p (hostdata->regScratchPad + DALE_SCRATH_DEVICE_0 + unit); + hostdata->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); + hostdata->device[unit].spigot = (UCHAR)(1 << (unit >> 1)); + hostdata->device[unit].sectors = DaleSetup.setupDevice[unit].sectors; + hostdata->device[unit].heads = DaleSetup.setupDevice[unit].heads; + hostdata->device[unit].cylinders = DaleSetup.setupDevice[unit].cylinders; + hostdata->device[unit].blocks = DaleSetup.setupDevice[unit].blocks; + DEB (printk ("\nHOSTDATA->device = %X", hostdata->device[unit].device)); + DEB (printk ("\n byte6 = %X", hostdata->device[unit].byte6)); + DEB (printk ("\n spigot = %X", hostdata->device[unit].spigot)); + DEB (printk ("\n sectors = %X", hostdata->device[unit].sectors)); + DEB (printk ("\n heads = %X", hostdata->device[unit].heads)); + DEB (printk ("\n cylinders = %X", hostdata->device[unit].cylinders)); + DEB (printk ("\n blocks = %lX", hostdata->device[unit].blocks)); } - - init_timer (&padapter->timer); - padapter->timer.function = TimerExpiry; - padapter->timer.data = (unsigned long)padapter; - init_timer (&padapter->reconTimer); - padapter->reconTimer.function = ReconTimerExpiry; - padapter->reconTimer.data = (unsigned long)padapter; - printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq); - printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); - NumAdapters++; + + printk("\nPSI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", hostdata->basePort, hostdata->regBase, pshost->irq); + printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); continue; -unregister:; +unregister: scsi_unregister (pshost); + NumAdapters++; } - } - return NumAdapters; } /**************************************************************** @@ -1848,6 +756,7 @@ ****************************************************************/ int Pci2220i_Abort (Scsi_Cmnd *SCpnt) { + DEB (printk ("pci2220i_abort\n")); return SCSI_ABORT_SNOOZE; } /**************************************************************** diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/pci2220i.h linux.ac/drivers/scsi/pci2220i.h --- linux.vanilla/drivers/scsi/pci2220i.h Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/scsi/pci2220i.h Wed Mar 24 12:55:50 1999 @@ -1,7 +1,7 @@ /*+M************************************************************************* * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. * - * Copyright (c) 1999 Perceptive Solutions, Inc. + * Copyright (c) 1997 Perceptive Solutions, Inc. * * 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 @@ -25,6 +25,12 @@ * *-M*************************************************************************/ +#ifndef _PCI2220I_H +#define _PCI2220I_H + +#include +#include + #ifndef PSI_EIDE_SCSIOP #define PSI_EIDE_SCSIOP 1 @@ -40,14 +46,11 @@ #define ULONG unsigned long #define VOID void -#include "psi_dale.h" - /************************************************/ /* Timeout konstants */ /************************************************/ -#define TIMEOUT_READY 100 // 100 mSec -#define TIMEOUT_DRQ 300 // 300 mSec -#define TIMEOUT_DATA (3 * HZ) // 3 seconds +#define TIMEOUT_READY 10 // 100 mSec +#define TIMEOUT_DRQ 40 // 400 mSec /************************************************/ /* Misc. macros */ @@ -73,9 +76,6 @@ + (((long)(((UCHAR *)up)[2])) << 8) \ + ((long)(((UCHAR *)up)[3])) ) -#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel) -#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd) - /************************************************/ /* SCSI CDB operation codes */ /************************************************/ @@ -163,6 +163,8 @@ #define IDE_CMD_READ_MULTIPLE 0xC4 #define IDE_CMD_WRITE_MULTIPLE 0xC5 #define IDE_CMD_SET_MULTIPLE 0xC6 +#define IDE_COMMAND_WRITE_DMA 0xCA +#define IDE_COMMAND_READ_DMA 0xC8 #define IDE_COMMAND_IDENTIFY 0xEC // IDE status definitions @@ -185,6 +187,23 @@ #define IDE_ERROR_UNC 0x40 #define IDE_ERROR_BBK 0x80 +// IDE interface structure +typedef struct _IDE_STRUCT + { + union + { + UCHAR ide[9]; + struct + { + USHORT data; + UCHAR sectors; + UCHAR lba[4]; + UCHAR cmd; + UCHAR spigot; + } ides; + } ide; + } IDE_STRUCT; + // SCSI read capacity structure typedef struct _READ_CAPACITY_DATA { @@ -219,64 +238,73 @@ } INQUIRYDATA, *PINQUIRYDATA; // IDE IDENTIFY data -#pragma pack (1) -#pragma align 1 typedef struct _IDENTIFY_DATA { - USHORT GeneralConfiguration; // 0 - USHORT NumberOfCylinders; // 1 - USHORT Reserved1; // 2 - USHORT NumberOfHeads; // 3 - USHORT UnformattedBytesPerTrack; // 4 - USHORT UnformattedBytesPerSector; // 5 - USHORT SectorsPerTrack; // 6 - USHORT NumBytesISG; // 7 Byte Len - inter-sector gap - USHORT NumBytesSync; // 8 - sync field - USHORT NumWordsVUS; // 9 Len - Vendor Unique Info - USHORT SerialNumber[10]; // 10 - USHORT BufferType; // 20 - USHORT BufferSectorSize; // 21 - USHORT NumberOfEccBytes; // 22 - USHORT FirmwareRevision[4]; // 23 - USHORT ModelNumber[20]; // 27 - USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk - USHORT Reserved2 :8; // 47 - USHORT DoubleWordMode; // 48 flag for double word mode capable - USHORT VendorUnique1 :8; // 49 - USHORT SupportDMA :1; // 49 DMA supported - USHORT SupportLBA :1; // 49 LBA supported - USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled - USHORT SupportIORDY :1; // 49 IORDY supported - USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support - USHORT Reserved3 :3; // 49 - USHORT Reserved4; // 50 - USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO - USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO - USHORT Reserved6 :8; // 52 - DMA - USHORT DMACycleTime :8; // 52 - DMA - USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild - USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid - USHORT Reserved7 :14; // 53 - USHORT LogNumCyl; // 54 Current Translation - Num Cyl - USHORT LogNumHeads; // 55 Num Heads - USHORT LogSectorsPerTrack; // 56 Sec/Trk - ULONG LogTotalSectors; // 57 Total Sec - USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt - USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt - USHORT Reserved8 :7; // 59 - ULONG LBATotalSectors; // 60 LBA Mode - Sectors - USHORT DMASWordFlags; // 62 - USHORT DMAMWordFlags; // 63 - USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported - USHORT Reserved9 :8; // 64 - USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word - USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time - USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control - USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control - USHORT ReservedSpace[256-69]; // 69 + USHORT GeneralConfiguration; // 00 + USHORT NumberOfCylinders; // 02 + USHORT Reserved1; // 04 + USHORT NumberOfHeads; // 06 + USHORT UnformattedBytesPerTrack; // 08 + USHORT UnformattedBytesPerSector; // 0A + USHORT SectorsPerTrack; // 0C + USHORT VendorUnique1[3]; // 0E + USHORT SerialNumber[10]; // 14 + USHORT BufferType; // 28 + USHORT BufferSectorSize; // 2A + USHORT NumberOfEccBytes; // 2C + USHORT FirmwareRevision[4]; // 2E + USHORT ModelNumber[20]; // 36 + UCHAR MaximumBlockTransfer; // 5E + UCHAR VendorUnique2; // 5F + USHORT DoubleWordIo; // 60 + USHORT Capabilities; // 62 + USHORT Reserved2; // 64 + UCHAR VendorUnique3; // 66 + UCHAR PioCycleTimingMode; // 67 + UCHAR VendorUnique4; // 68 + UCHAR DmaCycleTimingMode; // 69 + USHORT TranslationFieldsValid:1; // 6A + USHORT Reserved3:15; + USHORT NumberOfCurrentCylinders; // 6C + USHORT NumberOfCurrentHeads; // 6E + USHORT CurrentSectorsPerTrack; // 70 + ULONG CurrentSectorCapacity; // 72 + USHORT Reserved4[197]; // 76 } IDENTIFY_DATA, *PIDENTIFY_DATA; -#pragma pack () -#pragma align 0 + +// Identify data without the Reserved4. +typedef struct _IDENTIFY_DATA2 { + USHORT GeneralConfiguration; // 00 + USHORT NumberOfCylinders; // 02 + USHORT Reserved1; // 04 + USHORT NumberOfHeads; // 06 + USHORT UnformattedBytesPerTrack; // 08 + USHORT UnformattedBytesPerSector; // 0A + USHORT SectorsPerTrack; // 0C + USHORT VendorUnique1[3]; // 0E + USHORT SerialNumber[10]; // 14 + USHORT BufferType; // 28 + USHORT BufferSectorSize; // 2A + USHORT NumberOfEccBytes; // 2C + USHORT FirmwareRevision[4]; // 2E + USHORT ModelNumber[20]; // 36 + UCHAR MaximumBlockTransfer; // 5E + UCHAR VendorUnique2; // 5F + USHORT DoubleWordIo; // 60 + USHORT Capabilities; // 62 + USHORT Reserved2; // 64 + UCHAR VendorUnique3; // 66 + UCHAR PioCycleTimingMode; // 67 + UCHAR VendorUnique4; // 68 + UCHAR DmaCycleTimingMode; // 69 + USHORT TranslationFieldsValid:1; // 6A + USHORT Reserved3:15; + USHORT NumberOfCurrentCylinders; // 6C + USHORT NumberOfCurrentHeads; // 6E + USHORT CurrentSectorsPerTrack; // 70 + ULONG CurrentSectorCapacity; // 72 + } IDENTIFY_DATA2, *PIDENTIFY_DATA2; + #endif // PSI_EIDE_SCSIOP // function prototypes @@ -293,24 +321,18 @@ extern struct proc_dir_entry Proc_Scsi_Pci2220i; -#define PCI2220I { NULL, NULL, \ - &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ - NULL, \ - "PCI-2220I EIDE Disk Controller", \ - Pci2220i_Detect, \ - NULL, \ - NULL, \ - Pci2220i_Command, \ - Pci2220i_QueueCommand, \ - Pci2220i_Abort, \ - Pci2220i_Reset, \ - NULL, \ - Pci2220i_BiosParam, \ - 1, \ - -1, \ - SG_NONE, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } +#define PCI2220I { proc_dir: &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \ + name: "PCI-2220I EIDE Disk Controller",\ + detect: Pci2220i_Detect, \ + command: Pci2220i_Command, \ + queuecommand: Pci2220i_QueueCommand, \ + abort: Pci2220i_Abort, \ + reset: Pci2220i_Reset, \ + bios_param: Pci2220i_BiosParam, \ + can_queue: 1, \ + this_id: -1, \ + sg_tablesize: SG_NONE, \ + cmd_per_lun: 1, \ + use_clustering: DISABLE_CLUSTERING } +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ppa.c linux.ac/drivers/scsi/ppa.c --- linux.vanilla/drivers/scsi/ppa.c Thu Jan 14 01:25:25 1999 +++ linux.ac/drivers/scsi/ppa.c Mon Mar 1 14:24:09 1999 @@ -48,7 +48,6 @@ } #include "ppa.h" -#include #define NO_HOSTS 4 static ppa_struct ppa_hosts[NO_HOSTS] = diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/psi240i.c linux.ac/drivers/scsi/psi240i.c --- linux.vanilla/drivers/scsi/psi240i.c Sun Nov 8 15:07:56 1998 +++ linux.ac/drivers/scsi/psi240i.c Mon Jan 4 16:04:59 1999 @@ -129,7 +129,7 @@ outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256); return 0; } - } while ( timer > jiffies ); // test for timeout + } while ( time_after(timer, jiffies) ); // test for timeout padapter->ide.ide.ides.cmd = 0; // null out the command byte return 1; @@ -169,7 +169,7 @@ return 0; } - } while ( timer > jiffies ); // test for timeout + } while ( time_after(timer, jiffies) ); // test for timeout padapter->ide.ide.ides.cmd = 0; // null out the command byte return status; @@ -264,7 +264,7 @@ UCHAR status; int z; - DEB(printk ("\npsi240i recieved interrupt\n")); + DEB(printk ("\npsi240i received interrupt\n")); shost = PsiHost[irq - 10]; if ( !shost ) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfas.c linux.ac/drivers/scsi/qlogicfas.c --- linux.vanilla/drivers/scsi/qlogicfas.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/qlogicfas.c Tue Feb 23 14:26:02 1999 @@ -276,9 +276,9 @@ int i,k; k = 0; i = jiffies + WATCHDOG; - while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) + while ( time_after(i, jiffies) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) barrier(); - if (i <= jiffies) + if (time_before_eq(i, jiffies)) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -408,8 +408,8 @@ } /*** Enter Status (and Message In) Phase ***/ k = jiffies + WATCHDOG; - while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if ( k <= jiffies ) { + while ( time_after(k, jiffies) && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( time_before_eq(k, jiffies) ) { ql_zap(); return (DID_TIME_OUT << 16); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc.c linux.ac/drivers/scsi/qlogicfc.c --- linux.vanilla/drivers/scsi/qlogicfc.c Wed Mar 10 21:13:05 1999 +++ linux.ac/drivers/scsi/qlogicfc.c Tue Mar 16 19:04:21 1999 @@ -64,12 +64,13 @@ /* Configuration section **************************************************** */ /* Set the following macro to 1 to reload the ISP2100's firmware. This is - version 1.13 of the firmware. */ + version 1.15.19 of the firmware. */ #define RELOAD_FIRMWARE 1 #define USE_NVRAM_DEFAULTS 1 +#define ISP2100_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 */ @@ -316,16 +317,13 @@ /* status entry completion status definitions */ #define CS_COMPLETE 0x0000 -#define CS_INCOMPLETE 0x0001 #define CS_DMA_ERROR 0x0002 -#define CS_TRANSPORT_ERROR 0x0003 #define CS_RESET_OCCURRED 0x0004 #define CS_ABORTED 0x0005 #define CS_TIMEOUT 0x0006 #define CS_DATA_OVERRUN 0x0007 -#define CS_ABORT_MSG_FAILED 0x000e -#define CS_REJECT_MSG_FAILED 0x000f #define CS_DATA_UNDERRUN 0x0015 +#define CS_QUEUE_FULL 0x001c #define CS_PORT_UNAVAILABLE 0x0028 #define CS_PORT_LOGGED_OUT 0x0029 #define CS_PORT_CONFIG_CHANGED 0x002a @@ -645,9 +643,7 @@ static void isp2100_print_scsi_cmd(Scsi_Cmnd *); #endif -#if DEBUG_ISP2100_INTR static void isp2100_print_status_entry(struct Status_Entry *); -#endif static struct proc_dir_entry proc_scsi_isp2100 = { @@ -721,7 +717,7 @@ scsi_unregister(host); continue; } - host->this_id = tmpt->this_id; + host->this_id = 0; if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc : interrupt %d already in use\n", @@ -743,7 +739,7 @@ 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 + 20 * HZ; wait_time > jiffies && hostdata->loop_up == 0;) + for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->loop_up == 0;) barrier(); if (hostdata->loop_up == 0) { @@ -805,13 +801,17 @@ isp2100_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { - host->this_id = param[1]; hostdata->port_id = ((u_int) param[3]) << 16; hostdata->port_id |= param[2]; + temp[0].loop_id = param[1]; + temp[0].wwn = hostdata->wwn; + } + else { + printk("qlogicfc: error getting scsi id.\n"); } - for (i = 0, j = 0; i <= QLOGICFC_MAX_ID; i++) { - temp[i].loop_id = host->this_id; + for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) { + temp[i].loop_id = temp[0].loop_id; param[0] = MBOX_GET_PORT_NAME; param[1] = (i << 8) & 0xff00; @@ -848,7 +848,7 @@ } } if (j == QLOGICFC_MAX_ID + 1) - hostdata->port_db[i].loop_id = host->this_id; + hostdata->port_db[i].loop_id = temp[0].loop_id; for (j = 0; j <= QLOGICFC_MAX_ID; j++) { if (hostdata->port_db[j].wwn == temp[i].wwn || !hostdata->port_db[j].wwn) { @@ -1046,6 +1046,7 @@ host->max_id = 0; return 0; } + out_ptr = inw(host->io_port + MBOX4); in_ptr = hostdata->req_in_ptr; @@ -1099,10 +1100,13 @@ cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; +#if ISP2100_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; +#else + cmd->target_id = Cmnd->target; +#endif cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; - cmd->time_out = SCSI_TIMEOUT / HZ; - + cmd->time_out = (SCSI_TIMEOUT / HZ) * 5; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { @@ -1173,41 +1177,38 @@ if (Cmnd->device->tagged_supported) { - switch (Cmnd->tag) { - case SIMPLE_QUEUE_TAG: - cmd->control_flags |= CFLAG_SIMPLE_TAG; - break; - case HEAD_OF_QUEUE_TAG: - cmd->control_flags |= CFLAG_HEAD_TAG; - break; - case ORDERED_QUEUE_TAG: + if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { cmd->control_flags |= CFLAG_ORDERED_TAG; - break; - default: - if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (5 * HZ)) { + hostdata->tag_ages[Cmnd->target] = jiffies; + } else + switch (Cmnd->tag) { + case HEAD_OF_QUEUE_TAG: + cmd->control_flags |= CFLAG_HEAD_TAG; + break; + case ORDERED_QUEUE_TAG: cmd->control_flags |= CFLAG_ORDERED_TAG; - hostdata->tag_ages[Cmnd->target] = jiffies; - } else + break; + default: cmd->control_flags |= CFLAG_SIMPLE_TAG; + break; } } outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; hostdata->queued++; - num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); - num_free = num_free - 2; + num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); /* this is really gross */ - if (host->can_queue < host->host_busy){ + if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) - printk("qlogicfc.c crosses its fingers.\n"); - host->can_queue = host->host_busy; + DEBUG(printk("qlogicfc.c crosses its fingers.\n")); + host->can_queue = host->host_busy + 1; } LEAVE("isp2100_queuecommand"); @@ -1310,22 +1311,20 @@ while (out_ptr != in_ptr) { sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; - Cmnd = hostdata->handle_ptrs[sts->handle]; - - hostdata->handle_ptrs[sts->handle] = NULL; - - if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) { - hostdata->queued--; - hostdata->handle_serials[sts->handle] = 0; - outw(out_ptr, host->io_port + MBOX5); - continue; - } - hostdata->handle_serials[sts->handle] = 0; - + TRACE("done", out_ptr, Cmnd); DEBUG_INTR(isp2100_print_status_entry(sts)); if (sts->hdr.entry_type == ENTRY_STATUS) { + Cmnd = hostdata->handle_ptrs[sts->handle]; Cmnd->result = isp2100_return_status(sts); + hostdata->handle_ptrs[sts->handle] = NULL; + hostdata->queued--; + if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) { + hostdata->handle_serials[sts->handle] = 0; + outw(out_ptr, host->io_port + MBOX5); + continue; + } + hostdata->handle_serials[sts->handle] = 0; } else { outw(out_ptr, host->io_port + MBOX5); continue; @@ -1336,13 +1335,13 @@ || (sts->status_flags & STF_BUS_RESET)) hostdata->send_marker = 1; + memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); if (sts->scsi_status & 0x0200) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); outw(out_ptr, host->io_port + MBOX5); - hostdata->queued--; if (Cmnd->scsi_done != NULL) { (*Cmnd->scsi_done) (Cmnd); } else @@ -1356,16 +1355,16 @@ in_ptr = hostdata->req_in_ptr; num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); - num_free = num_free-2; + num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); - if (host->can_queue < host->host_busy){ + if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) DEBUG(printk("qlogicfc crosses its fingers.\n")); - host->can_queue = host->host_busy; + host->can_queue = host->host_busy + 1; } outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); @@ -1401,16 +1400,7 @@ case CS_COMPLETE: host_status = DID_OK; break; - case CS_INCOMPLETE: - if (!(sts->state_flags & SF_SENT_CDB)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_STATUS)) - host_status = DID_ERROR; - break; case CS_DMA_ERROR: - case CS_TRANSPORT_ERROR: host_status = DID_ERROR; break; case CS_RESET_OCCURRED: @@ -1423,7 +1413,6 @@ host_status = DID_TIME_OUT; break; case CS_DATA_OVERRUN: - case CS_ABORT_MSG_FAILED: host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: @@ -1434,6 +1423,9 @@ case CS_PORT_CONFIG_CHANGED: host_status = DID_BAD_TARGET; break; + case CS_QUEUE_FULL: + host_status = DID_ERROR; + break; default: printk("qlogicfc : unknown completion status 0x%04x\n", sts->completion_status); @@ -1539,8 +1531,6 @@ ip[0] = 255; ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); - if (ip[2] > 1023) - ip[2] = 1023; } LEAVE("isp2100_biosparam"); @@ -1678,9 +1668,6 @@ if (isp2100_read_nvram_word(host, 0) != 0x5349) return 1; - control_block->max_frame_len = isp2100_read_nvram_word(host, 5); - control_block->max_iocb = isp2100_read_nvram_word(host, 6); - control_block->exec_throttle = isp2100_read_nvram_word(host, 7); 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); @@ -1892,8 +1879,6 @@ } -#if DEBUG_ISP2100_INTR - void isp2100_print_status_entry(struct Status_Entry *status) { printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", @@ -1908,7 +1893,6 @@ } -#endif /* DEBUG_ISP2100_INTR */ #if DEBUG_ISP2100 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc_asm.c linux.ac/drivers/scsi/qlogicfc_asm.c --- linux.vanilla/drivers/scsi/qlogicfc_asm.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/scsi/qlogicfc_asm.c Tue Mar 16 18:58:50 1999 @@ -3,2983 +3,3290 @@ * --- ISP2100 Fabric Initiator/Target Firmware --- * * * * * - * * + ************************************************************************ + * * + * NOTICE * + * * + * COPYRIGHT 1998 QLOGIC CORPORATION * + * ALL RIGHTS RESERVED * + * * ************************************************************************ */ + /* - * Firmware Version 1.13.00 (18:06 May 04, 1998) + * Firmware Version 1.15.19 (14:58 Jan 19, 1999) */ -unsigned short risc_code_version = 1*1024+13; +unsigned short risc_code_version = 1*1024+15; + +unsigned char firmware_version[] = {1,15,19}; -unsigned char firmware_version[] = {1,13,0}; +#define FW_VERSION_STRING "1.15.19" unsigned short risc_code_addr01 = 0x1000 ; unsigned short risc_code01[] = { - 0x0078, 0x1029, 0x0000, 0x5c95, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x0078, 0x1029, 0x0000, 0x65e6, 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, 0x3133, 0x2020, 0x2020, - 0x2400, 0x20c1, 0x0021, 0x20a1, 0x6c95, 0x2009, 0x0000, 0x20a9, - 0x076b, 0x41a4, 0x3400, 0x20c9, 0x71ff, 0x2091, 0x2000, 0x2059, - 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x1e36, 0x2051, 0x6d00, - 0x2a70, 0x705b, 0x8c00, 0x705f, 0xffff, 0x7057, 0x8bf9, 0x7063, - 0x0300, 0x1078, 0x1264, 0x20a1, 0x7400, 0x715c, 0x810d, 0x810d, + 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, + 0x2a70, 0x705b, 0x9500, 0x705f, 0xffff, 0x7057, 0x94f9, 0x7063, + 0x0300, 0x1078, 0x1282, 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, 0x122b, 0x1078, 0x134e, 0x1078, 0x14d3, 0x1078, 0x17d7, - 0x1078, 0x324a, 0x1078, 0x54fc, 0x1078, 0x12d9, 0x1078, 0x2191, - 0x1078, 0x3875, 0x1078, 0x3655, 0x1078, 0x4064, 0x1078, 0x1c35, - 0x1078, 0x4213, 0x1078, 0x3d73, 0x1078, 0x1b5d, 0x1078, 0x1c14, + 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, 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, 0x2a96, 0x1078, 0x21b9, 0x1078, 0x38c5, - 0x1078, 0x373c, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, - 0x10c1, 0x1078, 0x4078, 0x0078, 0x10a4, 0x1079, 0x10c5, 0x0078, - 0x10aa, 0x1078, 0x52d8, 0x0078, 0x10b9, 0x10cf, 0x10d0, 0x1151, - 0x10cd, 0x11aa, 0x1228, 0x1229, 0x122a, 0x1078, 0x12b7, 0x007c, - 0x127e, 0x0f7e, 0x2091, 0x8000, 0x1078, 0x2aec, 0x2079, 0x0100, - 0x7844, 0xa005, 0x00c0, 0x1142, 0x2011, 0x318e, 0x1078, 0x40d1, + 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, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, - 0x73b8, 0x1078, 0x2a53, 0x1078, 0x5129, 0x2011, 0x0004, 0x1078, - 0x6135, 0x1078, 0x35ef, 0x70c7, 0x0000, 0x70bf, 0x0000, 0x70c3, - 0x0000, 0x1078, 0x1145, 0x2011, 0x0000, 0x2079, 0x6d51, 0x7804, + 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, 0x6135, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, - 0x0f7f, 0x1078, 0x1ee6, 0x2011, 0x0005, 0x1078, 0x5232, 0x1078, - 0x476a, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x127f, - 0x0078, 0x1144, 0x7003, 0x0003, 0x2001, 0x0000, 0x1078, 0x1dc9, - 0x2011, 0x0000, 0x1078, 0x5232, 0x2011, 0x0000, 0x1078, 0x523c, - 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x1078, 0x476a, - 0x1078, 0x4821, 0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, - 0x2009, 0x007e, 0x1078, 0x342f, 0x8108, 0x00f0, 0x114a, 0x0c7f, - 0x007c, 0x127e, 0x2091, 0x8000, 0x708c, 0xa086, 0xffff, 0x0040, - 0x115f, 0x1078, 0x1ee6, 0x1078, 0x476a, 0x0078, 0x11a8, 0x70bc, - 0xd09c, 0x0040, 0x1187, 0xd084, 0x0040, 0x1187, 0x0f7e, 0x2079, - 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, 0x0040, 0x1187, - 0x70c0, 0xa086, 0xffff, 0x0040, 0x1183, 0x1078, 0x1fdb, 0x1078, - 0x476a, 0x2011, 0x0001, 0x2019, 0x0000, 0x1078, 0x2013, 0x1078, - 0x476a, 0x0078, 0x11a8, 0x70c4, 0xa005, 0x00c0, 0x11a8, 0x7088, - 0xa005, 0x00c0, 0x11a8, 0x7003, 0x0003, 0x708f, 0xffff, 0x2001, - 0x0000, 0x1078, 0x1dc9, 0x1078, 0x2ad1, 0x2001, 0x6f11, 0x2004, - 0xa086, 0x0005, 0x00c0, 0x11a0, 0x2011, 0x0000, 0x1078, 0x5232, - 0x2011, 0x0000, 0x1078, 0x523c, 0x1078, 0x476a, 0x1078, 0x4821, - 0x127f, 0x007c, 0x017e, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, - 0x0100, 0x7843, 0x0000, 0x7924, 0xd1b4, 0x0040, 0x11b9, 0x7827, - 0x0040, 0xd19c, 0x0040, 0x11be, 0x7827, 0x0008, 0x007e, 0x037e, - 0x157e, 0x7900, 0xa18a, 0x0003, 0x0050, 0x11e4, 0x7954, 0xd1ac, - 0x00c0, 0x11e4, 0x2009, 0x00f8, 0x1078, 0x3233, 0x7843, 0x0090, - 0x7843, 0x0010, 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x11dc, - 0x7824, 0xd0ac, 0x00c0, 0x1218, 0x00f0, 0x11d4, 0x2001, 0x0001, - 0x1078, 0x1dc9, 0x0078, 0x1221, 0x7853, 0x0000, 0x782f, 0x0020, - 0x20a9, 0x0008, 0x00e0, 0x11ea, 0x2091, 0x6000, 0x00f0, 0x11ea, - 0x7853, 0x0400, 0x782f, 0x0000, 0x2009, 0x00f8, 0x1078, 0x3233, - 0x20a9, 0x000e, 0x0005, 0x00f0, 0x11fa, 0x7853, 0x1400, 0x7843, - 0x0090, 0x7843, 0x0010, 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, - 0xd08c, 0x0040, 0x120f, 0x7824, 0xd0ac, 0x00c0, 0x1218, 0x8319, - 0x00c0, 0x1205, 0x2001, 0x0001, 0x1078, 0x1dc9, 0x0078, 0x121f, - 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, 0x1237, 0x704f, 0xffff, 0x0078, 0x1239, 0x704f, - 0x0000, 0x7053, 0xffff, 0x7067, 0x0000, 0x706b, 0x0000, 0x2061, - 0x6f00, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, - 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, - 0x07d0, 0x2061, 0x6f08, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, - 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, - 0x0001, 0x601f, 0x0000, 0x007c, 0x1078, 0x128a, 0x2011, 0x0000, - 0x81ff, 0x0040, 0x1289, 0xa186, 0x0001, 0x00c0, 0x1279, 0x705f, - 0x8fff, 0x7057, 0x7c01, 0x7063, 0x0100, 0x705b, 0x7c00, 0x0078, - 0x1287, 0xa186, 0x0002, 0x00c0, 0x1281, 0x2011, 0x0000, 0x0078, - 0x1287, 0xa186, 0x0005, 0x00c0, 0x1287, 0x2011, 0x0001, 0x1078, - 0x12b1, 0x007c, 0x2009, 0x0000, 0x2011, 0x0000, 0x1078, 0x12b1, - 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2362, 0x2c24, 0x2061, 0x7fff, - 0x2c04, 0xa406, 0x0040, 0x129f, 0xc18d, 0x0078, 0x12ac, 0xc185, - 0x2011, 0x0001, 0x1078, 0x12b1, 0x2061, 0xffff, 0x2362, 0x2c04, - 0xa306, 0x00c0, 0x12ac, 0xc195, 0x2011, 0x0001, 0x1078, 0x12b1, - 0x007c, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x007c, 0x2091, - 0x8000, 0x0068, 0x12b9, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, - 0xa084, 0x0000, 0x00c0, 0x12bf, 0x017f, 0x792e, 0x007f, 0x782a, - 0x007f, 0x7826, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x2079, 0x6d00, 0x7803, 0x0005, 0x0078, 0x12d6, - 0x007c, 0x2071, 0x6d00, 0x7158, 0x712e, 0x2021, 0x0001, 0xa190, - 0x002d, 0xa298, 0x002d, 0x0048, 0x12ef, 0x705c, 0xa302, 0x00c8, - 0x12ef, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x12e1, 0x200b, + 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, + 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, + 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, + 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, + 0x0010, 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, + 0x122d, 0x7824, 0xd0ac, 0x00c0, 0x1236, 0x8319, 0x00c0, 0x1223, + 0x2001, 0x0001, 0x1078, 0x202b, 0x0078, 0x123d, 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, + 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, + 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, + 0xa084, 0xfffc, 0xa205, 0x20c0, 0x007c, 0x2091, 0x8000, 0x0068, + 0x12d7, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, + 0x00c0, 0x12dd, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, + 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, + 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12f6, + 0x007c, 0x2071, 0x7600, 0x7158, 0x712e, 0x2021, 0x0001, 0xa190, + 0x002d, 0xa298, 0x002d, 0x0048, 0x130f, 0x705c, 0xa302, 0x00c8, + 0x130f, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x1301, 0x200b, 0x0000, 0x749e, 0x74a2, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, - 0x2071, 0x6d00, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x1302, 0xa06e, - 0x0078, 0x130c, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, + 0x2071, 0x7600, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x1322, 0xa06e, + 0x0078, 0x132c, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, - 0x2071, 0x6d00, 0x127e, 0x2091, 0x8000, 0x70a0, 0x8001, 0x00c8, - 0x131c, 0xa06e, 0x0078, 0x1325, 0x70a2, 0x702c, 0x2068, 0x2d04, + 0x2071, 0x7600, 0x127e, 0x2091, 0x8000, 0x70a0, 0x8001, 0x00c8, + 0x133c, 0xa06e, 0x0078, 0x1345, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, - 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x6d00, 0x702c, 0x206a, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, 0x8000, 0x70a2, 0x127f, 0x0e7f, 0x007c, - 0x8dff, 0x0040, 0x1344, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, - 0x1328, 0x0d7f, 0x0078, 0x1338, 0x007c, 0x0e7e, 0x2071, 0x6d00, + 0x8dff, 0x0040, 0x1364, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, + 0x1348, 0x0d7f, 0x0078, 0x1358, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x70a0, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, 0x0e7e, 0x2071, - 0x6f31, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, + 0x7859, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, 0x007c, 0x0e7e, - 0x2270, 0x700b, 0x0000, 0x2071, 0x6f31, 0x7018, 0xa088, 0x6f3a, + 0x2270, 0x700b, 0x0000, 0x2071, 0x7859, 0x7018, 0xa088, 0x7862, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, - 0x1377, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1388, 0x0f7f, 0x0e7f, - 0x007c, 0x0e7e, 0x2071, 0x6f31, 0x7004, 0xa005, 0x00c0, 0x1386, - 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1388, 0x0f7f, 0x0e7f, 0x007c, - 0x7000, 0x0079, 0x138b, 0x138f, 0x13f9, 0x1416, 0x1416, 0x7018, - 0x711c, 0xa106, 0x00c0, 0x1397, 0x7007, 0x0000, 0x007c, 0x0d7e, - 0xa180, 0x6f3a, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, + 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, + 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, 0x13b9, 0x7007, 0x0001, 0x1078, 0x13be, - 0x007c, 0x7007, 0x0002, 0x1078, 0x13d4, 0x007c, 0x017e, 0x027e, - 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13c9, 0x2110, + 0x0d7f, 0xd084, 0x0040, 0x13d9, 0x7007, 0x0001, 0x1078, 0x13de, + 0x007c, 0x7007, 0x0002, 0x1078, 0x13f4, 0x007c, 0x017e, 0x027e, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13e9, 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, 0x13e8, 0x2110, 0xa006, + 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1408, 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0001, 0x3300, 0x7016, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, - 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x6dc5, 0x20a1, 0x0018, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x76e5, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, - 0x6dc0, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e, - 0x157e, 0x2001, 0x6df4, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, - 0x2001, 0x6df5, 0x20ac, 0x53a6, 0x2099, 0x6df6, 0x20a1, 0x0018, + 0x76e0, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e, + 0x157e, 0x2001, 0x7714, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, + 0x2001, 0x7715, 0x20ac, 0x53a6, 0x2099, 0x7716, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, - 0x6df1, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e, - 0x2071, 0x6f31, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, - 0xd1fc, 0x0040, 0x1459, 0xa18c, 0x0700, 0x0040, 0x1456, 0x7008, - 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, 0x1459, 0x7004, 0x1079, - 0x145d, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x1388, 0x1465, 0x1487, - 0x14a1, 0x14ca, 0x1463, 0x0078, 0x1463, 0x137e, 0x147e, 0x157e, + 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, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f, 0x137f, 0x700c, 0xa005, - 0x0040, 0x148e, 0x1078, 0x13be, 0x007c, 0x7008, 0xa080, 0x0002, - 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x1388, 0x007c, 0x700c, - 0xa005, 0x0040, 0x148e, 0x1078, 0x13d4, 0x007c, 0x0d7e, 0x7008, + 0x0040, 0x14ae, 0x1078, 0x13de, 0x007c, 0x7008, 0xa080, 0x0002, + 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x13a8, 0x007c, 0x700c, + 0xa005, 0x0040, 0x14ae, 0x1078, 0x13f4, 0x007c, 0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, - 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x1388, - 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x6dc3, 0x2004, 0xa080, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a8, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x76e3, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, - 0x53a5, 0x2001, 0x6dc5, 0x2004, 0xd0bc, 0x0040, 0x14c0, 0x2001, - 0x6dce, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, - 0x157f, 0x147f, 0x137f, 0x7007, 0x0000, 0x1078, 0x396e, 0x1078, - 0x1388, 0x007c, 0x2001, 0x6df3, 0x2003, 0x0100, 0x7007, 0x0000, - 0x1078, 0x1388, 0x007c, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, - 0x2071, 0x6f42, 0x7003, 0x0000, 0x700f, 0x6f48, 0x7013, 0x6f48, + 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14e0, 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, + 0x2071, 0x786a, 0x7003, 0x0000, 0x700f, 0x7870, 0x7013, 0x7870, 0x780f, 0x0070, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079, - 0x14e9, 0x14f1, 0x151b, 0x14f1, 0x14f1, 0x14f1, 0x1500, 0x14f1, - 0x14f5, 0xa085, 0x0001, 0x0078, 0x1531, 0x684c, 0xd0bc, 0x0040, - 0x14f1, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x1523, - 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, 0x14f1, 0x684c, 0xd0ac, - 0x0040, 0x14f1, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, - 0x000f, 0xa080, 0x1a82, 0x2004, 0x6832, 0xa006, 0x682e, 0x682a, - 0x6858, 0x0078, 0x152b, 0x684c, 0xd0ac, 0x0040, 0x14f1, 0xa006, - 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, 0x1a82, 0x210c, - 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, - 0x680a, 0x007c, 0x82ff, 0x0040, 0x1545, 0xa280, 0x0004, 0x0d7e, - 0x206c, 0x684c, 0xd0dc, 0x00c0, 0x1541, 0x1078, 0x14e4, 0x10c0, - 0x12b7, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, - 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, - 0x00c0, 0x1559, 0x7206, 0x2001, 0x156d, 0x007e, 0x2260, 0x0078, - 0x164f, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, - 0xa182, 0x6f63, 0x0048, 0x1566, 0x2009, 0x6f48, 0x710e, 0x7000, - 0xa005, 0x00c0, 0x156d, 0x1078, 0x1638, 0x127f, 0x007c, 0x127e, - 0x027e, 0x037e, 0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, - 0x037f, 0x027f, 0x0c7e, 0x0d7e, 0x2460, 0x6110, 0x2168, 0x6a62, - 0x6b5e, 0xa005, 0x0040, 0x15bc, 0x6808, 0xa005, 0x0040, 0x15ea, - 0x7000, 0xa005, 0x00c0, 0x158e, 0x0078, 0x15b4, 0x700c, 0x7110, - 0xa106, 0x00c0, 0x15ba, 0x7004, 0xa406, 0x00c0, 0x15b4, 0x2001, - 0x0005, 0x2004, 0xd08c, 0x00c0, 0x15ee, 0x2001, 0x0207, 0x2004, - 0xd09c, 0x00c0, 0x1597, 0x7804, 0xa084, 0x6000, 0x0040, 0x15ae, - 0xa086, 0x6000, 0x0040, 0x15ae, 0x0078, 0x1597, 0x7803, 0x0004, - 0x7003, 0x0000, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5591, - 0x0078, 0x15ee, 0x0078, 0x15ee, 0x6808, 0xa005, 0x0040, 0x15ea, - 0x7000, 0xa005, 0x00c0, 0x15c6, 0x0078, 0x15ea, 0x700c, 0x7110, - 0xa106, 0x00c0, 0x15ba, 0x7004, 0xa406, 0x00c0, 0x15ea, 0x2001, - 0x0005, 0x2004, 0xd08c, 0x00c0, 0x15ee, 0x2001, 0x0207, 0x2004, - 0xd09c, 0x00c0, 0x15cf, 0x7804, 0xa084, 0x6000, 0x0040, 0x15e6, - 0xa086, 0x6000, 0x0040, 0x15e6, 0x0078, 0x15cf, 0x7803, 0x0004, - 0x7003, 0x0000, 0x2009, 0x0048, 0x1078, 0x5591, 0x0d7f, 0x0c7f, - 0x127f, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x6f42, 0x7000, 0xa086, - 0x0000, 0x0040, 0x1635, 0x7004, 0xac06, 0x00c0, 0x1626, 0x2079, - 0x0030, 0x7804, 0xd0fc, 0x00c0, 0x1622, 0x2001, 0x0207, 0x2004, - 0xd09c, 0x00c0, 0x1601, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, - 0x160d, 0x7908, 0xd1ec, 0x00c0, 0x1619, 0x2009, 0x0009, 0x0078, - 0x161b, 0x2009, 0x0019, 0x7803, 0x0002, 0x7902, 0x7003, 0x0003, - 0x0078, 0x1635, 0x1078, 0x16e5, 0x0078, 0x15f6, 0x157e, 0x20a9, - 0x0009, 0x2009, 0x6f48, 0x2104, 0xac06, 0x00c0, 0x1630, 0x200a, - 0xa188, 0x0003, 0x00f0, 0x162b, 0x157f, 0x0e7f, 0x0f7f, 0x007c, - 0x700c, 0x7110, 0xa106, 0x00c0, 0x1640, 0x7003, 0x0000, 0x007c, - 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, - 0xa182, 0x6f63, 0x0048, 0x164e, 0x2009, 0x6f48, 0x7112, 0x8cff, - 0x00c0, 0x1658, 0x7803, 0x0019, 0x7003, 0x0003, 0x0078, 0x167b, - 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, 0x00c0, 0x1663, 0x682c, - 0xa306, 0x0040, 0x1667, 0x1078, 0x1aa2, 0x00c0, 0x1652, 0x6824, - 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, - 0x2009, 0x0011, 0x1078, 0x167c, 0x0040, 0x167a, 0x2009, 0x0001, - 0x1078, 0x167c, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x16e0, 0xa03e, - 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x169b, 0x0d7e, 0x2804, 0xac68, - 0x2900, 0x0079, 0x168b, 0x16ca, 0x16ab, 0x16ab, 0x16ca, 0x16ca, - 0x16c2, 0x16ca, 0x16ab, 0x16ca, 0x16b1, 0x16b1, 0x16ca, 0x16ca, - 0x16ca, 0x16ca, 0x16b1, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, - 0x6c20, 0x0d7e, 0xd99c, 0x0040, 0x16cd, 0x2804, 0xac68, 0x6f08, - 0x6e0c, 0x0078, 0x16cd, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, - 0x16cd, 0x7b0c, 0xd3bc, 0x0040, 0x16ba, 0x7b08, 0xa39c, 0x0fff, - 0x0078, 0x16bb, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, - 0x0078, 0x16cd, 0x0d7f, 0x1078, 0x1a3f, 0x00c0, 0x167c, 0xa00e, - 0x0078, 0x16e0, 0x0d7f, 0x1078, 0x12b7, 0x7b22, 0x7a26, 0x7d32, + 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, + 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, + 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, + 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, + 0x15a0, 0x7206, 0x2001, 0x15b4, 0x007e, 0x2260, 0x0078, 0x16cc, + 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, + 0x788b, 0x0048, 0x15ad, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, + 0x00c0, 0x15b4, 0x1078, 0x16b5, 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, + 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, + 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, + 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, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x0d7f, - 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x1078, 0x1a3f, - 0x007c, 0x1078, 0x12b7, 0x1078, 0x12b7, 0x127e, 0x2091, 0x2100, + 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x2300, 0x6b10, + 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, 0x6816, 0x1078, 0x1c40, + 0x007c, 0x1078, 0x12d5, 0x1078, 0x12d5, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, - 0xa184, 0x0700, 0x00c0, 0x16e3, 0xa184, 0x0003, 0xa086, 0x0003, - 0x0040, 0x16e3, 0x7000, 0x0079, 0x16fd, 0x1701, 0x1703, 0x1779, - 0x17c0, 0x1078, 0x12b7, 0x8001, 0x7002, 0xa184, 0x0880, 0x00c0, - 0x1718, 0x8aff, 0x0040, 0x175b, 0x2009, 0x0001, 0x1078, 0x167c, - 0x0040, 0x17d3, 0x2009, 0x0001, 0x1078, 0x167c, 0x0078, 0x17d3, - 0x7803, 0x0004, 0x7003, 0x0000, 0xd1dc, 0x0040, 0x1751, 0x027e, - 0x037e, 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, - 0xa213, 0x6b2a, 0x6a2e, 0x037f, 0x027f, 0x7830, 0x681e, 0x7834, - 0x6822, 0x1078, 0x1a58, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, - 0x6832, 0x7003, 0x0000, 0x6850, 0xc0fd, 0x6852, 0x6808, 0x8001, - 0x680a, 0x00c0, 0x174d, 0x684c, 0xd0e4, 0x0040, 0x174d, 0x7004, - 0x2060, 0x2009, 0x0048, 0x1078, 0x5591, 0x1078, 0x1638, 0x0078, - 0x17d3, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x1758, 0x1078, 0x6c41, - 0x057f, 0x0078, 0x1773, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, - 0x00c0, 0x1773, 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, - 0x176f, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5591, 0x1078, - 0x1638, 0x0078, 0x17d3, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, - 0x17d3, 0x8001, 0x7002, 0xd194, 0x0040, 0x178b, 0x7804, 0xd0fc, - 0x00c0, 0x16ed, 0x8aff, 0x0040, 0x17d3, 0x2009, 0x0001, 0x1078, - 0x167c, 0x0078, 0x17d3, 0xa184, 0x0880, 0x00c0, 0x1798, 0x8aff, - 0x0040, 0x17d3, 0x2009, 0x0001, 0x1078, 0x167c, 0x0078, 0x17d3, - 0x7803, 0x0004, 0x7003, 0x0000, 0xd1dc, 0x0040, 0x17b9, 0x027e, - 0x037e, 0x6b28, 0x6a2c, 0x1078, 0x1a58, 0x0d7e, 0x2804, 0xac68, - 0x6034, 0xd09c, 0x00c0, 0x17b2, 0x6808, 0xa31a, 0x680c, 0xa213, - 0x0078, 0x17b6, 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f, 0x0078, - 0x1723, 0x057e, 0x7d0c, 0x1078, 0x6c41, 0x057f, 0x0078, 0x1773, - 0x7003, 0x0000, 0x7004, 0xa00d, 0x0040, 0x17d1, 0x6808, 0x8001, - 0x680a, 0x00c0, 0x17d1, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, - 0x5591, 0x1078, 0x1638, 0x017f, 0x007f, 0x127f, 0x007c, 0x0e7e, - 0x2071, 0x6f63, 0x7003, 0x0000, 0x0e7f, 0x007c, 0x0d7e, 0xa280, - 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1836, 0x6934, 0xa184, - 0x0007, 0x0079, 0x17eb, 0x17f3, 0x1821, 0x17f3, 0x17f3, 0x17f3, - 0x1806, 0x17f3, 0x17f5, 0x1078, 0x12b7, 0x684c, 0xd0b4, 0x0040, - 0x192f, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, - 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1829, 0xa18c, 0x00ff, - 0xa186, 0x0015, 0x00c0, 0x1836, 0x684c, 0xd0b4, 0x0040, 0x192f, - 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, - 0x1a82, 0x2004, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0078, - 0x1832, 0x684c, 0xd0b4, 0x0040, 0x16e1, 0x6958, 0xa006, 0x682e, - 0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x1a82, - 0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, - 0x0f7e, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x10c0, 0x1933, 0x0e7e, - 0x0d7e, 0x2071, 0x6f63, 0x7000, 0xa005, 0x00c0, 0x18b2, 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, 0x1874, 0x017e, - 0x2009, 0x0008, 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, - 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, - 0x7004, 0x692c, 0x6814, 0xa106, 0x00c0, 0x188b, 0x6928, 0x6810, - 0xa106, 0x0040, 0x1898, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, - 0x1aa2, 0x047f, 0x037f, 0x0040, 0x1898, 0x0c7f, 0x0078, 0x18b2, - 0x8aff, 0x00c0, 0x18a0, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x18b2, - 0x127e, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, - 0x18b6, 0x0040, 0x18af, 0x2009, 0x0001, 0x1078, 0x18b6, 0x127f, - 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, - 0x057e, 0x047e, 0x037e, 0x027e, 0x8aff, 0x0040, 0x1928, 0x700c, - 0x7214, 0xa202, 0x7010, 0x7218, 0xa203, 0x0048, 0x1927, 0xa03e, - 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x18e3, 0x0d7e, 0x2804, 0xac68, - 0x2900, 0x0079, 0x18d3, 0x1909, 0x18f3, 0x18f3, 0x1909, 0x1909, - 0x1901, 0x1909, 0x18f3, 0x1909, 0x18f9, 0x18f9, 0x1909, 0x1909, - 0x1909, 0x1909, 0x18f9, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, - 0x6c20, 0xd99c, 0x0040, 0x190d, 0x0d7e, 0x2804, 0xac68, 0x6f08, - 0x6e0c, 0x0078, 0x190c, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, - 0x190c, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, - 0x190c, 0x0d7f, 0x1078, 0x1a3f, 0x00c0, 0x18bc, 0xa00e, 0x0078, - 0x1928, 0x0d7f, 0x1078, 0x12b7, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, - 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, - 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, - 0x7010, 0xa201, 0x7012, 0x1078, 0x1a3f, 0x0078, 0x1928, 0xa006, - 0x027f, 0x037f, 0x047f, 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, - 0x12b7, 0x1078, 0x12b7, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0x6f63, - 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, - 0x00c0, 0x1931, 0x7000, 0x0079, 0x194d, 0x1a09, 0x1951, 0x19d6, - 0x1a07, 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1965, 0x8aff, 0x0040, - 0x199a, 0x2009, 0x0001, 0x1078, 0x18b6, 0x0040, 0x1a09, 0x2009, - 0x0001, 0x1078, 0x18b6, 0x0078, 0x1a09, 0x7803, 0x0004, 0xd194, - 0x0040, 0x1975, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1990, - 0x684c, 0xc0f5, 0x684e, 0x0078, 0x1990, 0x027e, 0x037e, 0x6b28, - 0x6a2c, 0x701c, 0xa005, 0x10c0, 0x1a11, 0x7820, 0x686e, 0xa31a, - 0x7824, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x037f, 0x027f, 0x7830, - 0x681e, 0x7834, 0x6822, 0x1078, 0x1a58, 0x6850, 0xc0fd, 0x6852, - 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, - 0x0078, 0x1a09, 0x711c, 0x81ff, 0x0040, 0x19af, 0x7922, 0x7827, + 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, + 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x7820, + 0x6910, 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x037f, + 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c59, 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, + 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, + 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, + 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, 0x7816, + 0x0078, 0x18d6, 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, + 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, + 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, + 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, + 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, + 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, 0x1a09, 0x0f7e, + 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, 0x1c11, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x7820, 0xd0bc, 0x00c0, - 0x19bd, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, 0x007f, 0xa102, + 0x1bc5, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, 0x007f, 0xa102, 0x78c6, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, - 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1a09, 0x8001, 0x7002, - 0xd194, 0x0040, 0x19eb, 0x7804, 0xd0fc, 0x00c0, 0x1943, 0xd19c, - 0x00c0, 0x1a05, 0x8aff, 0x0040, 0x1a09, 0x2009, 0x0001, 0x1078, - 0x18b6, 0x0078, 0x1a09, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, - 0x1a58, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x19fe, - 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1a02, 0x6810, 0xa31a, - 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1979, 0x0078, 0x1975, 0x1078, - 0x12b7, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, - 0x007c, 0x7920, 0xa108, 0x7922, 0x7924, 0xa189, 0x0000, 0x7926, - 0x7930, 0xa10a, 0x7932, 0x7934, 0xa18b, 0x0000, 0x7936, 0x007c, - 0x0f7e, 0x0e7e, 0x2071, 0x6f63, 0x7000, 0xa086, 0x0000, 0x0040, - 0x1a3c, 0x2079, 0x0020, 0x7804, 0xa084, 0x0003, 0x0040, 0x1a36, - 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1a32, 0x20e1, 0x9040, - 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, 0x8840, - 0x2804, 0xa005, 0x00c0, 0x1a53, 0x6004, 0xa005, 0x0040, 0x1a55, - 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x1a82, 0x2044, - 0x88ff, 0x1040, 0x12b7, 0x8a51, 0x007c, 0x2051, 0x0000, 0x007c, - 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x1a72, 0x2c00, 0xad06, - 0x0040, 0x1a67, 0x6000, 0xa005, 0x00c0, 0x1a67, 0x2d00, 0x2060, - 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x1a92, 0x2044, 0x88ff, - 0x1040, 0x12b7, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, - 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, - 0x0027, 0x0000, 0x0000, 0x1a78, 0x1a74, 0x0000, 0x0000, 0x8000, - 0x0000, 0x1a78, 0x0000, 0x1a7f, 0x1a7c, 0x0000, 0x0000, 0x0000, - 0x0000, 0x1a7f, 0x0000, 0x1a7a, 0x1a7a, 0x0000, 0x0000, 0x8000, - 0x0000, 0x1a7a, 0x0000, 0x1a80, 0x1a80, 0x0000, 0x0000, 0x0000, - 0x0000, 0x1a80, 0x0a7e, 0x097e, 0x087e, 0x6858, 0xa055, 0x0040, - 0x1b28, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x1a82, 0xa986, - 0x0007, 0x0040, 0x1ab7, 0xa986, 0x000f, 0x00c0, 0x1abb, 0x605c, - 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x1ac9, 0x0050, - 0x1ac3, 0x0078, 0x1b28, 0x6004, 0xa065, 0x0040, 0x1b28, 0x0078, - 0x1aaa, 0x2804, 0xa005, 0x0040, 0x1ae7, 0xac68, 0xd99c, 0x00c0, - 0x1ad7, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x1adb, 0x6810, - 0xa422, 0x6814, 0xa31b, 0x0048, 0x1af5, 0x2300, 0xa405, 0x0040, - 0x1aed, 0x8a51, 0x0040, 0x1b28, 0x8840, 0x0078, 0x1ac9, 0x6004, - 0xa065, 0x0040, 0x1b28, 0x0078, 0x1aaa, 0x8a51, 0x8840, 0x2b68, - 0x6850, 0xc0fc, 0x6852, 0x0078, 0x1b22, 0x8422, 0x8420, 0x831a, - 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, - 0x00c0, 0x1b10, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, - 0x1048, 0x12b7, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x1b1c, - 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x12b7, - 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, - 0xc0fd, 0x6852, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x1b2d, - 0x087f, 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, - 0x2004, 0xa084, 0x0007, 0x0079, 0x1b35, 0x1b3d, 0x1b3e, 0x1b41, - 0x1b44, 0x1b49, 0x1b4c, 0x1b51, 0x1b56, 0x007c, 0x1078, 0x1933, - 0x007c, 0x1078, 0x16e5, 0x007c, 0x1078, 0x16e5, 0x1078, 0x1933, - 0x007c, 0x1078, 0x143e, 0x007c, 0x1078, 0x1933, 0x1078, 0x143e, - 0x007c, 0x1078, 0x16e5, 0x1078, 0x143e, 0x007c, 0x1078, 0x16e5, - 0x1078, 0x1933, 0x1078, 0x143e, 0x007c, 0x127e, 0x2091, 0x2300, - 0x2079, 0x0200, 0x2071, 0x7280, 0x2069, 0x6d00, 0x2009, 0x0004, - 0x7912, 0x7916, 0x1078, 0x1df6, 0x781b, 0x0002, 0x20e1, 0x8700, - 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, - 0x0079, 0x1b7a, 0x1b9e, 0x1b82, 0x1b86, 0x1b8a, 0x1b90, 0x1b94, - 0x1b98, 0x1b9c, 0x1078, 0x3d7c, 0x0078, 0x1b9e, 0x1078, 0x3db0, - 0x0078, 0x1b9e, 0x1078, 0x3d7c, 0x1078, 0x3db0, 0x0078, 0x1b9e, - 0x1078, 0x1ba0, 0x0078, 0x1b9e, 0x1078, 0x1ba0, 0x0078, 0x1b9e, - 0x1078, 0x1ba0, 0x0078, 0x1b9e, 0x1078, 0x1ba0, 0x127f, 0x007c, - 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, 0x1baa, - 0x1078, 0x12b7, 0xa184, 0x0030, 0x0040, 0x1bbb, 0x6a00, 0xa286, - 0x0003, 0x00c0, 0x1bb5, 0x1078, 0x12b7, 0x1078, 0x31cb, 0x20e1, - 0x9010, 0x0078, 0x1bc7, 0xa184, 0x00c0, 0x0040, 0x1bc1, 0x1078, - 0x12b7, 0xa184, 0x0300, 0x0040, 0x1bc7, 0x20e1, 0x9020, 0x7932, - 0x027f, 0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, - 0x6d00, 0x7128, 0x2001, 0x6f03, 0x2102, 0x2001, 0x6f0b, 0x2102, - 0xa182, 0x0211, 0x00c8, 0x1be0, 0x2009, 0x0008, 0x0078, 0x1c0a, - 0xa182, 0x0259, 0x00c8, 0x1be8, 0x2009, 0x0007, 0x0078, 0x1c0a, - 0xa182, 0x02c1, 0x00c8, 0x1bf0, 0x2009, 0x0006, 0x0078, 0x1c0a, - 0xa182, 0x0349, 0x00c8, 0x1bf8, 0x2009, 0x0005, 0x0078, 0x1c0a, - 0xa182, 0x0421, 0x00c8, 0x1c00, 0x2009, 0x0004, 0x0078, 0x1c0a, - 0xa182, 0x0581, 0x00c8, 0x1c08, 0x2009, 0x0003, 0x0078, 0x1c0a, - 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7916, 0x1078, 0x1df6, - 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, - 0x0100, 0x2071, 0x6d00, 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, 0x6d2d, 0x2003, - 0x0000, 0x2001, 0x6d2c, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, - 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, - 0x1c4d, 0xa184, 0x0007, 0x0079, 0x1c53, 0xa195, 0x0004, 0xa284, - 0x0007, 0x0079, 0x1c53, 0x1c7f, 0x1c5b, 0x1c5f, 0x1c63, 0x1c69, - 0x1c6d, 0x1c73, 0x1c79, 0x1078, 0x4226, 0x0078, 0x1c7f, 0x1078, - 0x42e4, 0x0078, 0x1c7f, 0x1078, 0x42e4, 0x1078, 0x4226, 0x0078, - 0x1c7f, 0x1078, 0x1c84, 0x0078, 0x1c7f, 0x1078, 0x4226, 0x1078, - 0x1c84, 0x0078, 0x1c7f, 0x1078, 0x42e4, 0x1078, 0x1c84, 0x0078, - 0x1c7f, 0x1078, 0x42e4, 0x1078, 0x4226, 0x1078, 0x1c84, 0x027f, - 0x017f, 0x007f, 0x127f, 0x007c, 0xd1ac, 0x0040, 0x1d24, 0x017e, - 0x047e, 0x0c7e, 0x644c, 0x74ba, 0xa48c, 0xff00, 0xa196, 0xff00, - 0x0040, 0x1cb3, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, - 0x1cb3, 0x7130, 0xd18c, 0x00c0, 0x1cb3, 0x2011, 0x6d52, 0x2214, - 0xd2ec, 0x0040, 0x1ca7, 0xc18d, 0x7132, 0x0078, 0x1cb3, 0x6240, - 0xa294, 0x0010, 0x0040, 0x1cf2, 0x6248, 0xa294, 0xff00, 0xa296, - 0xff00, 0x00c0, 0x1cf2, 0x2011, 0x8013, 0x1078, 0x2a53, 0x7130, - 0xc185, 0x7132, 0x2011, 0x6d52, 0x220c, 0xd1a4, 0x0040, 0x1cda, - 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x41f4, 0x2019, - 0x000e, 0x1078, 0x6b8f, 0xa484, 0x00ff, 0xa080, 0x2091, 0x200c, - 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x1078, - 0x6bf7, 0x017f, 0xd1ac, 0x00c0, 0x1ce3, 0x2019, 0x0004, 0x1078, - 0x202f, 0x0078, 0x1cf2, 0x157e, 0x20a9, 0x007f, 0x2009, 0x0000, - 0x1078, 0x3447, 0x00c0, 0x1cee, 0x1078, 0x3256, 0x8108, 0x00f0, - 0x1ce8, 0x157f, 0x0c7f, 0x047f, 0x6043, 0x0000, 0x2009, 0x00f7, - 0x1078, 0x3233, 0x2011, 0x0003, 0x1078, 0x5232, 0x2011, 0x0002, - 0x1078, 0x523c, 0x1078, 0x5148, 0x1078, 0x414c, 0x037e, 0x2019, - 0x0000, 0x1078, 0x51da, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, - 0x6d00, 0x2014, 0xa296, 0x0004, 0x00c0, 0x1d1c, 0xd19c, 0x00c0, - 0x1d1c, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0x6d20, - 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, 0x1d9d, 0x017e, - 0x6220, 0xd2b4, 0x0040, 0x1d5b, 0x1078, 0x414c, 0x1078, 0x4fe5, - 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, - 0x0040, 0x1d3e, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, - 0x2061, 0x6f10, 0x6028, 0xa09a, 0x0002, 0x00c8, 0x1d4e, 0x8000, - 0x602a, 0x0c7f, 0x1078, 0x4fd7, 0x0078, 0x1d9c, 0x2019, 0x6f19, - 0x2304, 0xa065, 0x0040, 0x1d58, 0x2009, 0x0014, 0x1078, 0x5591, - 0x0c7f, 0x0078, 0x1d9c, 0xd2bc, 0x0040, 0x1d9c, 0x1078, 0x415a, - 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, 0x6804, - 0xa084, 0x4000, 0x0040, 0x1d70, 0x6803, 0x1000, 0x6803, 0x0000, - 0x0d7f, 0x0c7e, 0x2061, 0x6f10, 0x6044, 0xa09a, 0x0002, 0x00c8, - 0x1d91, 0x8000, 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040, 0x1d9c, - 0x1078, 0x4151, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, - 0x1d8d, 0x6017, 0x0012, 0x0078, 0x1d9c, 0x6017, 0x0016, 0x0078, - 0x1d9c, 0x2019, 0x6f1f, 0x2304, 0xa065, 0x0040, 0x1d9b, 0x2009, - 0x004a, 0x1078, 0x5591, 0x0c7f, 0x017f, 0xd19c, 0x0040, 0x1dc5, - 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, 0x5232, - 0x2011, 0x0002, 0x1078, 0x523c, 0x1078, 0x5148, 0x1078, 0x414c, - 0x037e, 0x2019, 0x0000, 0x1078, 0x51da, 0x037f, 0x60e3, 0x0000, - 0x1078, 0x6c5f, 0x1078, 0x6c7d, 0x2001, 0x6d00, 0x2003, 0x0004, - 0x6027, 0x0008, 0x1078, 0x11aa, 0x017f, 0xa18c, 0xffd0, 0x6126, - 0x007c, 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, - 0x8000, 0x2071, 0x6d00, 0x71b0, 0x70b2, 0xa116, 0x0040, 0x1def, - 0x81ff, 0x0040, 0x1de1, 0x2011, 0x8011, 0x1078, 0x2a53, 0x0078, - 0x1def, 0x2011, 0x8012, 0x1078, 0x2a53, 0x037e, 0x0c7e, 0x2061, - 0x0100, 0x2019, 0x0028, 0x1078, 0x202f, 0x0c7f, 0x037f, 0x127f, - 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x0f7e, - 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x1e09, 0x2204, 0x60f2, - 0xa190, 0x1e12, 0x2204, 0x60ee, 0x027f, 0x007f, 0x0f7f, 0x0c7f, - 0x007c, 0x083e, 0x083e, 0x083e, 0x0580, 0x0420, 0x0348, 0x02c0, - 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8, - 0x00d0, 0x00b0, 0x00a0, 0x2028, 0x2130, 0xa094, 0xff00, 0x00c0, - 0x1e24, 0x81ff, 0x0040, 0x1e28, 0x1078, 0x3f00, 0x0078, 0x1e2f, - 0xa080, 0x2091, 0x200c, 0xa18c, 0xff00, 0x810f, 0xa006, 0x007c, - 0xa080, 0x2091, 0x200c, 0xa18c, 0x00ff, 0x007c, 0x1e56, 0x1e5a, - 0x1e5e, 0x1e64, 0x1e6a, 0x1e70, 0x1e76, 0x1e7e, 0x1e86, 0x1e8c, - 0x1e92, 0x1e9a, 0x1ea2, 0x1eaa, 0x1eb2, 0x1ebc, 0x1ec6, 0x1ec6, - 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, - 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x1ec6, 0x107e, 0x007e, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x0078, 0x1edf, 0x107e, 0x007e, - 0x1078, 0x1c3e, 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1c3e, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1b2e, 0x0078, 0x1edf, - 0x107e, 0x007e, 0x1078, 0x1b2e, 0x0078, 0x1edf, 0x107e, 0x007e, - 0x1078, 0x1c3e, 0x1078, 0x1b2e, 0x0078, 0x1edf, 0x107e, 0x007e, - 0x1078, 0x1c3e, 0x1078, 0x1b2e, 0x0078, 0x1edf, 0x107e, 0x007e, - 0x1078, 0x1b72, 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1b72, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1c3e, 0x1078, 0x1b72, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1c3e, 0x1078, 0x1b72, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1b2e, 0x1078, 0x1b72, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1b2e, 0x1078, 0x1b72, - 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1c3e, 0x1078, 0x1b2e, - 0x1078, 0x1b72, 0x0078, 0x1edf, 0x107e, 0x007e, 0x1078, 0x1c3e, - 0x1078, 0x1b2e, 0x1078, 0x1b72, 0x0078, 0x1edf, 0x0005, 0x0078, - 0x1ec6, 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x1ecf, 0x1edf, - 0x1e5c, 0x1e60, 0x1e66, 0x1e6c, 0x1e72, 0x1e78, 0x1e80, 0x1e88, - 0x1e8e, 0x1e94, 0x1e9c, 0x1ea4, 0x1eac, 0x1eb4, 0x1ebe, 0x0008, - 0x1ec9, 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e, 0x027e, - 0x2041, 0x007e, 0x70bc, 0xd09c, 0x0040, 0x1ef0, 0x2041, 0x007f, - 0x2001, 0x010c, 0x203c, 0x727c, 0x82ff, 0x0040, 0x1f3b, 0x037e, - 0x738c, 0xa38e, 0xffff, 0x00c0, 0x1eff, 0x2019, 0x0001, 0x8314, - 0xa2e0, 0x73c0, 0x2c04, 0xa38c, 0x0001, 0x0040, 0x1f0c, 0xa084, - 0xff00, 0x8007, 0x0078, 0x1f0e, 0xa084, 0x00ff, 0xa70e, 0x0040, - 0x1f30, 0xa08e, 0x00ff, 0x0040, 0x1f36, 0x2009, 0x0000, 0x1078, - 0x1e1b, 0x1078, 0x3410, 0x00c0, 0x1f33, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x00c0, 0x1f2a, 0x1078, 0x1f8d, 0x0040, 0x1f33, - 0x0078, 0x1f30, 0x1078, 0x208d, 0x1078, 0x1fb4, 0x0040, 0x1f33, - 0x8318, 0x0078, 0x1eff, 0x738e, 0x0078, 0x1f38, 0x708f, 0xffff, - 0x037f, 0x0078, 0x1f8a, 0xa780, 0x2091, 0x203c, 0xa7bc, 0xff00, - 0x873f, 0x708c, 0xa096, 0xffff, 0x0040, 0x1f4d, 0xa812, 0x00c8, - 0x1f5d, 0x708f, 0xffff, 0x0078, 0x1f87, 0x2009, 0x0000, 0x70bc, - 0xd09c, 0x0040, 0x1f58, 0xd094, 0x0040, 0x1f58, 0x2009, 0x007e, - 0x2100, 0xa802, 0x20a8, 0x0078, 0x1f61, 0x2008, 0x2810, 0xa202, - 0x20a8, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, 0x1f7e, 0x1078, - 0x3410, 0x00c0, 0x1f87, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x00c0, 0x1f78, 0x1078, 0x1f8d, 0x0040, 0x1f87, 0x0078, 0x1f7e, - 0x1078, 0x208d, 0x1078, 0x1fb4, 0x0040, 0x1f87, 0x017f, 0x8108, - 0x157f, 0x00f0, 0x1f61, 0x708f, 0xffff, 0x0078, 0x1f8a, 0x017f, - 0x157f, 0x718e, 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, - 0x0c7e, 0x2c68, 0x1078, 0x5504, 0x0040, 0x1faf, 0x2d00, 0x601a, - 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x33df, 0x2001, 0x0000, - 0x1078, 0x33f3, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, 0x708a, - 0x127f, 0x2009, 0x0004, 0x1078, 0x5591, 0xa085, 0x0001, 0x0c7f, - 0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, - 0x2c68, 0x1078, 0x5504, 0x0040, 0x1fd6, 0x2d00, 0x601a, 0x601f, - 0x0001, 0x2001, 0x0000, 0x1078, 0x33df, 0x2001, 0x0002, 0x1078, - 0x33f3, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, 0x708a, 0x127f, - 0x2009, 0x0002, 0x1078, 0x5591, 0xa085, 0x0001, 0x0c7f, 0x0d7f, - 0x077f, 0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, 0x0080, 0x1078, - 0x3410, 0x00c0, 0x1fe9, 0x1078, 0x1fec, 0x0040, 0x1fe9, 0x70c3, - 0xffff, 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, - 0x2c68, 0x1078, 0x5504, 0x0040, 0x200e, 0x2d00, 0x601a, 0x601f, - 0x0001, 0x2001, 0x0000, 0x1078, 0x33df, 0x2001, 0x0002, 0x1078, - 0x33f3, 0x127e, 0x2091, 0x8000, 0x70c4, 0x8000, 0x70c6, 0x127f, - 0x2009, 0x0002, 0x1078, 0x5591, 0xa085, 0x0001, 0x0c7f, 0x0d7f, - 0x077f, 0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x2009, 0x007f, 0x1078, - 0x3410, 0x00c0, 0x202c, 0x2c68, 0x1078, 0x5504, 0x0040, 0x202c, - 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, 0x2009, 0x0022, - 0x1078, 0x5591, 0xa085, 0x0001, 0x0d7f, 0x0c7f, 0x007c, 0x0e7e, - 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, 0x4463, 0x1078, 0x4417, - 0x1078, 0x59ce, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, - 0x3447, 0x00c0, 0x2047, 0x1078, 0x35cf, 0x1078, 0x3256, 0x017f, - 0x8108, 0x00f0, 0x203e, 0x027f, 0x037f, 0x067f, 0x0c7f, 0x0e7f, - 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270, - 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x445c, 0x1078, 0x43a9, - 0x2c08, 0x1078, 0x6a57, 0x017f, 0x2e60, 0x1078, 0x35cf, 0x1078, - 0x3256, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, - 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x2083, - 0x2071, 0x6d00, 0x7088, 0xa005, 0x0040, 0x2080, 0x8001, 0x708a, - 0x007f, 0x0e7f, 0x007c, 0x2071, 0x6d00, 0x70c4, 0xa005, 0x0040, - 0x2080, 0x8001, 0x70c6, 0x0078, 0x2080, 0x6000, 0xc08c, 0x6002, - 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, + 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, + 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, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x2071, 0x6d6d, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, - 0x703a, 0x703e, 0x7033, 0x6d7d, 0x7037, 0x6d7d, 0x7007, 0x0001, - 0x2061, 0x6d9d, 0x6003, 0x0002, 0x007c, 0x0090, 0x21b8, 0x0068, - 0x21b8, 0x2071, 0x6d6d, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x21b8, - 0x2a60, 0x7820, 0xa08e, 0x0069, 0x00c0, 0x229c, 0x0079, 0x223c, - 0x007c, 0x2071, 0x6d6d, 0x7004, 0x0079, 0x21be, 0x21c2, 0x21c3, - 0x21cd, 0x21df, 0x007c, 0x0090, 0x21cc, 0x0068, 0x21cc, 0x2b78, - 0x7818, 0xd084, 0x0040, 0x21eb, 0x007c, 0x2b78, 0x2061, 0x6d9d, - 0x6008, 0xa08e, 0x0100, 0x0040, 0x21da, 0xa086, 0x0200, 0x0040, - 0x2294, 0x007c, 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, - 0x2068, 0x6834, 0xa086, 0x0103, 0x0040, 0x21e7, 0x007c, 0x2a60, - 0x2b78, 0x7018, 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, - 0x21f4, 0x61b0, 0x0079, 0x21fc, 0x2100, 0xa08a, 0x0033, 0x00c8, - 0x2290, 0x61b0, 0x0079, 0x223c, 0x2272, 0x22a4, 0x22ac, 0x22b0, - 0x22b8, 0x22be, 0x22c2, 0x22cb, 0x22cf, 0x22d7, 0x22db, 0x2290, - 0x2290, 0x2290, 0x22df, 0x2290, 0x22ef, 0x2306, 0x231d, 0x2399, - 0x239e, 0x23cb, 0x2416, 0x2425, 0x2446, 0x247c, 0x2486, 0x2493, - 0x24a6, 0x24be, 0x24c7, 0x2504, 0x250a, 0x2290, 0x251a, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x251e, 0x2524, 0x2290, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x252c, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x2539, 0x253f, 0x2290, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x22d7, 0x22db, 0x2290, 0x2290, - 0x2551, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, - 0x2290, 0x2290, 0x2290, 0x2290, 0x259e, 0x265d, 0x2671, 0x2678, - 0x26db, 0x2736, 0x2741, 0x2783, 0x2790, 0x279d, 0x27a0, 0x2555, - 0x27c9, 0x2811, 0x281e, 0x28fd, 0x29cb, 0x29f2, 0x2ade, 0x713c, - 0x0078, 0x2272, 0x2021, 0x4000, 0x1078, 0x2a2d, 0x127e, 0x2091, - 0x8000, 0x0068, 0x227f, 0x7818, 0xd084, 0x0040, 0x2282, 0x127f, - 0x0078, 0x2276, 0x781b, 0x0001, 0x7c22, 0x7926, 0x7a2a, 0x7b2e, - 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, 0x127f, 0x007c, - 0x2021, 0x4001, 0x0078, 0x2274, 0x2021, 0x4002, 0x0078, 0x2274, - 0x2021, 0x4003, 0x0078, 0x2274, 0x2021, 0x4005, 0x0078, 0x2274, - 0x2021, 0x4006, 0x0078, 0x2274, 0xa02e, 0x2520, 0x7b28, 0x7a2c, - 0x7824, 0x7930, 0x0078, 0x2a3c, 0x7823, 0x0004, 0x7824, 0x007a, - 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x2a40, - 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2272, 0x7924, 0x2114, - 0x0078, 0x2272, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, 0x0007, - 0x53a3, 0x0078, 0x2272, 0x7824, 0x2060, 0x0078, 0x22e1, 0x2009, - 0x0001, 0x2011, 0x000d, 0x2019, 0x0000, 0x0078, 0x2272, 0x7d38, - 0x7c3c, 0x0078, 0x22a6, 0x7d38, 0x7c3c, 0x0078, 0x22b2, 0x2061, - 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0, - 0x22e3, 0x2010, 0xa005, 0x0040, 0x2272, 0x0078, 0x2298, 0x2061, - 0x6d51, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x22a0, 0x8019, 0x0040, - 0x22a0, 0x604a, 0x6142, 0x782c, 0x6052, 0x7828, 0x6056, 0xa006, - 0x605a, 0x605e, 0x1078, 0x3890, 0x0078, 0x2272, 0x2061, 0x6d51, - 0x7824, 0x7930, 0xa11a, 0x00c8, 0x22a0, 0x8019, 0x0040, 0x22a0, - 0x604e, 0x6146, 0x782c, 0x6062, 0x7828, 0x6066, 0xa006, 0x606a, - 0x606e, 0x1078, 0x366e, 0x0078, 0x2272, 0xa02e, 0x2520, 0x81ff, - 0x00c0, 0x229c, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1, - 0x6d74, 0x41a1, 0x1078, 0x2a04, 0x0040, 0x229c, 0x2009, 0x0020, - 0x1078, 0x2a3c, 0x701b, 0x2335, 0x007c, 0x6834, 0x2008, 0xa084, - 0x00ff, 0xa096, 0x0011, 0x0040, 0x2341, 0xa096, 0x0019, 0x00c0, - 0x229c, 0x810f, 0xa18c, 0x00ff, 0x0040, 0x229c, 0x710e, 0x700c, - 0x8001, 0x0040, 0x2372, 0x700e, 0x1078, 0x2a04, 0x0040, 0x229c, - 0x2009, 0x0020, 0x2061, 0x6d9d, 0x6224, 0x6328, 0x642c, 0x6530, - 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, - 0x1078, 0x2a3c, 0x701b, 0x2365, 0x007c, 0x6834, 0xa084, 0x00ff, - 0xa096, 0x0002, 0x0040, 0x2370, 0xa096, 0x000a, 0x00c0, 0x229c, - 0x0078, 0x2347, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x1078, - 0x3344, 0x00c0, 0x2380, 0x7007, 0x0003, 0x701b, 0x2382, 0x007c, - 0x1078, 0x372d, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, - 0x6d74, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, - 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, 0x0078, - 0x2a40, 0x6198, 0x7824, 0x609a, 0x0078, 0x2272, 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, 0x229c, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x7c28, 0x7d2c, 0x1078, 0x3592, 0xd28c, 0x00c0, - 0x23dd, 0x1078, 0x3522, 0x0078, 0x23df, 0x1078, 0x355e, 0x00c0, - 0x2409, 0x2061, 0x7400, 0x127e, 0x2091, 0x8000, 0x6000, 0xa086, - 0x0000, 0x0040, 0x23f7, 0x6010, 0xa06d, 0x0040, 0x23f7, 0x683c, - 0xa406, 0x00c0, 0x23f7, 0x6840, 0xa506, 0x0040, 0x2402, 0x127f, - 0xace0, 0x0008, 0x2001, 0x6d15, 0x2004, 0xac02, 0x00c8, 0x229c, - 0x0078, 0x23e3, 0x1078, 0x5f5d, 0x127f, 0x0040, 0x229c, 0x0078, - 0x2272, 0xa00e, 0x2001, 0x0005, 0x1078, 0x372d, 0x127e, 0x2091, - 0x8000, 0x1078, 0x36a1, 0x127f, 0x0078, 0x2272, 0x81ff, 0x00c0, - 0x229c, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x1078, 0x34d7, 0x1078, - 0x35a3, 0x0040, 0x229c, 0x0078, 0x2272, 0x81ff, 0x00c0, 0x229c, - 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x2031, 0x000f, 0x1078, 0x34d7, - 0x8631, 0x00c8, 0x242e, 0x2019, 0x0005, 0x1078, 0x35c4, 0x0040, - 0x229c, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x22a0, 0x8003, 0x800b, - 0x810b, 0xa108, 0x1078, 0x40de, 0x0078, 0x2272, 0x127e, 0x2091, - 0x8000, 0x81ff, 0x00c0, 0x2476, 0x2029, 0x00ff, 0x644c, 0x2400, - 0xa506, 0x0040, 0x2470, 0x2508, 0x1078, 0x3447, 0x00c0, 0x2470, - 0x2031, 0x000f, 0x1078, 0x34d7, 0x8631, 0x00c8, 0x245a, 0x2019, - 0x0004, 0x1078, 0x35c4, 0x0040, 0x2476, 0x7824, 0xa08a, 0x1000, - 0x00c8, 0x2479, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x40de, - 0x8529, 0x00c8, 0x244f, 0x127f, 0x0078, 0x2272, 0x127f, 0x0078, - 0x229c, 0x127f, 0x0078, 0x22a0, 0x1078, 0x2a1c, 0x0040, 0x22a0, - 0x1078, 0x3507, 0x1078, 0x3592, 0x0078, 0x2272, 0x81ff, 0x00c0, - 0x229c, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x1078, 0x34f0, 0x1078, - 0x3592, 0x0078, 0x2272, 0x81ff, 0x00c0, 0x229c, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x1078, 0x3561, 0x0040, 0x229c, 0x1078, 0x338c, - 0x1078, 0x351b, 0x1078, 0x3592, 0x0078, 0x2272, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x1078, 0x34d7, 0x62a0, 0x2019, 0x0005, 0x0c7e, - 0x1078, 0x35cf, 0x0c7f, 0x1078, 0x445c, 0x1078, 0x43a9, 0x2c08, - 0x1078, 0x6a57, 0x1078, 0x3592, 0x0078, 0x2272, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x1078, 0x3592, 0x2208, 0x0078, 0x2272, 0x157e, - 0x0d7e, 0x0e7e, 0x2069, 0x6ddf, 0x6810, 0x6914, 0xa10a, 0x00c8, - 0x24d3, 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, - 0x20a9, 0x007e, 0x2069, 0x6e00, 0x2d04, 0xa075, 0x0040, 0x24e8, - 0x704c, 0x1078, 0x24f2, 0xa210, 0x7080, 0x1078, 0x24f2, 0xa318, - 0x8d68, 0x00f0, 0x24dc, 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, - 0x0078, 0x2272, 0x0f7e, 0x017e, 0xa07d, 0x0040, 0x2501, 0x2001, - 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0040, 0x2501, 0x2178, 0x0078, - 0x24f9, 0x017f, 0x0f7f, 0x007c, 0x2069, 0x6ddf, 0x6910, 0x629c, - 0x0078, 0x2272, 0x81ff, 0x00c0, 0x229c, 0x614c, 0xa190, 0x2091, - 0x2214, 0xa294, 0x00ff, 0x6068, 0xa084, 0xff00, 0xa215, 0x6364, - 0x0078, 0x2272, 0x613c, 0x6240, 0x0078, 0x2272, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x0078, 0x2272, 0x1078, 0x2a1c, 0x0040, 0x22a0, - 0x6244, 0x6338, 0x0078, 0x2272, 0x613c, 0x6240, 0x7824, 0x603e, - 0x7b28, 0x6342, 0x2069, 0x6d51, 0x831f, 0xa305, 0x6816, 0x0078, - 0x2272, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x0078, 0x2272, 0x1078, - 0x2a1c, 0x0040, 0x22a0, 0x7828, 0xa00d, 0x0040, 0x22a0, 0x782c, - 0xa005, 0x0040, 0x22a0, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, - 0x2272, 0x7d38, 0x7c3c, 0x0078, 0x231f, 0x7824, 0xa09c, 0x00ff, - 0xa39a, 0x0003, 0x00c8, 0x229c, 0x624c, 0xa084, 0xff00, 0x8007, - 0xa206, 0x00c0, 0x256d, 0x2001, 0x6d40, 0x2009, 0x000c, 0x7a2c, - 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2a40, 0x81ff, 0x00c0, 0x229c, - 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x0006, 0x00c0, 0x229c, 0x0c7e, 0x1078, 0x2a04, 0x0c7f, 0x0040, - 0x229c, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6223, - 0x0040, 0x229c, 0x7007, 0x0003, 0x701b, 0x258f, 0x007c, 0x6830, - 0xa086, 0x0100, 0x0040, 0x229c, 0xad80, 0x000e, 0x2009, 0x000c, - 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2a40, 0x1078, 0x2a04, - 0x0040, 0x229c, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x1078, 0x2a3c, 0x701b, 0x25ad, 0x007c, 0xade8, 0x000d, 0x6800, - 0xa005, 0x0040, 0x22a0, 0x6804, 0xd0ac, 0x0040, 0x25ba, 0xd0a4, - 0x0040, 0x22a0, 0xd094, 0x0040, 0x25c5, 0x0c7e, 0x2061, 0x0100, - 0x6104, 0xa18c, 0xffdf, 0x6106, 0x0c7f, 0xd08c, 0x0040, 0x25d0, - 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18d, 0x0010, 0x6106, 0x0c7f, - 0x2009, 0x0100, 0x210c, 0xa18a, 0x0002, 0x0048, 0x25e5, 0xd084, - 0x0040, 0x25e5, 0x6828, 0xa08a, 0x007f, 0x00c8, 0x22a0, 0xa088, - 0x2091, 0x210c, 0xa18c, 0x00ff, 0x6152, 0xd0dc, 0x0040, 0x25ee, - 0x6828, 0xa08a, 0x007f, 0x00c8, 0x22a0, 0x604e, 0x6808, 0xa08a, - 0x0100, 0x0048, 0x22a0, 0xa08a, 0x0841, 0x00c8, 0x22a0, 0xa084, - 0x0007, 0x00c0, 0x22a0, 0x680c, 0xa005, 0x0040, 0x22a0, 0x6810, - 0xa005, 0x0040, 0x22a0, 0x6848, 0x6940, 0xa10a, 0x00c8, 0x22a0, - 0x8001, 0x0040, 0x22a0, 0x684c, 0x6944, 0xa10a, 0x00c8, 0x22a0, - 0x8001, 0x0040, 0x22a0, 0x20a9, 0x001c, 0x2d98, 0x2069, 0x6d51, - 0x2da0, 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, - 0x00ff, 0x6042, 0x1078, 0x3890, 0x1078, 0x366e, 0x6000, 0xa086, - 0x0000, 0x00c0, 0x265b, 0x6808, 0x602a, 0x1078, 0x1bcc, 0x6818, - 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, - 0x611a, 0x621e, 0x6322, 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, - 0x6312, 0x1078, 0x4168, 0x0c7e, 0x2061, 0x0100, 0x602f, 0x0040, - 0x602f, 0x0000, 0x0c7f, 0x60b4, 0xa005, 0x0040, 0x2657, 0x6003, - 0x0001, 0x2091, 0x301d, 0x1078, 0x31cb, 0x0078, 0x265b, 0x6003, - 0x0004, 0x2091, 0x301d, 0x0078, 0x2272, 0x6000, 0xa086, 0x0000, - 0x0040, 0x229c, 0x2069, 0x6d51, 0x7830, 0x6842, 0x7834, 0x6846, - 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, - 0x2a40, 0x81ff, 0x00c0, 0x229c, 0x1078, 0x31cb, 0x0078, 0x2272, - 0x81ff, 0x00c0, 0x229c, 0x617c, 0x81ff, 0x0040, 0x2692, 0x703f, - 0x0000, 0x2001, 0x73c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, - 0x7d38, 0x127e, 0x2091, 0x8000, 0x1078, 0x2a40, 0x701b, 0x226f, - 0x127f, 0x007c, 0x703f, 0x0001, 0x0d7e, 0x2069, 0x73c0, 0x20a9, - 0x0040, 0x20a1, 0x73c0, 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, - 0x2091, 0x210c, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, - 0x2100, 0xa506, 0x0040, 0x26c4, 0x1078, 0x3447, 0x00c0, 0x26c4, - 0x6014, 0x821c, 0x0048, 0x26bc, 0xa398, 0x73c0, 0xa085, 0xff00, - 0x8007, 0x201a, 0x0078, 0x26c3, 0xa398, 0x73c0, 0x2324, 0xa4a4, - 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, - 0x26cb, 0x0078, 0x26a8, 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, - 0x0d7f, 0x20a9, 0x0040, 0x20a1, 0x73c0, 0x2099, 0x73c0, 0x1078, - 0x3213, 0x0078, 0x2681, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x0c7e, - 0x1078, 0x2a04, 0x0c7f, 0x0040, 0x229c, 0x2001, 0x6d52, 0x2004, - 0xd0b4, 0x0040, 0x2708, 0x6000, 0xd08c, 0x00c0, 0x2708, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2708, 0x6837, 0x0000, - 0x6838, 0xc0fd, 0x683a, 0x1078, 0x625b, 0x0040, 0x229c, 0x7007, - 0x0003, 0x701b, 0x2704, 0x007c, 0x1078, 0x2a1c, 0x0040, 0x22a0, - 0x20a9, 0x0029, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, - 0x0002, 0xac80, 0x0004, 0x2098, 0xad80, 0x0004, 0x20a0, 0x1078, - 0x3213, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, 0x0006, - 0x20a0, 0x1078, 0x3213, 0x20a9, 0x0004, 0xac80, 0x000a, 0x2098, - 0xad80, 0x000a, 0x20a0, 0x1078, 0x3213, 0x2d00, 0x2009, 0x0029, - 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2a40, 0x81ff, 0x00c0, - 0x229c, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x1078, 0x35ae, 0x0078, - 0x2272, 0x81ff, 0x00c0, 0x229c, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x22a0, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x2031, 0x000f, 0x1078, - 0x34d7, 0x8631, 0x00c8, 0x274f, 0x2019, 0x0004, 0x1078, 0x35c4, - 0x7924, 0x810f, 0x7a28, 0x1078, 0x275f, 0x0078, 0x2272, 0xa186, - 0x00ff, 0x0040, 0x2767, 0x1078, 0x2777, 0x0078, 0x2776, 0x2029, - 0x007e, 0x2061, 0x6d00, 0x644c, 0x2400, 0xa506, 0x0040, 0x2773, - 0x2508, 0x1078, 0x2777, 0x8529, 0x00c8, 0x276c, 0x007c, 0x1078, - 0x3447, 0x00c0, 0x2782, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, - 0x1078, 0x40de, 0x007c, 0x81ff, 0x00c0, 0x229c, 0x1078, 0x2a1c, - 0x0040, 0x22a0, 0x1078, 0x34d7, 0x1078, 0x35b9, 0x0078, 0x2272, - 0x81ff, 0x00c0, 0x229c, 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x1078, - 0x34d7, 0x1078, 0x35a3, 0x0078, 0x2272, 0x6100, 0x0078, 0x2272, - 0x1078, 0x2a1c, 0x0040, 0x22a0, 0x6004, 0xa086, 0x0707, 0x0040, - 0x22a0, 0x2001, 0x6d00, 0x2004, 0xa086, 0x0003, 0x00c0, 0x229c, - 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x27b9, 0xace8, - 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, - 0x831f, 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, 0x0078, - 0x2272, 0x81ff, 0x00c0, 0x229c, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x22a0, 0x7924, 0xa184, 0x00ff, 0xa082, 0x0010, 0x00c8, 0x22a0, - 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, 0x27e6, 0xa182, - 0x007f, 0x00c8, 0x22a0, 0x2100, 0x1078, 0x1e30, 0x027e, 0x0c7e, - 0x127e, 0x2091, 0x8000, 0x2061, 0x6f23, 0x601b, 0x0000, 0x601f, - 0x0000, 0x2061, 0x6d00, 0x6003, 0x0001, 0x2061, 0x0100, 0x6030, - 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, - 0x0010, 0x2009, 0x001e, 0x2011, 0x31f0, 0x1078, 0x415f, 0x7924, - 0x810f, 0x7a28, 0x1078, 0x275f, 0x127f, 0x0c7f, 0x027f, 0x0078, - 0x2272, 0x7924, 0xa18c, 0xff00, 0x810f, 0x0c7e, 0x1078, 0x3410, - 0x2c08, 0x0c7f, 0x00c0, 0x22a0, 0x0078, 0x2272, 0x81ff, 0x00c0, - 0x229c, 0x60bc, 0xd09c, 0x0040, 0x229c, 0x1078, 0x2a04, 0x0040, - 0x229c, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2a3c, - 0x701b, 0x2833, 0x007c, 0x2009, 0x0080, 0x1078, 0x3447, 0x00c0, - 0x229c, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c, 0x6c10, - 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0040, 0x28a7, 0xa0be, - 0x0112, 0x0040, 0x28a7, 0xa0be, 0x0113, 0x0040, 0x28a7, 0xa0be, - 0x0114, 0x0040, 0x28a7, 0xa0be, 0x0117, 0x0040, 0x28a7, 0xa0be, - 0x011a, 0x0040, 0x28a7, 0xa0be, 0x0121, 0x0040, 0x289d, 0xa0be, - 0x0131, 0x0040, 0x289d, 0xa0be, 0x0171, 0x0040, 0x28a7, 0xa0be, - 0x01a1, 0x00c0, 0x2870, 0x6830, 0x8007, 0x6832, 0x0078, 0x28ad, - 0xa0be, 0x0212, 0x0040, 0x28a3, 0xa0be, 0x0213, 0x0040, 0x28a3, - 0xa0be, 0x0214, 0x0040, 0x2895, 0xa0be, 0x0217, 0x0040, 0x288f, - 0xa0be, 0x021a, 0x00c0, 0x2889, 0x6838, 0x8007, 0x683a, 0x0078, - 0x28a7, 0xa0be, 0x0300, 0x0040, 0x28a7, 0x0078, 0x229c, 0xad80, - 0x0010, 0x20a9, 0x0007, 0x1078, 0x28d9, 0xad80, 0x000e, 0x20a9, - 0x0001, 0x1078, 0x28d9, 0x0078, 0x28a7, 0xad80, 0x000c, 0x1078, - 0x28e7, 0x0078, 0x28ad, 0xad80, 0x000e, 0x1078, 0x28e7, 0xad80, - 0x000c, 0x20a9, 0x0001, 0x1078, 0x28d9, 0x0c7e, 0x1078, 0x2a04, - 0x0040, 0x28ce, 0x6837, 0x0119, 0x684f, 0x0020, 0x685b, 0x0001, - 0x810b, 0x697e, 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, - 0x6996, 0x689b, 0x0000, 0x0c7f, 0x0d7f, 0x1078, 0x623f, 0x0040, - 0x229c, 0x7007, 0x0003, 0x701b, 0x28d2, 0x007c, 0x0c7f, 0x0d7f, - 0x0078, 0x229c, 0x6820, 0xa086, 0x8001, 0x0040, 0x229c, 0x0078, - 0x2272, 0x017e, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, - 0x8108, 0x280a, 0x8108, 0x00f0, 0x28db, 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, 0x229c, - 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0081, 0x0048, 0x22a0, - 0xa182, 0x00ff, 0x00c8, 0x22a0, 0x7a2c, 0x7b28, 0x6064, 0xa306, - 0x00c0, 0x2918, 0x6068, 0xa206, 0x00c0, 0x2918, 0x0078, 0x22a0, - 0x0c7e, 0x1078, 0x297b, 0x2c68, 0x0c7f, 0x0040, 0x2939, 0xa0c6, - 0x4007, 0x00c0, 0x2926, 0x7c26, 0x0078, 0x2936, 0xa0c6, 0x4008, - 0x00c0, 0x292e, 0x7f26, 0x7e2a, 0x0078, 0x2936, 0xa0c6, 0x4009, - 0x00c0, 0x2934, 0x0078, 0x2936, 0x2001, 0x4006, 0x2020, 0x0078, - 0x2274, 0x017e, 0x0b7e, 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x5504, - 0x0040, 0x2969, 0x2d00, 0x601a, 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, - 0x1078, 0x2a04, 0x0c7f, 0x2b70, 0x0040, 0x229c, 0x6837, 0x0000, - 0x2d00, 0x6012, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x33df, - 0x2001, 0x0002, 0x1078, 0x33f3, 0x127e, 0x2091, 0x8000, 0x7088, - 0x8000, 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5591, 0xa085, - 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x0040, 0x229c, 0x7007, - 0x0003, 0x701b, 0x2974, 0x007c, 0x6830, 0xa086, 0x0100, 0x00c0, - 0x2272, 0x0078, 0x229c, 0x0e7e, 0x0d7e, 0x2029, 0x0000, 0x2021, - 0x0081, 0x20a9, 0x007e, 0x2071, 0x6e81, 0x2e04, 0xa005, 0x00c0, - 0x298f, 0x2100, 0xa406, 0x0040, 0x29c0, 0x0078, 0x29b4, 0x2068, - 0x6f10, 0x2700, 0xa306, 0x00c0, 0x29a5, 0x6e14, 0x2600, 0xa206, - 0x00c0, 0x29a5, 0x2400, 0xa106, 0x00c0, 0x29a1, 0x2d60, 0x0078, - 0x29c6, 0x2001, 0x4007, 0x0078, 0x29c7, 0x2400, 0xa106, 0x00c0, - 0x29b4, 0x6e14, 0x87ff, 0x00c0, 0x29b0, 0x86ff, 0x0040, 0x29c0, - 0x2001, 0x4008, 0x0078, 0x29c7, 0x8420, 0x8e70, 0x00f0, 0x2985, - 0x2001, 0x4009, 0x0078, 0x29c7, 0x2001, 0x0001, 0x0078, 0x29c7, - 0x1078, 0x3410, 0x00c0, 0x29bc, 0x6312, 0x6216, 0xa006, 0xa005, - 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, 0x229c, 0x1078, 0x2a04, - 0x0040, 0x229c, 0x6837, 0x0000, 0x7824, 0xa005, 0x0040, 0x22a0, - 0xa096, 0x00ff, 0x0040, 0x29e0, 0xa092, 0x0004, 0x00c8, 0x22a0, - 0x2010, 0x2d18, 0x1078, 0x2013, 0x0040, 0x229c, 0x7007, 0x0003, - 0x701b, 0x29eb, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x229c, - 0x0078, 0x2272, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0081, - 0x0048, 0x22a0, 0xa182, 0x00ff, 0x00c8, 0x22a0, 0x1078, 0x615b, - 0x1078, 0x342f, 0x0078, 0x2272, 0x1078, 0x12f4, 0x0040, 0x2a1b, - 0xa006, 0x6802, 0x7010, 0xa005, 0x00c0, 0x2a13, 0x2d00, 0x7012, - 0x7016, 0x0078, 0x2a19, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, - 0x7016, 0xad80, 0x000d, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, - 0x1078, 0x3447, 0x00c0, 0x2a2a, 0xa6b4, 0x00ff, 0xa682, 0x0010, - 0x0048, 0x2a2b, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, - 0x0040, 0x2a38, 0x2168, 0x6904, 0x1078, 0x1328, 0x0078, 0x2a2f, - 0x7112, 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x2a42, - 0x2031, 0x0000, 0x2061, 0x6d9d, 0x6606, 0x6112, 0x600e, 0x6226, - 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x135f, 0x7007, 0x0002, - 0x701b, 0x2272, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, - 0x0000, 0x2001, 0x6d7b, 0x2004, 0xa005, 0x00c0, 0x2a6e, 0x0068, - 0x2a6e, 0x7818, 0xd084, 0x00c0, 0x2a6e, 0x781b, 0x0001, 0x7a22, - 0x7b26, 0x7c2a, 0x2091, 0x4080, 0x0078, 0x2a93, 0x017e, 0x0c7e, - 0x0e7e, 0x2071, 0x6d6d, 0x7138, 0xa182, 0x0004, 0x0048, 0x2a7c, - 0x7030, 0x2060, 0x0078, 0x2a8d, 0x7030, 0xa0e0, 0x0008, 0xac82, - 0x6d9d, 0x0048, 0x2a85, 0x2061, 0x6d7d, 0x2c00, 0x7032, 0x81ff, - 0x00c0, 0x2a8b, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, - 0x0e7f, 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, - 0x6d6d, 0x7038, 0xa005, 0x0040, 0x2acf, 0x127e, 0x2091, 0x8000, - 0x0068, 0x2ace, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, - 0x2acd, 0x0c7e, 0x781b, 0x0001, 0x7034, 0x2060, 0x2c04, 0x7822, - 0x6004, 0x7826, 0x6008, 0x782a, 0x2091, 0x4080, 0x7038, 0x8001, - 0x703a, 0xa005, 0x00c0, 0x2ac3, 0x7033, 0x6d7d, 0x7037, 0x6d7d, - 0x0c7f, 0x0078, 0x2acd, 0xac80, 0x0008, 0xa0fa, 0x6d9d, 0x0048, - 0x2acb, 0x2001, 0x6d7d, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, - 0x007c, 0x027e, 0x2001, 0x6d52, 0x2004, 0xd0c4, 0x0040, 0x2adc, - 0x2011, 0x8014, 0x1078, 0x2a53, 0x027f, 0x007c, 0x81ff, 0x00c0, - 0x229c, 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x1078, - 0x31cb, 0x127f, 0x0078, 0x2272, 0x127e, 0x0c7e, 0x0e7e, 0x2061, - 0x0100, 0x2071, 0x6d00, 0x6044, 0xd0a4, 0x00c0, 0x2b11, 0xd084, - 0x0040, 0x2afe, 0x1078, 0x2c34, 0x0078, 0x2b11, 0xd08c, 0x0040, - 0x2b05, 0x1078, 0x2b4b, 0x0078, 0x2b11, 0xd094, 0x0040, 0x2b0c, - 0x1078, 0x2b2c, 0x0078, 0x2b11, 0xd09c, 0x0040, 0x2b11, 0x1078, - 0x2b15, 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x6043, 0x0040, 0x6043, + 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, + 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, + 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, + 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, + 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, - 0x73c0, 0x200b, 0x0000, 0x7073, 0x000f, 0x2009, 0x000f, 0x2011, - 0x3187, 0x1078, 0x415f, 0x007c, 0x7070, 0xa005, 0x00c0, 0x2b4a, - 0x2011, 0x3187, 0x1078, 0x40d1, 0x6043, 0x0020, 0x6043, 0x0000, - 0x6044, 0xd08c, 0x00c0, 0x2b46, 0x7003, 0x0001, 0x7083, 0x0000, - 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x2b4a, 0x7077, 0x0000, - 0x0078, 0x2b4a, 0x007c, 0x7074, 0xa08a, 0x0003, 0x00c8, 0x2b54, - 0x1079, 0x2b57, 0x0078, 0x2b56, 0x1078, 0x12b7, 0x007c, 0x2b5a, - 0x2ba9, 0x2c33, 0x0f7e, 0x7077, 0x0001, 0x20e1, 0xa000, 0x20e1, - 0x8700, 0x1078, 0x1bcc, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, - 0x7200, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, + 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, 0x720c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, - 0x6d05, 0x20a1, 0x720e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0x7212, - 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0x7200, 0x20a1, 0x020b, + 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, - 0x31b2, 0x0f7f, 0x707b, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, - 0x007c, 0x0d7e, 0x7078, 0x707b, 0x0000, 0xa025, 0x0040, 0x2c1d, - 0x6020, 0xd0b4, 0x00c0, 0x2c1b, 0x7184, 0x81ff, 0x0040, 0x2c04, - 0xa486, 0x000c, 0x00c0, 0x2c0f, 0xa480, 0x0018, 0x8004, 0x20a8, - 0x2011, 0x7280, 0x2019, 0x7200, 0x220c, 0x2304, 0xa106, 0x00c0, - 0x2bdb, 0x8210, 0x8318, 0x00f0, 0x2bc4, 0x6043, 0x0004, 0x608b, + 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, 0x2c1b, 0x2069, 0x7280, 0x6930, 0xa18e, 0x1101, - 0x00c0, 0x2c0f, 0x6834, 0xa005, 0x00c0, 0x2c0f, 0x6900, 0xa18c, - 0x00ff, 0x00c0, 0x2bef, 0x6804, 0xa005, 0x0040, 0x2c04, 0x2011, - 0x728e, 0x2019, 0x6d05, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, - 0x0048, 0x2c02, 0x00c0, 0x2c0f, 0x8210, 0x8318, 0x00f0, 0x2bf5, - 0x0078, 0x2c0f, 0x7087, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x2099, 0x7280, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, - 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x2c1b, 0x60c3, - 0x000c, 0x1078, 0x31b2, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0, - 0x2c1b, 0x60c3, 0x000c, 0x2011, 0x6f1a, 0x2013, 0x0000, 0x707b, + 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, - 0x4fdc, 0x0078, 0x2c1b, 0x007c, 0x7080, 0xa08a, 0x001d, 0x00c8, - 0x2c3d, 0x1079, 0x2c40, 0x0078, 0x2c3f, 0x1078, 0x12b7, 0x007c, - 0x2c64, 0x2c73, 0x2ca6, 0x2cbb, 0x2ced, 0x2d17, 0x2d49, 0x2d73, - 0x2da5, 0x2dcb, 0x2e1a, 0x2e3c, 0x2e60, 0x2e76, 0x2e9c, 0x2eaf, - 0x2eb8, 0x2ed1, 0x2f01, 0x2f2b, 0x2f5b, 0x2f85, 0x2fce, 0x3003, - 0x3025, 0x3063, 0x3087, 0x30a0, 0x30ad, 0x7003, 0x0007, 0x6004, + 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, 0x318e, - 0x1078, 0x40c4, 0x007c, 0x0f7e, 0x7078, 0xa086, 0x0014, 0x00c0, - 0x2ca4, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x2ca4, 0x2079, - 0x7280, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x2ca2, 0x7834, 0xa005, - 0x00c0, 0x2ca2, 0x7a38, 0xd2fc, 0x0040, 0x2c98, 0x70a4, 0xa005, - 0x00c0, 0x2c98, 0x2019, 0x002a, 0x1078, 0x202f, 0x70a7, 0x0001, - 0x2011, 0x318e, 0x1078, 0x40d1, 0x7083, 0x0010, 0x1078, 0x2eb8, - 0x0078, 0x2ca4, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0003, - 0x6043, 0x0004, 0x1078, 0x321b, 0x20a3, 0x1102, 0x20a3, 0x0000, - 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x2cb2, 0x60c3, 0x0014, - 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x2ceb, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0014, 0x00c0, 0x2ce7, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x2ce7, 0x7834, - 0xa005, 0x00c0, 0x2ce7, 0x7a38, 0xd2fc, 0x0040, 0x2ce1, 0x70a4, - 0xa005, 0x00c0, 0x2ce1, 0x2019, 0x002a, 0x1078, 0x202f, 0x70a7, - 0x0001, 0x7083, 0x0004, 0x1078, 0x2ced, 0x0078, 0x2ceb, 0x7083, - 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0005, 0x1078, - 0x321b, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x728e, - 0x706c, 0xa005, 0x00c0, 0x2d09, 0x714c, 0xa186, 0xffff, 0x0040, - 0x2d09, 0x1078, 0x3152, 0x0040, 0x2d09, 0x2019, 0x002a, 0x1078, - 0x202f, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x31b2, 0x007c, 0x0f7e, - 0x7078, 0xa005, 0x0040, 0x2d47, 0x2011, 0x318e, 0x1078, 0x40d1, - 0xa086, 0x0014, 0x00c0, 0x2d43, 0x2079, 0x7280, 0x7a30, 0xa296, - 0x1103, 0x00c0, 0x2d43, 0x7834, 0xa005, 0x00c0, 0x2d43, 0x7a38, - 0xd2fc, 0x0040, 0x2d3d, 0x70a4, 0xa005, 0x00c0, 0x2d3d, 0x2019, - 0x002a, 0x1078, 0x202f, 0x70a7, 0x0001, 0x7083, 0x0006, 0x1078, - 0x2d49, 0x0078, 0x2d47, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0007, 0x1078, 0x321b, 0x20a3, 0x1104, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x728e, 0x706c, 0xa005, 0x00c0, 0x2d65, - 0x7150, 0xa186, 0xffff, 0x0040, 0x2d65, 0xa180, 0x2091, 0x200c, - 0xa18c, 0xff00, 0x810f, 0x1078, 0x3152, 0x20a9, 0x0008, 0x2298, + 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, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x2da3, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0014, 0x00c0, 0x2d9f, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x2d9f, 0x7834, - 0xa005, 0x00c0, 0x2d9f, 0x7a38, 0xd2fc, 0x0040, 0x2d99, 0x70a4, - 0xa005, 0x00c0, 0x2d99, 0x2019, 0x002a, 0x1078, 0x202f, 0x70a7, - 0x0001, 0x7083, 0x0008, 0x1078, 0x2da5, 0x0078, 0x2da3, 0x7083, - 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0009, 0x1078, - 0x321b, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x706c, 0xa005, - 0x00c0, 0x2db8, 0x1078, 0x30bc, 0x0040, 0x2dc8, 0x0078, 0x2dc2, - 0x20a9, 0x0008, 0x2099, 0x728e, 0x26a0, 0x53a6, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x31b2, 0x0078, 0x2dca, - 0x1078, 0x2c5d, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x2e18, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0014, 0x00c0, 0x2e14, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1105, 0x00c0, 0x2e14, 0x7834, - 0x2011, 0x0100, 0xa21e, 0x00c0, 0x2dfb, 0x7a38, 0xd2fc, 0x0040, - 0x2df3, 0x70a4, 0xa005, 0x00c0, 0x2df3, 0x2019, 0x002a, 0x1078, - 0x202f, 0x70a7, 0x0001, 0x707f, 0x0001, 0x7083, 0x000a, 0x1078, - 0x2e1a, 0x0078, 0x2e18, 0xa005, 0x00c0, 0x2e14, 0x7a38, 0xd2fc, - 0x0040, 0x2e0c, 0x70a4, 0xa005, 0x00c0, 0x2e0c, 0x2019, 0x002a, - 0x1078, 0x202f, 0x70a7, 0x0001, 0x707f, 0x0000, 0x7083, 0x000e, - 0x1078, 0x2e9c, 0x0078, 0x2e18, 0x7083, 0x0002, 0x707b, 0x0000, - 0x0f7f, 0x007c, 0x7083, 0x000b, 0x2011, 0x720e, 0x22a0, 0x20a9, + 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, 0x321b, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x6030, + 0x41a4, 0x1078, 0x35cc, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x6030, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, - 0x2e5e, 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0084, 0x00c0, - 0x2e5a, 0x2079, 0x7280, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x2e5a, - 0x7834, 0xa005, 0x00c0, 0x2e5a, 0x7083, 0x000c, 0x1078, 0x2e60, - 0x0078, 0x2e5e, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, - 0x7083, 0x000d, 0x1078, 0x321b, 0x20a3, 0x1107, 0x20a3, 0x0000, - 0x2099, 0x728e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0084, 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, - 0xa005, 0x0040, 0x2e9a, 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, - 0x0084, 0x00c0, 0x2e96, 0x2079, 0x7280, 0x7a30, 0xa296, 0x1107, - 0x00c0, 0x2e96, 0x7834, 0xa005, 0x00c0, 0x2e96, 0x1078, 0x320d, - 0x7083, 0x000e, 0x1078, 0x2e9c, 0x0078, 0x2e9a, 0x7083, 0x0002, - 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000f, 0x707b, 0x0000, - 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, - 0x2009, 0x07d0, 0x2011, 0x318e, 0x1078, 0x40c4, 0x007c, 0x7078, - 0xa005, 0x0040, 0x2eb7, 0x2011, 0x318e, 0x1078, 0x40d1, 0x007c, - 0x7083, 0x0011, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7280, - 0x20a1, 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, - 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, 0x1078, 0x31b2, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x2eff, 0x2011, 0x318e, - 0x1078, 0x40d1, 0xa086, 0x0014, 0x00c0, 0x2efd, 0x2079, 0x7280, - 0x7a30, 0xa296, 0x1103, 0x00c0, 0x2efd, 0x7834, 0xa005, 0x00c0, - 0x2efd, 0x7a38, 0xd2fc, 0x0040, 0x2ef7, 0x70a4, 0xa005, 0x00c0, - 0x2ef7, 0x2019, 0x002a, 0x1078, 0x202f, 0x70a7, 0x0001, 0x7083, - 0x0012, 0x1078, 0x2f01, 0x0078, 0x2eff, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0013, 0x1078, 0x3227, 0x20a3, 0x1103, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x728e, 0x706c, 0xa005, 0x00c0, 0x2f1d, - 0x714c, 0xa186, 0xffff, 0x0040, 0x2f1d, 0x1078, 0x3152, 0x0040, - 0x2f1d, 0x2019, 0x002a, 0x1078, 0x202f, 0x20a9, 0x0008, 0x2298, - 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x2f59, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0014, 0x00c0, 0x2f57, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x2f57, 0x7834, - 0xa005, 0x00c0, 0x2f57, 0x7a38, 0xd2fc, 0x0040, 0x2f51, 0x70a4, - 0xa005, 0x00c0, 0x2f51, 0x2019, 0x002a, 0x1078, 0x202f, 0x70a7, - 0x0001, 0x7083, 0x0014, 0x1078, 0x2f5b, 0x0078, 0x2f59, 0x707b, - 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0015, 0x1078, 0x3227, 0x20a3, - 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0x728e, 0x706c, 0xa006, - 0x00c0, 0x2f77, 0x7150, 0xa186, 0xffff, 0x0040, 0x2f77, 0xa180, - 0x2091, 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x3152, 0x20a9, - 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, - 0x0040, 0x2fcc, 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0014, - 0x00c0, 0x2fca, 0x2079, 0x7280, 0x7a30, 0xa296, 0x1105, 0x00c0, - 0x2fca, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x2fb1, 0x7a38, - 0xd2fc, 0x0040, 0x2fad, 0x70a4, 0xa005, 0x00c0, 0x2fad, 0x2019, - 0x002a, 0x1078, 0x202f, 0x70a7, 0x0001, 0x707f, 0x0001, 0x0078, - 0x2fc4, 0xa005, 0x00c0, 0x2fca, 0x7a38, 0xd2fc, 0x0040, 0x2fc2, - 0x70a4, 0xa005, 0x00c0, 0x2fc2, 0x2019, 0x002a, 0x1078, 0x202f, - 0x70a7, 0x0001, 0x707f, 0x0000, 0x7083, 0x0016, 0x1078, 0x2fce, - 0x0078, 0x2fcc, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x2099, 0x7280, 0x20a1, 0x020b, 0x20a9, 0x000e, - 0x53a6, 0x3430, 0x2011, 0x728e, 0x707c, 0xa005, 0x0040, 0x2fe4, - 0x7083, 0x0017, 0x0078, 0x2fe6, 0x7083, 0x001b, 0x706c, 0xa005, - 0x00c0, 0x2ff0, 0x1078, 0x30bc, 0x0040, 0x3000, 0x0078, 0x2ffa, - 0x20a9, 0x0008, 0x2099, 0x728e, 0x26a0, 0x53a6, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x31b2, 0x0078, 0x3002, - 0x1078, 0x2c5d, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3023, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0084, 0x00c0, 0x3021, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3021, 0x7834, - 0xa005, 0x00c0, 0x3021, 0x7083, 0x0018, 0x1078, 0x3025, 0x0078, - 0x3023, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0019, 0x1078, - 0x3227, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, 0x728e, - 0x2039, 0x720e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x2728, 0x2514, - 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, - 0xa205, 0x202a, 0x6030, 0x2310, 0x8214, 0xa2a0, 0x720e, 0x2414, - 0xa38c, 0x0001, 0x0040, 0x3050, 0xa294, 0xff00, 0x0078, 0x3053, - 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, - 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, - 0x1078, 0x31b2, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3085, - 0x2011, 0x318e, 0x1078, 0x40d1, 0xa086, 0x0084, 0x00c0, 0x3083, - 0x2079, 0x7280, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x3083, 0x7834, - 0xa005, 0x00c0, 0x3083, 0x1078, 0x320d, 0x7083, 0x001a, 0x1078, - 0x3087, 0x0078, 0x3085, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, - 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7280, 0x20a1, - 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, - 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x31b2, 0x007c, - 0x7078, 0xa005, 0x0040, 0x30ac, 0x2011, 0x318e, 0x1078, 0x40d1, - 0x7083, 0x001c, 0x1078, 0x30ad, 0x007c, 0x707b, 0x0000, 0x608b, - 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0001, 0x2009, 0x07d0, 0x2011, - 0x318e, 0x1078, 0x40c4, 0x007c, 0x087e, 0x097e, 0x2029, 0x6d52, - 0x252c, 0x20a9, 0x0008, 0x2041, 0x720e, 0x28a0, 0x2099, 0x728e, - 0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0040, 0x30d2, - 0x2011, 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0, - 0x30e4, 0xd5d4, 0x0040, 0x30df, 0x8210, 0x0078, 0x30e0, 0x8211, - 0x00f0, 0x30d2, 0x0078, 0x3149, 0x82ff, 0x00c0, 0x30f6, 0xd5d4, - 0x0040, 0x30f0, 0xa1a6, 0x3fff, 0x0040, 0x30dc, 0x0078, 0x30f4, - 0xa1a6, 0x3fff, 0x0040, 0x3149, 0xa18d, 0xc000, 0x20a9, 0x0010, - 0x2019, 0x0001, 0xd5d4, 0x0040, 0x30ff, 0x2019, 0x0010, 0x2120, - 0xd5d4, 0x0040, 0x3106, 0x8423, 0x0078, 0x3107, 0x8424, 0x00c8, - 0x3114, 0xd5d4, 0x0040, 0x310f, 0x8319, 0x0078, 0x3110, 0x8318, - 0x00f0, 0x3100, 0x0078, 0x3149, 0x23a8, 0x2021, 0x0001, 0x8426, - 0x8425, 0x00f0, 0x3118, 0x2328, 0x8529, 0xa2be, 0x0007, 0x0040, - 0x312c, 0x007e, 0x2039, 0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8, - 0xa5a8, 0x0010, 0x00f0, 0x3128, 0x754e, 0xa5c8, 0x2091, 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, - 0x314f, 0xa006, 0x0078, 0x314f, 0xa006, 0x1078, 0x12b7, 0x097f, - 0x087f, 0x007c, 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, - 0x0010, 0x0048, 0x315f, 0x8420, 0x8001, 0x0078, 0x3157, 0x2118, - 0x84ff, 0x0040, 0x3168, 0xa39a, 0x0010, 0x8421, 0x00c0, 0x3163, - 0x2021, 0x0001, 0x83ff, 0x0040, 0x3171, 0x8423, 0x8319, 0x00c0, - 0x316d, 0xa238, 0x2704, 0xa42c, 0x00c0, 0x3186, 0xa405, 0x203a, - 0x714e, 0xa1a0, 0x2091, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, - 0x0000, 0x65ea, 0x706f, 0x0001, 0xa084, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0x6d00, 0x7073, 0x0000, 0x0e7f, 0x007c, 0x0e7e, 0x0f7e, - 0x2079, 0x0100, 0x2071, 0x0140, 0x1078, 0x4fe5, 0x7004, 0xa084, - 0x4000, 0x0040, 0x319f, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, - 0x2091, 0x8000, 0x2071, 0x6d00, 0x7003, 0x0001, 0x2071, 0x6d20, + 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, + 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, + 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, + 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, + 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, + 0x007c, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, + 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, 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, + 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, + 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, + 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, + 0x1000, 0x7003, 0x0000, 0x127e, 0x2091, 0x8000, 0x2071, 0x7620, 0x2073, 0x0000, 0x7843, 0x0090, 0x7843, 0x0010, 0x127f, 0x0f7f, - 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0x6f1a, 0x2013, + 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0x7840, 0x2013, 0x0000, 0x707b, 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, - 0x60a7, 0x9575, 0x1078, 0x4fdc, 0x2009, 0x07d0, 0x2011, 0x318e, - 0x1078, 0x415f, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x2009, 0x00f7, 0x1078, 0x3233, 0x2061, 0x6f23, 0x601b, - 0x0000, 0x601f, 0x0000, 0x2061, 0x6d00, 0x6003, 0x0001, 0x2061, + 0x60a7, 0x9575, 0x1078, 0x5579, 0x2009, 0x07d0, 0x2011, 0x3542, + 0x1078, 0x45fe, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x2009, 0x00f7, 0x1078, 0x35e4, 0x2061, 0x7849, 0x601b, + 0x0000, 0x601f, 0x0000, 0x2061, 0x7600, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, - 0x31f0, 0x1078, 0x40c4, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, + 0x35a0, 0x1078, 0x4561, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x0100, 0x1078, - 0x4fe5, 0x2071, 0x0140, 0xa084, 0x4000, 0x0040, 0x3203, 0x7003, - 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x1dc9, 0x1078, - 0x31cb, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, 0x20a1, - 0x73c0, 0x2099, 0x728e, 0x3304, 0x8007, 0x20a2, 0x9398, 0x94a0, - 0x00f0, 0x3213, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, - 0x7200, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x2099, 0x7280, 0x20a1, 0x020b, 0x20a9, - 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e, 0x2061, 0x0100, 0x810f, - 0x2001, 0x6d2c, 0x2004, 0xa005, 0x00c0, 0x3244, 0x6030, 0xa084, - 0x00ff, 0xa105, 0x0078, 0x3246, 0xa185, 0x00f7, 0x604a, 0x007f, - 0x0c7f, 0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009, 0x6e00, 0xa006, - 0x200a, 0x8108, 0x00f0, 0x3250, 0x157f, 0x007c, 0x0d7e, 0x037e, - 0x157e, 0x137e, 0x147e, 0x2069, 0x6d51, 0xa006, 0x6002, 0x6007, - 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x2091, 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, 0x6082, 0x6086, 0x608a, - 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x61a2, 0x604a, 0x6810, - 0x603a, 0x680c, 0x6046, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, - 0x007c, 0x127e, 0x2091, 0x8000, 0x6944, 0xa1b4, 0x00ff, 0xa682, - 0x0010, 0x00c8, 0x3337, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, - 0x00c8, 0x333d, 0xa188, 0x6e00, 0x2104, 0xa065, 0x0040, 0x3316, - 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x331c, 0x6078, - 0xa00d, 0x0040, 0x32c1, 0xa680, 0x6c84, 0x2004, 0xa10c, 0x00c0, - 0x3310, 0x607c, 0xa00d, 0x0040, 0x32dd, 0xa680, 0x6c84, 0x2004, - 0xa10c, 0x0040, 0x32dd, 0x694c, 0xd1fc, 0x00c0, 0x32d3, 0x1078, - 0x33d0, 0x0078, 0x330b, 0x1078, 0x33a1, 0x694c, 0xd1ec, 0x00c0, - 0x330b, 0x1078, 0x34f0, 0x0078, 0x330b, 0x694c, 0xa184, 0xa000, - 0x0040, 0x32fb, 0xd1ec, 0x0040, 0x32f4, 0xd1fc, 0x0040, 0x32ec, - 0x1078, 0x3507, 0x0078, 0x32f7, 0xa680, 0x6c84, 0x200c, 0x607c, - 0xa105, 0x607e, 0x0078, 0x32fb, 0xd1fc, 0x0040, 0x32fb, 0x1078, - 0x33a1, 0x0078, 0x330b, 0x6050, 0xa00d, 0x0040, 0x3306, 0x2d00, - 0x200a, 0x6803, 0x0000, 0x6052, 0x0078, 0x330b, 0x2d00, 0x6052, - 0x604e, 0x6803, 0x0000, 0x1078, 0x4346, 0xa006, 0x127f, 0x007c, - 0x2001, 0x0005, 0x2009, 0x0000, 0x0078, 0x3341, 0x2001, 0x0028, - 0x2009, 0x0000, 0x0078, 0x3341, 0xa082, 0x0006, 0x0048, 0x32b7, - 0x2009, 0x6d0c, 0x210c, 0xd18c, 0x0040, 0x332a, 0x2001, 0x0004, - 0x0078, 0x3333, 0xd184, 0x0040, 0x3331, 0x2001, 0x0004, 0x0078, - 0x3333, 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x3341, 0x2001, - 0x0029, 0x2009, 0x0000, 0x0078, 0x3341, 0x2001, 0x0029, 0x2009, - 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0xa1b4, 0x00ff, 0xa682, - 0x0010, 0x00c8, 0x3386, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, - 0x00c8, 0x3376, 0xa188, 0x6e00, 0x2104, 0xa065, 0x0040, 0x3376, - 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x337c, 0x684c, - 0xd0ec, 0x0040, 0x3369, 0x1078, 0x3507, 0x1078, 0x33a1, 0x0078, - 0x3371, 0x1078, 0x33a1, 0x684c, 0xd0fc, 0x0040, 0x3371, 0x1078, - 0x34f0, 0x1078, 0x351b, 0xa006, 0x0078, 0x338a, 0x2001, 0x0028, - 0x2009, 0x0000, 0x0078, 0x338a, 0xa082, 0x0006, 0x0048, 0x335f, - 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x338a, 0x2001, 0x0029, - 0x2009, 0x0000, 0xa005, 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, - 0xa00d, 0x0040, 0x339a, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, - 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, - 0x3398, 0x127e, 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x33ad, - 0x6802, 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, - 0x6803, 0x0000, 0x0078, 0x33ab, 0x127e, 0x2091, 0x8000, 0x604c, - 0xa06d, 0x0040, 0x33c2, 0x6800, 0xa005, 0x00c0, 0x33c0, 0x6052, - 0x604e, 0xad05, 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x33cf, - 0x6800, 0xa005, 0x00c0, 0x33cd, 0x6052, 0x604e, 0xad05, 0x007c, - 0x6803, 0x0000, 0x6084, 0xa00d, 0x0040, 0x33da, 0x2d00, 0x200a, - 0x6086, 0x007c, 0x2d00, 0x6086, 0x6082, 0x0078, 0x33d9, 0x127e, - 0x0c7e, 0x027e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, - 0x0040, 0x33ed, 0xc285, 0x0078, 0x33ee, 0xc284, 0x6202, 0x027f, - 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, - 0x2260, 0x6204, 0xa294, 0xff00, 0xa215, 0x6206, 0x0c7f, 0x127f, + 0x5582, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0040, 0x35b4, + 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x202b, + 0x1078, 0x357b, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, + 0x20a1, 0x7cc0, 0x2099, 0x7b8e, 0x3304, 0x8007, 0x20a2, 0x9398, + 0x94a0, 0x00f0, 0x35c4, 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, + 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, + 0x007c, 0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0x7651, + 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, + 0x232f, 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, + 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, + 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, + 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, + 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, + 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, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, - 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f, 0x007c, - 0x027e, 0xa182, 0x00ff, 0x0048, 0x3419, 0xa085, 0x0001, 0x0078, - 0x342d, 0xa190, 0x6e00, 0x2204, 0xa065, 0x00c0, 0x342c, 0x017e, - 0x0d7e, 0x1078, 0x12f4, 0x2d60, 0x0d7f, 0x017f, 0x0040, 0x3415, - 0x2c00, 0x2012, 0x1078, 0x3256, 0xa006, 0x027f, 0x007c, 0x027e, - 0xa182, 0x00ff, 0x0048, 0x3438, 0xa085, 0x0001, 0x0078, 0x3445, - 0x0d7e, 0xa190, 0x6e00, 0x2204, 0xa06d, 0x0040, 0x3443, 0x2013, - 0x0000, 0x1078, 0x1328, 0x0d7f, 0xa006, 0x027f, 0x007c, 0x017e, - 0xa182, 0x00ff, 0x0048, 0x3450, 0xa085, 0x0001, 0x0078, 0x3457, - 0xa188, 0x6e00, 0x2104, 0xa065, 0x0040, 0x344c, 0xa006, 0x017f, - 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, - 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0x728e, 0x6808, 0x605e, - 0x6810, 0x6062, 0x6138, 0xa10a, 0x0048, 0x346f, 0x603a, 0x6814, - 0x6066, 0x2099, 0x7296, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, - 0x53a3, 0x2099, 0x729a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, - 0x53a3, 0x2069, 0x72ae, 0x6904, 0xa18c, 0x00ff, 0x810f, 0x6808, - 0xa084, 0x00ff, 0xa105, 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, - 0x6818, 0x6076, 0xa182, 0x0211, 0x00c8, 0x349a, 0x2009, 0x0008, - 0x0078, 0x34c4, 0xa182, 0x0259, 0x00c8, 0x34a2, 0x2009, 0x0007, - 0x0078, 0x34c4, 0xa182, 0x02c1, 0x00c8, 0x34aa, 0x2009, 0x0006, - 0x0078, 0x34c4, 0xa182, 0x0349, 0x00c8, 0x34b2, 0x2009, 0x0005, - 0x0078, 0x34c4, 0xa182, 0x0421, 0x00c8, 0x34ba, 0x2009, 0x0004, - 0x0078, 0x34c4, 0xa182, 0x0581, 0x00c8, 0x34c2, 0x2009, 0x0003, - 0x0078, 0x34c4, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, - 0x0d7f, 0x007c, 0x0e7e, 0x2071, 0x728d, 0x2e04, 0x6896, 0x2071, - 0x728e, 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, - 0x6c84, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10d, - 0x617a, 0x127f, 0x007c, 0x2001, 0x6c84, 0xa600, 0x2004, 0x8002, - 0x127e, 0x2091, 0x8000, 0x6178, 0xa10c, 0x617a, 0x127f, 0x007c, - 0x2001, 0x6c84, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, - 0x617c, 0xa10c, 0x617e, 0x127f, 0x0078, 0x3500, 0x1078, 0x338c, - 0x1078, 0x3561, 0x00c0, 0x34fe, 0x1078, 0x351b, 0x007c, 0x2001, - 0x6c84, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x617c, 0xa10d, - 0x617e, 0x127f, 0x0078, 0x3516, 0x1078, 0x33d0, 0x1078, 0x3525, - 0x00c0, 0x3514, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4346, - 0x127f, 0x007c, 0xa01e, 0x0078, 0x3527, 0x2019, 0x0001, 0xa00e, - 0x127e, 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, - 0x3547, 0x8dff, 0x0040, 0x355c, 0x83ff, 0x0040, 0x353f, 0x6844, - 0xa084, 0x00ff, 0xa606, 0x0040, 0x354c, 0x0078, 0x3547, 0x683c, - 0xa406, 0x00c0, 0x3547, 0x6840, 0xa506, 0x0040, 0x354c, 0x2d08, - 0x6800, 0x2068, 0x0078, 0x3531, 0x6a00, 0x604c, 0xad06, 0x00c0, - 0x3554, 0x624e, 0x0078, 0x3557, 0xa180, 0x0000, 0x2202, 0x82ff, - 0x00c0, 0x355c, 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, - 0x3563, 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, - 0x3591, 0x83ff, 0x0040, 0x3574, 0x6844, 0xa084, 0x00ff, 0xa606, - 0x0040, 0x3581, 0x0078, 0x357c, 0x683c, 0xa406, 0x00c0, 0x357c, - 0x6840, 0xa506, 0x0040, 0x3581, 0x2d08, 0x6800, 0x2068, 0x0078, - 0x3566, 0x6a00, 0x6080, 0xad06, 0x00c0, 0x3589, 0x6282, 0x0078, - 0x358c, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x3591, 0x6186, - 0x8dff, 0x007c, 0x2001, 0x6c84, 0xa600, 0x2004, 0x6178, 0xa10c, - 0x0040, 0x359c, 0x2011, 0x0001, 0x617c, 0xa10c, 0x0040, 0x35a2, - 0xa295, 0x0002, 0x007c, 0x1078, 0x35ec, 0x0040, 0x35ab, 0x1078, - 0x61f8, 0x0078, 0x35ad, 0xa085, 0x0001, 0x007c, 0x1078, 0x35ec, - 0x0040, 0x35b6, 0x1078, 0x6187, 0x0078, 0x35b8, 0xa085, 0x0001, - 0x007c, 0x1078, 0x35ec, 0x0040, 0x35c1, 0x1078, 0x61cd, 0x0078, - 0x35c3, 0xa085, 0x0001, 0x007c, 0x1078, 0x35ec, 0x0040, 0x35cc, - 0x1078, 0x61a3, 0x0078, 0x35ce, 0xa085, 0x0001, 0x007c, 0x127e, - 0x007e, 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, 0x0040, 0x35e4, - 0x6800, 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x36a1, 0x007f, 0x0078, 0x35d5, 0x6083, 0x0000, 0x6087, 0x0000, - 0x0d7f, 0x007f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, - 0x2079, 0x6d51, 0x7804, 0xd0a4, 0x0040, 0x3618, 0x157e, 0x0c7e, - 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3447, 0x00c0, - 0x360c, 0x6004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, 0x00c0, - 0x360c, 0x6000, 0xc0ed, 0x6002, 0x017f, 0x8108, 0x00f0, 0x35fc, - 0x0c7f, 0x157f, 0x2009, 0x07d0, 0x2011, 0x361a, 0x1078, 0x415f, - 0x0f7f, 0x007c, 0x2011, 0x361a, 0x1078, 0x40d1, 0x157e, 0x0c7e, - 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3447, 0x00c0, - 0x3646, 0x6000, 0xd0ec, 0x0040, 0x3646, 0x047e, 0x62a0, 0xa294, - 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x6bf7, 0x6000, - 0xc0e5, 0xc0ec, 0x6002, 0x2019, 0x0029, 0x1078, 0x445c, 0x1078, - 0x43a9, 0x2009, 0x0000, 0x1078, 0x6a57, 0x047f, 0x017f, 0x8108, - 0x00f0, 0x3624, 0x0c7f, 0x157f, 0x007c, 0x0c7e, 0x6018, 0x2060, - 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x2071, 0x6ddf, 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, - 0x6ddf, 0x684c, 0xa005, 0x00c0, 0x367c, 0x7028, 0xc085, 0x702a, - 0xa085, 0x0001, 0x0078, 0x369f, 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, 0x36f2, 0x6804, 0xa00d, - 0x0040, 0x36c0, 0x0d7e, 0x0e7e, 0x2071, 0x6d00, 0x027e, 0xa016, - 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x00c0, - 0x36b1, 0x702e, 0x70a0, 0xa200, 0x70a2, 0x027f, 0x0e7f, 0x0d7f, - 0x2071, 0x6ddf, 0x701c, 0xa005, 0x00c0, 0x3703, 0x0068, 0x3701, - 0x2071, 0x6d51, 0x7004, 0xd09c, 0x0040, 0x3701, 0x6934, 0xa186, - 0x0103, 0x00c0, 0x3714, 0x6948, 0x6844, 0xa105, 0x00c0, 0x36f4, - 0x2009, 0x8020, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x3701, - 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, - 0x4080, 0x2071, 0x6d00, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, - 0x8000, 0x70a2, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0, - 0x3701, 0x6868, 0xa005, 0x00c0, 0x3701, 0x2009, 0x8020, 0x0078, - 0x36da, 0x2071, 0x6ddf, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, - 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x3711, 0x6902, 0x0078, - 0x3712, 0x711e, 0x0078, 0x36f2, 0xa18c, 0x00ff, 0xa18e, 0x0017, - 0x0040, 0x371e, 0xa18e, 0x001f, 0x00c0, 0x3701, 0x684c, 0xd0cc, - 0x0040, 0x3701, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, - 0x3701, 0x2009, 0x8021, 0x0078, 0x36da, 0x007e, 0x6837, 0x0103, - 0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, - 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0x6ddf, 0x7004, 0x0079, - 0x3741, 0x3749, 0x3758, 0x37e4, 0x37e5, 0x37f5, 0x37fb, 0x374a, - 0x37d2, 0x007c, 0x127e, 0x2091, 0x8000, 0x0068, 0x3757, 0x2009, - 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x127f, - 0x701c, 0xa06d, 0x0040, 0x37d1, 0x0e7e, 0x2071, 0x6d51, 0x7004, - 0xd09c, 0x0040, 0x37b3, 0x6934, 0xa186, 0x0103, 0x00c0, 0x378d, - 0x6948, 0x6844, 0xa105, 0x00c0, 0x37a6, 0x2009, 0x8020, 0x127e, - 0x2091, 0x8000, 0x0068, 0x3789, 0x2071, 0x0000, 0x7018, 0xd084, - 0x00c0, 0x3789, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, - 0x0001, 0x2091, 0x4080, 0x127f, 0x0e7f, 0x1078, 0x382e, 0x0078, - 0x37d1, 0x127f, 0x0e7f, 0x0078, 0x37d1, 0xa18c, 0x00ff, 0xa18e, - 0x0017, 0x0040, 0x3797, 0xa18e, 0x001f, 0x00c0, 0x37b3, 0x684c, - 0xd0cc, 0x0040, 0x37b3, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, - 0x00c0, 0x37b3, 0x2009, 0x8021, 0x0078, 0x376f, 0x6844, 0xa086, - 0x0100, 0x00c0, 0x37b3, 0x6868, 0xa005, 0x00c0, 0x37b3, 0x2009, - 0x8020, 0x0078, 0x376f, 0x0e7f, 0x1078, 0x3842, 0x0040, 0x37d1, - 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x00c0, - 0x37c8, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x37c8, 0x710e, - 0x7007, 0x0003, 0x1078, 0x3862, 0x7050, 0xa086, 0x0100, 0x0040, - 0x37e5, 0x007c, 0x701c, 0xa06d, 0x0040, 0x37e3, 0x1078, 0x3842, - 0x0040, 0x37e3, 0x7007, 0x0003, 0x1078, 0x3862, 0x7050, 0xa086, - 0x0100, 0x0040, 0x37e5, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100, - 0x00c0, 0x37ee, 0x7007, 0x0004, 0x0078, 0x37f5, 0xa086, 0x0200, - 0x00c0, 0x37f4, 0x7007, 0x0005, 0x007c, 0x1078, 0x37fc, 0x7006, - 0x1078, 0x382e, 0x007c, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, - 0x0048, 0x3809, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0078, - 0x3813, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x3813, 0x7070, - 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, 0x00c0, - 0x3827, 0x127e, 0x2091, 0x8000, 0x0068, 0x382a, 0x2001, 0x000d, - 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x127f, 0x007c, 0x2001, - 0x0007, 0x007c, 0x2001, 0x0006, 0x127f, 0x007c, 0x701c, 0xa06d, - 0x0040, 0x3841, 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, - 0x2d04, 0x701e, 0xa005, 0x00c0, 0x383e, 0x701a, 0x127f, 0x1078, - 0x1328, 0x007c, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, - 0x3851, 0x2304, 0x230c, 0xa10e, 0x0040, 0x3851, 0xa006, 0x0078, - 0x3861, 0x732c, 0x8319, 0x7130, 0xa102, 0x00c0, 0x385b, 0x2300, - 0xa005, 0x0078, 0x3861, 0x0048, 0x3860, 0xa302, 0x0078, 0x3861, - 0x8002, 0x007c, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, - 0x0000, 0x127e, 0x2091, 0x8000, 0x2009, 0x6f31, 0x2104, 0xc08d, - 0x200a, 0x127f, 0x1078, 0x1379, 0x007c, 0x2071, 0x6dad, 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, 0x6dad, 0x6848, 0xa005, 0x00c0, 0x389e, 0x7028, - 0xc085, 0x702a, 0xa085, 0x0001, 0x0078, 0x38c3, 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, 0x6dad, - 0x7004, 0x1079, 0x3923, 0x700c, 0x0079, 0x38ce, 0x38d3, 0x38c8, - 0x38c8, 0x38c8, 0x38c8, 0x007c, 0x700c, 0x0079, 0x38d7, 0x38dc, - 0x3921, 0x3921, 0x3922, 0x3922, 0x7830, 0x7930, 0xa106, 0x0040, - 0x38e6, 0x7830, 0x7930, 0xa106, 0x00c0, 0x390c, 0x7030, 0xa10a, - 0x0040, 0x390c, 0x00c8, 0x38ee, 0x712c, 0xa10a, 0xa18a, 0x0002, - 0x00c8, 0x390d, 0x1078, 0x12f4, 0x0040, 0x390c, 0x2d00, 0x705a, - 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, - 0x2091, 0x8000, 0x2009, 0x6f31, 0x2104, 0xc085, 0x200a, 0x007f, - 0x700e, 0x127f, 0x1078, 0x1379, 0x007c, 0x1078, 0x12f4, 0x0040, - 0x390c, 0x2d00, 0x705a, 0x1078, 0x12f4, 0x00c0, 0x3919, 0x0078, - 0x38f8, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x0078, - 0x38fc, 0x007c, 0x007c, 0x3934, 0x3935, 0x396c, 0x396d, 0x3921, - 0x39a3, 0x39a8, 0x39df, 0x39e0, 0x39fb, 0x39fc, 0x39fd, 0x39fe, - 0x39ff, 0x3a00, 0x3a69, 0x3a93, 0x007c, 0x700c, 0x0079, 0x3938, - 0x393d, 0x3940, 0x3950, 0x396b, 0x396b, 0x1078, 0x38d4, 0x007c, - 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x3d52, 0x0040, - 0x394d, 0x2091, 0x8000, 0x1078, 0x38d4, 0x0d7f, 0x0078, 0x3959, - 0x127e, 0x8001, 0x700e, 0x1078, 0x3d52, 0x7058, 0x2068, 0x7084, - 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, - 0xa08a, 0x0020, 0x00c8, 0x3968, 0x1079, 0x3983, 0x127f, 0x007c, - 0x127f, 0x1078, 0x3a01, 0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, - 0x6dad, 0x700c, 0x0079, 0x3974, 0x3979, 0x3979, 0x3979, 0x397b, - 0x397f, 0x0e7f, 0x007c, 0x700f, 0x0001, 0x0078, 0x3981, 0x700f, - 0x0002, 0x0e7f, 0x007c, 0x3a01, 0x3a01, 0x3a1d, 0x3a01, 0x3aff, - 0x3a01, 0x3a01, 0x3a01, 0x3a01, 0x3a01, 0x3a1d, 0x3b44, 0x3b8d, - 0x3be5, 0x3bf8, 0x3a01, 0x3a01, 0x3a39, 0x3a1d, 0x3a01, 0x3a01, - 0x3a4f, 0x3c74, 0x3c91, 0x3a01, 0x3a39, 0x3a01, 0x3a01, 0x3a01, - 0x3a01, 0x3a01, 0x3c91, 0x7020, 0x2068, 0x1078, 0x1328, 0x007c, - 0x700c, 0x0079, 0x39ab, 0x39b0, 0x39b3, 0x39c3, 0x39de, 0x39de, - 0x1078, 0x38d4, 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, - 0x1078, 0x3d52, 0x0040, 0x39c0, 0x2091, 0x8000, 0x1078, 0x38d4, - 0x0d7f, 0x0078, 0x39cc, 0x127e, 0x8001, 0x700e, 0x1078, 0x3d52, - 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, - 0x6834, 0xa084, 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x39db, 0x1079, - 0x39e1, 0x127f, 0x007c, 0x127f, 0x1078, 0x3a01, 0x007c, 0x007c, - 0x007c, 0x3a01, 0x3a1d, 0x3ae9, 0x3a01, 0x3a1d, 0x3a01, 0x3a1d, - 0x3a1d, 0x3a01, 0x3a1d, 0x3ae9, 0x3a1d, 0x3a1d, 0x3a1d, 0x3a1d, - 0x3a1d, 0x3a01, 0x3a1d, 0x3ae9, 0x3a01, 0x3a01, 0x3a1d, 0x3a01, - 0x3a01, 0x3a01, 0x3a1d, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, - 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, - 0x127e, 0x2091, 0x8000, 0x1078, 0x36a1, 0x127f, 0x007c, 0x7007, - 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, - 0x8000, 0x1078, 0x36a1, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, - 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, - 0x36a1, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, - 0xc0dd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x36a1, 0x127f, - 0x007c, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3a0f, 0x8001, - 0x00c0, 0x3a46, 0x7007, 0x0001, 0x0078, 0x3ac8, 0x7007, 0x0006, - 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x3ac8, 0x007c, 0x2d00, - 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, - 0x6dd8, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, 0x3a2b, - 0x6884, 0xa08a, 0x0003, 0x00c8, 0x3a2b, 0xa080, 0x3ab9, 0x2004, - 0x70c6, 0x7010, 0xa015, 0x0040, 0x3ab3, 0x1078, 0x12f4, 0x00c0, - 0x3a74, 0x7007, 0x000f, 0x007c, 0x2d00, 0x7022, 0x70c4, 0x2060, - 0x6000, 0x6836, 0x6004, 0xad00, 0x7096, 0x6008, 0xa20a, 0x00c8, - 0x3a83, 0xa00e, 0x2200, 0x7112, 0x620c, 0x8003, 0x800b, 0xa296, - 0x0004, 0x0040, 0x3a8c, 0xa108, 0x719a, 0x810b, 0x719e, 0xae90, - 0x0022, 0x1078, 0x135f, 0x7090, 0xa08e, 0x0100, 0x0040, 0x3aa7, - 0xa086, 0x0200, 0x0040, 0x3a9f, 0x7007, 0x0010, 0x007c, 0x7020, - 0x2068, 0x1078, 0x1328, 0x7014, 0x2068, 0x0078, 0x3a2b, 0x7020, - 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, 0x2068, 0x6906, - 0x711a, 0x0078, 0x3a69, 0x7014, 0x2068, 0x7007, 0x0001, 0x0078, - 0x3ac8, 0x3abc, 0x3ac0, 0x3ac4, 0x0002, 0x0011, 0x0007, 0x0004, + 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, + 0x157e, 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, + 0xc08c, 0x6002, 0x2069, 0x7b8e, 0x6808, 0x605e, 0x6810, 0x6062, + 0x6138, 0xa10a, 0x0048, 0x384d, 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, + 0x007c, 0x0e7e, 0x2071, 0x7b8d, 0x2e04, 0x6896, 0x2071, 0x7b8e, + 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75d5, + 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10d, 0x617a, + 0x127f, 0x007c, 0x2001, 0x75d5, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, + 0x00c0, 0x3c08, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c0b, 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, + 0x7053, 0x0000, 0x127e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, + 0xc08d, 0x200a, 0x127f, 0x1078, 0x1399, 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, + 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, + 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, + 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, + 0x007c, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, + 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, + 0x2091, 0x8000, 0x1078, 0x3a7a, 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, + 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, + 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, + 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, 0x000a, 0x000f, 0x0005, 0x0006, 0x0012, 0x000f, 0x0005, 0x0006, - 0x2009, 0x6d2c, 0x210c, 0x81ff, 0x00c0, 0x3ae3, 0x6838, 0xa084, - 0x00ff, 0x683a, 0x6853, 0x0000, 0x1078, 0x3299, 0x00c0, 0x3ad9, - 0x007c, 0x1078, 0x372d, 0x127e, 0x2091, 0x8000, 0x1078, 0x36a1, - 0x127f, 0x0078, 0x3ad8, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, - 0x3ad9, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, 0x7010, - 0x8001, 0x7012, 0x0040, 0x3af8, 0x7007, 0x0006, 0x0078, 0x3afe, - 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c, 0x7007, - 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, 0x00ff, - 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x3b2a, 0x2009, 0x0000, - 0x20a9, 0x007e, 0xa096, 0x0002, 0x0040, 0x3b2a, 0xa005, 0x00c0, - 0x3b41, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x3447, 0x00c0, - 0x3b41, 0x067e, 0x6e44, 0xa6b4, 0x000f, 0x1078, 0x34e3, 0x067f, - 0x0078, 0x3b41, 0x047e, 0x2011, 0x6d0c, 0x2224, 0xc484, 0xc48c, - 0x2412, 0x047f, 0x0c7e, 0x1078, 0x3447, 0x00c0, 0x3b3d, 0x2091, - 0x8000, 0x607b, 0x0000, 0x2091, 0x8001, 0x8108, 0x00f0, 0x3b33, - 0x0c7f, 0x1078, 0x1328, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, - 0x0001, 0x2001, 0x6d52, 0x2004, 0xd0a4, 0x0040, 0x3b84, 0x6944, - 0x1078, 0x3d6e, 0x6100, 0xd184, 0x0040, 0x3b69, 0x6858, 0xa084, - 0x00ff, 0x00c0, 0x3b87, 0x6000, 0xd084, 0x0040, 0x3b84, 0x6004, - 0xa005, 0x00c0, 0x3b8a, 0x6003, 0x0000, 0x600b, 0x0000, 0x0078, - 0x3b81, 0x2011, 0x0001, 0x6860, 0xa005, 0x00c0, 0x3b71, 0x2001, - 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, 0x0040, 0x3b84, - 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3b84, 0x600a, - 0x6202, 0x127f, 0x0078, 0x3d41, 0x127f, 0x0078, 0x3d39, 0x127f, - 0x0078, 0x3d31, 0x127f, 0x0078, 0x3d35, 0x127e, 0x2091, 0x8000, - 0x7007, 0x0001, 0x2001, 0x6d52, 0x2004, 0xd0a4, 0x0040, 0x3be2, - 0x6944, 0x1078, 0x3d6e, 0x6000, 0xa084, 0x0001, 0x0040, 0x3be2, - 0x6204, 0x6308, 0x6c48, 0xa484, 0x0003, 0x0040, 0x3bba, 0x6958, - 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x3bb3, 0x2100, 0xa210, 0x0048, - 0x3bdf, 0x0078, 0x3bba, 0x8001, 0x00c0, 0x3bdf, 0x2100, 0xa212, - 0x0048, 0x3bdf, 0xa484, 0x000c, 0x0040, 0x3bd4, 0x6958, 0x810f, - 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, 0x3bcc, 0x2100, 0xa318, - 0x0048, 0x3bdf, 0x0078, 0x3bd4, 0xa082, 0x0004, 0x00c0, 0x3bdf, - 0x2100, 0xa31a, 0x0048, 0x3bdf, 0x6860, 0xa005, 0x0040, 0x3bda, - 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, 0x0078, 0x3d41, 0x127f, - 0x0078, 0x3d3d, 0x127f, 0x0078, 0x3d39, 0x127e, 0x2091, 0x8000, - 0x7007, 0x0001, 0x6944, 0x1078, 0x3d6e, 0x6308, 0x8318, 0x0048, - 0x3bf5, 0x630a, 0x127f, 0x0078, 0x3d4f, 0x127f, 0x0078, 0x3d3d, - 0x127e, 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, - 0x0040, 0x3c0c, 0x027e, 0x2009, 0x0000, 0x2011, 0xfcff, 0x1078, - 0x41f4, 0x027f, 0x0078, 0x3c42, 0x6858, 0xa005, 0x0040, 0x3c56, - 0x685c, 0xa065, 0x0040, 0x3c52, 0x2001, 0x6d2c, 0x2004, 0xa005, - 0x0040, 0x3c1e, 0x1078, 0x6283, 0x0078, 0x3c24, 0x6013, 0x0400, - 0x2009, 0x0041, 0x1078, 0x5591, 0x6958, 0xa18c, 0xe600, 0xa186, - 0x2000, 0x0040, 0x3c3a, 0xa186, 0x0400, 0x0040, 0x3c3a, 0x6944, - 0x0c7e, 0x1078, 0x416d, 0x6000, 0xa084, 0xfdff, 0x6002, 0x0c7f, - 0x0078, 0x3c42, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078, - 0x41f4, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x3c4e, 0x6944, 0x1078, - 0x416d, 0x6008, 0x8000, 0x0048, 0x3c4e, 0x600a, 0x0c7f, 0x127f, - 0x0078, 0x3d41, 0x0c7f, 0x127f, 0x0078, 0x3d39, 0x6954, 0xa186, - 0x0020, 0x0040, 0x3c6c, 0xa186, 0x0029, 0x00c0, 0x3c52, 0x6944, - 0xa18c, 0xff00, 0x810f, 0x1078, 0x3447, 0x00c0, 0x3c42, 0x6000, - 0xc0e4, 0x6002, 0x0078, 0x3c42, 0x685c, 0xa065, 0x0040, 0x3c52, - 0x6017, 0x0014, 0x0078, 0x3c42, 0x6944, 0x1078, 0x3d6e, 0x6000, - 0xa084, 0x0001, 0x0040, 0x3c8d, 0x2091, 0x8000, 0x6204, 0x8210, - 0x0048, 0x3c87, 0x6206, 0x2091, 0x8001, 0x0078, 0x3d4f, 0x2091, - 0x8001, 0x6853, 0x0016, 0x0078, 0x3d48, 0x6853, 0x0007, 0x0078, - 0x3d48, 0x6834, 0x8007, 0xa084, 0x00ff, 0x00c0, 0x3c9b, 0x1078, - 0x3a0f, 0x0078, 0x3cad, 0x2030, 0x8001, 0x00c0, 0x3ca5, 0x7007, - 0x0001, 0x1078, 0x3cae, 0x0078, 0x3cad, 0x7007, 0x0006, 0x7012, - 0x2d00, 0x7016, 0x701a, 0x704b, 0x3cae, 0x007c, 0x0e7e, 0x2009, - 0x6d2c, 0x210c, 0x81ff, 0x00c0, 0x3d28, 0x6848, 0x2070, 0xae82, - 0x7400, 0x0048, 0x3d18, 0x2001, 0x6d15, 0x2004, 0xae02, 0x00c8, - 0x3d18, 0x6944, 0x1078, 0x3d6e, 0x6100, 0xa184, 0x0001, 0x0040, - 0x3cfe, 0xa184, 0x0100, 0x00c0, 0x3d1c, 0xa184, 0x0200, 0x00c0, - 0x3d20, 0x601c, 0xa005, 0x00c0, 0x3d24, 0x711c, 0xa186, 0x0006, - 0x00c0, 0x3d03, 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x127e, - 0x2091, 0x8000, 0x7010, 0xa005, 0x00c0, 0x3cf5, 0x7112, 0x7018, - 0xa065, 0x0040, 0x3d28, 0x6000, 0xd0e4, 0x00c0, 0x3d2c, 0x2e60, - 0x1078, 0x4176, 0x127f, 0x0e7f, 0x007c, 0x2068, 0x6800, 0xa005, - 0x00c0, 0x3cf5, 0x6902, 0x127f, 0x0e7f, 0x007c, 0x0e7f, 0x6853, - 0x0006, 0x0078, 0x3d48, 0x6944, 0xa18c, 0xff00, 0x810f, 0x1078, - 0x3447, 0x00c0, 0x3d2c, 0x6000, 0xd0e4, 0x00c0, 0x3d2c, 0x711c, - 0xa186, 0x0007, 0x00c0, 0x3d18, 0x6853, 0x0002, 0x0078, 0x3d2e, - 0x6853, 0x0008, 0x0078, 0x3d2e, 0x6853, 0x000e, 0x0078, 0x3d2e, - 0x6853, 0x0017, 0x0078, 0x3d2e, 0x6853, 0x0035, 0x0078, 0x3d2e, - 0x6853, 0x0028, 0x0078, 0x3d2e, 0x6853, 0x0029, 0x0e7f, 0x0078, - 0x3d48, 0x2009, 0x003e, 0x0078, 0x3d43, 0x2009, 0x0004, 0x0078, - 0x3d43, 0x2009, 0x0006, 0x0078, 0x3d43, 0x2009, 0x0016, 0x0078, - 0x3d43, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, - 0x2091, 0x8000, 0x1078, 0x36a1, 0x2091, 0x8001, 0x007c, 0x1078, - 0x1328, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, 0x3d5f, - 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, 0x3d6b, 0x7070, - 0xa080, 0x0040, 0x7072, 0x00c8, 0x3d6b, 0x7074, 0xa081, 0x0000, - 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, 0x1078, - 0x416d, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, - 0x8002, 0x2012, 0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, 0x20e1, - 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x3d8a, 0xa086, 0x1000, - 0x00c0, 0x3dab, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x3d91, - 0x3e60, 0xac84, 0x0007, 0x00c0, 0x3dab, 0xac82, 0x7400, 0x0048, - 0x3dab, 0x6854, 0xac02, 0x00c8, 0x3dab, 0x2009, 0x0047, 0x1078, - 0x5591, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x7a28, 0x7a1c, 0xd284, - 0x00c0, 0x3d7c, 0x007c, 0xa016, 0x1078, 0x1532, 0x0078, 0x3da1, - 0x157e, 0x137e, 0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, - 0x0070, 0x00c0, 0x3dd9, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, - 0x3dd9, 0x1078, 0x3de6, 0x0040, 0x3dd9, 0x20e1, 0x3000, 0x7828, - 0x7828, 0x1078, 0x3e04, 0x147f, 0x137f, 0x157f, 0x2009, 0x6f18, - 0x2104, 0xa005, 0x00c0, 0x3dd5, 0x007c, 0x1078, 0x476a, 0x0078, - 0x3dd4, 0x1078, 0x6c23, 0x1078, 0x3de6, 0x20e1, 0x3000, 0x7828, - 0x7828, 0x147f, 0x137f, 0x157f, 0x0078, 0x3dd4, 0xa484, 0x01ff, - 0x687a, 0xa005, 0x0040, 0x3df8, 0xa080, 0x001f, 0xa084, 0x03f8, - 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, - 0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, - 0xa085, 0x0001, 0x0078, 0x3df7, 0x7000, 0xa084, 0xff00, 0xa08c, - 0xf000, 0x8007, 0xa196, 0x0000, 0x00c0, 0x3e11, 0x0078, 0x3f51, - 0x007c, 0xa196, 0x2000, 0x00c0, 0x3e22, 0x6900, 0xa18e, 0x0001, - 0x00c0, 0x3e1e, 0x1078, 0x2aec, 0x0078, 0x3e10, 0x1078, 0x3e2a, - 0x0078, 0x3e10, 0xa196, 0x8000, 0x00c0, 0x3e10, 0x1078, 0x3fd7, - 0x0078, 0x3e10, 0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, - 0x0001, 0x0040, 0x3e37, 0xa196, 0x0023, 0x00c0, 0x3ef8, 0xa08e, - 0x0023, 0x00c0, 0x3e68, 0x1078, 0x404e, 0x0040, 0x3ef8, 0x7124, - 0x610a, 0x7030, 0xa08e, 0x0200, 0x00c0, 0x3e50, 0x7034, 0xa005, - 0x00c0, 0x3ef8, 0x2009, 0x0015, 0x1078, 0x5591, 0x0078, 0x3ef8, - 0xa08e, 0x0210, 0x00c0, 0x3e5a, 0x2009, 0x0015, 0x1078, 0x5591, - 0x0078, 0x3ef8, 0xa08e, 0x0100, 0x00c0, 0x3ef8, 0x7034, 0xa005, - 0x00c0, 0x3ef8, 0x2009, 0x0016, 0x1078, 0x5591, 0x0078, 0x3ef8, - 0xa08e, 0x0022, 0x00c0, 0x3ef8, 0x7030, 0xa08e, 0x0300, 0x00c0, - 0x3e79, 0x7034, 0xa005, 0x00c0, 0x3ef8, 0x2009, 0x0017, 0x0078, - 0x3eda, 0xa08e, 0x0500, 0x00c0, 0x3e85, 0x7034, 0xa005, 0x00c0, - 0x3ef8, 0x2009, 0x0018, 0x0078, 0x3eda, 0xa08e, 0x2010, 0x00c0, - 0x3e8d, 0x2009, 0x0019, 0x0078, 0x3eda, 0xa08e, 0x2110, 0x00c0, - 0x3e95, 0x2009, 0x001a, 0x0078, 0x3eda, 0xa08e, 0x5200, 0x00c0, - 0x3ea1, 0x7034, 0xa005, 0x00c0, 0x3ef8, 0x2009, 0x001b, 0x0078, - 0x3eda, 0xa08e, 0x5000, 0x00c0, 0x3ead, 0x7034, 0xa005, 0x00c0, - 0x3ef8, 0x2009, 0x001c, 0x0078, 0x3eda, 0xa08e, 0x2400, 0x00c0, - 0x3eb3, 0x0078, 0x3ed8, 0xa08e, 0x5300, 0x00c0, 0x3eb9, 0x0078, - 0x3ed8, 0xa08e, 0x0f00, 0x00c0, 0x3ec1, 0x2009, 0x0020, 0x0078, - 0x3eda, 0xa08e, 0x5300, 0x00c0, 0x3ec7, 0x0078, 0x3ed8, 0xa08e, - 0x6104, 0x00c0, 0x3ed8, 0x2009, 0x728e, 0x2011, 0x8015, 0x211c, - 0x8108, 0x2124, 0x1078, 0x2a53, 0x2009, 0x0023, 0x0078, 0x3eda, - 0x2009, 0x001d, 0x017e, 0x2011, 0x7283, 0x2204, 0x8211, 0x220c, - 0x1078, 0x1e1b, 0x00c0, 0x3efa, 0x1078, 0x3410, 0x00c0, 0x3efa, - 0x6612, 0x6516, 0x0c7e, 0x1078, 0x5504, 0x0040, 0x3efd, 0x017f, - 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x5591, - 0x0c7f, 0x007c, 0x017f, 0x0078, 0x3ef8, 0x0c7f, 0x0078, 0x3efa, - 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, 0x00c0, 0x3f20, - 0xa596, 0xfffd, 0x00c0, 0x3f10, 0x2009, 0x007f, 0x0078, 0x3f4d, - 0xa596, 0xfffe, 0x00c0, 0x3f18, 0x2009, 0x007e, 0x0078, 0x3f4d, - 0xa596, 0xfffc, 0x00c0, 0x3f20, 0x2009, 0x0080, 0x0078, 0x3f4d, - 0x2011, 0x0000, 0x2021, 0x007e, 0x20a9, 0x0082, 0x2071, 0x6e7e, - 0x2e1c, 0x83ff, 0x00c0, 0x3f32, 0x82ff, 0x00c0, 0x3f41, 0x2410, - 0x0078, 0x3f41, 0x2368, 0x6b10, 0x007e, 0x2100, 0xa31e, 0x007f, - 0x00c0, 0x3f41, 0x6b14, 0xa31e, 0x00c0, 0x3f41, 0x2408, 0x0078, - 0x3f4d, 0x8420, 0x8e70, 0x00f0, 0x3f28, 0x82ff, 0x00c0, 0x3f4c, - 0xa085, 0x0001, 0x0078, 0x3f4e, 0x2208, 0xa006, 0x0d7f, 0x0e7f, - 0x007c, 0xa084, 0x0007, 0x0079, 0x3f56, 0x007c, 0x3f5e, 0x3f5e, - 0x3f5e, 0x3f5e, 0x3f5e, 0x3f5f, 0x3f78, 0x3fc0, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x3f77, 0x7120, 0x2160, 0xac8c, 0x0007, 0x00c0, - 0x3f77, 0xac8a, 0x7400, 0x0048, 0x3f77, 0x6854, 0xac02, 0x00c8, - 0x3f77, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x5591, 0x007c, - 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x3fbe, 0x2011, 0x7283, 0x2204, - 0x8211, 0x220c, 0x1078, 0x1e1b, 0x00c0, 0x3fbe, 0x1078, 0x3447, - 0x00c0, 0x3fbe, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, - 0x00c0, 0x3fa3, 0x0c7e, 0x1078, 0x5504, 0x017f, 0x0040, 0x3fbe, + 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, + 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, + 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, + 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, + 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, + 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, + 0x1078, 0x460c, 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, + 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, + 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, 0x20e1, 0x1000, + 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41f3, + 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, + 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, + 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, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x2009, 0x0044, 0x1078, - 0x5591, 0x0078, 0x3fbe, 0x0c7e, 0x1078, 0x5504, 0x017f, 0x0040, - 0x3fbe, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, - 0x00c0, 0x3fb6, 0x6007, 0x0005, 0x0078, 0x3fb8, 0x6007, 0x0001, - 0x6003, 0x0001, 0x1078, 0x4376, 0x1078, 0x476a, 0x0c7f, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x3fd6, 0x7020, 0x2060, 0xac84, 0x0007, - 0x00c0, 0x3fd6, 0xac82, 0x7400, 0x0048, 0x3fd6, 0x6854, 0xac02, - 0x00c8, 0x3fd6, 0x2009, 0x0045, 0x1078, 0x5591, 0x007c, 0x7110, - 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x3fe7, 0xa084, - 0x000f, 0xa08a, 0x0006, 0x10c8, 0x12b7, 0x1079, 0x3fe8, 0x007c, - 0x3fee, 0x3fef, 0x3fee, 0x3fee, 0x4030, 0x403f, 0x007c, 0x7110, - 0xd1bc, 0x00c0, 0x402f, 0x700c, 0x7108, 0x1078, 0x1e1b, 0x00c0, - 0x402f, 0x1078, 0x3410, 0x00c0, 0x402f, 0x6612, 0x6516, 0x6204, - 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x00c0, 0x4018, 0x0c7e, - 0x1078, 0x5504, 0x017f, 0x0040, 0x402f, 0x611a, 0x601f, 0x0005, - 0x7120, 0x610a, 0x2009, 0x0028, 0x1078, 0x5591, 0x0078, 0x402f, - 0x0c7e, 0x1078, 0x5504, 0x017f, 0x0040, 0x402f, 0x611a, 0x601f, - 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x402b, 0x2009, - 0x0005, 0x0078, 0x402d, 0x2009, 0x0001, 0x1078, 0x5591, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x403e, 0x1078, 0x404e, 0x0040, 0x403e, - 0x7124, 0x610a, 0x2009, 0x0029, 0x1078, 0x5591, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x404d, 0x1078, 0x404e, 0x0040, 0x404d, 0x7124, - 0x610a, 0x2009, 0x002a, 0x1078, 0x5591, 0x007c, 0x7020, 0x2060, - 0xac84, 0x0007, 0x00c0, 0x4061, 0xac82, 0x7400, 0x0048, 0x4061, - 0x2001, 0x6d15, 0x2004, 0xac02, 0x00c8, 0x4061, 0xa085, 0x0001, - 0x007c, 0xa006, 0x0078, 0x4060, 0x2071, 0x6f23, 0x7003, 0x0003, - 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, 0x7017, 0x7400, 0x7007, - 0x0000, 0x7026, 0x702b, 0x4ff2, 0x7032, 0x7037, 0x503e, 0x007c, - 0x2071, 0x6f23, 0x00e0, 0x40be, 0x2091, 0x6000, 0x700c, 0x8001, - 0x700e, 0x00c0, 0x4087, 0x700f, 0x0361, 0x7007, 0x0001, 0x127e, - 0x2091, 0x8000, 0x7024, 0xa00d, 0x0040, 0x409b, 0x7020, 0x8001, - 0x7022, 0x00c0, 0x409b, 0x7023, 0x0009, 0x8109, 0x7126, 0x00c0, - 0x409b, 0x7028, 0x107a, 0x7030, 0xa00d, 0x0040, 0x40ac, 0x702c, - 0x8001, 0x702e, 0x00c0, 0x40ac, 0x702f, 0x0009, 0x8109, 0x7132, - 0x00c0, 0x40ac, 0x7034, 0x107a, 0x7018, 0xa00d, 0x0040, 0x40bd, - 0x7008, 0x8001, 0x700a, 0x00c0, 0x40bd, 0x700b, 0x0009, 0x8109, - 0x711a, 0x00c0, 0x40bd, 0x701c, 0x107a, 0x127f, 0x7004, 0x0079, - 0x40c1, 0x40e8, 0x40e9, 0x4105, 0x0e7e, 0x2071, 0x6f23, 0x7018, - 0xa005, 0x00c0, 0x40cf, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, - 0x007c, 0x0e7e, 0x007e, 0x2071, 0x6f23, 0x701c, 0xa206, 0x00c0, - 0x40db, 0x701a, 0x701e, 0x007f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, - 0x6f23, 0x6088, 0xa102, 0x0048, 0x40e6, 0x618a, 0x0e7f, 0x007c, - 0x007c, 0x7110, 0x1078, 0x3447, 0x00c0, 0x40fb, 0x6088, 0x8001, - 0x0048, 0x40fb, 0x608a, 0x00c0, 0x40fb, 0x127e, 0x2091, 0x8000, - 0x1078, 0x476a, 0x127f, 0x8108, 0xa182, 0x00ff, 0x0048, 0x4103, - 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c, 0x7014, 0x2060, 0x127e, - 0x2091, 0x8000, 0x6014, 0xa005, 0x0040, 0x4134, 0x8001, 0x6016, - 0x00c0, 0x4134, 0x611c, 0xa186, 0x0003, 0x0040, 0x411b, 0xa186, - 0x0006, 0x00c0, 0x4132, 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, - 0x0048, 0x4132, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, - 0x412b, 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, - 0x0078, 0x4134, 0x1078, 0x5fea, 0x127f, 0xac88, 0x0008, 0x7116, - 0x2001, 0x6d16, 0x2004, 0xa102, 0x0048, 0x4142, 0x7017, 0x7400, - 0x7007, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x6f23, 0x7027, 0x07d0, - 0x7023, 0x0009, 0x0e7f, 0x007c, 0x2001, 0x6f2c, 0x2003, 0x0000, - 0x007c, 0x0e7e, 0x2071, 0x6f23, 0x7033, 0x07d0, 0x702f, 0x0009, - 0x0e7f, 0x007c, 0x2011, 0x6f2f, 0x2013, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0x6f23, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, - 0x0c7e, 0x2061, 0x6fb2, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0x6fb2, 0x2060, 0x007c, 0x684c, 0xa08c, - 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x41ac, 0xd0b4, 0x00c0, 0x4188, - 0xd0bc, 0x00c0, 0x419a, 0x2009, 0x0006, 0x1078, 0x41cf, 0x007c, - 0xd0fc, 0x0040, 0x4195, 0xa084, 0x0003, 0xa08e, 0x0003, 0x0040, - 0x41c8, 0xa08e, 0x0000, 0x00c0, 0x41c8, 0x2009, 0x0043, 0x1078, - 0x5591, 0x007c, 0xd0fc, 0x0040, 0x41a7, 0xa084, 0x0003, 0xa08e, - 0x0003, 0x0040, 0x41c8, 0xa08e, 0x0000, 0x00c0, 0x41c8, 0x2009, - 0x0042, 0x1078, 0x5591, 0x007c, 0xd0fc, 0x0040, 0x41be, 0xa084, - 0x0003, 0xa08e, 0x0003, 0x0040, 0x41c8, 0xa08e, 0x0002, 0x0040, - 0x41c2, 0x2009, 0x0041, 0x1078, 0x5591, 0x007c, 0x1078, 0x41cd, - 0x0078, 0x41bd, 0x2009, 0x0043, 0x1078, 0x5591, 0x0078, 0x41bd, - 0x2009, 0x0004, 0x1078, 0x41cf, 0x007c, 0x2009, 0x0001, 0x6010, - 0xa0ec, 0xf000, 0x0040, 0x41f3, 0x2068, 0x6952, 0x6800, 0x6012, - 0xa186, 0x0001, 0x00c0, 0x41ed, 0x694c, 0xa18c, 0x8100, 0xa18e, - 0x8100, 0x00c0, 0x41ed, 0x0c7e, 0x6944, 0x1078, 0x416d, 0x6204, - 0x8210, 0x0048, 0x41ec, 0x6206, 0x0c7f, 0x1078, 0x36a1, 0x6010, - 0xa06d, 0x10c0, 0x4176, 0x007c, 0x157e, 0x0c7e, 0x20a9, 0x0010, - 0x2061, 0x6fb2, 0x6000, 0x81ff, 0x0040, 0x4201, 0xa205, 0x0078, - 0x4202, 0xa204, 0x6002, 0xace0, 0x0008, 0x00f0, 0x41fa, 0x0c7f, - 0x157f, 0x007c, 0x6808, 0xa005, 0x0040, 0x4212, 0x8001, 0x680a, - 0xa085, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x2079, 0x6f10, - 0x127f, 0x0d7e, 0x2069, 0x6f10, 0x6803, 0x0005, 0x2069, 0x0004, + 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, + 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, + 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, + 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, + 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, + 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4578, 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, + 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, + 0x0e7e, 0x2071, 0x7849, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, + 0x0002, 0x0e7f, 0x007c, 0x2001, 0x7852, 0x2003, 0x0000, 0x007c, + 0x0e7e, 0x2071, 0x7849, 0x7033, 0x07d0, 0x702f, 0x0009, 0x0e7f, + 0x007c, 0x2011, 0x7855, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, + 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, + 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, + 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, 0x422e, 0x4238, 0x425d, - 0x428e, 0x423e, 0x425d, 0x4236, 0x4236, 0x4236, 0x1078, 0x12b7, - 0x1078, 0x414c, 0x1078, 0x476a, 0x0c7f, 0x007c, 0x62c0, 0x82ff, - 0x00c0, 0x4244, 0x0c7f, 0x007c, 0x2011, 0x318e, 0x1078, 0x40d1, - 0x7828, 0xa092, 0x0002, 0x00c8, 0x4253, 0x8000, 0x782a, 0x1078, - 0x31c2, 0x0078, 0x4242, 0x1078, 0x318e, 0x7807, 0x0003, 0x7827, - 0x0000, 0x782b, 0x0000, 0x0078, 0x4242, 0x1078, 0x414c, 0x62c0, - 0x82ff, 0x00c0, 0x426f, 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, - 0x12b7, 0x2009, 0x0013, 0x1078, 0x5591, 0x0c7f, 0x007c, 0x0c7e, - 0x7824, 0xa065, 0x1040, 0x12b7, 0x7804, 0xa086, 0x0004, 0x0040, - 0x42cc, 0x7828, 0xa092, 0x2710, 0x00c8, 0x4285, 0x8000, 0x782a, - 0x0c7f, 0x1078, 0x4fd7, 0x0078, 0x426d, 0x1078, 0x6c76, 0x2009, - 0x0014, 0x1078, 0x5591, 0x0c7f, 0x0078, 0x426d, 0x2001, 0x6f2c, - 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x42a2, 0x782b, 0x0000, - 0x7824, 0xa065, 0x1040, 0x12b7, 0x2009, 0x0013, 0x1078, 0x55df, - 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x7824, 0xa005, 0x1040, 0x12b7, - 0x781c, 0xa06d, 0x1040, 0x12b7, 0x6800, 0xc0dc, 0x6802, 0x7924, - 0x2160, 0x1078, 0x556a, 0x693c, 0x81ff, 0x1040, 0x12b7, 0x8109, - 0x693e, 0x6854, 0xa015, 0x0040, 0x42c0, 0x7a1e, 0x0078, 0x42c2, - 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, 0x0c7f, - 0x1078, 0x476a, 0x0078, 0x42a0, 0x6104, 0xa186, 0x0002, 0x0040, - 0x42d7, 0xa186, 0x0004, 0x0040, 0x42d7, 0x0078, 0x4279, 0x7808, - 0xac06, 0x0040, 0x4279, 0x1078, 0x4671, 0x1078, 0x4376, 0x0c7f, - 0x1078, 0x476a, 0x0078, 0x426d, 0x0c7e, 0x6027, 0x0002, 0x2011, - 0x6f2f, 0x2013, 0x0000, 0x62c8, 0x82ff, 0x00c0, 0x42fe, 0x62c4, - 0x82ff, 0x00c0, 0x42fe, 0x793c, 0xa1e5, 0x0000, 0x0040, 0x42fc, - 0x2009, 0x0049, 0x1078, 0x5591, 0x0c7f, 0x007c, 0x6017, 0x0010, - 0x793c, 0x81ff, 0x0040, 0x42fc, 0x7944, 0xa192, 0x2710, 0x00c8, - 0x431d, 0x8108, 0x7946, 0x1078, 0x4151, 0x793c, 0xa188, 0x0007, - 0x210c, 0xa18e, 0x0006, 0x00c0, 0x4319, 0x6017, 0x0012, 0x0078, - 0x42fc, 0x6017, 0x0016, 0x0078, 0x42fc, 0x1078, 0x6c76, 0x793c, - 0x2160, 0x2009, 0x004a, 0x1078, 0x5591, 0x0078, 0x42fc, 0x007e, - 0x017e, 0x0c7e, 0x127e, 0x600f, 0x0000, 0x2c08, 0x2061, 0x6f10, - 0x2091, 0x8000, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, - 0x4342, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f, 0x017f, - 0x007f, 0x007c, 0x6116, 0x6112, 0x0078, 0x433d, 0x0d7e, 0x2069, - 0x6f10, 0x6000, 0xd0d4, 0x0040, 0x435d, 0x6820, 0x8000, 0x6822, - 0xa086, 0x0001, 0x00c0, 0x4356, 0x2c00, 0x681e, 0x6804, 0xa084, - 0x0007, 0x0079, 0x4772, 0x0d7f, 0x007c, 0xc0d5, 0x6002, 0x6818, - 0xa005, 0x0040, 0x436f, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, - 0x681a, 0x0d7f, 0x685a, 0x2069, 0x6f10, 0x0078, 0x434d, 0x6056, - 0x605a, 0x2c00, 0x681a, 0x681e, 0x0078, 0x434d, 0x007e, 0x017e, - 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, - 0x6f10, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040, 0x4391, - 0xa080, 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, - 0x007c, 0x610e, 0x610a, 0x0078, 0x438c, 0x0c7e, 0x600f, 0x0000, - 0x2c08, 0x2061, 0x6f10, 0x6034, 0xa005, 0x0040, 0x43a5, 0xa080, - 0x0003, 0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136, 0x0078, - 0x43a3, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, - 0x127e, 0x2071, 0x6f10, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, - 0x8cff, 0x0040, 0x4405, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, - 0x00c0, 0x4400, 0x703c, 0xac06, 0x00c0, 0x43cb, 0x6003, 0x000a, - 0x630a, 0x0078, 0x4400, 0x7038, 0xac36, 0x00c0, 0x43d1, 0x660c, - 0x763a, 0x7034, 0xac36, 0x00c0, 0x43df, 0x2c00, 0xaf36, 0x0040, - 0x43dd, 0x2f00, 0x7036, 0x0078, 0x43df, 0x7037, 0x0000, 0x660c, - 0x067e, 0x2c00, 0xaf06, 0x0040, 0x43e8, 0x7e0e, 0x0078, 0x43e9, - 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, - 0x00c0, 0x440e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x36a1, 0x1078, 0x6276, 0x1078, 0x6283, 0x0c7f, 0x0078, 0x43b8, - 0x2c78, 0x600c, 0x2060, 0x0078, 0x43b8, 0x127f, 0x007f, 0x027f, - 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, - 0x0006, 0x00c0, 0x43f2, 0x1078, 0x6bb3, 0x0078, 0x43fb, 0x007e, - 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, 0x127e, 0x2091, - 0x8000, 0x2079, 0x6f10, 0x7838, 0xa065, 0x0040, 0x444a, 0x600c, - 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, 0x4435, 0x6003, - 0x000a, 0x630a, 0x2c30, 0x0078, 0x4447, 0x6010, 0x2068, 0x601c, - 0xa086, 0x0003, 0x00c0, 0x4453, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x36a1, 0x1078, 0x6276, 0x1078, 0x6283, 0x007f, - 0x0078, 0x4424, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, - 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x443c, - 0x1078, 0x6bb3, 0x0078, 0x4445, 0x027e, 0x1078, 0x4470, 0x1078, - 0x4507, 0x027f, 0x007c, 0x0f7e, 0x127e, 0x2079, 0x6f10, 0x2091, - 0x8000, 0x1078, 0x4599, 0x1078, 0x4601, 0x127f, 0x0f7f, 0x007c, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, - 0x8000, 0x2071, 0x6f10, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, - 0x44f6, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x44f1, - 0x7024, 0xac06, 0x00c0, 0x44b6, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x44b1, 0x1078, 0x4fe5, 0x68c3, 0x0000, 0x1078, 0x54a4, - 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x44a6, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x44ae, 0x6827, 0x0001, 0x037f, 0x0078, - 0x44b6, 0x6003, 0x0009, 0x630a, 0x0078, 0x44f1, 0x7014, 0xac36, - 0x00c0, 0x44bc, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x44ca, - 0x2c00, 0xaf36, 0x0040, 0x44c8, 0x2f00, 0x7012, 0x0078, 0x44ca, - 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x44d3, - 0x7e0e, 0x0078, 0x44d4, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, - 0x1078, 0x6120, 0x0040, 0x44ea, 0x601c, 0xa086, 0x0003, 0x00c0, - 0x44fe, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x36a1, - 0x1078, 0x6276, 0x1078, 0x6283, 0x1078, 0x5374, 0x0c7f, 0x0078, - 0x447e, 0x2c78, 0x600c, 0x2060, 0x0078, 0x447e, 0x127f, 0x007f, + 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, + 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, + 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, + 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4840, 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, + 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, + 0x7836, 0x0078, 0x484b, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, + 0x0078, 0x484b, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6020, 0x8000, 0x6022, + 0x6008, 0xa005, 0x0040, 0x488d, 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, + 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, + 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x48f2, 0x1078, 0x74fd, 0x0078, + 0x48fd, 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, + 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, 0x0f7e, 0x127e, 0x2079, 0x7836, 0x2091, 0x8000, 0x1078, + 0x4aa6, 0x1078, 0x4b0e, 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, + 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, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, - 0x0006, 0x00c0, 0x44e1, 0x1078, 0x6bb3, 0x0078, 0x44ea, 0x0c7e, - 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0x6e00, 0x2004, 0xa065, - 0x0040, 0x4595, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, 0x2071, 0x6f10, - 0x6654, 0x7018, 0xac06, 0x00c0, 0x451e, 0x761a, 0x701c, 0xac06, - 0x00c0, 0x452a, 0x86ff, 0x00c0, 0x4529, 0x7018, 0x701e, 0x0078, - 0x452a, 0x761e, 0x6058, 0xa07d, 0x0040, 0x452f, 0x7e56, 0xa6ed, - 0x0000, 0x0040, 0x4535, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, - 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x33c4, 0x0040, - 0x4591, 0x7624, 0x86ff, 0x0040, 0x4586, 0xa680, 0x0004, 0x2004, - 0xad06, 0x00c0, 0x4586, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x457d, 0x1078, 0x4fe5, 0x68c3, 0x0000, 0x1078, 0x54a4, + 0x0006, 0x00c0, 0x49e7, 0x1078, 0x74fd, 0x0078, 0x49f2, 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, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x4566, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x456e, 0x6827, 0x0001, 0x037f, 0x0d7f, - 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4577, 0x8001, 0x603e, 0x2660, - 0x1078, 0x6283, 0x0c7f, 0x0078, 0x4586, 0x0d7f, 0x0c7e, 0x2660, - 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x453d, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x36a1, 0x1078, 0x5374, 0x0078, - 0x453d, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f, 0x127f, 0x007f, 0x0c7f, - 0x007c, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, - 0xa065, 0x0040, 0x45f1, 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, - 0xac06, 0x00c0, 0x45d6, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, - 0x45d0, 0x1078, 0x4fe5, 0x68c3, 0x0000, 0x1078, 0x54a4, 0x7827, - 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, - 0x45c5, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, - 0xd084, 0x0040, 0x45cd, 0x6827, 0x0001, 0x037f, 0x0078, 0x45d6, - 0x6003, 0x0009, 0x630a, 0x2c30, 0x0078, 0x45ee, 0x6010, 0x2068, - 0x1078, 0x6120, 0x0040, 0x45ea, 0x601c, 0xa086, 0x0003, 0x00c0, - 0x45f8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x36a1, - 0x1078, 0x6276, 0x1078, 0x6283, 0x1078, 0x5374, 0x007f, 0x0078, - 0x45a0, 0x7e16, 0x7e12, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, - 0x601c, 0xa086, 0x0006, 0x00c0, 0x45e1, 0x1078, 0x6bb3, 0x0078, - 0x45ea, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, - 0x466a, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, - 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x33c4, 0x0040, 0x4667, 0x7e24, - 0x86ff, 0x0040, 0x465c, 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, - 0x465c, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x4653, - 0x1078, 0x4fe5, 0x68c3, 0x0000, 0x1078, 0x54a4, 0x7827, 0x0000, - 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x463c, - 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, - 0x0040, 0x4644, 0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, - 0xa005, 0x0040, 0x464d, 0x8001, 0x603e, 0x2660, 0x1078, 0x6283, - 0x0c7f, 0x0078, 0x465c, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, - 0x630a, 0x0c7f, 0x0078, 0x4613, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x36a1, 0x1078, 0x5374, 0x0078, 0x4613, 0x007f, - 0x0078, 0x4606, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, - 0x007c, 0x0e7e, 0x0c7e, 0x2071, 0x6f10, 0x7004, 0xa084, 0x0007, - 0x0079, 0x467a, 0x4684, 0x4687, 0x46a0, 0x46bc, 0x4701, 0x4684, - 0x4682, 0x4682, 0x1078, 0x12b7, 0x0c7f, 0x0e7f, 0x007c, 0x7024, - 0xa065, 0x0040, 0x4695, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, - 0x0040, 0x469c, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, - 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x4695, - 0x6018, 0x2060, 0x1078, 0x33c4, 0x6000, 0xc0dc, 0x6002, 0x7020, - 0x8001, 0x7022, 0x0040, 0x46b1, 0x6054, 0xa015, 0x0040, 0x46b8, + 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, + 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, + 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x4aee, 0x1078, 0x74fd, 0x0078, 0x4af7, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b7a, 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, + 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, + 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, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, - 0x7218, 0x721e, 0x0078, 0x46b1, 0x7024, 0xa065, 0x0040, 0x46fe, - 0x700c, 0xac06, 0x00c0, 0x46d3, 0x1078, 0x5374, 0x600c, 0xa015, - 0x0040, 0x46cf, 0x720e, 0x600f, 0x0000, 0x0078, 0x46fc, 0x720e, - 0x720a, 0x0078, 0x46fc, 0x7014, 0xac06, 0x00c0, 0x46e6, 0x1078, - 0x5374, 0x600c, 0xa015, 0x0040, 0x46e2, 0x7216, 0x600f, 0x0000, - 0x0078, 0x46fc, 0x7216, 0x7212, 0x0078, 0x46fc, 0x6018, 0x2060, - 0x1078, 0x33c4, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x5374, 0x701c, - 0xa065, 0x0040, 0x46fc, 0x6054, 0xa015, 0x0040, 0x46fa, 0x721e, - 0x0078, 0x46fc, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, - 0x007c, 0x7024, 0xa065, 0x0040, 0x470e, 0x1078, 0x5374, 0x600c, - 0xa015, 0x0040, 0x4715, 0x720e, 0x600f, 0x0000, 0x1078, 0x54a4, + 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, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, - 0x470e, 0x0d7e, 0x2069, 0x6f10, 0x6830, 0xa084, 0x0003, 0x0079, - 0x4721, 0x4727, 0x4729, 0x474f, 0x4725, 0x1078, 0x12b7, 0x0d7f, - 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x4745, 0x683c, - 0xa065, 0x0040, 0x473a, 0x600c, 0xa015, 0x0040, 0x4741, 0x6a3a, + 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, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, - 0x007c, 0x683a, 0x6836, 0x0078, 0x473a, 0x6843, 0x0000, 0x6838, - 0xa065, 0x0040, 0x473a, 0x6003, 0x0003, 0x0078, 0x473a, 0x0c7e, - 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x4767, - 0x600c, 0xa015, 0x0040, 0x4763, 0x6a3a, 0x600f, 0x0000, 0x683f, - 0x0000, 0x0078, 0x4767, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, - 0x0d7f, 0x007c, 0x0d7e, 0x2069, 0x6f10, 0x6804, 0xa084, 0x0007, - 0x0079, 0x4772, 0x477c, 0x4810, 0x4810, 0x4810, 0x4810, 0x4812, - 0x477a, 0x477a, 0x1078, 0x12b7, 0x6820, 0xa005, 0x00c0, 0x4782, - 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4791, 0x6807, - 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4858, 0x0c7f, 0x0d7f, - 0x007c, 0x6814, 0xa065, 0x0040, 0x479f, 0x6807, 0x0001, 0x6826, - 0x682b, 0x0000, 0x1078, 0x4858, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, - 0x037e, 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x480b, 0x704c, 0xa00d, - 0x0040, 0x47ae, 0x7088, 0xa005, 0x0040, 0x47c6, 0x7054, 0xa075, - 0x0040, 0x47b7, 0xa20e, 0x0040, 0x480b, 0x0078, 0x47bc, 0x6818, - 0xa20e, 0x0040, 0x480b, 0x2070, 0x704c, 0xa00d, 0x0040, 0x47ae, - 0x7088, 0xa005, 0x00c0, 0x47ae, 0x2e00, 0x681e, 0x733c, 0x7038, - 0xa302, 0x00c8, 0x47ae, 0x1078, 0x5539, 0x0040, 0x480b, 0x8318, + 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, + 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, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0015, 0x2004, 0xa08a, - 0x199a, 0x0048, 0x47dd, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, + 0x199a, 0x0048, 0x4ced, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, 0x0040, - 0x47ed, 0x2009, 0x0000, 0x0078, 0x47f2, 0xa1e0, 0x2091, 0x2c0c, - 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x4c44, 0x7300, - 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, - 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x0f7f, 0x0e7f, - 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, 0x0078, 0x4809, - 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x481e, 0x6807, - 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4858, 0x0c7f, 0x0d7f, - 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0x6f10, 0x6830, 0xa086, 0x0000, - 0x00c0, 0x483f, 0x6838, 0xa07d, 0x0040, 0x483f, 0x6833, 0x0001, - 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, 0x2200, 0x027f, - 0x1078, 0x1838, 0x00c0, 0x4842, 0x127f, 0x1078, 0x4ed5, 0x0d7f, - 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, - 0xa015, 0x0040, 0x4854, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, - 0x683f, 0x0000, 0x0078, 0x483f, 0x683a, 0x6836, 0x0078, 0x484e, - 0x601c, 0xa084, 0x000f, 0x1079, 0x485e, 0x007c, 0x4867, 0x4869, - 0x4b33, 0x4c15, 0x4869, 0x4b33, 0x4c15, 0x4867, 0x4869, 0x1078, - 0x12b7, 0x157e, 0x137e, 0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, - 0x0024, 0x10c8, 0x12b7, 0x6118, 0x2178, 0x79a0, 0xa1f8, 0x2091, - 0x2f0c, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0x1079, - 0x4887, 0x0f7f, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c, 0x48ad, - 0x48ec, 0x4904, 0x494c, 0x4979, 0x4981, 0x49a2, 0x49b3, 0x49c4, - 0x49cc, 0x49dd, 0x49cc, 0x4a25, 0x49b3, 0x4a55, 0x4a5d, 0x49c4, - 0x4a5d, 0x4a6e, 0x48ab, 0x48ab, 0x48ab, 0x48ab, 0x48ab, 0x48ab, - 0x48ab, 0x48ab, 0x48ab, 0x48ab, 0x48ab, 0x48ab, 0x50b8, 0x50cd, - 0x50f0, 0x5114, 0x49a2, 0x1078, 0x12b7, 0x20a1, 0x020b, 0x1078, - 0x4a83, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x0d7e, 0x2069, 0x6d51, - 0x6804, 0xd084, 0x0040, 0x48ce, 0x6828, 0x017e, 0x2069, 0x6d00, - 0x694c, 0xa106, 0x017f, 0x00c0, 0x48ce, 0x20a3, 0x0000, 0x6030, - 0xa084, 0x00ff, 0x20a2, 0x0d7f, 0x0078, 0x48d3, 0x0d7f, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x6d05, 0x53a6, - 0x20a9, 0x0004, 0x2099, 0x6d01, 0x53a6, 0x20a3, 0x0000, 0x6030, - 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x001c, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4a83, - 0x20a3, 0x0500, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6030, 0xa084, - 0x00ff, 0x20a2, 0x20a9, 0x0004, 0x2099, 0x6d05, 0x53a6, 0x60c3, - 0x0010, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4a83, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x4917, - 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0078, 0x4919, 0x20a3, - 0x0300, 0x20a3, 0x0000, 0x2099, 0x6f00, 0x20a9, 0x0008, 0x53a6, - 0x20a9, 0x0004, 0x2099, 0x6d05, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0x6d01, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x492c, - 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4932, 0x2099, 0x6f08, + 0x4d06, 0x7100, 0xd1f4, 0x0040, 0x4d02, 0x7114, 0xa18c, 0x00ff, + 0x0078, 0x4d0b, 0x2009, 0x0000, 0x0078, 0x4d0b, 0xa1e0, 0x232f, + 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x51c2, + 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, + 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa086, + 0x0000, 0x00c0, 0x4d58, 0x6838, 0xa07d, 0x0040, 0x4d58, 0x6833, + 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, 0x2200, + 0x027f, 0x1078, 0x1a4c, 0x00c0, 0x4d5b, 0x127f, 0x1078, 0x5457, + 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, + 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, + 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, + 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x00c0, 0x4e83, 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, + 0x2099, 0x7828, 0x33a6, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, + 0x4e7d, 0x0078, 0x4ea3, 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, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, - 0x493d, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4943, 0x60c3, - 0x0074, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4a83, + 0x4ea5, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4eab, 0x60c3, + 0x0074, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, - 0x6d51, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x4968, 0xa085, 0x0020, - 0xd1a4, 0x0040, 0x496d, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4fd1, - 0x007c, 0x20a1, 0x020b, 0x1078, 0x4a83, 0x20a3, 0x5000, 0x0078, - 0x4919, 0x20a1, 0x020b, 0x1078, 0x4a83, 0x20a3, 0x2110, 0x20a3, - 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0x20a3, 0x0000, 0x20a3, + 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, + 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0022, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, - 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4afa, 0x20a3, 0x0200, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, + 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, - 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4afa, 0x20a3, + 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, - 0x0008, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4afa, - 0x20a3, 0x0200, 0x0078, 0x4919, 0x20a1, 0x020b, 0x1078, 0x4afa, + 0x0008, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, + 0x20a3, 0x0200, 0x0078, 0x4e4a, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x7810, 0x20a2, - 0x60c3, 0x0008, 0x1078, 0x4fd1, 0x007c, 0x0d7e, 0x20a1, 0x020b, - 0x1078, 0x4afa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, - 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x4a03, 0x6998, - 0xa184, 0xc000, 0x00c0, 0x49ff, 0xd1ec, 0x0040, 0x49fb, 0x20a3, - 0x2100, 0x0078, 0x4a05, 0x20a3, 0x0100, 0x0078, 0x4a05, 0x20a3, - 0x0400, 0x0078, 0x4a05, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0x6d51, 0x7904, 0x0f7f, - 0xd1ac, 0x00c0, 0x4a15, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4a1a, + 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, + 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0x7651, 0x7904, 0x0f7f, + 0xd1ac, 0x00c0, 0x4f7d, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f82, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, 0x60c3, - 0x0014, 0x1078, 0x4fd1, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4afa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x6018, - 0x0d7e, 0x2068, 0x6804, 0x0d7f, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x0040, 0x4a3e, 0x20a3, 0x0400, 0x0078, 0x4a40, 0x20a3, 0x0100, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4afa, 0x20a3, 0x0200, 0x0078, 0x48b3, 0x20a1, 0x020b, 0x1078, - 0x4afa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, - 0x2a00, 0x60c3, 0x0008, 0x1078, 0x4fd1, 0x007c, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, 0x4afa, 0x20a3, 0x0100, - 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, - 0x1078, 0x4fd1, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, 0x4a96, - 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x0078, 0x4ac4, 0xa286, 0x007f, - 0x00c0, 0x4aa1, 0x0d7e, 0x20a3, 0x22ff, 0x20a3, 0xfffd, 0x0078, - 0x4ab8, 0xd2bc, 0x0040, 0x4ac0, 0xa286, 0x0080, 0x0d7e, 0x00c0, - 0x4aaf, 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0078, 0x4ab8, 0xa2e8, - 0x6e00, 0x2d6c, 0x6810, 0xa085, 0x2200, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x4ac8, - 0x20a3, 0x2200, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, - 0x20a3, 0x0129, 0x20a3, 0x0000, 0x1078, 0x4fc0, 0x22a2, 0x20a3, - 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, - 0x02ff, 0x2011, 0xfffc, 0x22a2, 0x0d7e, 0x2069, 0x6d19, 0x2da6, - 0x8d68, 0x2da6, 0x0d7f, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, - 0x4acc, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, - 0x0000, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x4b19, 0x0d7e, - 0xa0e8, 0x6e00, 0x2d6c, 0x6810, 0xa085, 0x2300, 0x20a2, 0x6814, - 0x20a2, 0x2069, 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, - 0x4b21, 0x20a3, 0x2300, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, - 0x22a2, 0x20a3, 0x0198, 0x20a3, 0x0000, 0x1078, 0x4fc0, 0x22a2, - 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x027f, 0x007c, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0025, - 0x1048, 0x12b7, 0xa08a, 0x002c, 0x10c8, 0x12b7, 0x6118, 0x2178, - 0x79a0, 0xa1f8, 0x2091, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, 0x2061, - 0x0100, 0x619a, 0xa082, 0x0025, 0x1079, 0x4b51, 0x0f7f, 0x0c7f, - 0x007c, 0x4b5a, 0x4b65, 0x4b7f, 0x4b58, 0x4b58, 0x4b58, 0x4b5a, - 0x1078, 0x12b7, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4b8e, 0x60c3, - 0x0000, 0x1078, 0x4fd1, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x4bbb, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, - 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x000c, 0x1078, 0x4fd1, 0x147f, 0x007c, 0x147e, - 0x20a1, 0x020b, 0x1078, 0x4be8, 0x20a3, 0x0003, 0x20a3, 0x0300, - 0x60c3, 0x0004, 0x1078, 0x4fd1, 0x147f, 0x007c, 0x027e, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, - 0x007e, 0x0048, 0x4bad, 0x0d7e, 0xa0e8, 0x6e00, 0x2d6c, 0x6810, - 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x6d19, 0x2da6, - 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x4bb5, 0x20a3, 0x8100, 0x6298, - 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, - 0x0000, 0x0078, 0x4acc, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x4bda, - 0x0d7e, 0xa0e8, 0x6e00, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x4be2, 0x20a3, 0x8400, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x00d1, 0x20a3, 0x0000, 0x0078, 0x4b25, - 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xa092, 0x007e, 0x0048, 0x4c07, 0x0d7e, 0xa0e8, 0x6e00, - 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, - 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x4c0f, 0x20a3, - 0x8500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, - 0x00d1, 0x20a3, 0x0000, 0x0078, 0x4b25, 0x0c7e, 0x0f7e, 0x2c78, - 0x7804, 0xa08a, 0x0040, 0x1048, 0x12b7, 0xa08a, 0x004f, 0x10c8, - 0x12b7, 0x7918, 0x2160, 0x61a0, 0xa1e0, 0x2091, 0x2c0c, 0xa18c, - 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, 0x0040, 0x1079, 0x4c33, - 0x0f7f, 0x0c7f, 0x007c, 0x4c44, 0x4d28, 0x4cd0, 0x4e50, 0x4c42, - 0x4c42, 0x4c42, 0x4c42, 0x4c42, 0x4c42, 0x4c42, 0x528d, 0x529e, - 0x52af, 0x52c0, 0x1078, 0x12b7, 0x0d7e, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x4c93, 0x7910, 0x2168, 0x6944, 0xa18c, 0x00ff, - 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x0006, - 0x8004, 0x20a2, 0xd1ac, 0x0040, 0x4c61, 0x20a3, 0x0002, 0x0078, - 0x4c6d, 0xd1b4, 0x0040, 0x4c68, 0x20a3, 0x0001, 0x0078, 0x4c6d, - 0x20a3, 0x0000, 0x2230, 0x0078, 0x4c6f, 0x6a80, 0x6e7c, 0x20a9, - 0x0008, 0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, - 0x4c73, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, - 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0x6f2c, 0x2003, - 0x07d0, 0x2001, 0x6f2b, 0x2003, 0x0009, 0x1078, 0x14e4, 0x147f, - 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, - 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, - 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x4cb9, 0x0d7e, - 0xa0e8, 0x6e00, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, - 0x20a2, 0x2069, 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, - 0x4cc1, 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, 0x4cf0, - 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, - 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x60c3, - 0x000c, 0x1078, 0x4fd1, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, - 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xd0bc, 0x0040, 0x4d0e, 0x0d7e, 0xa0e8, 0x6e00, 0x2d6c, - 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x6d19, - 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x4d16, 0x20a3, 0x0500, - 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0889, - 0x20a3, 0x0000, 0x1078, 0x4fc0, 0x22a2, 0x20a3, 0x0000, 0x7a08, - 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, - 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4e18, - 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x7810, 0xa084, 0xf000, 0x00c0, 0x4d45, 0x7810, 0xa084, 0x0700, - 0x8007, 0x1079, 0x4d4d, 0x0078, 0x4d48, 0xa006, 0x1079, 0x4d4d, - 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x4d57, 0x4db9, 0x4dbd, - 0x4de0, 0x4ded, 0x4dff, 0x4e03, 0x4d55, 0x1078, 0x12b7, 0x017e, - 0x037e, 0x694c, 0xa18c, 0x0003, 0xa186, 0x0000, 0x00c0, 0x4d6a, - 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x037f, 0x017f, - 0x0078, 0x4de4, 0xa186, 0x0001, 0x00c0, 0x4db4, 0x6b78, 0x23a2, - 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2, 0x22a2, - 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, 0x0040, 0x4db3, - 0xd3c4, 0x0040, 0x4d85, 0x687c, 0xa108, 0xd3cc, 0x0040, 0x4d8a, - 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, 0x0020, 0x201c, - 0x831f, 0x23a2, 0x8000, 0x00f0, 0x4d8f, 0x157f, 0x22a2, 0x22a2, - 0x22a2, 0xa184, 0x0003, 0x0040, 0x4db3, 0x20a1, 0x020b, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, - 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0898, 0x20a2, 0x1078, 0x4fc0, - 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, 0x017f, 0x1078, 0x4fd1, - 0x007c, 0x20a3, 0x0008, 0x0078, 0x4de2, 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, 0x4fd1, 0x007c, - 0x20a3, 0x0028, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x60c3, 0x0018, 0x1078, 0x4fd1, 0x007c, 0x20a3, 0x0100, 0x22a2, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x4fd1, 0x007c, 0x20a3, - 0x0008, 0x0078, 0x4de2, 0x037e, 0x7b10, 0xa384, 0xff00, 0x7812, - 0xa384, 0x00ff, 0x8001, 0x00c0, 0x4e11, 0x22a2, 0x037f, 0x0078, - 0x4de2, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x037f, 0x0078, 0x4de4, + 0x0014, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x5053, 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, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, + 0x0008, 0x1078, 0x556e, 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, + 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, + 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, + 0x20a3, 0x0000, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5072, + 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, + 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, + 0x20a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x007c, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x5155, 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, + 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, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xd0bc, 0x0040, 0x4e36, 0x0d7e, 0xa0e8, 0x6e00, 0x2d6c, - 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x6d19, - 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x4e3e, 0x20a3, 0x0700, - 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0898, - 0x20a3, 0x0000, 0x1078, 0x4fc0, 0x22a2, 0x20a3, 0x0000, 0x7a08, - 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, - 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810, 0xa084, - 0x0700, 0x8007, 0x1079, 0x4e63, 0x037f, 0x017f, 0x147f, 0x137f, - 0x157f, 0x0d7f, 0x007c, 0x4e6b, 0x4e6b, 0x4e6d, 0x4e6b, 0x4e6b, - 0x4e6b, 0x4e92, 0x4e6b, 0x1078, 0x12b7, 0x7910, 0xa18c, 0xf8ff, - 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, - 0x4e9c, 0x0d7e, 0x2069, 0x6d51, 0x6804, 0xd0bc, 0x0040, 0x4e87, - 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x4e89, 0x20a3, - 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x1078, - 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, 0x4e9c, - 0x20a3, 0x7f00, 0x0078, 0x4e8a, 0x027e, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x4eba, - 0x0d7e, 0xa0e8, 0x6e00, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0x6d19, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x4ec2, 0x20a3, 0x0100, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078, - 0x4fc0, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, - 0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0x6d00, 0x6130, - 0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x4eee, 0xa080, - 0x2091, 0x2014, 0xa294, 0x00ff, 0x0078, 0x4ef2, 0x6910, 0x6a14, - 0x7364, 0x7468, 0x781c, 0xa086, 0x0006, 0x0040, 0x4f3d, 0xd5bc, - 0x0040, 0x4f02, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, - 0x0078, 0x4f08, 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, 0x4f31, 0x2011, - 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, 0x4151, 0x037f, 0x047f, - 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, 0x2070, 0x704c, - 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x4f83, 0xd5bc, 0x0040, - 0x4f51, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, - 0x4f57, 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, 0x4f7e, 0x2011, 0x0000, 0x629e, 0x6017, - 0x0012, 0x0078, 0x4f34, 0xd5bc, 0x0040, 0x4f8e, 0xa185, 0x0700, - 0x20a2, 0x6266, 0x636a, 0x646e, 0x0078, 0x4f94, 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, + 0x2004, 0xa092, 0x007e, 0x0048, 0x5147, 0x0d7e, 0xa0e8, 0x7720, + 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x514f, 0x20a3, + 0x8400, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, + 0x00d1, 0x20a3, 0x0000, 0x0078, 0x507e, 0x027e, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, + 0x0048, 0x5174, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x517c, 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, + 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, + 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, + 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, + 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, + 0x523b, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, + 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, + 0x0d7f, 0x0078, 0x5243, 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, + 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x137f, 0x157f, + 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5290, 0x0d7e, 0xa0e8, + 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5298, + 0x20a3, 0x0500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x555d, 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, + 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, + 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, + 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, + 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, + 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53c0, + 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, + 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x555d, 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, + 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, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, + 0x0040, 0x543c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x5444, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, + 0x21a2, 0x1078, 0x555d, 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, + 0x6910, 0x6a14, 0x7364, 0x7468, 0x781c, 0xa086, 0x0006, 0x0040, + 0x54c8, 0xd5bc, 0x0040, 0x5484, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x548a, 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, - 0x4fbb, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x0078, 0x4f34, - 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, - 0x8217, 0x007c, 0x0d7e, 0x2069, 0x6f10, 0x6843, 0x0001, 0x0d7f, - 0x007c, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, - 0x4fdc, 0x1078, 0x4143, 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, 0x414c, - 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, - 0x503a, 0x1078, 0x4fe5, 0x6803, 0x1000, 0x6803, 0x0000, 0x0c7e, - 0x2061, 0x6f10, 0x6128, 0xa192, 0x0002, 0x00c8, 0x5027, 0x8108, - 0x612a, 0x613c, 0x0c7f, 0x81ff, 0x0040, 0x5035, 0x1078, 0x4143, - 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x5023, 0x6017, - 0x0012, 0x0078, 0x5035, 0x1078, 0x4fdc, 0x0078, 0x5035, 0x6124, - 0xa1e5, 0x0000, 0x0040, 0x5032, 0x1078, 0x6c76, 0x2009, 0x0014, - 0x1078, 0x5591, 0x0c7f, 0x0078, 0x5035, 0x027f, 0x017f, 0x0d7f, - 0x0c7f, 0x007c, 0x1078, 0x31cb, 0x0078, 0x5035, 0x0c7e, 0x0d7e, - 0x0e7e, 0x017e, 0x027e, 0x1078, 0x415a, 0x2071, 0x6f10, 0x713c, - 0x81ff, 0x0040, 0x5079, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, - 0x017e, 0x017f, 0xa194, 0x4000, 0x0040, 0x507f, 0x6017, 0x0010, - 0x7144, 0xa192, 0x0002, 0x00c8, 0x5071, 0x8108, 0x7146, 0x1078, - 0x4151, 0x713c, 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, - 0x506d, 0x6017, 0x0012, 0x0078, 0x5079, 0x6017, 0x0016, 0x0078, - 0x5079, 0x1078, 0x6c76, 0x2009, 0x004a, 0x1078, 0x5591, 0x0078, - 0x5079, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x1078, - 0x4151, 0x0078, 0x5079, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, + 0x54bc, 0x6a00, 0xd2f4, 0x0040, 0x54ba, 0x6a14, 0xa294, 0x00ff, + 0x0078, 0x54bc, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, + 0x45f0, 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, + 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, + 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, + 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, + 0x2069, 0x7836, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5579, 0x1078, 0x45e0, + 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, + 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, 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, - 0x2071, 0x6f10, 0x7018, 0x2068, 0x8dff, 0x0040, 0x50af, 0x68a0, - 0xa406, 0x0040, 0x509f, 0x6854, 0x2068, 0x0078, 0x5094, 0x6010, + 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x5637, 0x68a0, + 0xa406, 0x0040, 0x5627, 0x6854, 0x2068, 0x0078, 0x561c, 0x6010, 0x2060, 0x643c, 0x6540, 0x6644, 0xa6b4, 0x000f, 0x2d60, 0x1078, - 0x3522, 0x0040, 0x50af, 0x1078, 0x5374, 0xa085, 0x0001, 0x127f, + 0x38f9, 0x0040, 0x5637, 0x1078, 0x5902, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, - 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4a83, 0x20a3, 0x0f00, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, - 0x1078, 0x4fd1, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x4afa, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a9, - 0x0006, 0x2011, 0x6d40, 0x2019, 0x6d40, 0x23a6, 0x22a6, 0xa398, - 0x0002, 0xa290, 0x0002, 0x00f0, 0x50dd, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x001c, 0x1078, 0x4fd1, 0x147f, 0x157f, 0x007c, - 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x4ada, - 0x1078, 0x4af1, 0x7810, 0x007e, 0xa080, 0x0015, 0x2098, 0x7808, + 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x5053, 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, 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, - 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x4fd1, 0x027f, + 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x556e, 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x4a83, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x4fd1, 0x147f, 0x157f, + 0x1078, 0x4fdc, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x6f10, 0x700c, 0x2060, 0x8cff, 0x0040, 0x513f, 0x600c, 0x007e, - 0x1078, 0x556a, 0x1078, 0x5374, 0x0c7f, 0x0078, 0x5133, 0x700f, - 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f, 0x0e7f, 0x007c, + 0x7836, 0x700c, 0x2060, 0x8cff, 0x0040, 0x56cd, 0x1078, 0x6ace, + 0x00c0, 0x56c4, 0x1078, 0x5e57, 0x600c, 0x007e, 0x1078, 0x5c02, + 0x1078, 0x5902, 0x0c7f, 0x0078, 0x56bb, 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, + 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, + 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, - 0x6f10, 0x7024, 0x2060, 0x8cff, 0x0040, 0x5198, 0x1078, 0x4fe5, - 0x68c3, 0x0000, 0x1078, 0x414c, 0x2009, 0x0013, 0x1078, 0x5591, - 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x517b, 0x6827, 0x0004, - 0x7804, 0xa084, 0x4000, 0x0040, 0x518d, 0x7803, 0x1000, 0x7803, - 0x0000, 0x0078, 0x518d, 0xd084, 0x0040, 0x5182, 0x6827, 0x0001, - 0x0078, 0x5184, 0x00f0, 0x516a, 0x7804, 0xa084, 0x1000, 0x0040, - 0x518d, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, + 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, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, - 0x2001, 0x6d00, 0x2004, 0xa096, 0x0001, 0x0040, 0x51d0, 0xa096, - 0x0004, 0x0040, 0x51d0, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, - 0x318e, 0x1078, 0x40d1, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, - 0x51be, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x51d0, - 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x51d0, 0xd084, 0x0040, - 0x51c5, 0x6827, 0x0001, 0x0078, 0x51c7, 0x00f0, 0x51ad, 0x7804, - 0xa084, 0x1000, 0x0040, 0x51d0, 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, 0x6f10, 0x703c, 0x2060, 0x8cff, 0x0040, 0x5228, - 0x6817, 0x0010, 0x68cb, 0x0000, 0x68c7, 0x0000, 0x1078, 0x415a, - 0x1078, 0x1a20, 0xa39d, 0x0000, 0x00c0, 0x5202, 0x2009, 0x0049, - 0x1078, 0x5591, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x5215, - 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x5227, 0x7803, - 0x1000, 0x7803, 0x0000, 0x0078, 0x5227, 0xd094, 0x0040, 0x521c, - 0x6827, 0x0002, 0x0078, 0x521e, 0x00f0, 0x5204, 0x7804, 0xa084, - 0x1000, 0x0040, 0x5227, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, - 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, - 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0x6f10, - 0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, - 0x2069, 0x6f10, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, - 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0x6f10, 0x7614, 0x2660, - 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x5286, 0x601c, 0xa206, - 0x00c0, 0x5281, 0x7014, 0xac36, 0x00c0, 0x5260, 0x660c, 0x7616, - 0x7010, 0xac36, 0x00c0, 0x526e, 0x2c00, 0xaf36, 0x0040, 0x526c, - 0x2f00, 0x7012, 0x0078, 0x526e, 0x7013, 0x0000, 0x660c, 0x067e, - 0x2c00, 0xaf06, 0x0040, 0x5277, 0x7e0e, 0x0078, 0x5278, 0x2678, - 0x600f, 0x0000, 0x1078, 0x6283, 0x1078, 0x5374, 0x0c7f, 0x0078, - 0x5253, 0x2c78, 0x600c, 0x2060, 0x0078, 0x5253, 0x127f, 0x007f, - 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x4c93, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0078, 0x52cf, 0x157e, 0x147e, - 0x20a1, 0x020b, 0x1078, 0x4c93, 0x7810, 0x20a2, 0xa006, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x52cf, 0x157e, - 0x147e, 0x20a1, 0x020b, 0x1078, 0x4c93, 0x7810, 0x20a2, 0xa006, - 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x52cf, - 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4c93, 0x7810, 0x20a2, - 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, - 0x537f, 0x60c3, 0x0020, 0x1078, 0x4fd1, 0x147f, 0x157f, 0x007c, - 0x127e, 0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, - 0x00c0, 0x52e7, 0xd1bc, 0x00c0, 0x5331, 0x0078, 0x5371, 0x2009, + 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, + 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, + 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, + 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, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, - 0x5328, 0x6020, 0xd0b4, 0x0040, 0x5328, 0x6024, 0xd094, 0x00c0, - 0x5328, 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x5328, - 0x00f0, 0x52f4, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, 0x6130, - 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, 0xbc91, - 0x6043, 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, - 0x00c0, 0x5327, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x531e, 0x027f, - 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, - 0x5371, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, - 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, - 0x4000, 0x0040, 0x536a, 0x6020, 0xd0bc, 0x0040, 0x536a, 0x2104, - 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x536a, 0x00f0, 0x533e, - 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, - 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, - 0x6043, 0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, - 0x5364, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, - 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0x6f10, 0x7020, - 0xa005, 0x0040, 0x537d, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, - 0x0008, 0x20a2, 0x00f0, 0x5381, 0x20a2, 0x20a2, 0x007c, 0x0f7e, - 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, 0x2091, - 0x8000, 0x2071, 0x6f10, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, - 0x87ff, 0x0040, 0x5417, 0x8cff, 0x0040, 0x5417, 0x601c, 0xa086, - 0x0006, 0x00c0, 0x5412, 0x88ff, 0x0040, 0x53ae, 0x2800, 0xac06, - 0x00c0, 0x5412, 0x2039, 0x0000, 0x0078, 0x53b2, 0x6018, 0xa206, - 0x00c0, 0x5412, 0x7024, 0xac06, 0x00c0, 0x53e0, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x53db, 0x6817, 0x0008, 0x68c3, 0x0000, - 0x1078, 0x54a4, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, - 0xa384, 0x1000, 0x0040, 0x53d0, 0x6803, 0x0100, 0x6803, 0x0000, - 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x53d8, 0x6827, 0x0001, - 0x037f, 0x0078, 0x53e0, 0x6003, 0x0009, 0x630a, 0x0078, 0x5412, - 0x7014, 0xac36, 0x00c0, 0x53e6, 0x660c, 0x7616, 0x7010, 0xac36, - 0x00c0, 0x53f4, 0x2c00, 0xaf36, 0x0040, 0x53f2, 0x2f00, 0x7012, - 0x0078, 0x53f4, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, - 0x0040, 0x53fd, 0x7e0e, 0x0078, 0x53fe, 0x2678, 0x600f, 0x0000, - 0x6010, 0x2068, 0x1078, 0x6120, 0x0040, 0x5408, 0x1078, 0x6bb3, - 0x1078, 0x6283, 0x1078, 0x5374, 0x88ff, 0x00c0, 0x5421, 0x0c7f, - 0x0078, 0x5398, 0x2c78, 0x600c, 0x2060, 0x0078, 0x5398, 0xa006, - 0x127f, 0x007f, 0x067f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, - 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x5418, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, - 0x2091, 0x8000, 0x2071, 0x6f10, 0x7638, 0x2660, 0x2678, 0x8cff, - 0x0040, 0x5493, 0x601c, 0xa086, 0x0006, 0x00c0, 0x548e, 0x88ff, - 0x0040, 0x5448, 0x2800, 0xac06, 0x00c0, 0x548e, 0x0078, 0x544c, - 0x6018, 0xa206, 0x00c0, 0x548e, 0x703c, 0xac06, 0x00c0, 0x545e, - 0x037e, 0x2019, 0x0001, 0x1078, 0x51da, 0x7033, 0x0000, 0x703f, - 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, - 0x00c0, 0x5464, 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x5472, - 0x2c00, 0xaf36, 0x0040, 0x5470, 0x2f00, 0x7036, 0x0078, 0x5472, - 0x7037, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x547b, - 0x7e0e, 0x0078, 0x547c, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, - 0x1078, 0x6120, 0x0040, 0x5486, 0x1078, 0x6bb3, 0x1078, 0x6283, - 0x88ff, 0x00c0, 0x549d, 0x0c7f, 0x0078, 0x5437, 0x2c78, 0x600c, - 0x2060, 0x0078, 0x5437, 0xa006, 0x127f, 0x007f, 0x027f, 0x067f, - 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, - 0xa8c5, 0x0001, 0x0078, 0x5494, 0x0e7e, 0x2071, 0x6f10, 0x2001, - 0x6d00, 0x2004, 0xa086, 0x0002, 0x00c0, 0x54b2, 0x7007, 0x0005, - 0x0078, 0x54b4, 0x7007, 0x0000, 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, - 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x6f10, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x54f4, - 0x2200, 0xac06, 0x00c0, 0x54ef, 0x7038, 0xac36, 0x00c0, 0x54d2, - 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x54e0, 0x2c00, 0xaf36, - 0x0040, 0x54de, 0x2f00, 0x7036, 0x0078, 0x54e0, 0x7037, 0x0000, - 0x660c, 0x2c00, 0xaf06, 0x0040, 0x54e8, 0x7e0e, 0x0078, 0x54e9, - 0x2678, 0x600f, 0x0000, 0xa085, 0x0001, 0x0078, 0x54f4, 0x2c78, - 0x600c, 0x2060, 0x0078, 0x54c5, 0x127f, 0x007f, 0x027f, 0x067f, - 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x2061, 0x7400, 0x2a70, 0x7060, - 0x7046, 0x704b, 0x7400, 0x007c, 0x0e7e, 0x127e, 0x2071, 0x6d00, - 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0048, 0x5536, 0x7048, - 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5522, 0xace0, 0x0008, - 0x7054, 0xac02, 0x00c8, 0x551e, 0x0078, 0x5511, 0x2061, 0x7400, - 0x0078, 0x5511, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0008, - 0x7054, 0xa502, 0x00c8, 0x5532, 0x754a, 0xa085, 0x0001, 0x127f, - 0x0e7f, 0x007c, 0x704b, 0x7400, 0x0078, 0x552d, 0xa006, 0x0078, - 0x552f, 0x0e7e, 0x2071, 0x6d00, 0x7544, 0xa582, 0x0001, 0x0048, - 0x5567, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5554, - 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x5550, 0x0078, 0x5543, - 0x2061, 0x7400, 0x0078, 0x5543, 0x6003, 0x0008, 0x8529, 0x7546, - 0xaca8, 0x0008, 0x7054, 0xa502, 0x00c8, 0x5563, 0x754a, 0xa085, - 0x0001, 0x0e7f, 0x007c, 0x704b, 0x7400, 0x0078, 0x555f, 0xa006, - 0x0078, 0x5561, 0xac82, 0x7400, 0x1048, 0x12b7, 0x2001, 0x6d15, - 0x2004, 0xac02, 0x10c8, 0x12b7, 0xa006, 0x6006, 0x600a, 0x600e, + 0x58f8, 0x6020, 0xd0bc, 0x0040, 0x58f8, 0x2104, 0xa084, 0x000f, + 0xa086, 0x0004, 0x00c0, 0x58f8, 0x00f0, 0x58cc, 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, + 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, + 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, + 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, + 0x067f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, + 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x59a6, 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, + 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, 0x0001, + 0x0078, 0x5a22, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, + 0xa086, 0x0002, 0x00c0, 0x5a40, 0x7007, 0x0005, 0x0078, 0x5a42, + 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, + 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, + 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x147f, + 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, + 0x5053, 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, + 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, + 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, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x2061, - 0x6d00, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0040, 0x5589, - 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x476a, 0x127f, 0x0078, - 0x5588, 0x601c, 0xa084, 0x000f, 0x0079, 0x5596, 0x559f, 0x55a7, - 0x55c3, 0x55df, 0x629a, 0x62b6, 0x62d2, 0x559f, 0x55a7, 0xa18e, - 0x0047, 0x00c0, 0x55a6, 0xa016, 0x1078, 0x1532, 0x007c, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12b7, 0x1079, 0x55b1, 0x067f, - 0x007c, 0x55c1, 0x5698, 0x5792, 0x55c1, 0x57d7, 0x55c1, 0x55c1, - 0x55c1, 0x5653, 0x5a4d, 0x55c1, 0x55c1, 0x55c1, 0x55c1, 0x55c1, - 0x55c1, 0x1078, 0x12b7, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12b7, 0x1079, 0x55cd, 0x067f, 0x007c, 0x55dd, 0x55dd, 0x55dd, - 0x55dd, 0x55dd, 0x55dd, 0x55dd, 0x55dd, 0x5e10, 0x5edd, 0x55dd, - 0x5e29, 0x5e8f, 0x5e29, 0x5e8f, 0x55dd, 0x1078, 0x12b7, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12b7, 0x1079, 0x55e9, 0x067f, - 0x007c, 0x55f9, 0x5a96, 0x5b05, 0x5bbb, 0x5cd2, 0x55f9, 0x55f9, - 0x55f9, 0x5a75, 0x5dc6, 0x5dca, 0x55f9, 0x55f9, 0x55f9, 0x55f9, - 0x5df0, 0x1078, 0x12b7, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, + 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, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, 0xa5a8, 0x0002, 0xa398, - 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x5609, 0x0e7e, 0x6010, 0x2070, - 0x7007, 0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x556a, 0x007c, - 0x0d7e, 0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x562d, 0x6018, - 0x2068, 0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, - 0x5637, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, - 0x556a, 0x037f, 0x0d7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, - 0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x5650, 0x6018, - 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, - 0x0d7f, 0x0078, 0x5615, 0x2100, 0xa1b2, 0x0024, 0x10c8, 0x12b7, - 0x0079, 0x565a, 0x5680, 0x568c, 0x5680, 0x5680, 0x5680, 0x5680, - 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, - 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, - 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, 0x567e, - 0x567e, 0x5680, 0x567e, 0x5680, 0x5680, 0x567e, 0x1078, 0x12b7, - 0x6003, 0x0001, 0x6106, 0x1078, 0x4376, 0x127e, 0x2091, 0x8000, - 0x1078, 0x476a, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4376, 0x127e, 0x2091, 0x8000, 0x1078, 0x476a, 0x127f, 0x007c, - 0x6004, 0xa0b2, 0x0024, 0x10c8, 0x12b7, 0xa1b6, 0x0013, 0x00c0, - 0x56a4, 0x2008, 0x0079, 0x5706, 0xa1b6, 0x0014, 0x00c0, 0x56fd, - 0x1078, 0x4671, 0x6004, 0xa08e, 0x0000, 0x0040, 0x56fe, 0xa08e, - 0x0002, 0x0040, 0x56c9, 0xa08e, 0x0003, 0x0040, 0x56c9, 0xa08e, - 0x0004, 0x0040, 0x56c9, 0xa08e, 0x001f, 0x0040, 0x56fe, 0xa08e, - 0x0021, 0x0040, 0x5702, 0xa08e, 0x0022, 0x0040, 0x56fe, 0x0078, - 0x56f9, 0x1078, 0x206f, 0x2001, 0x0007, 0x1078, 0x33f3, 0x6018, - 0xa080, 0x0028, 0x200c, 0x1078, 0x5778, 0xa186, 0x007e, 0x00c0, - 0x56df, 0x2001, 0x6d2f, 0x2014, 0xa295, 0x0001, 0x2202, 0x017e, - 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, 0x1078, 0x445c, 0x1078, - 0x43a9, 0x0c7e, 0x6018, 0xa065, 0x0040, 0x56f0, 0x1078, 0x35cf, - 0x0c7f, 0x2c08, 0x1078, 0x6a57, 0x037f, 0x027f, 0x017f, 0x1078, - 0x342f, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, 0x1078, 0x5778, - 0x0078, 0x56f9, 0x1078, 0x5786, 0x0078, 0x56f9, 0x572c, 0x572e, - 0x5732, 0x5736, 0x573a, 0x573e, 0x572a, 0x572a, 0x572a, 0x572a, - 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, - 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, 0x572a, - 0x572a, 0x572a, 0x572a, 0x572a, 0x5742, 0x5748, 0x572a, 0x5752, - 0x5748, 0x572a, 0x1078, 0x12b7, 0x0078, 0x5748, 0x2001, 0x000b, - 0x0078, 0x575b, 0x2001, 0x0003, 0x0078, 0x575b, 0x2001, 0x0005, - 0x0078, 0x575b, 0x2001, 0x0001, 0x0078, 0x575b, 0x2001, 0x0009, - 0x0078, 0x575b, 0x1078, 0x12b7, 0x0078, 0x575a, 0x1078, 0x33f3, - 0x1078, 0x4671, 0x6003, 0x0002, 0x6017, 0x0028, 0x1078, 0x476a, - 0x0078, 0x575a, 0x1078, 0x4671, 0x6003, 0x0004, 0x6017, 0x0028, - 0x1078, 0x476a, 0x007c, 0x1078, 0x33f3, 0x1078, 0x4671, 0x6003, - 0x0002, 0x037e, 0x2019, 0x6d5c, 0x2304, 0xa084, 0xff00, 0x00c0, - 0x576d, 0x2019, 0x0028, 0x0078, 0x5772, 0x8007, 0x8003, 0x801b, - 0x831b, 0xa318, 0x6316, 0x037f, 0x1078, 0x476a, 0x0078, 0x575a, - 0x0e7e, 0x6010, 0xa005, 0x0040, 0x5784, 0x2070, 0x7007, 0x0000, + 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, + 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, 0x12b7, 0x6604, 0xa6b6, 0x001f, - 0x00c0, 0x57a6, 0x1078, 0x55fb, 0x0078, 0x57c6, 0x6604, 0xa6b6, - 0x0000, 0x00c0, 0x57af, 0x1078, 0x563c, 0x0078, 0x57c6, 0x6604, - 0xa6b6, 0x0022, 0x00c0, 0x57b8, 0x1078, 0x5620, 0x0078, 0x57c6, - 0xa1b6, 0x0015, 0x00c0, 0x57c0, 0x1079, 0x57cb, 0x0078, 0x57c6, - 0xa1b6, 0x0016, 0x00c0, 0x57c7, 0x1079, 0x58f6, 0x007c, 0x1078, - 0x559f, 0x0078, 0x57c6, 0x57ef, 0x57f2, 0x57ef, 0x5833, 0x57ef, - 0x5892, 0x57ef, 0x57ef, 0x57ef, 0x58ce, 0x57ef, 0x58e4, 0xa1b6, - 0x0048, 0x0040, 0x57e3, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, - 0x1078, 0x1532, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, - 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x556a, 0x007c, 0x0005, - 0x0005, 0x007c, 0x0e7e, 0x2071, 0x6d00, 0x7078, 0xa086, 0x0074, - 0x00c0, 0x581c, 0x1078, 0x6a2b, 0x00c0, 0x580e, 0x0d7e, 0x6018, - 0x2068, 0x1078, 0x5820, 0x0d7f, 0x2001, 0x0006, 0x1078, 0x33f3, - 0x1078, 0x206f, 0x1078, 0x556a, 0x0078, 0x581e, 0x2001, 0x000a, - 0x1078, 0x33f3, 0x1078, 0x206f, 0x6003, 0x0001, 0x6007, 0x0001, - 0x1078, 0x4376, 0x0078, 0x581e, 0x1078, 0x5889, 0x0e7f, 0x007c, - 0x6800, 0xd084, 0x0040, 0x5832, 0x2001, 0x0000, 0x1078, 0x33df, - 0x2069, 0x6d51, 0x6804, 0xd0a4, 0x0040, 0x5832, 0x2001, 0x0006, - 0x1078, 0x3401, 0x007c, 0x0d7e, 0x2011, 0x6d1e, 0x2204, 0xa086, - 0x0074, 0x00c0, 0x5885, 0x1078, 0x599f, 0x6018, 0x2068, 0xa080, - 0x0028, 0x2014, 0xa286, 0x007e, 0x0040, 0x5850, 0xa286, 0x0080, - 0x00c0, 0x5879, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x0078, 0x586f, - 0x0e7e, 0x0f7e, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0x6d2f, - 0x2e04, 0xa085, 0x0003, 0x2072, 0x2071, 0x7280, 0x2079, 0x0100, - 0x2e04, 0xa084, 0x00ff, 0x2069, 0x6d19, 0x206a, 0x78e6, 0x8e70, - 0x2e04, 0x2069, 0x6d1a, 0x206a, 0x78ea, 0x0f7f, 0x0e7f, 0x2001, - 0x0006, 0x1078, 0x33f3, 0x1078, 0x206f, 0x1078, 0x556a, 0x0078, - 0x5887, 0x2001, 0x0004, 0x1078, 0x33f3, 0x6003, 0x0001, 0x6007, - 0x0003, 0x1078, 0x4376, 0x0078, 0x5887, 0x1078, 0x5889, 0x0d7f, - 0x007c, 0x2001, 0x0007, 0x1078, 0x33f3, 0x1078, 0x206f, 0x1078, - 0x556a, 0x007c, 0x0e7e, 0x2071, 0x6d00, 0x7078, 0xa086, 0x0014, - 0x00c0, 0x58c8, 0x7000, 0xa086, 0x0003, 0x00c0, 0x58a5, 0x6010, - 0xa005, 0x00c0, 0x58a5, 0x1078, 0x2ad1, 0x0d7e, 0x6018, 0x2068, - 0x1078, 0x34ca, 0x1078, 0x5820, 0x0d7f, 0x1078, 0x59a9, 0x00c0, - 0x58c8, 0x2001, 0x0006, 0x1078, 0x33f3, 0x0e7e, 0x6010, 0xa005, - 0x0040, 0x58c1, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, 0x7033, - 0x0200, 0x0e7f, 0x1078, 0x206f, 0x1078, 0x556a, 0x0078, 0x58cc, - 0x1078, 0x5778, 0x1078, 0x5889, 0x0e7f, 0x007c, 0x2011, 0x6d1e, - 0x2204, 0xa086, 0x0014, 0x00c0, 0x58e1, 0x2001, 0x0002, 0x1078, - 0x33f3, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x4376, 0x0078, - 0x58e3, 0x1078, 0x5889, 0x007c, 0x2011, 0x6d1e, 0x2204, 0xa086, - 0x0004, 0x00c0, 0x58f3, 0x2001, 0x0007, 0x1078, 0x33f3, 0x1078, - 0x556a, 0x0078, 0x58f5, 0x1078, 0x5889, 0x007c, 0x57ef, 0x5902, - 0x57ef, 0x5928, 0x57ef, 0x5952, 0x57ef, 0x57ef, 0x57ef, 0x5967, - 0x57ef, 0x597a, 0x0c7e, 0x1078, 0x598d, 0x00c0, 0x5917, 0x2001, - 0x0000, 0x1078, 0x33df, 0x2001, 0x0002, 0x1078, 0x33f3, 0x6003, - 0x0001, 0x6007, 0x0002, 0x1078, 0x4376, 0x0078, 0x5926, 0x2009, - 0x728f, 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, 0x00c0, 0x5924, - 0x1078, 0x556a, 0x0078, 0x5926, 0x1078, 0x5889, 0x0c7f, 0x007c, - 0x1078, 0x599c, 0x00c0, 0x593c, 0x2001, 0x0000, 0x1078, 0x33df, - 0x2001, 0x0002, 0x1078, 0x33f3, 0x6003, 0x0001, 0x6007, 0x0002, - 0x1078, 0x4376, 0x0078, 0x5951, 0x1078, 0x5778, 0x2009, 0x728f, - 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, 0x00c0, 0x594f, 0x2001, - 0x0004, 0x1078, 0x33f3, 0x1078, 0x556a, 0x0078, 0x5951, 0x1078, - 0x5889, 0x007c, 0x1078, 0x599c, 0x00c0, 0x5962, 0x2001, 0x0004, - 0x1078, 0x33f3, 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x4376, - 0x0078, 0x5966, 0x1078, 0x5778, 0x1078, 0x5889, 0x007c, 0x1078, - 0x599c, 0x00c0, 0x5977, 0x2001, 0x0008, 0x1078, 0x33f3, 0x6003, - 0x0001, 0x6007, 0x0005, 0x1078, 0x4376, 0x0078, 0x5979, 0x1078, - 0x5889, 0x007c, 0x1078, 0x599c, 0x00c0, 0x598a, 0x2001, 0x000a, - 0x1078, 0x33f3, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x4376, - 0x0078, 0x598c, 0x1078, 0x5889, 0x007c, 0x2009, 0x728e, 0x2104, - 0xa086, 0x0003, 0x00c0, 0x599b, 0x2009, 0x728f, 0x2104, 0xa084, - 0xff00, 0xa086, 0x2a00, 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, - 0x017e, 0xac88, 0x0006, 0x2164, 0x1078, 0x3459, 0x017f, 0x0c7f, - 0x007c, 0x0e7e, 0x2071, 0x728c, 0x7004, 0xa086, 0x0014, 0x00c0, - 0x59cc, 0x7008, 0xa086, 0x0800, 0x00c0, 0x59cc, 0x700c, 0xd0ec, - 0x0040, 0x59ca, 0xa084, 0x0f00, 0xa086, 0x0100, 0x00c0, 0x59ca, - 0x7024, 0xd0a4, 0x0040, 0x59ca, 0xd08c, 0x0040, 0x59ca, 0xa006, - 0x0078, 0x59cc, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x0e7e, 0x0d7e, - 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e, 0x127e, 0x2091, - 0x8000, 0x2029, 0x6f19, 0x252c, 0x2021, 0x6f1f, 0x2424, 0x2061, - 0x7400, 0x2071, 0x6d00, 0x7244, 0x7060, 0xa202, 0x00c8, 0x5a23, - 0x1078, 0x6c0f, 0x0040, 0x5a1b, 0x671c, 0xa786, 0x0001, 0x0040, - 0x5a1b, 0xa786, 0x0007, 0x0040, 0x5a1b, 0x2500, 0xac06, 0x0040, - 0x5a1b, 0x2400, 0xac06, 0x0040, 0x5a1b, 0x0c7e, 0x6010, 0x2068, - 0x1078, 0x6120, 0x0040, 0x5a11, 0xa786, 0x0003, 0x00c0, 0x5a2d, - 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x36a1, 0x1078, - 0x6276, 0x6000, 0xa086, 0x0004, 0x00c0, 0x5a18, 0x1078, 0x15f2, - 0x1078, 0x6283, 0x0c7f, 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, - 0x5a23, 0x0078, 0x59e3, 0x127f, 0x007f, 0x027f, 0x047f, 0x057f, - 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, - 0x5a08, 0x1078, 0x6bb3, 0x0078, 0x5a11, 0x220c, 0x2304, 0xa106, - 0x00c0, 0x5a40, 0x8210, 0x8318, 0x00f0, 0x5a35, 0xa006, 0x007c, - 0x2304, 0xa102, 0x0048, 0x5a48, 0x2001, 0x0001, 0x0078, 0x5a4a, - 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a, 0x0024, - 0x10c8, 0x12b7, 0xa08e, 0x0000, 0x0040, 0x5a71, 0xa08e, 0x0002, - 0x0040, 0x5a68, 0xa08e, 0x0003, 0x0040, 0x5a68, 0xa08e, 0x0004, - 0x0040, 0x5a68, 0xa08e, 0x001f, 0x0040, 0x5a71, 0x0078, 0x5a6a, - 0x1078, 0x206f, 0x1078, 0x4671, 0x1078, 0x556a, 0x1078, 0x476a, - 0x007c, 0x1078, 0x5778, 0x0078, 0x5a6a, 0xa182, 0x0040, 0x0079, - 0x5a79, 0x5a88, 0x5a88, 0x5a88, 0x5a88, 0x5a88, 0x5a88, 0x5a88, - 0x5a88, 0x5a88, 0x5a88, 0x5a88, 0x5a8a, 0x5a8a, 0x5a8a, 0x5a8a, - 0x1078, 0x12b7, 0x6003, 0x0001, 0x6106, 0x1078, 0x4327, 0x127e, - 0x2091, 0x8000, 0x1078, 0x476a, 0x127f, 0x007c, 0xa186, 0x0013, - 0x00c0, 0x5a9f, 0x6004, 0xa082, 0x0040, 0x0079, 0x5adf, 0xa186, - 0x0014, 0x10c0, 0x12b7, 0x6004, 0xa082, 0x0040, 0x0079, 0x5aa8, - 0x5ab9, 0x5ab7, 0x5ab7, 0x5ab7, 0x5ab7, 0x5ab7, 0x5ab7, 0x5ab7, - 0x5ab7, 0x5ab7, 0x5ab7, 0x5ad4, 0x5ad4, 0x5ad4, 0x5ad4, 0x1078, - 0x12b7, 0x2001, 0x0007, 0x1078, 0x33f3, 0x1078, 0x4671, 0x0d7e, - 0x6110, 0x2168, 0x1078, 0x6120, 0x0040, 0x5ace, 0x6837, 0x0103, - 0x684b, 0x0028, 0x1078, 0x36a1, 0x1078, 0x6276, 0x0d7f, 0x1078, - 0x556a, 0x1078, 0x476a, 0x007c, 0x2001, 0x0007, 0x1078, 0x33f3, - 0x1078, 0x4671, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, 0x5af0, - 0x5aee, 0x5aee, 0x5aee, 0x5aee, 0x5aee, 0x5aee, 0x5aee, 0x5aee, - 0x5aee, 0x5aee, 0x5afe, 0x5afe, 0x5afe, 0x5afe, 0x1078, 0x12b7, - 0x1078, 0x4671, 0x6003, 0x0002, 0x1078, 0x476a, 0x6010, 0xa088, - 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, 0x4671, - 0x6003, 0x000f, 0x1078, 0x476a, 0x007c, 0xa182, 0x0040, 0x0079, - 0x5b09, 0x5b18, 0x5b18, 0x5b18, 0x5b18, 0x5b18, 0x5b1a, 0x5b98, - 0x5bb0, 0x5b18, 0x5b18, 0x5b18, 0x5b18, 0x5b18, 0x5b18, 0x5b18, - 0x1078, 0x12b7, 0x0e7e, 0x0d7e, 0x2071, 0x728c, 0x6110, 0x2168, - 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, 0x5b87, 0xa68c, 0x00ff, - 0xa186, 0x0002, 0x0040, 0x5b4c, 0xa186, 0x0028, 0x00c0, 0x5b36, - 0x1078, 0x628a, 0x684b, 0x001c, 0x0078, 0x5b4e, 0xd6dc, 0x0040, - 0x5b41, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, - 0x5b4e, 0xd6d4, 0x0040, 0x5b4c, 0x684b, 0x0007, 0x7318, 0x6b62, - 0x731c, 0x6b5e, 0x0078, 0x5b4e, 0x684b, 0x0000, 0x6837, 0x0103, - 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x5b61, 0x7328, 0x732c, 0x6b56, - 0x037e, 0x2308, 0x2019, 0x7298, 0xad90, 0x0019, 0x1078, 0x5f4c, - 0x037f, 0xd6cc, 0x0040, 0x5b8c, 0x7124, 0x695a, 0xa192, 0x0021, - 0x00c8, 0x5b75, 0x2071, 0x7298, 0x831c, 0x2300, 0xae18, 0xad90, - 0x001d, 0x1078, 0x5f4c, 0x0078, 0x5b8c, 0x6838, 0xd0fc, 0x0040, - 0x5b7e, 0x2009, 0x0020, 0x695a, 0x0078, 0x5b6a, 0x0f7e, 0x2d78, - 0x1078, 0x5ee4, 0x0f7f, 0x1078, 0x5f39, 0x0078, 0x5b8e, 0x684b, - 0x0000, 0x6837, 0x0103, 0x6e46, 0x1078, 0x36a1, 0x6218, 0x2268, - 0x6a3c, 0x8211, 0x6a3e, 0x0d7f, 0x0e7f, 0x1078, 0x556a, 0x007c, - 0x0f7e, 0x6003, 0x0003, 0x2079, 0x728c, 0x7c04, 0x7b00, 0x7e0c, - 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, - 0x2c10, 0x1078, 0x17de, 0x1078, 0x4395, 0x1078, 0x4821, 0x007c, - 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, - 0x1078, 0x1532, 0x007c, 0xa182, 0x0040, 0x0079, 0x5bbf, 0x5bce, - 0x5bce, 0x5bce, 0x5bce, 0x5bce, 0x5bd0, 0x5c5e, 0x5bce, 0x5bce, - 0x5c74, 0x5cb4, 0x5bce, 0x5bce, 0x5bce, 0x5bce, 0x1078, 0x12b7, - 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0x728c, 0x6110, 0x2178, - 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, - 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x5c59, 0xa694, - 0xff00, 0xa284, 0x0c00, 0x0040, 0x5bf1, 0x7018, 0x7862, 0x701c, - 0x785e, 0xa284, 0x0300, 0x0040, 0x5c59, 0x1078, 0x130f, 0x1040, - 0x12b7, 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, - 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, - 0x00ff, 0xa186, 0x0002, 0x0040, 0x5c2b, 0xa186, 0x0028, 0x00c0, - 0x5c15, 0x684b, 0x001c, 0x0078, 0x5c2d, 0xd6dc, 0x0040, 0x5c20, - 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x5c2d, - 0xd6d4, 0x0040, 0x5c2b, 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x5c2d, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, - 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x5c42, 0x7328, 0x732c, - 0x6b56, 0x037e, 0x2308, 0x2019, 0x7298, 0xad90, 0x0019, 0x1078, - 0x5f4c, 0x037f, 0xd6cc, 0x0040, 0x5c59, 0x7124, 0x695a, 0xa192, - 0x0021, 0x00c8, 0x5c56, 0x2071, 0x7298, 0x831c, 0x2300, 0xae18, - 0xad90, 0x001d, 0x1078, 0x5f4c, 0x0078, 0x5c59, 0x2d78, 0x1078, - 0x5ee4, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, - 0x0003, 0x2079, 0x728c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, - 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, - 0x17de, 0x1078, 0x4fca, 0x007c, 0x0d7e, 0x6003, 0x0002, 0x1078, - 0x4719, 0x1078, 0x4821, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, - 0x5cb2, 0xd1cc, 0x0040, 0x5c8d, 0x6948, 0x017e, 0x1078, 0x1338, - 0x0d7f, 0x1078, 0x5f39, 0x0078, 0x5cb0, 0x6837, 0x0103, 0x6944, - 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x5cac, 0xa086, 0x0028, - 0x00c0, 0x5c9e, 0x684b, 0x001c, 0x0078, 0x5cae, 0xd1dc, 0x0040, - 0x5ca5, 0x684b, 0x0015, 0x0078, 0x5cae, 0xd1d4, 0x0040, 0x5cac, - 0x684b, 0x0007, 0x0078, 0x5cae, 0x684b, 0x0000, 0x1078, 0x36a1, - 0x1078, 0x556a, 0x0d7f, 0x007c, 0x2001, 0x0007, 0x1078, 0x33f3, - 0x1078, 0x4719, 0x0f7e, 0x0d7e, 0x6110, 0x2178, 0x1078, 0x6120, - 0x0040, 0x5ccb, 0x7837, 0x0103, 0x784b, 0x0028, 0x2f68, 0x1078, - 0x36a1, 0x1078, 0x6276, 0x0d7f, 0x0f7f, 0x1078, 0x556a, 0x1078, - 0x4821, 0x007c, 0xa182, 0x0040, 0x0079, 0x5cd6, 0x5ce5, 0x5ce5, - 0x5ce5, 0x5ce5, 0x5ce5, 0x5ce7, 0x5ce5, 0x5d82, 0x5d8a, 0x5ce5, - 0x5ce5, 0x5ce5, 0x5ce5, 0x5ce5, 0x5ce5, 0x1078, 0x12b7, 0x077e, - 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0x728c, 0x6110, 0x2178, 0x7614, - 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, - 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x5d74, 0xa694, 0xff00, - 0xa284, 0x0c00, 0x0040, 0x5d08, 0x7018, 0x7862, 0x701c, 0x785e, - 0xa284, 0x0300, 0x0040, 0x5d71, 0x1078, 0x130f, 0x1040, 0x12b7, - 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, - 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, - 0x00ff, 0xa186, 0x0002, 0x0040, 0x5d43, 0xa186, 0x0028, 0x00c0, - 0x5d2d, 0x684b, 0x001c, 0x0078, 0x5d45, 0xd6dc, 0x0040, 0x5d38, - 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x5d45, - 0xd6d4, 0x0040, 0x5d43, 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x5d45, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, - 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x5d5a, 0x7328, 0x732c, - 0x6b56, 0x037e, 0x2308, 0x2019, 0x7298, 0xad90, 0x0019, 0x1078, - 0x5f4c, 0x037f, 0xd6cc, 0x0040, 0x5d71, 0x7124, 0x695a, 0xa192, - 0x0021, 0x00c8, 0x5d6e, 0x2071, 0x7298, 0x831c, 0x2300, 0xae18, - 0xad90, 0x001d, 0x1078, 0x5f4c, 0x0078, 0x5d71, 0x2d78, 0x1078, - 0x5ee4, 0xd6dc, 0x00c0, 0x5d77, 0xa006, 0x0078, 0x5d7b, 0x2001, - 0x0001, 0x7218, 0x731c, 0x1078, 0x156f, 0x0d7f, 0x0e7f, 0x0f7f, - 0x077f, 0x007c, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, - 0x1532, 0x007c, 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, - 0xd1e4, 0x0040, 0x5dc4, 0xd1cc, 0x0040, 0x5d9f, 0x6948, 0x017e, - 0x1078, 0x1338, 0x0d7f, 0x1078, 0x5f39, 0x0078, 0x5dc2, 0x6837, - 0x0103, 0x6944, 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x5dbe, - 0xa086, 0x0028, 0x00c0, 0x5db0, 0x684b, 0x001c, 0x0078, 0x5dc0, - 0xd1dc, 0x0040, 0x5db7, 0x684b, 0x0015, 0x0078, 0x5dc0, 0xd1d4, - 0x0040, 0x5dbe, 0x684b, 0x0007, 0x0078, 0x5dc0, 0x684b, 0x0000, - 0x1078, 0x36a1, 0x1078, 0x556a, 0x0d7f, 0x007c, 0x1078, 0x4671, - 0x0078, 0x5dcc, 0x1078, 0x4719, 0x1078, 0x6120, 0x0040, 0x5de3, - 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0x6d0c, 0x210c, - 0xd18c, 0x00c0, 0x5dec, 0xd184, 0x00c0, 0x5de8, 0x6108, 0x694a, - 0x1078, 0x36a1, 0x0d7f, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, - 0x684b, 0x0004, 0x0078, 0x5de0, 0x684b, 0x0004, 0x0078, 0x5de0, - 0xa182, 0x0040, 0x0079, 0x5df4, 0x5e03, 0x5e03, 0x5e03, 0x5e03, - 0x5e03, 0x5e05, 0x5e03, 0x5e08, 0x5e03, 0x5e03, 0x5e03, 0x5e03, - 0x5e03, 0x5e03, 0x5e03, 0x1078, 0x12b7, 0x1078, 0x556a, 0x007c, - 0x007e, 0x027e, 0xa016, 0x1078, 0x1532, 0x027f, 0x007f, 0x007c, - 0xa182, 0x0025, 0x0079, 0x5e14, 0x5e1d, 0x5e1b, 0x5e1b, 0x5e1b, - 0x5e1b, 0x5e1b, 0x5e1b, 0x1078, 0x12b7, 0x6003, 0x0001, 0x6106, - 0x1078, 0x4327, 0x127e, 0x2091, 0x8000, 0x1078, 0x476a, 0x127f, - 0x007c, 0xa186, 0x0013, 0x00c0, 0x5e33, 0x6004, 0xa082, 0x0025, - 0x2008, 0x0079, 0x5e74, 0xa186, 0x0014, 0x00c0, 0x5e70, 0x1078, - 0x4671, 0x2001, 0x0007, 0x1078, 0x33f3, 0x6018, 0xa080, 0x0028, - 0x200c, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, 0x1078, - 0x445c, 0x1078, 0x43a9, 0x0c7e, 0x6018, 0xa065, 0x0040, 0x5e52, - 0x1078, 0x35cf, 0x0c7f, 0x2c08, 0x1078, 0x6a57, 0x037f, 0x027f, - 0x017f, 0x1078, 0x342f, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6120, - 0x0040, 0x5e6a, 0x6837, 0x0103, 0x684b, 0x0006, 0x1078, 0x36a1, - 0x1078, 0x6276, 0x0d7f, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, - 0x1078, 0x559f, 0x0078, 0x5e6f, 0x5e7d, 0x5e7b, 0x5e7b, 0x5e7b, - 0x5e7b, 0x5e7b, 0x5e86, 0x1078, 0x12b7, 0x1078, 0x4671, 0x6017, - 0x0014, 0x6003, 0x000c, 0x1078, 0x476a, 0x007c, 0x1078, 0x4671, - 0x6017, 0x0014, 0x6003, 0x000e, 0x1078, 0x476a, 0x007c, 0xa182, - 0x002c, 0x00c8, 0x5e99, 0xa182, 0x0025, 0x0048, 0x5e99, 0x0079, - 0x5e9c, 0x1078, 0x559f, 0x007c, 0x5ea3, 0x5ea3, 0x5ea3, 0x5ea3, - 0x5ea5, 0x5ebf, 0x5ea3, 0x1078, 0x12b7, 0x0d7e, 0x1078, 0x6276, - 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xa084, 0x0040, 0x0040, - 0x5eb5, 0x684b, 0x0006, 0x0078, 0x5eb7, 0x684b, 0x0005, 0x6847, - 0x0000, 0x1078, 0x36a1, 0x1078, 0x556a, 0x0d7f, 0x007c, 0x0d7e, - 0x6010, 0x2068, 0x1078, 0x6120, 0x0040, 0x5ed9, 0x6837, 0x0103, - 0x6850, 0xa084, 0x0040, 0x0040, 0x5ed1, 0x684b, 0x0006, 0x0078, - 0x5ed3, 0x684b, 0x0005, 0x6847, 0x0000, 0x1078, 0x36a1, 0x1078, - 0x6276, 0x0d7f, 0x1078, 0x556a, 0x007c, 0x1078, 0x4671, 0x1078, - 0x556a, 0x1078, 0x476a, 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, - 0x2029, 0x0001, 0xa182, 0x0101, 0x00c8, 0x5ef0, 0x0078, 0x5ef2, - 0x2009, 0x0100, 0x2130, 0x2069, 0x7298, 0x831c, 0x2300, 0xad18, - 0x2009, 0x0020, 0xaf90, 0x001d, 0x1078, 0x5f4c, 0xa6b2, 0x0020, - 0x7804, 0xa06d, 0x0040, 0x5f06, 0x1078, 0x1338, 0x1078, 0x130f, - 0x0040, 0x5f30, 0x8528, 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, - 0x7c06, 0xa68a, 0x003d, 0x00c8, 0x5f1c, 0x2608, 0xad90, 0x000f, - 0x1078, 0x5f4c, 0x0078, 0x5f30, 0xa6b2, 0x003c, 0x2009, 0x003c, - 0x2d78, 0xad90, 0x000f, 0x1078, 0x5f4c, 0x0078, 0x5f06, 0x0f7f, - 0x852f, 0xa5ad, 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x5f35, - 0x0f7f, 0x852f, 0xa5ad, 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, - 0x007c, 0x0f7e, 0x8dff, 0x0040, 0x5f4a, 0x6804, 0xa07d, 0x0040, - 0x5f48, 0x6807, 0x0000, 0x1078, 0x36a1, 0x2f68, 0x0078, 0x5f3d, - 0x1078, 0x36a1, 0x0f7f, 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, - 0x5f52, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, - 0x8210, 0x00f0, 0x5f54, 0x157f, 0x007c, 0x127e, 0x2091, 0x8000, - 0x601c, 0xa084, 0x000f, 0x1079, 0x5f67, 0x127f, 0x007c, 0x5f76, - 0x5f6f, 0x5f71, 0x5f8d, 0x5f6f, 0x5f71, 0x5f71, 0x5f71, 0x1078, - 0x12b7, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0x0d7e, 0x6010, - 0x2068, 0x1078, 0x6120, 0x0040, 0x5f8a, 0xa00e, 0x2001, 0x0005, - 0x1078, 0x372d, 0x1078, 0x36a1, 0x1078, 0x556a, 0xa085, 0x0001, - 0x0d7f, 0x007c, 0xa006, 0x0078, 0x5f88, 0x6000, 0xa08a, 0x0010, - 0x10c8, 0x12b7, 0x1079, 0x5f95, 0x007c, 0x5fa5, 0x5fc4, 0x5fa7, - 0x5fd5, 0x5fc0, 0x5fa5, 0x5f71, 0x5f76, 0x5f76, 0x5f71, 0x5f71, - 0x5f71, 0x5f71, 0x5f71, 0x5f71, 0x5f71, 0x1078, 0x12b7, 0x0d7e, - 0x6010, 0x2068, 0x1078, 0x6120, 0x0040, 0x5fb2, 0x6850, 0xa085, - 0x0005, 0x6852, 0x0d7f, 0x6007, 0x0025, 0x6003, 0x000b, 0x601f, - 0x0002, 0x1078, 0x4327, 0x1078, 0x476a, 0xa085, 0x0001, 0x007c, - 0x1078, 0x15f2, 0x0078, 0x5fa7, 0x0e7e, 0x2071, 0x6f10, 0x7024, - 0xac06, 0x00c0, 0x5fcd, 0x1078, 0x5148, 0x1078, 0x5083, 0x0e7f, - 0x00c0, 0x5fa7, 0x1078, 0x5f71, 0x007c, 0x037e, 0x0e7e, 0x2071, - 0x6f10, 0x703c, 0xac06, 0x00c0, 0x5fe1, 0x2019, 0x0000, 0x1078, - 0x51da, 0x1078, 0x54b6, 0x0e7f, 0x037f, 0x00c0, 0x5fa7, 0x1078, - 0x5f71, 0x007c, 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x5ff2, - 0x0c7f, 0x007c, 0x5ffb, 0x605b, 0x60c8, 0x5fff, 0x5ffb, 0x5ffb, - 0x5ffb, 0x556a, 0x605b, 0x007c, 0x6017, 0x0001, 0x007c, 0x6000, - 0xa08a, 0x0010, 0x10c8, 0x12b7, 0x1079, 0x6007, 0x007c, 0x6017, - 0x6019, 0x603a, 0x604d, 0x604d, 0x6017, 0x5ffb, 0x5ffb, 0x5ffb, - 0x604d, 0x604d, 0x6017, 0x6017, 0x6017, 0x6017, 0x6058, 0x1078, - 0x12b7, 0x0e7e, 0x6010, 0x2070, 0x7050, 0xa085, 0x0040, 0x7052, - 0x2071, 0x6f10, 0x7024, 0xac06, 0x0040, 0x6036, 0x1078, 0x5083, - 0x6007, 0x0025, 0x6003, 0x000b, 0x601f, 0x0002, 0x6017, 0x0014, - 0x1078, 0x4327, 0x1078, 0x476a, 0x0e7f, 0x007c, 0x6017, 0x0001, - 0x0078, 0x6034, 0x0d7e, 0x6010, 0x2068, 0x6850, 0xa085, 0x0040, - 0x6852, 0x0d7f, 0x6007, 0x0025, 0x6003, 0x000b, 0x601f, 0x0002, - 0x1078, 0x4327, 0x1078, 0x476a, 0x007c, 0x0d7e, 0x6017, 0x0001, - 0x6010, 0x2068, 0x6850, 0xa085, 0x0040, 0x6852, 0x0d7f, 0x007c, - 0x1078, 0x556a, 0x007c, 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12b7, - 0x1079, 0x6063, 0x007c, 0x6073, 0x5ffc, 0x6075, 0x6073, 0x6075, - 0x6073, 0x6073, 0x6073, 0x5ffb, 0x5ffb, 0x6073, 0x6073, 0x6073, - 0x6073, 0x6073, 0x6073, 0x1078, 0x12b7, 0x0d7e, 0x6018, 0x2068, - 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c, 0x10c8, 0x12b7, - 0x1079, 0x6083, 0x007c, 0x608f, 0x60b1, 0x608f, 0x60b1, 0x608f, - 0x60b1, 0x6091, 0x609a, 0x608f, 0x60b1, 0x608f, 0x60aa, 0x1078, - 0x12b7, 0x6004, 0xa08e, 0x0004, 0x0040, 0x60ac, 0xa08e, 0x0002, - 0x0040, 0x60ac, 0xa08e, 0x0000, 0x0040, 0x60c0, 0xa08e, 0x001f, - 0x0040, 0x60c0, 0xa08e, 0x0021, 0x0040, 0x60c4, 0xa08e, 0x0022, - 0x0040, 0x60c0, 0x1078, 0x2051, 0x1078, 0x5778, 0x1078, 0x556a, - 0x007c, 0x1078, 0x5778, 0x1078, 0x2051, 0x0e7e, 0x127e, 0x2091, - 0x8000, 0x1078, 0x206f, 0x127f, 0x0e7f, 0x1078, 0x556a, 0x007c, - 0x1078, 0x5778, 0x0078, 0x60ac, 0x1078, 0x5786, 0x0078, 0x60ac, - 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12b7, 0x1079, 0x60d0, 0x007c, - 0x60e0, 0x60e0, 0x60e0, 0x60e0, 0x60e0, 0x60e0, 0x60e0, 0x60e0, - 0x60e0, 0x5ffb, 0x60e0, 0x5ffc, 0x60e2, 0x5ffc, 0x60eb, 0x60e0, - 0x1078, 0x12b7, 0x6007, 0x002b, 0x6003, 0x000d, 0x1078, 0x4327, - 0x1078, 0x476a, 0x007c, 0x1078, 0x6276, 0x1078, 0x6120, 0x0040, - 0x6109, 0x1078, 0x2051, 0x0d7e, 0x6010, 0x2068, 0x6837, 0x0103, - 0x684b, 0x0006, 0x1078, 0x36a1, 0x0d7f, 0x601f, 0x0001, 0x6007, - 0x0001, 0x6003, 0x0001, 0x1078, 0x4376, 0x1078, 0x476a, 0x0078, - 0x610b, 0x1078, 0x556a, 0x007c, 0xa284, 0x0007, 0x00c0, 0x611d, - 0xa282, 0x7400, 0x0048, 0x611d, 0x2001, 0x6d15, 0x2004, 0xa202, - 0x00c8, 0x611d, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x611c, - 0x027e, 0x0e7e, 0x2071, 0x6d00, 0x6210, 0x7058, 0xa202, 0x0048, - 0x6132, 0x705c, 0xa202, 0x00c8, 0x6132, 0xa085, 0x0001, 0x0e7f, - 0x027f, 0x007c, 0xa006, 0x0078, 0x612f, 0x0e7e, 0x0c7e, 0x037e, - 0x007e, 0x127e, 0x2091, 0x8000, 0x2061, 0x7400, 0x2071, 0x6d00, - 0x7344, 0x7060, 0xa302, 0x00c8, 0x6155, 0x601c, 0xa206, 0x00c0, - 0x614d, 0x0c7e, 0x1078, 0x556a, 0x0c7f, 0xace0, 0x0008, 0x7054, - 0xac02, 0x00c8, 0x6155, 0x0078, 0x6140, 0x127f, 0x007f, 0x037f, - 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0x127e, 0x2091, - 0x8000, 0xa188, 0x6e00, 0x210c, 0x81ff, 0x0040, 0x6182, 0x2061, - 0x7400, 0x2071, 0x6d00, 0x7344, 0x7060, 0xa302, 0x00c8, 0x6182, - 0x6018, 0xa106, 0x00c0, 0x617c, 0x1078, 0x2051, 0x017e, 0x0c7e, - 0x1078, 0x556a, 0x0c7f, 0x017f, 0xace0, 0x0008, 0x7054, 0xac02, - 0x0048, 0x6170, 0x127f, 0x017f, 0x0c7f, 0x0e7f, 0x007c, 0x0c7e, - 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5504, 0x057f, - 0x0040, 0x61a0, 0x6612, 0x651a, 0x601f, 0x0003, 0x2009, 0x004b, - 0x1078, 0x5591, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x619c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, - 0x62a0, 0x0c7e, 0x1078, 0x5504, 0x057f, 0x0040, 0x61ca, 0x6013, - 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, 0x2560, 0x1078, 0x35cf, - 0x0c7f, 0x1078, 0x445c, 0x1078, 0x43a9, 0x2c08, 0x1078, 0x6a57, - 0x2009, 0x004c, 0x1078, 0x5591, 0xa085, 0x0001, 0x127f, 0x057f, - 0x0c7f, 0x007c, 0xa006, 0x0078, 0x61c6, 0x0c7e, 0x057e, 0x127e, - 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x5504, 0x057f, 0x0040, - 0x61f5, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, 0x0c7e, - 0x2560, 0x1078, 0x35cf, 0x0c7f, 0x1078, 0x445c, 0x1078, 0x43a9, - 0x2c08, 0x1078, 0x6a57, 0x2009, 0x004d, 0x1078, 0x5591, 0xa085, - 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x61f1, - 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, - 0x5504, 0x057f, 0x0040, 0x6220, 0x6612, 0x651a, 0x601f, 0x0003, - 0x2019, 0x0005, 0x0c7e, 0x2560, 0x1078, 0x35cf, 0x0c7f, 0x1078, - 0x445c, 0x1078, 0x43a9, 0x2c08, 0x1078, 0x6a57, 0x2009, 0x004e, - 0x1078, 0x5591, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x621c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, - 0x1078, 0x5504, 0x017f, 0x0040, 0x623c, 0x660a, 0x611a, 0x601f, - 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, 0x1078, 0x5591, 0xa085, - 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6239, 0x0c7e, - 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5504, 0x017f, 0x0040, - 0x6258, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, - 0x0021, 0x1078, 0x5591, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x6255, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, - 0x1078, 0x5504, 0x017f, 0x0040, 0x6273, 0x611a, 0x601f, 0x0001, - 0x2d00, 0x6012, 0x2009, 0x0000, 0x1078, 0x5591, 0xa085, 0x0001, - 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6270, 0x027e, 0x0d7e, - 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0040, 0x6280, 0x8211, 0x6a3e, - 0x0d7f, 0x027f, 0x007c, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, - 0x0014, 0x007c, 0x067e, 0x0c7e, 0x2031, 0x6d52, 0x2634, 0xd6e4, - 0x0040, 0x6297, 0x6618, 0x2660, 0x6e44, 0x1078, 0x3507, 0x0c7f, - 0x067f, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12b7, - 0x1079, 0x62a4, 0x067f, 0x007c, 0x62b4, 0x640b, 0x64d4, 0x62b4, - 0x62b4, 0x62b4, 0x62b4, 0x62b4, 0x62ee, 0x6542, 0x62b4, 0x62b4, - 0x62b4, 0x62b4, 0x62b4, 0x62b4, 0x1078, 0x12b7, 0x067e, 0x6000, - 0xa0b2, 0x0010, 0x10c8, 0x12b7, 0x1079, 0x62c0, 0x067f, 0x007c, - 0x62d0, 0x6837, 0x62d0, 0x62d0, 0x62d0, 0x62d0, 0x62d0, 0x62d0, - 0x6812, 0x687d, 0x62d0, 0x62d0, 0x62d0, 0x62d0, 0x62d0, 0x62d0, - 0x1078, 0x12b7, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12b7, - 0x1079, 0x62dc, 0x067f, 0x007c, 0x62ec, 0x668f, 0x66fb, 0x671c, - 0x6769, 0x62ec, 0x62ec, 0x67be, 0x654e, 0x67fa, 0x67fe, 0x62ec, - 0x62ec, 0x62ec, 0x62ec, 0x62ec, 0x1078, 0x12b7, 0xa1b2, 0x0024, - 0x10c8, 0x12b7, 0x2100, 0x0079, 0x62f5, 0x6319, 0x63f5, 0x6319, - 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, - 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, 0x6319, - 0x6319, 0x6319, 0x6319, 0x6319, 0x631b, 0x634a, 0x6354, 0x637c, - 0x6382, 0x63b6, 0x63ee, 0x6319, 0x6319, 0x63fd, 0x6319, 0x6319, - 0x6404, 0x1078, 0x12b7, 0x1078, 0x364d, 0x6618, 0x0c7e, 0x2660, - 0x1078, 0x3459, 0x0c7f, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, - 0xa082, 0x0006, 0x0048, 0x633c, 0x1078, 0x6993, 0x00c0, 0x6376, - 0x1078, 0x6931, 0x00c0, 0x6338, 0x6007, 0x0008, 0x0078, 0x63f0, - 0x6007, 0x0009, 0x0078, 0x63f0, 0x1078, 0x6b02, 0x0040, 0x6346, - 0x1078, 0x6993, 0x0040, 0x6330, 0x0078, 0x6376, 0x6013, 0x1900, - 0x0078, 0x6338, 0x1078, 0x68b7, 0x6007, 0x0006, 0x0078, 0x63f0, - 0x6007, 0x0007, 0x0078, 0x63f0, 0x0d7e, 0x6618, 0x2668, 0x6e04, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6366, 0xa686, - 0x0004, 0x0040, 0x6366, 0x0d7f, 0x0078, 0x6376, 0x1078, 0x69f1, - 0x00c0, 0x6371, 0x1078, 0x34ca, 0x6007, 0x000a, 0x0d7f, 0x0078, - 0x63f0, 0x6007, 0x000b, 0x0d7f, 0x0078, 0x63f0, 0x1078, 0x2051, - 0x6007, 0x0001, 0x0078, 0x63f0, 0x1078, 0x2051, 0x6007, 0x000c, - 0x0078, 0x63f0, 0x1078, 0x364d, 0x6618, 0xa6b0, 0x0001, 0x2634, - 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x63a3, 0xa6b4, 0xff00, - 0x8637, 0xa686, 0x0006, 0x00c0, 0x6376, 0x1078, 0x6a00, 0x00c0, - 0x639d, 0x6007, 0x000e, 0x0078, 0x63f0, 0x1078, 0x2051, 0x6007, - 0x000f, 0x0078, 0x63f0, 0x1078, 0x6b02, 0x0040, 0x63b0, 0xa6b4, - 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6395, 0x0078, 0x6376, - 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, 0x63f0, 0x1078, 0x364d, - 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, - 0x0048, 0x63db, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x00c0, - 0x6376, 0x1078, 0x6a2b, 0x00c0, 0x63d5, 0x1078, 0x6931, 0x00c0, - 0x63d5, 0x6007, 0x0010, 0x0078, 0x63f0, 0x1078, 0x2051, 0x6007, - 0x0011, 0x0078, 0x63f0, 0x1078, 0x6b02, 0x0040, 0x63e8, 0xa6b4, - 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x63c9, 0x0078, 0x6376, - 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, 0x63f0, 0x6007, 0x0012, - 0x6003, 0x0001, 0x1078, 0x4376, 0x007c, 0x6007, 0x0001, 0x6003, - 0x0001, 0x1078, 0x4376, 0x0078, 0x63f4, 0x6007, 0x0020, 0x6003, - 0x0001, 0x1078, 0x4376, 0x007c, 0x6007, 0x0023, 0x6003, 0x0001, - 0x1078, 0x4376, 0x007c, 0x6004, 0xa0b2, 0x0024, 0x10c8, 0x12b7, - 0xa1b6, 0x0013, 0x00c0, 0x6417, 0x2008, 0x0079, 0x6426, 0xa1b6, - 0x0014, 0x10c0, 0x12b7, 0x2001, 0x0007, 0x1078, 0x3401, 0x1078, - 0x4671, 0x1078, 0x6283, 0x1078, 0x476a, 0x007c, 0x644a, 0x644c, - 0x644a, 0x644a, 0x644a, 0x644c, 0x6454, 0x64af, 0x6472, 0x64af, - 0x6486, 0x64af, 0x6454, 0x64af, 0x64a7, 0x64af, 0x64a7, 0x64af, - 0x64af, 0x644a, 0x644a, 0x644a, 0x644a, 0x644a, 0x644a, 0x644a, - 0x644a, 0x644a, 0x644a, 0x644a, 0x644a, 0x644a, 0x64af, 0x644a, - 0x644a, 0x64af, 0x1078, 0x12b7, 0x1078, 0x4671, 0x6003, 0x0002, - 0x1078, 0x476a, 0x0078, 0x64b5, 0x0f7e, 0x2079, 0x6d51, 0x7804, - 0x0f7f, 0xd0ac, 0x00c0, 0x64af, 0x2001, 0x0000, 0x1078, 0x33df, - 0x2001, 0x0002, 0x1078, 0x33f3, 0x1078, 0x4671, 0x601f, 0x0001, - 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x4376, 0x1078, 0x476a, - 0x0078, 0x64b5, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, - 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x64af, 0xa686, 0x0004, - 0x0040, 0x64af, 0x2001, 0x0004, 0x0078, 0x64ad, 0x2001, 0x6d00, - 0x2004, 0xa086, 0x0003, 0x00c0, 0x648f, 0x1078, 0x2ad1, 0x2001, - 0x0006, 0x1078, 0x64b6, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x64af, 0x2001, - 0x0006, 0x0078, 0x64ad, 0x2001, 0x0004, 0x0078, 0x64ad, 0x2001, - 0x0006, 0x1078, 0x64b6, 0x0078, 0x64af, 0x1078, 0x3401, 0x1078, - 0x4671, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, 0x017e, 0x0d7e, - 0x6118, 0x2168, 0x6900, 0xd184, 0x0040, 0x64d1, 0x6104, 0xa18e, - 0x000a, 0x00c0, 0x64c9, 0x699c, 0xd1a4, 0x00c0, 0x64c9, 0x2001, - 0x0007, 0x1078, 0x33f3, 0x2001, 0x0000, 0x1078, 0x33df, 0x1078, - 0x206f, 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, - 0xa084, 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x12b7, - 0xa1b6, 0x0015, 0x00c0, 0x64e8, 0x1079, 0x64ef, 0x0078, 0x64ee, - 0xa1b6, 0x0016, 0x10c0, 0x12b7, 0x1079, 0x6527, 0x007c, 0x57ef, - 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x64fb, 0x57ef, - 0x57ef, 0x57ef, 0x57ef, 0x0f7e, 0x2079, 0x6d51, 0x7804, 0x0f7f, - 0xd0ac, 0x00c0, 0x6517, 0x2001, 0x0000, 0x1078, 0x33df, 0x2001, - 0x0002, 0x1078, 0x33f3, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, - 0x0002, 0x1078, 0x4376, 0x1078, 0x476a, 0x0078, 0x6526, 0x2011, - 0x7283, 0x220c, 0x017e, 0x0c7e, 0x1078, 0x3447, 0x00c0, 0x6526, - 0x1078, 0x3256, 0x0c7f, 0x017f, 0x1078, 0x556a, 0x007c, 0x57ef, - 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x57ef, 0x6533, 0x57ef, - 0x57ef, 0x57ef, 0x57ef, 0x1078, 0x599c, 0x00c0, 0x653f, 0x6003, - 0x0001, 0x6007, 0x0001, 0x1078, 0x4376, 0x0078, 0x6541, 0x1078, - 0x556a, 0x007c, 0x6004, 0xa08a, 0x0024, 0x10c8, 0x12b7, 0x1078, - 0x4671, 0x1078, 0x6283, 0x1078, 0x476a, 0x007c, 0xa182, 0x0040, - 0x0079, 0x6552, 0x6561, 0x6561, 0x6561, 0x6561, 0x6563, 0x6561, - 0x6561, 0x6561, 0x6561, 0x6561, 0x6561, 0x6561, 0x6561, 0x6561, - 0x6561, 0x1078, 0x12b7, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, - 0x027e, 0x2071, 0x7280, 0x7444, 0xa4a4, 0xe600, 0x0040, 0x65d4, - 0xa486, 0x2000, 0x0040, 0x6592, 0xa486, 0x0400, 0x0040, 0x6592, - 0x7130, 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, 0x6663, 0x0c7e, - 0x1078, 0x416d, 0x2c68, 0x0c7f, 0x6a00, 0xa284, 0x0001, 0x0040, - 0x6644, 0x1078, 0x420a, 0x0040, 0x666f, 0xa295, 0x0200, 0x6a02, - 0x0078, 0x6598, 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x41f4, - 0x1078, 0x130f, 0x1040, 0x12b7, 0x6003, 0x0007, 0x6106, 0x2d00, - 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, - 0x685e, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0xa18c, 0x00ff, - 0xa10d, 0x6946, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x36a1, - 0xa486, 0x2000, 0x00c0, 0x65c2, 0x2019, 0x0017, 0x1078, 0x6b8f, - 0x0078, 0x6631, 0xa486, 0x0400, 0x00c0, 0x65cc, 0x2019, 0x0002, - 0x1078, 0x6b8f, 0x0078, 0x6631, 0xa486, 0x0200, 0x00c0, 0x65d2, - 0x1078, 0x6b80, 0x0078, 0x6631, 0x7130, 0xa18c, 0x00ff, 0xa182, - 0x0010, 0x00c8, 0x6687, 0x0c7e, 0x1078, 0x416d, 0x2c68, 0x0c7f, - 0x6a00, 0xa284, 0x0001, 0x0040, 0x668b, 0xa284, 0x0300, 0x00c0, - 0x6683, 0x6804, 0xa005, 0x0040, 0x666f, 0x8001, 0x6806, 0x6003, - 0x0007, 0x6106, 0x1078, 0x12f4, 0x0040, 0x6638, 0x6013, 0x0000, - 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x2c00, 0x684a, - 0x6018, 0x2078, 0x78a0, 0x8007, 0xa10d, 0x6946, 0x6853, 0x003d, - 0x7044, 0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, 0x6613, 0x684f, - 0x0040, 0x0078, 0x661d, 0xa086, 0x0001, 0x00c0, 0x661b, 0x684f, - 0x0080, 0x0078, 0x661d, 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, - 0x7290, 0xad90, 0x0015, 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, - 0x00f0, 0x6623, 0x200c, 0x6982, 0x8000, 0x200c, 0x697e, 0x1078, - 0x36a1, 0x027f, 0x047f, 0x157f, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, - 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4327, - 0x1078, 0x476a, 0x0078, 0x6631, 0x2069, 0x7292, 0x2d04, 0xa084, - 0xff00, 0xa086, 0x1200, 0x00c0, 0x6663, 0x2069, 0x7280, 0x686c, - 0xa084, 0x00ff, 0x017e, 0x6110, 0xa18c, 0x0700, 0xa10d, 0x6112, - 0x017f, 0x6003, 0x0001, 0x6007, 0x0043, 0x1078, 0x4327, 0x1078, - 0x476a, 0x0078, 0x6631, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, - 0x0041, 0x1078, 0x4327, 0x1078, 0x476a, 0x0078, 0x6631, 0xa284, - 0x0004, 0x00c0, 0x6677, 0x6013, 0x0300, 0x0078, 0x6679, 0x6013, - 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4327, 0x1078, - 0x476a, 0x0078, 0x6631, 0x6013, 0x0500, 0x0078, 0x6679, 0x6013, - 0x0600, 0x0078, 0x6644, 0x6013, 0x0200, 0x0078, 0x6644, 0xa186, - 0x0013, 0x00c0, 0x66a1, 0x6004, 0xa08a, 0x0040, 0x1048, 0x12b7, - 0xa08a, 0x004f, 0x10c8, 0x12b7, 0xa082, 0x0040, 0x2008, 0x0079, - 0x66cd, 0xa186, 0x0047, 0x00c0, 0x66a7, 0x0078, 0x66fb, 0xa186, - 0x0014, 0x10c0, 0x12b7, 0x6004, 0xa082, 0x0040, 0x2008, 0x0079, - 0x66b1, 0x66c0, 0x66c2, 0x66c2, 0x66c0, 0x66c0, 0x66c0, 0x66c0, - 0x66c0, 0x66c0, 0x66c0, 0x66c0, 0x66c0, 0x66c0, 0x66c0, 0x66c0, - 0x1078, 0x12b7, 0x2001, 0x0007, 0x1078, 0x3401, 0x1078, 0x4671, - 0x1078, 0x6283, 0x1078, 0x476a, 0x007c, 0x66dc, 0x66ec, 0x66e5, - 0x66f5, 0x66dc, 0x66dc, 0x66dc, 0x66dc, 0x66dc, 0x66dc, 0x66dc, - 0x66dc, 0x66dc, 0x66dc, 0x66dc, 0x1078, 0x12b7, 0x6010, 0xa088, - 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x1078, 0x4671, 0x6003, - 0x0002, 0x1078, 0x476a, 0x007c, 0x1078, 0x4671, 0x1078, 0x41cd, - 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, 0x1078, 0x4671, 0x2009, - 0x0041, 0x0078, 0x67be, 0xa182, 0x0040, 0x0079, 0x66ff, 0x670e, - 0x6710, 0x670e, 0x670e, 0x670e, 0x670e, 0x670e, 0x6711, 0x670e, - 0x670e, 0x670e, 0x670e, 0x670e, 0x670e, 0x670e, 0x1078, 0x12b7, + 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, + 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, + 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, 0x1532, 0x007c, 0xa182, 0x0040, 0x0079, 0x6720, - 0x672f, 0x672f, 0x672f, 0x672f, 0x672f, 0x672f, 0x672f, 0x672f, - 0x672f, 0x6731, 0x6754, 0x672f, 0x672f, 0x672f, 0x672f, 0x1078, - 0x12b7, 0x1078, 0x4719, 0x1078, 0x4821, 0x6010, 0x0d7e, 0x2068, - 0x684c, 0xd0fc, 0x0040, 0x6747, 0xa08c, 0x0003, 0xa18e, 0x0002, - 0x0040, 0x674d, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x67be, 0x6003, - 0x0007, 0x1078, 0x41cd, 0x0d7f, 0x007c, 0x1078, 0x41cd, 0x1078, - 0x556a, 0x0d7f, 0x0078, 0x674c, 0x2001, 0x0007, 0x1078, 0x3401, - 0x1078, 0x4719, 0x1078, 0x4821, 0x6010, 0x0d7e, 0x2068, 0x037e, - 0x2019, 0x0004, 0x1078, 0x6bb3, 0x037f, 0x1078, 0x6283, 0x0d7f, - 0x007c, 0xa186, 0x0013, 0x00c0, 0x6777, 0x6004, 0xa086, 0x0042, - 0x10c0, 0x12b7, 0x1078, 0x4671, 0x1078, 0x476a, 0x007c, 0xa186, - 0x0014, 0x00c0, 0x678b, 0x6004, 0xa086, 0x0042, 0x10c0, 0x12b7, - 0x2001, 0x0007, 0x1078, 0x3401, 0x1078, 0x4671, 0x1078, 0x6283, - 0x1078, 0x476a, 0x007c, 0xa182, 0x0040, 0x0079, 0x678f, 0x679e, - 0x679e, 0x679e, 0x679e, 0x679e, 0x679e, 0x679e, 0x67a0, 0x67ac, - 0x679e, 0x679e, 0x679e, 0x679e, 0x679e, 0x679e, 0x1078, 0x12b7, - 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, - 0x1532, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, 0x2068, 0x684c, - 0xd0fc, 0x0040, 0x67b8, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x67be, - 0x6003, 0x0007, 0x1078, 0x41cd, 0x0d7f, 0x007c, 0xa182, 0x0040, - 0x0079, 0x67c2, 0x67d1, 0x67d3, 0x67df, 0x67eb, 0x67d1, 0x67d1, - 0x67d1, 0x67d1, 0x67d1, 0x67d1, 0x67d1, 0x67d1, 0x67d1, 0x67d1, - 0x67d1, 0x1078, 0x12b7, 0x6003, 0x0001, 0x6106, 0x1078, 0x4327, - 0x127e, 0x2091, 0x8000, 0x1078, 0x476a, 0x127f, 0x007c, 0x6003, - 0x0001, 0x6106, 0x1078, 0x4327, 0x127e, 0x2091, 0x8000, 0x1078, - 0x476a, 0x127f, 0x007c, 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, - 0x17de, 0x127e, 0x2091, 0x8000, 0x1078, 0x4395, 0x1078, 0x4821, - 0x127f, 0x007c, 0x1078, 0x4671, 0x0078, 0x6800, 0x1078, 0x4719, - 0x6110, 0x81ff, 0x0040, 0x680d, 0x0d7e, 0x2168, 0x037e, 0x2019, - 0x0029, 0x1078, 0x6bb3, 0x037f, 0x0d7f, 0x1078, 0x6283, 0x1078, - 0x476a, 0x007c, 0xa182, 0x0025, 0x0079, 0x6816, 0x681d, 0x681d, - 0x681d, 0x681f, 0x681d, 0x681d, 0x681d, 0x1078, 0x12b7, 0x027e, - 0x0e7e, 0x2071, 0x7280, 0x7220, 0x1078, 0x6ad1, 0x0040, 0x682c, - 0x6007, 0x0026, 0x0078, 0x682e, 0x6007, 0x0027, 0x6003, 0x0001, - 0x1078, 0x4327, 0x1078, 0x476a, 0x0e7f, 0x027f, 0x007c, 0xa186, - 0x0013, 0x00c0, 0x6848, 0x6004, 0xa08a, 0x0025, 0x1048, 0x12b7, - 0xa08a, 0x002c, 0x10c8, 0x12b7, 0xa082, 0x0025, 0x0079, 0x6857, - 0xa186, 0x0014, 0x10c0, 0x12b7, 0x2001, 0x0007, 0x1078, 0x3401, - 0x1078, 0x4671, 0x1078, 0x6283, 0x1078, 0x476a, 0x007c, 0x685e, - 0x6860, 0x6860, 0x685e, 0x685e, 0x685e, 0x685e, 0x1078, 0x12b7, - 0x1078, 0x4671, 0x1078, 0x556a, 0x1078, 0x476a, 0x007c, 0xa182, - 0x0025, 0x1048, 0x12b7, 0xa182, 0x002c, 0x10c8, 0x12b7, 0xa182, - 0x0025, 0x0079, 0x6873, 0x687a, 0x687a, 0x687a, 0x687c, 0x687a, - 0x687a, 0x687a, 0x1078, 0x12b7, 0x007c, 0x1078, 0x4671, 0x1078, - 0x6283, 0x1078, 0x476a, 0x007c, 0x127e, 0x037e, 0x087e, 0x2091, - 0x8000, 0x2c40, 0x2019, 0x0002, 0x1078, 0x5387, 0x00c0, 0x68b3, - 0x1078, 0x5428, 0x00c0, 0x68b3, 0x6000, 0xa086, 0x0000, 0x0040, - 0x68b3, 0x601c, 0xa086, 0x0007, 0x0040, 0x68b3, 0x0d7e, 0x6010, - 0x2068, 0x1078, 0x6120, 0x0040, 0x68a7, 0x1078, 0x6bb3, 0x0d7f, - 0x6000, 0xa086, 0x0004, 0x00c0, 0x68af, 0x1078, 0x15f2, 0x6013, + 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, 0x7280, 0x7938, 0x783c, 0x1078, - 0x1e1b, 0x00c0, 0x68e8, 0x017e, 0x0c7e, 0x1078, 0x3447, 0x00c0, - 0x68e8, 0x2011, 0x7290, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, - 0x5a35, 0x00c0, 0x68e8, 0x017f, 0x027f, 0x027e, 0x017e, 0x2019, - 0x0029, 0x1078, 0x445c, 0x1078, 0x43a9, 0x017f, 0x1078, 0x6a57, - 0x1078, 0x35cf, 0x017f, 0x1078, 0x3256, 0xa006, 0x0078, 0x68ea, - 0x0c7f, 0x017f, 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0e7e, - 0x0d7e, 0x0c7e, 0x047e, 0x037e, 0x027e, 0x2061, 0x7400, 0x2071, - 0x6d00, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, 0x6929, 0x2100, - 0xac06, 0x0040, 0x691b, 0x6000, 0xa086, 0x0000, 0x0040, 0x691b, - 0x6018, 0x2068, 0x68a0, 0xa206, 0x00c0, 0x691b, 0x631c, 0xa386, - 0x0004, 0x0040, 0x6925, 0xa386, 0x0005, 0x0040, 0x6925, 0xa386, - 0x0006, 0x0040, 0x6925, 0xace0, 0x0008, 0x2001, 0x6d15, 0x2004, - 0xac02, 0x00c8, 0x6929, 0x0078, 0x68f7, 0xa085, 0x0001, 0x0078, - 0x692a, 0xa006, 0x027f, 0x037f, 0x047f, 0x0c7f, 0x0d7f, 0x0e7f, - 0x007c, 0x0c7e, 0x0d7e, 0x017e, 0x2009, 0x6d1e, 0x2104, 0xa086, - 0x0074, 0x00c0, 0x6988, 0x2069, 0x728e, 0x690c, 0xa182, 0x0100, - 0x0048, 0x6978, 0x6908, 0xa184, 0x8000, 0x0040, 0x6984, 0xa184, - 0x0800, 0x0040, 0x6984, 0x6910, 0xa18a, 0x0001, 0x0048, 0x697c, - 0x6914, 0x2069, 0x72ae, 0x6904, 0x81ff, 0x00c0, 0x6970, 0x690c, - 0xa182, 0x0100, 0x0048, 0x6978, 0x6908, 0x81ff, 0x00c0, 0x6974, - 0x6910, 0xa18a, 0x0001, 0x0048, 0x697c, 0x6918, 0xa18a, 0x0001, - 0x0048, 0x6984, 0x0078, 0x698e, 0x6013, 0x0100, 0x0078, 0x698a, - 0x6013, 0x0300, 0x0078, 0x698a, 0x6013, 0x0500, 0x0078, 0x698a, - 0x6013, 0x0700, 0x0078, 0x698a, 0x6013, 0x0900, 0x0078, 0x698a, - 0x6013, 0x0b00, 0x0078, 0x698a, 0x6013, 0x0f00, 0x0078, 0x698a, - 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x698f, 0xa006, 0x017f, - 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e, 0x157e, - 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006, 0x0040, - 0x69b7, 0xa286, 0x0004, 0x0040, 0x69b7, 0xa394, 0xff00, 0x8217, - 0xa286, 0x0006, 0x0040, 0x69b7, 0xa286, 0x0004, 0x0040, 0x69b7, - 0x0c7e, 0x2d60, 0x1078, 0x3459, 0x0c7f, 0x0078, 0x69ea, 0x2011, - 0x7296, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x5a35, 0x00c0, - 0x69eb, 0x2011, 0x729a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x1078, - 0x5a35, 0x00c0, 0x69eb, 0x047e, 0x017e, 0x6aa0, 0xa294, 0x00ff, - 0x8227, 0xa006, 0x2009, 0x6d52, 0x210c, 0xd1a4, 0x0040, 0x69df, - 0x2009, 0x0029, 0x1078, 0x6bf7, 0x6800, 0xc0e5, 0x6802, 0x2019, - 0x0029, 0x1078, 0x445c, 0x1078, 0x43a9, 0x2c08, 0x1078, 0x6a57, - 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f, 0x0c7f, - 0x007c, 0x0d7e, 0x2069, 0x728e, 0x6800, 0xa086, 0x0800, 0x0040, - 0x69fd, 0x6013, 0x0000, 0x0078, 0x69fe, 0xa006, 0x0d7f, 0x007c, - 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079, 0x728c, - 0x7930, 0x7834, 0x1078, 0x1e1b, 0x00c0, 0x6a24, 0x1078, 0x3447, - 0x00c0, 0x6a24, 0x2011, 0x7290, 0xac98, 0x000a, 0x20a9, 0x0004, - 0x1078, 0x5a35, 0x00c0, 0x6a24, 0x2011, 0x7294, 0xac98, 0x0006, - 0x20a9, 0x0004, 0x1078, 0x5a35, 0x157f, 0x037f, 0x027f, 0x017f, - 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e, 0x037e, - 0x157e, 0x2011, 0x7283, 0x2204, 0x8211, 0x220c, 0x1078, 0x1e1b, - 0x00c0, 0x6a50, 0x1078, 0x3447, 0x00c0, 0x6a50, 0x2011, 0x7296, - 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x5a35, 0x00c0, 0x6a50, - 0x2011, 0x729a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, 0x5a35, - 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c, 0x0e7e, - 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x127e, 0x2091, - 0x8000, 0x2029, 0x6f19, 0x252c, 0x2021, 0x6f1f, 0x2424, 0x2061, - 0x7400, 0x2071, 0x6d00, 0x7644, 0x7060, 0x8001, 0xa602, 0x00c8, - 0x6abc, 0x2100, 0xac06, 0x0040, 0x6ab2, 0x1078, 0x6c0f, 0x0040, - 0x6ab2, 0x671c, 0xa786, 0x0001, 0x0040, 0x6ab2, 0xa786, 0x0007, - 0x0040, 0x6ab2, 0x2500, 0xac06, 0x0040, 0x6ab2, 0x2400, 0xac06, - 0x0040, 0x6ab2, 0x6018, 0x2070, 0x70a0, 0xa206, 0x00c0, 0x6ab2, - 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6120, 0x0040, 0x6aa6, 0xa786, - 0x0003, 0x00c0, 0x6ac5, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, - 0x017e, 0x1078, 0x36a1, 0x017f, 0x1078, 0x6276, 0x0d7f, 0x6000, - 0xa086, 0x0004, 0x00c0, 0x6ab0, 0x017e, 0x1078, 0x15f2, 0x017f, - 0x1078, 0x6283, 0xace0, 0x0008, 0x2001, 0x6d15, 0x2004, 0xac02, - 0x00c8, 0x6abc, 0x0078, 0x6a69, 0x127f, 0x027f, 0x047f, 0x057f, - 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, - 0x6a9b, 0xa386, 0x0005, 0x0040, 0x6ab2, 0x1078, 0x6bb3, 0x0078, - 0x6aa6, 0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x6bca, - 0x017f, 0x0040, 0x6ae0, 0x601c, 0xa084, 0x000f, 0x1079, 0x6ae3, - 0x0e7f, 0x0c7f, 0x007c, 0x6aeb, 0x6aeb, 0x6aeb, 0x6aeb, 0x6aeb, - 0x6aeb, 0x6aed, 0x6aeb, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, - 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, - 0x0020, 0x1078, 0x6bf7, 0x017f, 0x047f, 0x1078, 0x6884, 0xa085, - 0x0001, 0x007c, 0x2001, 0x0001, 0x1078, 0x33df, 0x157e, 0x017e, - 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, 0x6d05, 0x2011, 0x7296, - 0x1078, 0x5a35, 0x037f, 0x027f, 0x017f, 0x157f, 0xa005, 0x007c, - 0x0f7e, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x027e, 0x127e, 0x2091, - 0x8000, 0x2061, 0x7400, 0x2079, 0x0001, 0x8fff, 0x0040, 0x6b73, - 0x2071, 0x6d00, 0x7644, 0x7060, 0x8001, 0xa602, 0x00c8, 0x6b73, - 0x88ff, 0x0040, 0x6b39, 0x2800, 0xac06, 0x00c0, 0x6b69, 0x2079, - 0x0000, 0x1078, 0x6c0f, 0x0040, 0x6b69, 0x2400, 0xac06, 0x0040, - 0x6b69, 0x671c, 0xa786, 0x0006, 0x00c0, 0x6b69, 0xa786, 0x0007, - 0x0040, 0x6b69, 0x88ff, 0x00c0, 0x6b51, 0x6018, 0xa206, 0x00c0, - 0x6b69, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6120, 0x0040, 0x6b5c, - 0x047e, 0x1078, 0x6bb3, 0x047f, 0x0d7f, 0x6000, 0xa086, 0x0004, - 0x00c0, 0x6b64, 0x1078, 0x15f2, 0x1078, 0x6283, 0x88ff, 0x00c0, - 0x6b7c, 0xace0, 0x0008, 0x2001, 0x6d15, 0x2004, 0xac02, 0x00c8, - 0x6b73, 0x0078, 0x6b25, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f, - 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078, 0x6b74, - 0x087e, 0x2041, 0x0000, 0x2c20, 0x2019, 0x0002, 0x6218, 0x1078, - 0x5387, 0x1078, 0x5428, 0x1078, 0x6b18, 0x087f, 0x007c, 0x027e, - 0x047e, 0x087e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x017e, 0x037e, 0x1078, 0x3447, 0x00c0, 0x6ba8, 0x2c10, - 0x2041, 0x0000, 0x1078, 0x5387, 0x1078, 0x5428, 0x1078, 0x6b18, - 0x037f, 0x017f, 0x8108, 0x00f0, 0x6b99, 0x157f, 0x0c7f, 0x087f, - 0x047f, 0x027f, 0x007c, 0x017e, 0x0f7e, 0x8dff, 0x0040, 0x6bc7, - 0x6800, 0xa07d, 0x0040, 0x6bc4, 0x6803, 0x0000, 0x6b52, 0x1078, - 0x36a1, 0x2f68, 0x0078, 0x6bb8, 0x6b52, 0x1078, 0x36a1, 0x0f7f, - 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, 0x7400, 0x2071, - 0x6d00, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, 0x6bf2, 0x2100, - 0xac06, 0x0040, 0x6be4, 0x6000, 0xa086, 0x0000, 0x0040, 0x6be4, - 0x6008, 0xa206, 0x0040, 0x6bee, 0xace0, 0x0008, 0x2001, 0x6d15, - 0x2004, 0xac02, 0x00c8, 0x6bf2, 0x0078, 0x6bcf, 0xa085, 0x0001, - 0x0078, 0x6bf3, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, 0x0d7e, - 0x007e, 0x1078, 0x130f, 0x007f, 0x1040, 0x12b7, 0x6837, 0x010d, - 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x685e, 0x6956, - 0x6c46, 0x684f, 0x0000, 0x1078, 0x36a1, 0x0d7f, 0x007c, 0x6700, - 0xa786, 0x0000, 0x0040, 0x6c22, 0xa786, 0x0001, 0x0040, 0x6c22, - 0xa786, 0x000a, 0x0040, 0x6c22, 0xa786, 0x0009, 0x0040, 0x6c22, - 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, - 0x2071, 0x6d00, 0xd5a4, 0x0040, 0x6c30, 0x7034, 0x8000, 0x7036, - 0xd5b4, 0x0040, 0x6c36, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, - 0x6c3d, 0x2071, 0x6d0a, 0x1078, 0x6c6c, 0x0e7f, 0x007f, 0x127f, - 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x6d00, - 0xd5a4, 0x0040, 0x6c4e, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, - 0x6c54, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0x6c5b, 0x2071, - 0x6d0a, 0x1078, 0x6c6c, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, - 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x6d02, 0x1078, 0x6c6c, - 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, 0x00c8, - 0x6c75, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, 0x2071, - 0x6d00, 0x1078, 0x6c6c, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x6d04, - 0x1078, 0x6c6c, 0x0e7f, 0x007c, 0x0001, 0x0002, 0x0004, 0x0008, - 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, - 0x1000, 0x2000, 0x4000, 0x8000, 0x614c + 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 }; -unsigned short risc_code_length01 = 0x5c95; +unsigned short risc_code_length01 = 0x65e6; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.h linux.ac/drivers/scsi/scsi.h --- linux.vanilla/drivers/scsi/scsi.h Wed Mar 24 10:55:22 1999 +++ linux.ac/drivers/scsi/scsi.h Wed Mar 24 18:23:12 1999 @@ -376,6 +376,9 @@ extern int scsi_decide_disposition (Scsi_Cmnd * SCpnt); extern int scsi_block_when_processing_errors(Scsi_Device *); extern void scsi_sleep(int); +extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, + unsigned int *secs); /* * scsi_abort aborts the current command that is executing on host host. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_syms.c linux.ac/drivers/scsi/scsi_syms.c --- linux.vanilla/drivers/scsi/scsi_syms.c Sun Jan 3 03:52:02 1999 +++ linux.ac/drivers/scsi/scsi_syms.c Mon Mar 1 00:30:47 1999 @@ -53,6 +53,7 @@ EXPORT_SYMBOL(scsi_init_malloc); EXPORT_SYMBOL(scsi_init_free); EXPORT_SYMBOL(scsi_ioctl); +EXPORT_SYMBOL(scsi_partsize); EXPORT_SYMBOL(print_command); EXPORT_SYMBOL(print_sense); EXPORT_SYMBOL(print_msg); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsicam.c linux.ac/drivers/scsi/scsicam.c --- linux.vanilla/drivers/scsi/scsicam.c Fri Nov 13 01:37:14 1998 +++ linux.ac/drivers/scsi/scsicam.c Mon Mar 1 00:30:26 1999 @@ -22,7 +22,7 @@ #include "hosts.h" #include "sd.h" -static int partsize(struct buffer_head *bh, unsigned long capacity, +int scsi_partsize(struct buffer_head *bh, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds, unsigned int *secs); @@ -51,7 +51,7 @@ return -1; /* try to infer mapping from partition table */ - ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, + ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, (unsigned int *) ip + 0, (unsigned int *) ip + 1); brelse (bh); @@ -80,7 +80,7 @@ } /* - * Function : static int partsize(struct buffer_head *bh, unsigned long + * Function : int scsi_partsize(struct buffer_head *bh, unsigned long * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); * * Purpose : to determine the BIOS mapping used to create the partition @@ -90,7 +90,7 @@ * */ -static int partsize(struct buffer_head *bh, unsigned long capacity, +int scsi_partsize(struct buffer_head *bh, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs) { struct partition *p, *largest = NULL; int i, largest_cyl; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sd.c linux.ac/drivers/scsi/sd.c --- linux.vanilla/drivers/scsi/sd.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/sd.c Tue Feb 16 16:59:16 1999 @@ -1126,8 +1126,8 @@ unsigned char cmd[10]; char nbuff[6]; unsigned char *buffer; - unsigned long spintime; - int the_result, retries; + unsigned long spintime_value = 0; + int the_result, retries, spintime; Scsi_Cmnd * SCpnt; /* @@ -1222,16 +1222,18 @@ SCpnt->request.sem = NULL; } - spintime = jiffies; + spintime = 1; + spintime_value = jiffies; } time1 = jiffies + HZ; spin_unlock_irq(&io_request_lock); - while(jiffies < time1); /* Wait 1 second for next try */ + while(time_before(jiffies, time1)); /* Wait 1 second for next try */ printk( "." ); spin_lock_irq(&io_request_lock); } - } while(the_result && spintime && spintime+100*HZ > jiffies); + } while(the_result && spintime && + time_after(spintime_value+100*HZ, jiffies)); if (spintime) { if (the_result) printk( "not responding...\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sg.c linux.ac/drivers/scsi/sg.c --- linux.vanilla/drivers/scsi/sg.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/sg.c Wed Mar 24 18:10:30 1999 @@ -4,7 +4,45 @@ * to allow user process control of SCSI devices. * Development Sponsored by Killy Corp. NY NY * - * Borrows code from st driver. + * Original driver (sg.c): + * Copyright (C) 1992 Lawrence Foard + * 2.x extensions to driver: + * Copyright (C) 1998, 1999 Douglas Gilbert + * + * 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. + * + * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book. + */ + static char * sg_version_str = "Version: 2.1.30 (990320)"; +/* + * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + * - scatter list logic replaces previous large atomic SG_BIG_BUFF + * sized allocation. See notes in include file. + * + * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First + * the kernel/module needs to be built with CONFIG_SCSI_LOGGING + * (otherwise the macros compile to empty statements), then do + * something like: 'echo "scsi log all" > /proc/scsi/scsi' to log + * everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi' + * where {token} is one of [error,timeout,scan,mlqueue,mlcomplete, + * llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7 + * (with 0 meaning off). For example: 'scsi log timeout 7 > + * /proc/scsi/scsi' to get all logging messages from this driver. + * Should use hlcomplete but it is too "noisy" (sd uses it). + * + * - This driver obtains memory (heap) for the low-level driver to + * transfer/dma to and from. It is obtained from up to 4 sources: + * - 1 SG_SCATTER_SZ sized buffer on open() (per fd) + * [could be less if SG_SCATTER_SZ bytes not available] + * - obtain heap as required on write()s (get_free_pages) + * - obtain heap from kernel directly (kmalloc) + * - obtain heap from the shared scsi dma pool + * the 'alt_address' field in the scatter_list structure and the + * related 'mem_src' indicate the source of the heap allocation. + * */ #include @@ -28,541 +66,849 @@ #include #include -int sg_big_buff = SG_BIG_BUFF; /* for now, sg_big_buff is read-only through sysctl */ + +int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */ +/* N.B. This global is here to keep existing software happy. It now holds + the size of the "first buffer" of the most recent sucessful sg_open(). */ +/* Only available when 'sg' compiled into kernel (rather than a module). */ + +#define SG_SECTOR_SZ 512 +#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) + +#define SG_LOW_POOL_THRESHHOLD 30 +#define SG_MAX_POOL_SECTORS 150 /* Maximum number pool sectors to take */ + +static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; + +/* #define SG_DEBUG */ /* for counting varieties of allocations */ + +#ifdef SG_DEBUG +static int sg_num_kmal = 0; +static int sg_num_pool = 0; +static int sg_num_page = 0; +#endif + +#define SG_HEAP_FB 0 /* heap obtained at open() (one buffer per fd) */ +#define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ +#define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ +#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ + static int sg_init(void); static int sg_attach(Scsi_Device *); +static void sg_finish(void); static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, - SCSI_GENERIC_MAJOR, 0, 0, 0, 0, - sg_detect, sg_init, - NULL, sg_attach, sg_detach}; - -#ifdef SG_BIG_BUFF -static char *big_buff = NULL; -static struct wait_queue *big_wait; /* wait for buffer available */ -static int big_inuse=0; -#endif + SCSI_GENERIC_MAJOR, 0, 0, 0, 0, + sg_detect, sg_init, + sg_finish, sg_attach, sg_detach}; + -struct scsi_generic +typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { - Scsi_Device *device; - int users; /* how many people have it open? */ - struct wait_queue *generic_wait; /* wait for device to be available */ - struct wait_queue *read_wait; /* wait for response */ - struct wait_queue *write_wait; /* wait for free buffer */ - int timeout; /* current default value for device */ - int buff_len; /* length of current buffer */ - char *buff; /* the buffer */ - struct sg_header header; /* header of pending command */ - char exclude; /* opened for exclusive access */ - char pending; /* don't accept writes now */ - char complete; /* command complete allow a read */ -}; + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned bufflen; /* Size of data buffer */ + unsigned b_malloc_len; /* actual len malloc'ed in buffer */ + void * buffer; /* Data buffer or scatter list (12 bytes) */ + char mem_src; /* heap whereabouts of 'buffer' */ +} Sg_scatter_hold; /* 20 bytes long on i386 */ -static struct scsi_generic *scsi_generics=NULL; -static void sg_free(char *buff,int size); +struct sg_device; /* forward declarations */ +struct sg_fd; -static int sg_ioctl(struct inode * inode,struct file * file, - unsigned int cmd_in, unsigned long arg) +typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ { - int dev = MINOR(inode->i_rdev); - int result; + Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */ + struct sg_request * nextrp; /* NULL -> tail request (slist) */ + struct sg_fd * parentfp; /* NULL -> not in use */ + Sg_scatter_hold data; /* hold buffers, perhaps scatter list */ + struct sg_header header; /* scsi command+info */ + char fb_used; /* 1 -> using fst_buf, normally 0 (used) */ +} Sg_request; /* around 72 bytes long on i386 */ - if ((dev<0) || (dev>=sg_template.dev_max)) - return -ENXIO; - - /* - * If we are in the middle of error recovery, then don't allow any - * access to this device. Also, error recovery *may* have taken the - * device offline, in which case all further access is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } +typedef struct sg_fd /* holds the state of a file descriptor */ +{ + struct sg_fd * nextfp; /* NULL when last opened fd on this device */ + struct sg_device * parentdp; /* owning device */ + struct wait_queue * read_wait; /* queue read until command done */ + int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ + char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */ + int fb_size; /* actual size of allocated fst_buf */ + Sg_request * headrp; /* head of request slist, NULL->empty */ + struct fasync_struct * async_qp; /* used by asynchronous notification */ + Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ + char low_dma; /* as in parent but possible overridden to 1 */ + char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ + char closed; /* 1 -> fd closed but request(s) outstanding */ + char my_mem_src; /* heap whereabouts of this sg_fb object */ + char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ +} Sg_fd; /* around 1192 bytes long on i386 */ + +typedef struct sg_device /* holds the state of each scsi generic device */ +{ + Scsi_Device * device; + struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */ + int sg_tablesize; /* adapter's max scatter-gather table size */ + Sg_fd * headfp; /* first open fd belonging to this device */ + kdev_t i_rdev; /* holds device major+minor number */ + char exclude; /* opened for exclusive access */ + char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ + unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */ +} Sg_device; /* around 24 bytes long on i386 */ + + +static int sg_fasync(int fd, struct file * filp, int mode); +static void sg_command_done(Scsi_Cmnd * SCpnt); +static int sg_sc_build(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer); +static int sg_sc_undo_rem(Sg_request * srp, char * outp, + int num_read_xfer); +static char * sg_malloc(Sg_request * srp, int size, int * retSzp, + int * mem_srcp); +static void sg_free(Sg_request * srp, char * buff, int size, int mem_src); +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, + int * retSzp); +static void sg_low_free(char * buff, int size, int mem_src); +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev); +static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); +static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); +static Sg_request * sg_add_request(Sg_fd * sfp); +static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp); +static int sg_fb_in_use(const Sg_fd * sfp); +static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); +static void sg_shorten_timeout(Scsi_Cmnd * scpnt); +static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of); +static void sg_debug_all(const Sg_fd * sfp); + +static Sg_device * sg_dev_arr = NULL; +static const int size_sg_header = sizeof(struct sg_header); - switch(cmd_in) - { - case SG_SET_TIMEOUT: - result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); - if (result) return result; - get_user(scsi_generics[dev].timeout, (int *) arg); - return 0; - case SG_GET_TIMEOUT: - return scsi_generics[dev].timeout; - case SG_EMULATED_HOST: - return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg); - case SCSI_IOCTL_SEND_COMMAND: - /* - Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the - user already has read/write access to the generic device and so - can execute arbitrary SCSI commands. - */ - return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg); - default: - return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg); - } -} static int sg_open(struct inode * inode, struct file * filp) { - int dev=MINOR(inode->i_rdev); - int flags=filp->f_flags; - if (dev>=sg_template.dev_max || !scsi_generics[dev].device) - return -ENXIO; - - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } - - if (O_RDWR!=(flags & O_ACCMODE)) - return -EACCES; - - /* - * If we want exclusive access, then wait until the device is not - * busy, and then set the flag to prevent anyone else from using it. - */ - if (flags & O_EXCL) - { - while(scsi_generics[dev].users) - { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&scsi_generics[dev].generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - scsi_generics[dev].exclude=1; - } - else - /* - * Wait until nobody has an exclusive open on - * this device. - */ - while(scsi_generics[dev].exclude) - { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&scsi_generics[dev].generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } + int dev = MINOR(inode->i_rdev); + int flags = filp->f_flags; + Sg_device * sdp; + Sg_fd * sfp; - /* - * OK, we should have grabbed the device. Mark the thing so + if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) + return -ENXIO; + sdp = &sg_dev_arr[dev]; + if ((! sdp->device) || (! sdp->device->host)) + return -ENXIO; + if (sdp->i_rdev != inode->i_rdev) + printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", + MAJOR(inode->i_rdev), MINOR(inode->i_rdev), + MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev)); + if(! scsi_block_when_processing_errors(sdp->device)) + return -ENXIO; +/* if (O_RDWR != (flags & O_ACCMODE)) */ +/* return -EACCES; May just want to get to a ioctl, so remove */ + + SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); + /* If we want exclusive access, then wait until the device is not + * busy, and then set the flag to prevent anyone else from using it. */ + if (flags & O_EXCL) { + if (O_RDONLY == (flags & O_ACCMODE)) + return -EACCES; /* Can't lock it with read only access */ + while (sdp->headfp) { + if (flags & O_NONBLOCK) + return -EBUSY; + interruptible_sleep_on(&sdp->generic_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + sdp->exclude = 1; + } + else { /* Wait until nobody has an exclusive open on this device. */ + while (sdp->exclude) { + if (flags & O_NONBLOCK) + return -EBUSY; + interruptible_sleep_on(&sdp->generic_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + } + /* OK, we should have grabbed the device. Mark the thing so * that other processes know that we have it, and initialize the - * state variables to known values. - */ - if (!scsi_generics[dev].users - && scsi_generics[dev].pending - && scsi_generics[dev].complete) - { - if (scsi_generics[dev].buff != NULL) - sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len); - scsi_generics[dev].buff=NULL; - scsi_generics[dev].pending=0; - } - if (!scsi_generics[dev].users) - scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT; - if (scsi_generics[dev].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + * state variables to known values. */ + if (! sdp->headfp) { /* no existing opens on this device */ + sdp->sgdebug = 0; + sdp->sg_tablesize = sdp->device->host->sg_tablesize; + sdp->merge_fd = SG_DEF_MERGE_FD; + } + if ((sfp = sg_add_sfp(sdp, dev))) { + if (0 == sdp->merge_fd) + filp->private_data = sfp; + } + else { + if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */ + return -ENOMEM; + } + + if (sdp->device->host->hostt->module) + __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); if (sg_template.module) __MOD_INC_USE_COUNT(sg_template.module); - scsi_generics[dev].users++; return 0; } -static int sg_close(struct inode * inode, struct file * filp) +/* Following function was formerly called 'sg_close' */ +static int sg_release(struct inode * inode, struct file * filp) { - int dev=MINOR(inode->i_rdev); - scsi_generics[dev].users--; - if (scsi_generics[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + Sg_device * sdp; + Sg_fd * sfp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev))); + sg_fasync(-1, filp, 0); /* remove filp from async notification list */ + sg_remove_sfp(sdp, sfp); + if (! sdp->headfp) { + filp->private_data = NULL; + sdp->merge_fd = 0; + } + + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); if(sg_template.module) __MOD_DEC_USE_COUNT(sg_template.module); - scsi_generics[dev].exclude=0; - wake_up(&scsi_generics[dev].generic_wait); + sdp->exclude = 0; + wake_up_interruptible(&sdp->generic_wait); return 0; } -static char *sg_malloc(int size) +/* Read back the results of a SCSI command which was sent in a prior + write(). */ +static ssize_t sg_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) { - if (size<=4096) - return (char *) scsi_malloc(size); -#ifdef SG_BIG_BUFF - if (size<=SG_BIG_BUFF) - { - while(big_inuse) - { - interruptible_sleep_on(&big_wait); - if (signal_pending(current)) - return NULL; - } - big_inuse=1; - return big_buff; + int k; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + int req_pack_id = -1; + struct sg_header * shp = (struct sg_header *)buf; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", + MINOR(sdp->i_rdev), (int)count)); + + /* If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device)) + return -ENXIO; + + if (ppos != &filp->f_pos) + ; /* FIXME: Hmm. Seek to the right place, or fail? */ + if ((k = verify_area(VERIFY_WRITE, buf, count))) + return k; + if (sfp->force_packid && (count >= size_sg_header)) + req_pack_id = shp->pack_id; + srp = sg_get_request(sfp, req_pack_id); + while(! srp) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&sfp->read_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + srp = sg_get_request(sfp, req_pack_id); } -#endif - return NULL; -} + srp->header.pack_len = srp->header.reply_len; /* Why ????? */ -static void sg_free(char *buff,int size) -{ -#ifdef SG_BIG_BUFF - if (buff==big_buff) - { - big_inuse=0; - wake_up(&big_wait); - return; + /* Now copy the result back to the user buffer. */ + if (count >= size_sg_header) { + copy_to_user(buf, &srp->header, size_sg_header); + buf += size_sg_header; + if (count > srp->header.reply_len) + count = srp->header.reply_len; + if (count > size_sg_header) /* release does copy_to_user */ + sg_sc_undo_rem(srp, buf, count - size_sg_header); + else + sg_sc_undo_rem(srp, NULL, 0); } -#endif - scsi_free(buff,size); + else { + count = (srp->header.result == 0) ? 0 : -EIO; + sg_sc_undo_rem(srp, NULL, 0); + } + return count; } -/* - * Read back the results of a previous command. We use the pending and - * complete semaphores to tell us whether the buffer is available for us - * and whether the command is actually done. - */ -static ssize_t sg_read(struct file *filp, char *buf, - size_t count, loff_t *ppos) +static ssize_t sg_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - int dev=MINOR(inode->i_rdev); - int i; - struct scsi_generic *device=&scsi_generics[dev]; + unsigned long flags; + int mxsize, cmd_size, k; + unsigned char cmnd[MAX_COMMAND_SIZE]; + int input_size; + unsigned char opcode; + Scsi_Cmnd * SCpnt; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - } + SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", + MINOR(sdp->i_rdev), (int)count)); - if (ppos != &filp->f_pos) { - /* FIXME: Hmm. Seek to the right place, or fail? */ +/* If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device) ) + return -ENXIO; + + if (ppos != &filp->f_pos) + ; /* FIXME: Hmm. Seek to the right place, or fail? */ + + if ((k = verify_area(VERIFY_READ, buf, count))) + return k; +/* The minimum scsi command length is 6 bytes. If we get anything + * less than this, it is clearly bogus. */ + if (count < (size_sg_header + 6)) + return -EIO; + + srp = sg_add_request(sfp); + if (! srp) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n")); + return -EDOM; + } + copy_from_user(&srp->header, buf, size_sg_header); + buf += size_sg_header; + srp->header.pack_len = count; + get_user(opcode, buf); + cmd_size = COMMAND_SIZE(opcode); + if ((opcode >= 0xc0) && srp->header.twelve_byte) + cmd_size = 12; + SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", + (int)opcode, cmd_size)); +/* Determine buffer size. */ + input_size = count - cmd_size; + mxsize = (input_size > srp->header.reply_len) ? input_size : + srp->header.reply_len; +/* Don't include the command header itself in the size. */ + mxsize -= size_sg_header; + input_size -= size_sg_header; +/* Verify user has actually passed enough bytes for this command. */ + if (input_size < 0) { + sg_sc_undo_rem(srp, NULL, 0); + return -EIO; } - if ((i=verify_area(VERIFY_WRITE,buf,count))) - return i; +/* If we cannot allocate the buffer, report an error. */ + if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k)); + sg_sc_undo_rem(srp, NULL, 0); + return k; + } - /* - * Wait until the command is actually done. - */ - while(!device->pending || !device->complete) - { - if (filp->f_flags & O_NONBLOCK) - { - return -EAGAIN; - } - interruptible_sleep_on(&device->read_wait); - if (signal_pending(current)) - { - return -ERESTARTSYS; - } - } - - /* - * Now copy the result back to the user buffer. - */ - device->header.pack_len=device->header.reply_len; +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ +/* Grab a command pointer for the device we want to talk to. If we + * don't want to block, just return with the appropriate message. */ + if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, + !(filp->f_flags & O_NONBLOCK)))) { + sg_sc_undo_rem(srp, NULL, 0); + return -EAGAIN; + } +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ + + srp->my_cmdp = SCpnt; + SCpnt->request.rq_dev = sdp->i_rdev; + SCpnt->request.rq_status = RQ_ACTIVE; + SCpnt->sense_buffer[0] = 0; + SCpnt->cmd_len = cmd_size; + /* Now copy the SCSI command from the user's address space. */ + copy_from_user(cmnd, buf, cmd_size); + +/* Set the LUN field in the command structure. */ + cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5); +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ +/* Now pass the actual command down to the low-level driver. We + * do not do any more here - when the interrupt arrives, we will + * then do the post-processing. */ + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->use_sg = srp->data.use_sg; + SCpnt->sglist_len = srp->data.sglist_len; + SCpnt->bufflen = srp->data.bufflen; + SCpnt->underflow = srp->data.bufflen; +/* Not many drivers look at this: + aic7xxx driver gives DID_RETRY_COMMAND on underrun + seagate comments out its underrun checking code, and the rest ... +*/ + SCpnt->buffer = srp->data.buffer; + srp->data.use_sg = 0; + srp->data.sglist_len = 0; + srp->data.bufflen = 0; + srp->data.buffer = NULL; + scsi_do_cmd(SCpnt, (void *)cmnd, + (void *)SCpnt->buffer, mxsize, + sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES); + /* 'mxsize' overwrites SCpnt->bufflen, hence need for b_malloc_len */ + spin_unlock_irqrestore(&io_request_lock, flags); +/* SCSI_LOG_TIMEOUT(6, printk("sg_write: sent scsi cmd to mid-level\n")); */ + return count; +} - if (count>=sizeof(struct sg_header)) +static int sg_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg) +{ + int result, val; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", + MINOR(sdp->i_rdev), (int)cmd_in)); + /* If we are in the middle of error recovery, then don't allow any + * access to this device. Also, error recovery *may* have taken the + * device offline, in which case all further access is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device) ) + return -ENXIO; + + switch(cmd_in) { - copy_to_user(buf,&device->header,sizeof(struct sg_header)); - buf+=sizeof(struct sg_header); - if (count>device->header.pack_len) - count=device->header.pack_len; - if (count > sizeof(struct sg_header)) { - copy_to_user(buf,device->buff,count-sizeof(struct sg_header)); - } + case SG_SET_TIMEOUT: + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + return get_user(sfp->timeout, (int *)arg); + case SG_GET_TIMEOUT: + return sfp->timeout; /* strange ..., for backward compatibility */ + case SG_SET_FORCE_LOW_DMA: + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + result = get_user(val, (int *)arg); + if (result) return result; + if (val) { + if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) { + sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); + sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1, + SG_HEAP_PAGE, &sfp->fb_size); + } + sfp->low_dma = 1; + if (! sfp->fst_buf) + return -ENOMEM; + } + else + sfp->low_dma = sdp->device->host->unchecked_isa_dma; + return 0; + case SG_GET_LOW_DMA: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user((int)sfp->low_dma, (int *)arg); + return 0; + case SG_GET_SCSI_ID: + result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id)); + if (result) return result; + else { + Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg; + put_user((int)sdp->device->host->host_no, &sg_idp->host_no); + put_user((int)sdp->device->channel, &sg_idp->channel); + put_user((int)sdp->device->id, &sg_idp->scsi_id); + put_user((int)sdp->device->lun, &sg_idp->lun); + put_user((int)sdp->device->type, &sg_idp->scsi_type); + put_user(0, &sg_idp->unused1); + put_user(0, &sg_idp->unused2); + put_user(0, &sg_idp->unused3); + return 0; + } + case SG_SET_FORCE_PACK_ID: + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + result = get_user(val, (int *)arg); + if (result) return result; + sfp->force_packid = val ? 1 : 0; + return 0; + case SG_GET_PACK_ID: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + srp = sfp->headrp; + while (srp) { + if (! srp->my_cmdp) { + put_user(srp->header.pack_id, (int *)arg); + return 0; + } + srp = srp->nextrp; + } + put_user(-1, (int *)arg); + return 0; + case SG_GET_NUM_WAITING: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + srp = sfp->headrp; + val = 0; + while (srp) { + if (! srp->my_cmdp) + ++val; + srp = srp->nextrp; + } + put_user(val, (int *)arg); + return 0; + case SG_GET_SG_TABLESIZE: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user(sdp->sg_tablesize, (int *)arg); + return 0; + case SG_SET_RESERVED_SIZE: + /* currently ignored, future extension */ + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + return 0; + case SG_GET_RESERVED_SIZE: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user(sfp->fb_size, (int *)arg); + return 0; + case SG_GET_MERGE_FD: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user((int)sdp->merge_fd, (int *)arg); + return 0; + case SG_SET_MERGE_FD: + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since effect wider + then just this fd */ + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + result = get_user(val, (int *)arg); + if (result) return result; + val = val ? 1 : 0; + if ((val ^ (0 != sdp->merge_fd)) && + sdp->headfp && sdp->headfp->nextfp) + return -EBUSY; /* too much work if multiple fds already */ + sdp->merge_fd = val; + return 0; + case SG_SET_COMMAND_Q: + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + result = get_user(val, (int *)arg); + if (result) return result; + sfp->cmd_q = val ? 1 : 0; + return 0; + case SG_GET_COMMAND_Q: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user((int)sfp->cmd_q, (int *)arg); + return 0; + case SG_EMULATED_HOST: + return put_user(sdp->device->host->hostt->emulated, (int *)arg); + case SCSI_IOCTL_SEND_COMMAND: + /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the + user already has read/write access to the generic device and so + can execute arbitrary SCSI commands. */ + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since these could be + dangerous */ + return scsi_ioctl_send_command(sdp->device, (void *)arg); + case SG_SET_DEBUG: + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); + if (result) return result; + result = get_user(val, (int *)arg); + if (result) return result; + sdp->sgdebug = (char)val; + if (9 == sdp->sgdebug) + sg_debug(sdp, sfp, 0); + else if (sdp->sgdebug > 9) + sg_debug_all(sfp); + return 0; + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + return scsi_ioctl(sdp->device, cmd_in, (void *)arg); + default: + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since these could be + dangerous */ + return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } - else - count= device->header.result==0 ? 0 : -EIO; +} - /* - * Clean up, and release the device so that we can send another - * command. - */ - sg_free(device->buff,device->buff_len); - device->buff = NULL; - device->pending=0; - wake_up(&device->write_wait); - return count; +static unsigned int sg_poll(struct file * filp, poll_table * wait) +{ + unsigned int res = 0; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + int count = 0; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return POLLERR; + poll_wait(filp, &sfp->read_wait, wait); + srp = sfp->headrp; + while (srp) { /* if any read waiting, flag it */ + if (! (res || srp->my_cmdp)) + res = POLLIN | POLLRDNORM; + ++count; + srp = srp->nextrp; + } + if (0 == sfp->cmd_q) { + if (0 == count) + res |= POLLOUT | POLLWRNORM; + } + else if (count < SG_MAX_QUEUE) + res |= POLLOUT | POLLWRNORM; + SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", + MINOR(sdp->i_rdev), (int)res)); + return res; } -/* - * This function is called by the interrupt handler when we +static int sg_fasync(int fd, struct file * filp, int mode) +{ + int retval; + Sg_device * sdp; + Sg_fd * sfp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", + MINOR(sdp->i_rdev), mode)); + + retval = fasync_helper(fd, filp, mode, &sfp->async_qp); + return (retval < 0) ? retval : 0; +} + +/* This function is called by the interrupt handler when we * actually have a command that is complete. Change the - * flags to indicate that we have a result. - */ + * flags to indicate that we have a result. */ static void sg_command_done(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); - struct scsi_generic *device = &scsi_generics[dev]; - if (!device->pending) - { - printk("unexpected done for sg %d\n",dev); + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp = NULL; + int closed = 0; + + if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) { + SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; - return; + return; } - - /* - * See if the command completed normally, or whether something went - * wrong. - */ - memcpy(device->header.sense_buffer, SCpnt->sense_buffer, - sizeof(SCpnt->sense_buffer)); - switch (host_byte(SCpnt->result)) { + sdp = &sg_dev_arr[dev]; + if (NULL == sdp->device) + return; /* Get out of here quick ... */ + sfp = sdp->headfp; + while (sfp) { + srp = sfp->headrp; + while (srp) { + if (SCpnt == srp->my_cmdp) + break; + srp = srp->nextrp; + } + if (srp) + break; + sfp = sfp->nextfp; + } + if (! srp) { + SCSI_LOG_TIMEOUT(1, printk("sg__done: req missing, dev=%d\n", dev)); + scsi_release_command(SCpnt); + SCpnt = NULL; + return; + } +/* First transfer ownership of data buffers to sg_device object. */ + srp->data.use_sg = SCpnt->use_sg; + srp->data.sglist_len = SCpnt->sglist_len; + srp->data.bufflen = SCpnt->bufflen; + srp->data.buffer = SCpnt->buffer; + sg_clr_scpnt(SCpnt); + srp->my_cmdp = NULL; + + SCSI_LOG_TIMEOUT(4, + printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", + dev, (int)status_byte(SCpnt->result), (int)SCpnt->result)); +/* See if the command completed normally, or whether something went wrong. */ + memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, + sizeof(SCpnt->sense_buffer)); + switch (host_byte(SCpnt->result)) + { case DID_OK: - device->header.result = 0; + case DID_PASSTHROUGH: /* just guessing */ + case DID_SOFT_ERROR: /* just guessing */ + srp->header.result = 0; break; case DID_NO_CONNECT: case DID_BUS_BUSY: case DID_TIME_OUT: - device->header.result = EBUSY; + srp->header.result = EBUSY; break; case DID_BAD_TARGET: case DID_ABORT: case DID_PARITY: case DID_RESET: case DID_BAD_INTR: - device->header.result = EIO; + srp->header.result = EIO; break; case DID_ERROR: - /* - * There really should be DID_UNDERRUN and DID_OVERRUN error values, + /* There really should be DID_UNDERRUN and DID_OVERRUN error values, * and a means for callers of scsi_do_cmd to indicate whether an * underrun or overrun should signal an error. Until that can be * implemented, this kludge allows for returning useful error values * except in cases that return DID_ERROR that might be due to an - * underrun. - */ + * underrun. [Underrun on advansys adapter yields DID_ABORT -dpg] */ if (SCpnt->sense_buffer[0] == 0 && - status_byte(SCpnt->result) == GOOD) - device->header.result = 0; - else device->header.result = EIO; + status_byte(SCpnt->result) == GOOD) + srp->header.result = 0; + else + srp->header.result = EIO; break; + default: + SCSI_LOG_TIMEOUT(1, printk( + "sg: unexpected host_byte=%d, dev=%d in 'done'\n", + host_byte(SCpnt->result), dev)); + srp->header.result = EIO; + break; + } + +/* Following if statement is a patch supplied by Eric Youngdale */ + if (driver_byte(SCpnt->result) != 0 + && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 + && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + && sdp->device->removable) { +/* Detected disc change. Set the bit - this may be used if there are */ +/* filesystems using this device. */ + sdp->device->changed = 1; } - /* - * Now wake up the process that is waiting for the - * result. - */ - device->complete=1; +/* Pick up error and status information */ + srp->header.target_status = status_byte(SCpnt->result); + if ((sdp->sgdebug > 0) && + ((CHECK_CONDITION == srp->header.target_status) || + (COMMAND_TERMINATED == srp->header.target_status))) + print_sense("sg_command_done", SCpnt); + srp->header.host_status = host_byte(SCpnt->result); + srp->header.driver_status = driver_byte(SCpnt->result); + scsi_release_command(SCpnt); SCpnt = NULL; - wake_up(&scsi_generics[dev].read_wait); + if (sfp->closed) { /* whoops this fd already released, cleanup */ + closed = 1; + SCSI_LOG_TIMEOUT(1, + printk("sg__done: already closed, freeing ...\n")); +/* should check if module is unloaded <<<<<<< */ + sg_sc_undo_rem(srp, NULL, 0); + if (NULL == sfp->headrp) { + SCSI_LOG_TIMEOUT(1, + printk("sg__done: already closed, final cleanup\n")); + sg_remove_sfp(sdp, sfp); + } + } +/* Now wake up the process that is waiting for the result. */ + /* A. Rubini says this is preferable+faster than wake_up() */ + wake_up_interruptible(&sfp->read_wait); + if ((sfp->async_qp) && (! closed)) + kill_fasync(sfp->async_qp, SIGPOLL); } -static ssize_t sg_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos) +static void sg_debug_all(const Sg_fd * sfp) { - unsigned long flags; - struct inode *inode = filp->f_dentry->d_inode; - int bsize,size,amt,i; - unsigned char cmnd[MAX_COMMAND_SIZE]; - kdev_t devt = inode->i_rdev; - int dev = MINOR(devt); - struct scsi_generic * device=&scsi_generics[dev]; - int input_size; - unsigned char opcode; - Scsi_Cmnd * SCpnt; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } - - if (ppos != &filp->f_pos) { - /* FIXME: Hmm. Seek to the right place, or fail? */ - } - - if ((i=verify_area(VERIFY_READ,buf,count))) - return i; - /* - * The minimum scsi command length is 6 bytes. If we get anything - * less than this, it is clearly bogus. - */ - if (count<(sizeof(struct sg_header) + 6)) - return -EIO; - - /* - * If we still have a result pending from a previous command, - * wait until the result has been read by the user before sending - * another command. - */ - while(device->pending) - { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; -#ifdef DEBUG - printk("sg_write: sleeping on pending request\n"); + const Sg_device * sdp = sg_dev_arr; + int k; + + if (NULL == sg_dev_arr) { + printk("sg_debug_all: sg_dev_arr NULL, death is imminent\n"); + return; + } + if (! sfp) + printk("sg_debug_all: sfp (file descriptor pointer) NULL\n"); + + printk("sg_debug_all: dev_max=%d, %s\n", + sg_template.dev_max, sg_version_str); + printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", + scsi_dma_free_sectors, sg_pool_secs_avail); + printk(" sg_big_buff=%d\n", sg_big_buff); +#ifdef SG_DEBUG + printk(" malloc counts, kmallocs=%d, dma_pool=%d, pages=%d\n", + sg_num_kmal, sg_num_pool, sg_num_page); #endif - interruptible_sleep_on(&device->write_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - /* - * Mark the device flags for the new state. - */ - device->pending=1; - device->complete=0; - copy_from_user(&device->header,buf,sizeof(struct sg_header)); - - device->header.pack_len=count; - buf+=sizeof(struct sg_header); - - /* - * Now we need to grab the command itself from the user's buffer. - */ - get_user(opcode, buf); - size=COMMAND_SIZE(opcode); - if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; - - /* - * Determine buffer size. - */ - input_size = device->header.pack_len - size; - if( input_size > device->header.reply_len) - { - bsize = input_size; - } else { - bsize = device->header.reply_len; + for (k = 0; k < sg_template.dev_max; ++k, ++sdp) { + if (sdp->headfp) { + if (! sfp) + sfp = sdp->headfp; /* just to keep things going */ + else if (sdp == sfp->parentdp) + printk(" ***** Invoking device follows *****\n"); + sg_debug(sdp, sfp, 1); + } } +} - /* - * Don't include the command header itself in the size. - */ - bsize-=sizeof(struct sg_header); - input_size-=sizeof(struct sg_header); - - /* - * Verify that the user has actually passed enough bytes for this command. - */ - if( input_size < 0 ) - { - device->pending=0; - wake_up( &device->write_wait ); - return -EIO; - } - - /* - * Allocate a buffer that is large enough to hold the data - * that has been requested. Round up to an even number of sectors, - * since scsi_malloc allocates in chunks of 512 bytes. - */ - amt=bsize; - if (!bsize) - bsize++; - bsize=(bsize+511) & ~511; - - /* - * If we cannot allocate the buffer, report an error. - */ - if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize))) - { - device->pending=0; - wake_up(&device->write_wait); - return -ENOMEM; +static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of) +{ + Sg_fd * fp; + Sg_request * srp; + int dev; + int k; + + if (! sfp) + printk("sg_debug: sfp (file descriptor pointer) NULL\n"); + if (! sdp) { + printk("sg_debug: sdp pointer (to device) NULL\n"); + return; } - -#ifdef DEBUG - printk("allocating device\n"); -#endif - - /* - * Grab a device pointer for the device we want to talk to. If we - * don't want to block, just return with the appropriate message. - */ - if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK)))) - { - device->pending=0; - wake_up(&device->write_wait); - sg_free(device->buff,device->buff_len); - device->buff = NULL; - return -EAGAIN; + else if (! sdp->device) { + printk("sg_debug: device detached ??\n"); + return; } -#ifdef DEBUG - printk("device allocated\n"); -#endif - - SCpnt->request.rq_dev = devt; - SCpnt->request.rq_status = RQ_ACTIVE; - SCpnt->sense_buffer[0]=0; - SCpnt->cmd_len = size; - - /* - * Now copy the SCSI command from the user's address space. - */ - copy_from_user(cmnd,buf,size); - buf+=size; - - /* - * If we are writing data, copy the data we are writing. The pack_len - * field also includes the length of the header and the command, - * so we need to subtract these off. - */ - if (input_size > 0) copy_from_user(device->buff, buf, input_size); - - /* - * Set the LUN field in the command structure. - */ - cmnd[1]= (cmnd[1] & 0x1f) | (device->device->lun<<5); - -#ifdef DEBUG - printk("do cmd\n"); -#endif - - /* - * Now pass the actual command down to the low-level driver. We - * do not do any more here - when the interrupt arrives, we will - * then do the post-processing. - */ - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd (SCpnt,(void *) cmnd, - (void *) device->buff,amt, - sg_command_done,device->timeout,SG_DEFAULT_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); + dev = MINOR(sdp->i_rdev); -#ifdef DEBUG - printk("done cmd\n"); + if (part_of) + printk(" >>> device=%d(sg%c), ", dev, 'a' + dev); + else + printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev); + printk("scsi%d chan=%d id=%d lun=%d em=%d\n", sdp->device->host->host_no, + sdp->device->channel, sdp->device->id, sdp->device->lun, + sdp->device->host->hostt->emulated); + printk(" sg_tablesize=%d, excl=%d, sgdebug=%d, merge_fd=%d\n", + sdp->sg_tablesize, sdp->exclude, sdp->sgdebug, sdp->merge_fd); + if (! part_of) { + printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", + scsi_dma_free_sectors, sg_pool_secs_avail); +#ifdef SG_DEBUG + printk(" mallocs: kmallocs=%d, dma_pool=%d, pages=%d\n", + sg_num_kmal, sg_num_pool, sg_num_page); #endif + } - return count; -} - -static unsigned int sg_poll(struct file *file, poll_table * wait) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - struct scsi_generic *device = &scsi_generics[dev]; - unsigned int mask = 0; - - poll_wait(file, &scsi_generics[dev].read_wait, wait); - poll_wait(file, &scsi_generics[dev].write_wait, wait); - if(device->pending && device->complete) - mask |= POLLIN | POLLRDNORM; - if(!device->pending) - mask |= POLLOUT | POLLWRNORM; - - return mask; + fp = sdp->headfp; + for (k = 1; fp; fp = fp->nextfp, ++k) { + if (sfp == fp) + printk(" *** Following data belongs to invoking FD ***\n"); + else if (! fp->parentdp) + printk(">> Following FD has NULL parent pointer ???\n"); + printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n", + k, fp->timeout, fp->fb_size, (int)fp->cmd_q); + printk(" low_dma=%d, force_packid=%d, closed=%d\n", + (int)fp->low_dma, (int)fp->force_packid, (int)fp->closed); + srp = fp->headrp; + if (NULL == srp) + printk(" No requests active\n"); + while (srp) { + if (srp->fb_used) + printk("using 1st buff >> "); + else + printk(" "); + if (srp->my_cmdp) + printk("written: pack_id=%d, bufflen=%d, use_sg=%d\n", + srp->header.pack_id, srp->my_cmdp->bufflen, + srp->my_cmdp->use_sg); + else + printk("to_read: pack_id=%d, bufflen=%d, use_sg=%d\n", + srp->header.pack_id, srp->data.bufflen, srp->data.use_sg); + if (! srp->parentfp) + printk(">> request has NULL parent pointer ???\n"); + srp = srp->nextrp; + } + } } static struct file_operations sg_fops = { @@ -574,24 +920,30 @@ sg_ioctl, /* ioctl */ NULL, /* mmap */ sg_open, /* open */ - NULL, /* flush */ - sg_close, /* release */ - NULL /* fsync */ + NULL, /* flush */ + sg_release, /* release, was formerly sg_close */ + NULL, /* fsync */ + sg_fasync, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ }; -static int sg_detect(Scsi_Device * SDp){ - - switch (SDp->type) { - case TYPE_DISK: - case TYPE_MOD: - case TYPE_ROM: - case TYPE_WORM: - case TYPE_TAPE: break; - default: - printk("Detected scsi generic sg%c at scsi%d, channel %d, id %d, lun %d\n", - 'a'+sg_template.dev_noticed, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); +static int sg_detect(Scsi_Device * scsidp) +{ + switch (scsidp->type) { + case TYPE_DISK: + case TYPE_MOD: + case TYPE_ROM: + case TYPE_WORM: + case TYPE_TAPE: break; + default: + printk("Detected scsi generic sg%c at scsi%d," + " channel %d, id %d, lun %d\n", + 'a'+sg_template.dev_noticed, + scsidp->host->host_no, scsidp->channel, + scsidp->id, scsidp->lun); } sg_template.dev_noticed++; return 1; @@ -605,84 +957,108 @@ if (sg_template.dev_noticed == 0) return 0; if(!sg_registered) { - if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) - { - printk("Unable to get major %d for generic SCSI device\n", - SCSI_GENERIC_MAJOR); - return 1; - } - sg_registered++; + if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + { + printk("Unable to get major %d for generic SCSI device\n", + SCSI_GENERIC_MAJOR); + return 1; + } + sg_registered++; } /* If we have already been through here, return */ - if(scsi_generics) return 0; - -#ifdef DEBUG - printk("sg: Init generic device.\n"); -#endif - -#ifdef SG_BIG_BUFF - big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); -#endif - - scsi_generics = (struct scsi_generic *) - scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic), GFP_ATOMIC); - memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic)); + if(sg_dev_arr) return 0; + SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); + sg_dev_arr = (Sg_device *) + scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(Sg_device), GFP_ATOMIC); + if (NULL == sg_dev_arr) { + printk("sg_init: no space for sg_dev_arr\n"); + return 1; + } sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } -static int sg_attach(Scsi_Device * SDp) +static int sg_attach(Scsi_Device * scsidp) { - struct scsi_generic * gpnt; - int i; + Sg_device * sdp = sg_dev_arr; + int k; - if(sg_template.nr_dev >= sg_template.dev_max) + if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp)) { - SDp->attached--; - return 1; + scsidp->attached--; + return 1; } - for(gpnt = scsi_generics, i=0; idevice) break; + for(k = 0; k < sg_template.dev_max; k++, sdp++) + if(! sdp->device) break; - if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); + if(k >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); - scsi_generics[i].device=SDp; - scsi_generics[i].users=0; - scsi_generics[i].generic_wait=NULL; - scsi_generics[i].read_wait=NULL; - scsi_generics[i].write_wait=NULL; - scsi_generics[i].buff=NULL; - scsi_generics[i].exclude=0; - scsi_generics[i].pending=0; - scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT; + SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); + sdp->device = scsidp; + sdp->generic_wait = NULL; + sdp->headfp= NULL; + sdp->exclude = 0; + sdp->merge_fd = 0; + sdp->sgdebug = 0; + sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; + sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); sg_template.nr_dev++; return 0; -}; - - +} -static void sg_detach(Scsi_Device * SDp) +/* Called at 'finish' of init process, after all attaches */ +static void sg_finish(void) { - struct scsi_generic * gpnt; - int i; + SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n", + scsi_dma_free_sectors)); +} - for(gpnt = scsi_generics, i=0; idevice == SDp) { - gpnt->device = NULL; - SDp->attached--; - sg_template.nr_dev--; - /* - * avoid associated device /dev/sg? bying incremented - * each time module is inserted/removed , - */ - sg_template.dev_noticed--; - return; - } +static void sg_detach(Scsi_Device * scsidp) +{ + Sg_device * sdp = sg_dev_arr; + unsigned long flags = 0; + Sg_fd * sfp; + Sg_request * srp; + int k; + + if (NULL == sdp) return; /* all is not well ... */ + for (k = 0; k < sg_template.dev_max; k++, sdp++) { + if(sdp->device != scsidp) + continue; /* dirty but lowers nesting */ + if (sdp->headfp) { +/* Need to stop sg_command_done() playing with this list during this loop */ + spin_lock_irqsave(&io_request_lock, flags); + sfp = sdp->headfp; + while (sfp) { + srp = sfp->headrp; + while (srp) { + if (srp->my_cmdp) + sg_shorten_timeout(srp->my_cmdp); + srp = srp->nextrp; + } + sfp = sfp->nextfp; + } + spin_unlock_irqrestore(&io_request_lock, flags); + SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); + scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ + } + else { + SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); + sdp->device = NULL; + } + scsidp->attached--; + sg_template.nr_dev--; + /* + * avoid associated device /dev/sg? bying incremented + * each time module is inserted/removed , + */ + sg_template.dev_noticed--; + return; + } return; } @@ -698,34 +1074,553 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); - if(scsi_generics != NULL) { - scsi_init_free((char *) scsi_generics, - (sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic)); + if(sg_dev_arr != NULL) { +/* Really worrying situation of writes still pending and get here */ +/* Strategy: shorten timeout on release + wait on detach ... */ + scsi_init_free((char *) sg_dev_arr, + (sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(Sg_device)); + sg_dev_arr = NULL; } sg_template.dev_max = 0; -#ifdef SG_BIG_BUFF - if(big_buff != NULL) - scsi_init_free(big_buff, SG_BIG_BUFF); -#endif } #endif /* MODULE */ -/* - * Overrides for Emacs so that we almost 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: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ + +#if 0 +extern void scsi_times_out (Scsi_Cmnd * SCpnt); +extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); +#endif + +/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ +static void sg_shorten_timeout(Scsi_Cmnd * scpnt) +{ +#if 0 /* scsi_syms.c is very miserly about exported functions */ + scsi_delete_timer(scpnt); + if (! scpnt) + return; + scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */ + if (scpnt->host->hostt->use_new_eh_code) + scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out); + else + scsi_add_timer(scpnt, scpnt->timeout_per_command, + scsi_old_times_out); +#else + scsi_sleep(HZ); /* just sleep 1 second and hope ... */ +#endif +} + +static int sg_sc_build(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer) +{ + int ret_sz, mem_src; + int blk_size = max_buff_size; + char * p = NULL; + + if ((blk_size < 0) || (! srp)) + return -EFAULT; + + SCSI_LOG_TIMEOUT(4, printk("sg build: m_b_s=%d, num_write_xfer=%d\n", + max_buff_size, num_write_xfer)); + if (0 == blk_size) + ++blk_size; /* don't know why */ +/* round request up to next highest SG_SECTOR_SZ byte boundary */ + blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); + SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size)); + + if (blk_size <= SG_SCATTER_SZ) { + mem_src = SG_HEAP_FB; + p = sg_malloc(srp, blk_size, &ret_sz, &mem_src); + if (! p) + return -ENOMEM; + if (blk_size == ret_sz) { /* got it on the first attempt */ + srp->data.buffer = p; + srp->data.bufflen = blk_size; + srp->data.mem_src = mem_src; + srp->data.b_malloc_len = blk_size; + if (inp && (num_write_xfer > 0)) + copy_from_user(srp->data.buffer, inp, num_write_xfer); + return 0; + } + } + else { + mem_src = SG_HEAP_PAGE; + p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src); + if (! p) + return -ENOMEM; + } +/* Want some local declarations, so start new block ... */ + { /* lets try and build a scatter gather list */ + struct scatterlist * sclp; + int k, rem_sz, num, nxt; + int sc_bufflen = PAGE_SIZE; + int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; + int sg_tablesize = srp->parentfp->parentdp->sg_tablesize; + int first = 1; + + k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */ + srp->data.buffer = (struct scatterlist *)sg_malloc(srp, + sc_bufflen, &num, &k); + srp->data.mem_src = (char)k; + /* N.B. ret_sz and mem_src carried into this block ... */ + if (! srp->data.buffer) + return -ENOMEM; + else if (num != sc_bufflen) { + sc_bufflen = num; + mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; + } + srp->data.sglist_len = sc_bufflen; + memset(srp->data.buffer, 0, sc_bufflen); + for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0; + (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + ++k, rem_sz -= ret_sz, ++sclp) { + if (first) + first = 0; + else { + num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; + mem_src = SG_HEAP_PAGE; + p = sg_malloc(srp, num, &ret_sz, &mem_src); + if (! p) + break; + } + sclp->address = p; + sclp->length = ret_sz; + sclp->alt_address = (char *)mem_src; + + if(inp && (num_write_xfer > 0)) { + num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz; + copy_from_user(sclp->address, inp, num); + num_write_xfer -= num; + inp += num; + } + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_build: k=%d, a=0x%x, len=%d, ms=%d\n", + k, (int)sclp->address, ret_sz, (int)sclp->alt_address)); + } /* end of for loop */ + srp->data.use_sg = k; + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz)); + srp->data.bufflen = blk_size; + if (rem_sz > 0) /* must have failed */ + return -ENOMEM; + } + return 0; +} + +static int sg_sc_undo_rem(Sg_request * srp, char * outp, + int num_read_xfer) +{ + if (! srp) + return -EFAULT; + SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n", + num_read_xfer)); + if (! outp) + num_read_xfer = 0; + if(srp->data.use_sg) { + int k, num, mem_src; + struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer; + + for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) { + if (num_read_xfer > 0) { + num = (int)sclp->length; + if (num > num_read_xfer) { + copy_to_user(outp, sclp->address, num_read_xfer); + outp += num_read_xfer; + num_read_xfer = 0; + } + else { + copy_to_user(outp, sclp->address, num); + outp += num; + num_read_xfer -= num; + } + } + mem_src = (int)sclp->alt_address; + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_undo_rem: k=%d, a=0x%x, len=%d, ms=%d\n", + k, (int)sclp->address, sclp->length, mem_src)); + sg_free(srp, sclp->address, sclp->length, mem_src); + } + sg_free(srp, srp->data.buffer, srp->data.sglist_len, + srp->data.mem_src); + } + else { + if (num_read_xfer > 0) + copy_to_user(outp, srp->data.buffer, num_read_xfer); + sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, + srp->data.mem_src); + } + if (0 == sg_remove_request(srp->parentfp, srp)) { + SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=%d not found\n", + (int)srp)); + } + return 0; +} + +static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) +{ + Sg_request * resp = NULL; + + resp = sfp->headrp; + while (resp) { + if ((! resp->my_cmdp) && + ((-1 == pack_id) || (resp->header.pack_id == pack_id))) + return resp; + resp = resp->nextrp; + } + return resp; +} + +/* always adds to end of list */ +static Sg_request * sg_add_request(Sg_fd * sfp) +{ + int k; + Sg_request * resp = NULL; + Sg_request * rp; + + resp = sfp->headrp; + rp = sfp->req_arr; + if (! resp) { + resp = rp; + sfp->headrp = resp; + } + else { + if (0 == sfp->cmd_q) + resp = NULL; /* command queuing disallowed */ + else { + for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) { + if (! rp->parentfp) + break; + } + if (k < SG_MAX_QUEUE) { + while (resp->nextrp) resp = resp->nextrp; + resp->nextrp = rp; + resp = rp; + } + else + resp = NULL; + } + } + if (resp) { + resp->parentfp = sfp; + resp->nextrp = NULL; + resp->fb_used = 0; + memset(&resp->data, 0, sizeof(Sg_scatter_hold)); + memset(&resp->header, 0, sizeof(struct sg_header)); + resp->my_cmdp = NULL; + } + return resp; +} + +/* Return of 1 for found; 0 for not found */ +static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp) +{ + Sg_request * prev_rp; + Sg_request * rp; + + if ((! sfp) || (! srp) || (! sfp->headrp)) + return 0; + prev_rp = sfp->headrp; + if (srp == prev_rp) { + prev_rp->parentfp = NULL; + sfp->headrp = prev_rp->nextrp; + return 1; + } + while ((rp = prev_rp->nextrp)) { + if (srp == rp) { + rp->parentfp = NULL; + prev_rp->nextrp = rp->nextrp; + return 1; + } + prev_rp = rp; + } + return 0; +} + +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) +{ + Sg_fd * sfp; + + if (sdp->merge_fd) { + ++sdp->merge_fd; + return sdp->headfp; + } + sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); + if (sfp) { + memset(sfp, 0, sizeof(Sg_fd)); + sfp->my_mem_src = SG_HEAP_KMAL; + } + else + return NULL; + + sfp->timeout = SG_DEFAULT_TIMEOUT; + sfp->force_packid = SG_DEF_FORCE_PACK_ID; + sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? + sdp->device->host->unchecked_isa_dma : 1; + sfp->cmd_q = SG_DEF_COMMAND_Q; + sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, + SG_HEAP_PAGE, &sfp->fb_size); + if (! sfp->fst_buf) + sfp->fb_size = 0; + sfp->parentdp = sdp; + if (! sdp->headfp) + sdp->headfp = sfp; + else { /* add to tail of existing list */ + Sg_fd * pfp = sdp->headfp; + while (pfp->nextfp) + pfp = pfp->nextfp; + pfp->nextfp = sfp; + } + sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */ + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%x, m_s=%d\n", + (int)sfp, (int)sfp->my_mem_src)); + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%x\n", + sfp->fb_size, (int)sfp->fst_buf)); + return sfp; +} + +static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) +{ + Sg_request * srp; + Sg_request * tsrp; + int dirty = 0; + int res = 0; + + if (sdp->merge_fd) { + if (--sdp->merge_fd) + return 0; /* if merge_fd then dec merge_fd counter */ + } + srp = sfp->headrp; + if (srp) { +/* Need to stop sg_command_done() playing with this list during this loop */ + while (srp) { + tsrp = srp->nextrp; + if (! srp->my_cmdp) + sg_sc_undo_rem(srp, NULL, 0); + else + ++dirty; + srp = tsrp; + } + } + if (0 == dirty) { + Sg_fd * fp; + Sg_fd * prev_fp = sdp->headfp; + + if (sfp == prev_fp) + sdp->headfp = prev_fp->nextfp; + else { + while ((fp = prev_fp->nextfp)) { + if (sfp == fp) { + prev_fp->nextfp = fp->nextfp; + break; + } + prev_fp = fp; + } + } +SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%x\n", + sfp->fb_size, (int)sfp->fst_buf)); + sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); + sfp->parentdp = NULL; + sfp->fst_buf = NULL; + sfp->fb_size = 0; + SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%x\n", (int)sfp)); + sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src); + res = 1; + } + else { + sfp->closed = 1; /* flag dirty state on this fd */ + SCSI_LOG_TIMEOUT(1, printk( + "sg_remove_sfp: worrisome, %d writes pending\n", dirty)); + } + return res; +} + +static int sg_fb_in_use(const Sg_fd * sfp) +{ + const Sg_request * srp = sfp->headrp; + + while (srp) { + if (srp->fb_used) + return 1; + srp = srp->nextrp; + } + return 0; +} + +/* If retSzp==NULL want exact size or fail */ +/* sg_low_malloc() should always be called from a process context allowing + GFP_KERNEL to be used instead of GFP_ATOMIC */ +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) +{ + char * resp = NULL; + int page_mask = lowDma ? (GFP_KERNEL | GFP_DMA) : GFP_KERNEL; + + if (rqSz <= 0) + return resp; + if (SG_HEAP_KMAL == mem_src) { + resp = kmalloc(rqSz, page_mask); + if (resp && retSzp) *retSzp = rqSz; +#ifdef SG_DEBUG + ++sg_num_kmal; +#endif + return resp; + } + if (SG_HEAP_POOL == mem_src) { + int num_sect = rqSz / SG_SECTOR_SZ; + + if (0 != (rqSz & SG_SECTOR_MSK)) { + if (! retSzp) + return resp; + ++num_sect; + rqSz = num_sect * SG_SECTOR_SZ; + } + while (num_sect > 0) { + if ((num_sect <= sg_pool_secs_avail) && + (scsi_dma_free_sectors > (SG_LOW_POOL_THRESHHOLD + num_sect))) { + resp = scsi_malloc(rqSz); + if (resp) { + if (retSzp) *retSzp = rqSz; + sg_pool_secs_avail -= num_sect; +#ifdef SG_DEBUG + ++sg_num_pool; +#endif + return resp; + } + } + if (! retSzp) + return resp; + num_sect /= 2; /* try half as many */ + rqSz = num_sect * SG_SECTOR_SZ; + } + } + else if (SG_HEAP_PAGE == mem_src) { + int order, a_size; + int resSz = rqSz; + + for (order = 0, a_size = PAGE_SIZE; + a_size < rqSz; order++, a_size <<= 1) + ; + resp = (char *)__get_free_pages(page_mask, order); + while ((! resp) && order && retSzp) { + --order; + a_size >>= 1; /* divide by 2, until PAGE_SIZE */ + resp = (char *)__get_free_pages(page_mask, order); /* try half */ + resSz = a_size; + } + if (retSzp) *retSzp = resSz; +#ifdef SG_DEBUG + if (resp) ++sg_num_page; +#endif + } + else + printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz); + return resp; +} + +static char * sg_malloc(Sg_request * srp, int size, int * retSzp, + int * mem_srcp) +{ + char * resp = NULL; + + if (retSzp) *retSzp = size; + if (size <= 0) + ; + else { + Sg_fd * sfp = srp->parentfp; + int low_dma = sfp->low_dma; + int l_ms = -1; /* invalid value */ + + switch (*mem_srcp) + { + case SG_HEAP_PAGE: + case SG_HEAP_FB: + l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; + resp = sg_low_malloc(size, low_dma, l_ms, 0); + if (resp) + break; + if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) { + SCSI_LOG_TIMEOUT(6, + printk("sg_malloc: scsi_malloc failed, get fst_buf\n")); + resp = sfp->fst_buf; + srp->fb_used = 1; + l_ms = SG_HEAP_FB; + break; + } + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (! resp) { + l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (! resp) { + l_ms = SG_HEAP_KMAL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + } + } + if (resp && retSzp) *retSzp = size; + break; + case SG_HEAP_KMAL: + l_ms = SG_HEAP_PAGE; + resp = sg_low_malloc(size, low_dma, l_ms, 0); + if (resp) + break; + l_ms = SG_HEAP_POOL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (resp && retSzp) *retSzp = size; + break; + default: + SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp)); + break; + } + if (resp) *mem_srcp = l_ms; + } + SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%x\n", + size, *mem_srcp, (int)resp)); + return resp; +} + +static void sg_low_free(char * buff, int size, int mem_src) +{ + if (! buff) + return; + if (SG_HEAP_POOL == mem_src) { + int num_sect = size / SG_SECTOR_SZ; + scsi_free(buff, size); + sg_pool_secs_avail += num_sect; + } + else if (SG_HEAP_KMAL == mem_src) + kfree(buff); /* size not used */ + else if (SG_HEAP_PAGE == mem_src) { + int order, a_size; + + for (order = 0, a_size = PAGE_SIZE; + a_size < size; order++, a_size <<= 1) + ; + free_pages((unsigned long)buff, order); + } + else + printk("sg_low_free: bad mem_src=%d, buff=0x%x, rqSz=%df\n", + mem_src, (int)buff, size); +} + +static void sg_free(Sg_request * srp, char * buff, int size, int mem_src) +{ + Sg_fd * sfp = srp->parentfp; + + SCSI_LOG_TIMEOUT(6, + printk("sg_free: buff=0x%x, size=%d\n", (int)buff, size)); + if ((! sfp) || (! buff) || (size <= 0)) + ; + else if (sfp->fst_buf == buff) { + srp->fb_used = 0; + SCSI_LOG_TIMEOUT(6, printk("sg_free: left cause fst_buf\n")); + } + else + sg_low_free(buff, size, mem_src); +} + +static void sg_clr_scpnt(Scsi_Cmnd * SCpnt) +{ + SCpnt->use_sg = 0; + SCpnt->sglist_len = 0; + SCpnt->bufflen = 0; + SCpnt->buffer = NULL; +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Config.in linux.ac/drivers/sound/Config.in --- linux.vanilla/drivers/sound/Config.in Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/sound/Config.in Wed Mar 17 23:18:49 1999 @@ -97,6 +97,9 @@ comment 'Enter -1 to the following question if you have something else such as SB16/32.' int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi + + dep_tristate 'PCI Legacy soundblaster enabler' CONFIG_SOUND_PCISB $CONFIG_SOUND_OSS + dep_tristate 'ESS-Tech Maestro support' CONFIG_SOUND_ESSMAESTRO $CONFIG_SOUND_OSS dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS @@ -272,16 +275,18 @@ hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi + + dep_tristate 'USB audio support' CONFIG_SOUND_USBAUDIO $CONFIG_SOUND_OSS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate 'VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then - hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 - int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 - int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 - fi + fi + dep_tristate 'Rockwell WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_WAVEARTIST" = "y" ]; then + hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 + int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Makefile linux.ac/drivers/sound/Makefile --- linux.vanilla/drivers/sound/Makefile Tue Jan 19 02:57:32 1999 +++ linux.ac/drivers/sound/Makefile Fri Feb 26 20:41:48 1999 @@ -53,6 +53,8 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_ESSMAESTRO) += ess_pci.o sb.o uart401.o +obj-$(CONFIG_SOUND_PCISB) += pci_legacy.o sb.o uart401.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o @@ -69,6 +71,7 @@ obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o +obj-$(CONFIG_SOUND_USBAUDIO) += usb_audio.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1370.c linux.ac/drivers/sound/es1370.c --- linux.vanilla/drivers/sound/es1370.c Wed Mar 24 10:55:23 1999 +++ linux.ac/drivers/sound/es1370.c Wed Mar 24 18:11:47 1999 @@ -83,6 +83,8 @@ * 16.12.98 0.16 Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.17 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.18 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes * * some important things missing in Ensoniq documentation: * @@ -1455,7 +1457,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1468,7 +1470,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1866,7 +1868,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2271,7 +2273,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.17 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.18 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1371.c linux.ac/drivers/sound/es1371.c --- linux.vanilla/drivers/sound/es1371.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/sound/es1371.c Wed Mar 24 18:11:48 1999 @@ -54,6 +54,8 @@ * Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.8 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.9 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes * */ @@ -1897,7 +1899,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1910,7 +1912,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -2301,7 +2303,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2708,7 +2710,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.8 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.9 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ess_pci.c linux.ac/drivers/sound/ess_pci.c --- linux.vanilla/drivers/sound/ess_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/ess_pci.c Tue Mar 16 19:05:32 1999 @@ -0,0 +1,895 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "maestro.h" +#include "maestro_tables.h" + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS19XX 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_SBBASE 0x220 + +struct address_info maestro_cfg; + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(100); + outw(0x0000, ioaddr+0x36); + udelay(100); +} + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +static u16 maestro_map[32]; +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(int ioaddr, u16 reg, u16 data) +{ + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(int ioaddr, u16 reg) +{ + if(READABLE_MAP & (1<base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring ESS Maestro at 0x%04X\n", iobase); + + if(check_region(ESS_SBBASE, 16)) + { + printk(KERN_WARNING "ess_pci: skipping - I/O 0x%03X is not free.\n", + ESS_SBBASE); + return 0; + } + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(i=0;i<16;i++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+i, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + (wave_get_register(iobase, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|~0x400); + + maestro_write(iobase, IDR2_CRAM_DATA, 0x0000); + maestro_write(iobase, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(iobase, 0x09, 0x001B); + maestro_write(iobase, 0x0A, 0x8000); + maestro_write(iobase, 0x0B, 0x3F37); + maestro_write(iobase, 0x0C, 0x0098); + + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0xF000)|0x8000); + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0x0F00)|0x0500); + + maestro_write(iobase, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + + for(i=0;i<64;i++) + { + for(w=0;w<0x0E;w++) + apu_set_register(iobase, i, w, 0); + } + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<14)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<13)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<12)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xFCFF); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xF3FF); + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase, 6, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0x00FF); + apu_set_register(iobase, 6, 3, 0x0000); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFF3F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)|(1<<5)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&~(1<<4)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFFF0); + apu_set_register(iobase, 6, 4, 0x4B5F); + apu_set_register(iobase, 6, 5, 0xFDD5); + apu_set_register(iobase, 6, 6, 0xFE00); + apu_set_register(iobase, 6, 7, 0x0100); + apu_set_register(iobase, 6, 8, 0x78FF); + apu_set_register(iobase, 6, 9, 0xFFFF); + apu_set_register(iobase, 6, 0xA,0x8A10); + apu_set_register(iobase, 6, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<14)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<13)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<12)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xFCFF); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xF3FF); + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase, 62, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0x00FF); + apu_set_register(iobase, 62, 3, 0x1000); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFF3F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<5)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<4)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFFF0); + apu_set_register(iobase, 62, 4, 0x7F00); + apu_set_register(iobase, 62, 5, 0x8000); + apu_set_register(iobase, 62, 6, 0x8080); + apu_set_register(iobase, 62, 7, 0x0080); + apu_set_register(iobase, 62, 8, 0x7F00); + apu_set_register(iobase, 62, 9, 0xFFFF); + apu_set_register(iobase, 62, 0xA,0x7F00); + apu_set_register(iobase, 62, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<14)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<13)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<12)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xFCFF); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xF3FF); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase, 63, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0x00FF); + apu_set_register(iobase, 63, 3, 0x1000); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFF3F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<5)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<4)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFFF0); + apu_set_register(iobase, 63, 4, 0x7F00); + apu_set_register(iobase, 63, 5, 0x0000); + apu_set_register(iobase, 63, 6, 0x0080); + apu_set_register(iobase, 63, 7, 0x0080); + apu_set_register(iobase, 63, 8, 0x7F00); + apu_set_register(iobase, 63, 9, 0xFFFF); + apu_set_register(iobase, 63, 0xA,0x7F10); + apu_set_register(iobase, 63, 0xB,0x00F0); + + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + + load_tables(iobase); + + outb(0x41, ESS_SETUP_A4+iobase); + udelay(1); + + printk(KERN_INFO "ess_pci: Programmed ESS Maestro at 0x%X to legacy mode.\n", + iobase); + +#if 0 + /* + * Test noise + */ + + for(i=0;i<16;i++) + apu_set_register(iobase, 0,i, 0x0000); + + outw(0x01FC, iobase+0x10); + outw(0x0000, iobase+0x12); + outw(0x0000, iobase+0x10); + outw(0x0000, iobase+0x12); + + apu_set_register(iobase, 0x00, 0x02,0xCD00); + apu_set_register(iobase, 0x00, 0x03,0x0039); + apu_set_register(iobase, 0x00, 0x06,0xFFFF); + apu_set_register(iobase, 0x00, 0x07,0xFFFF); + apu_set_register(iobase, 0x00, 0x09,0xD000); + apu_set_register(iobase, 0x00, 0x0A,0x8F00); + apu_set_register(iobase, 0x00, 0x0B,0x0000); + apu_set_register(iobase, 0x00, 0x00,0x000F); + + outw(inw(iobase+0x18)|0x04, iobase+0x18); + + apu_set_register(iobase, 0x00, 0x00,0x040F); + + printk("Playing"); + cli(); + + for(i=0;i<10;i++) + { + printk("."); + udelay(100000); + } + printk("\n"); + outw(inw(iobase+0x18)&~(1<<4), iobase+0x18); + apu_set_register(iobase, 0x00, 0x00, 0x0000); + + sti(); +#endif + maestro_cfg.dma = 1; + maestro_cfg.irq = pcidev->irq; + maestro_cfg.io_base = ESS_SBBASE; + maestro_cfg.dma2 = -1; + if(sb_dsp_detect(&maestro_cfg, SB_PCI_ESSMAESTRO, iobase)==-1) + { + printk(KERN_WARNING "esspci: Sound blaster emulation not responding.\n"); + } + attach_sb_card(&maestro_cfg); + return 1; +} + +/* + * For now this does one card only. It is written this way as it will change + */ + +int init_ess19xx(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + + if(!pci_present()) + return -ENODEV; + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + count+=maestro_install(pcidev); + if(count) + return 0; + } + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS19XX, pcidev))!=NULL) + { + count+=maestro_install(pcidev); + if(count) + return 0; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { + count+=maestro_install(pcidev); + if(count) + return 0; + } + + /* + * Clone vendors using ESS Maestro chipset. + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + count+=maestro_install(pcidev); + if(count) + return 0; + } + if(count==0) + return -ENODEV; + return 0; +} + + +int init_module(void) +{ + if(init_ess19xx()<0) + { + printk(KERN_ERR "No ESS Maestro cards found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + if(maestro_cfg.slots[0] != -1) + unload_sb(&maestro_cfg); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.h linux.ac/drivers/sound/maestro.h --- linux.vanilla/drivers/sound/maestro.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.h Fri Feb 19 18:11:03 1999 @@ -0,0 +1,60 @@ +/* + * Registers for the ESS PCI cards + */ + +/* + * Memory access + */ + +#define ESS_MEM_DATA 0x00 +#define ESS_MEM_INDEX 0x02 + +/* + * AC-97 Codec port. Delay 1uS after each write. This is used to + * talk AC-97 (see intel.com). Write data then register. + */ + +#define ESS_AC97_INDEX 0x30 /* byte wide */ +#define ESS_AC97_DATA 0x32 + +/* + * Reading is a bit different. You write register|0x80 to ubdex + * delay 1uS poll the low bit of index, when it clears read the + * data value. + */ + +/* + * Control port. Not yet fully understood + * The value 0xC090 gets loaded to it then 0x0000 and 0x2800 + * to the data port. Then after 4uS the value 0x300 is written + */ + +#define RING_BUS_CTRL_L 0x34 +#define RING_BUS_CTRL_H 0x36 + +/* + * This is also used during setup. The value 0x17 is written to it + */ + +#define ESS_SETUP_18 0x18 + +/* + * And this one gets 0x000b + */ + +#define ESS_SETUP_A2 0xA2 + +/* + * And this 0x0000 + */ + +#define ESS_SETUP_A4 0xA4 +#define ESS_SETUP_A6 0xA6 + +/* + * Stuff to do with Harpo - the wave stuff + */ + +#define ESS_WAVETABLE_SIZE 0x14 +#define ESS_WAVETABLE_2M 0xA180 + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro_tables.h linux.ac/drivers/sound/maestro_tables.h --- linux.vanilla/drivers/sound/maestro_tables.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro_tables.h Sun Feb 28 02:33:47 1999 @@ -0,0 +1,211 @@ +/* + * Set up data block for the ESS soundblaster emulation. This is like + * the example code from ftp.esstech.com.tw (104T31.ZIP) + */ + +u16 asp_block_0[]= { + 0x7980, 0x003a, 0x7980, 0x007d, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0x7980, 0x0be6, 0x7980, 0x0069, 0xbe3a, 0x8b00, 0x8048, 0x6945, + 0xb801, 0x9045, 0x6941, 0xe388, 0x0031, 0x6944, 0xba50, 0xe38c, + 0x0031, 0x8b88, 0x6942, 0x304a, 0xe308, 0x0028, 0x6949, 0x9042, + 0x0042, 0xafa0, 0x8000, 0xafa0, 0x8000, 0x8042, 0x6944, 0xb801, + 0x9044, 0x0048, 0xbe3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xbe41, 0xbf80, 0x0101, 0x8806, 0x8804, 0xb912, + 0x8807, 0xbc26, 0xbe40, 0xb92f, 0x9001, 0x9002, 0x003b, 0x0122, + 0x7a88, 0x0055, 0x003a, 0x013c, 0x7a88, 0x0055, 0x4902, 0xe100, + 0x0800, 0x0c02, 0xa000, 0x7980, 0x004e, 0xb908, 0x8809, 0xbec6, + 0x0067, 0x4a80, 0xe200, 0x0065, 0x4880, 0xe200, 0x0063, 0xb97f, + 0x6e80, 0x7980, 0x0066, 0x1089, 0x9088, 0xb900, 0x90a9, 0x8ba8, + 0xef00, 0x803d, 0x0003, 0x1007, 0x881f, 0x8b88, 0xbb0f, 0xada0, + 0x0810, 0x9003, 0x4903, 0xe200, 0x007b, 0x9002, 0x6a05, 0x6d04, + 0x9803, 0x9804, 0x9005, 0x003d, 0xbe3a, 0xaf06, 0x0000, 0x803d, + 0x8b88, 0x6906, 0x8810, 0xaf06, 0x0001, 0xbfb0, 0x00ff, 0xbaf5, + 0xe3cc, 0x009a, 0x5e06, 0x003f, 0xbf80, 0x0080, 0x4a06, 0xe200, + 0x0095, 0x6e80, 0x6d06, 0x7980, 0x009b, 0x9080, 0x0810, 0xba46, + 0x8810, 0x8b00, 0x1006, 0x9080, 0x003d, 0xbe3a, 0x1024, 0x2009, + 0x8810, 0x8b88, 0x8b00, 0x1089, 0xbfb0, 0x000e, 0xbe0a, 0x880d, + 0x903e, 0x1038, 0x2008, 0x8810, 0x1037, 0x2008, 0x8811, 0x5f3e, + 0x0000, 0x8b00, 0xf500, 0x5e80, 0xfffe, 0x1039, 0x2008, 0x8815, + 0x8b8d, 0x0231, 0x0333, 0x108a, 0x90ad, 0x1025, 0x200a, 0x8815, + 0x0605, 0xb91f, 0x8809, 0x4f16, 0x1080, 0xf600, 0xbfb0, + 0x0003, 0xbfb0, 0x0007, 0x9089, 0xbe47, 0xbe43, 0xbec6, + 0x00f6, 0x4f8b, 0x14a8, 0xe500, 0x6380, 0x8b89, 0x4e8a, + 0xbfe3, 0xe500, 0x2480, 0xbe46, 0x8b9d, 0xbfe7, 0xbfb0, + 0x00ff, 0x288c, 0x2026, 0x8814, 0xbe47, 0x8b00, 0x738f, + 0x54aa, 0xbe03, 0xbe0a, 0x2fa8, 0x988a, 0x8da9, 0xbe03, + 0x4d8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe03, + 0x4c8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe42, + 0x1039, 0x2008, 0x8815, 0x8b8d, 0x8b00, 0x8d8a, 0x7980, + 0x0bcf}; + +u16 asp_block_1[]={ + 0x0005, 0xb900, 0x9008, 0x9009, 0x900a, 0xbb3f, 0x90a0, + 0x001a, 0x011b, 0x021c, 0x0323, 0x1089, 0x9015, 0x108a, + 0x9016, 0x108b, 0x9017, 0x1088, 0x9018, 0x0137, 0x0524, + 0x8b8d, 0x4f16, 0xe200, 0x0827, 0x4f15, 0xe200, 0x0827, + 0x7a80, 0x08e6, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb900, + 0x90a0, 0x908d, 0x7980, 0x0833, 0x7a80, 0x0913, 0x7803, + 0x7a80, 0x0913, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb903, + 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 0x0845, 0x4e15, + 0xe200, 0x0845, 0x7a80, 0x08e6, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb901, 0x90a0, 0x908d, 0x7980, 0x0851, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb904, 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, + 0x0863, 0x4d15, 0xe200, 0x0863, 0x7a80, 0x08e6, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb902, 0x90a0, 0x908d, 0x7980, + 0x086f, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb905, 0x90a0, 0x908d, 0x7801, + 0x7a80, 0x0913, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x1024, 0xbf90, 0x0100, 0x8815, 0x4f16, 0xe200, + 0x088e, 0x4c15, 0xe200, 0x088e, 0x7a80, 0x08e6, 0x102c, + 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0100, 0x90a0, 0x908d, + 0x7980, 0x089b, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, + 0x102c, 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0103, 0x90a0, + 0x908d, 0x7c02, 0x4f16, 0xe200, 0x08ae, 0x4b15, 0xe200, + 0x08ae, 0x7a80, 0x08e6, 0x102c, 0xb818, 0x8813, 0x8b8b, + 0xbf80, 0x0101, 0x90a0, 0x908d, 0x7980, 0x08bb, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb818, 0x8813, + 0x8b8b, 0xbf80, 0x0104, 0x90a0, 0x908d, 0x7c02, 0x4f16, + 0xe200, 0x08ce, 0x4a15, 0xe200, 0x08ce, 0x7a80, 0x08e6, + 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0102, 0x90a0, + 0x908d, 0x7980, 0x08db, 0x7a80, 0x0913, 0x7803, 0x7a80, + 0x0913, 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0105, + 0x90a0, 0x908d, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x7801, 0x7a80, 0x0913, 0x7980, 0x0920, 0x4f80, + 0x7803, 0xe100, 0x08fe, 0x4f89, 0xe100, 0x08f5, 0xb901, + 0x90a0, 0xb902, 0x90a0, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb901, 0x90a0, 0xb906, 0x90a0, 0xb900, 0x90a0, 0xb906, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x090a, 0xb905, 0x90a0, + 0xb900, 0x90a0, 0xb902, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb905, 0x90a0, 0xb900, 0x90a0, 0xb906, 0x90a0, 0xb904, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x091b, 0xb901, 0x90a0, + 0xb906, 0x90ad, 0xef00, 0xb905, 0x90a0, 0xb904, 0x90ad, + 0xef00, 0xb91f, 0x8809, 0x0034, 0x8b88, 0xbec6, 0x0932, + 0x1313, 0xbe1e, 0x1014, 0xbe1a, 0xbe01, 0xbfe8, 0xbe17, + 0x6a13, 0x6214, 0xbe14, 0x9813, 0x9014, 0x98a0, 0xbe47, + 0x5f0f, 0x002e, 0xe200, 0x093d, 0xbf80, 0xffd2, 0x900f, + 0x7980, 0x0940, 0x100f, 0xb801, 0x900f, 0x400f, 0x8b00, + 0xe500, 0xbe01, 0xbe09, 0x9010, 0xbe46, 0x5f11, 0x003f, + 0xe200, 0x094f, 0xb900, 0x9011, 0x7980, 0x0952, 0x1011, + 0xb801, 0x9011, 0x1001, 0xe388, 0x0bcf, 0x1021, 0x2009, + 0x8813, 0x8b8b, 0x8b00, 0x1080, 0xbfe6, 0x7810, 0x8b00, + 0x8b00, 0x2180, 0xbfb0, 0x0007, 0x4c11, 0x8b00, 0xe100, + 0x096c, 0x4b11, 0x8b00, 0xe600, 0xb900, 0x7980, 0x096d, + 0xbe0a, 0x4a11, 0x8b00, 0xe500, 0xbe01, 0x9012, 0x1037, + 0x2008, 0x8811, 0x102e, 0x2008, 0x8812, 0x4a89, 0xb901, + 0xe500, 0x9019, 0xe100, 0x09c9, 0xb900, 0x9019, 0x4a18, + 0xe200, 0x09c9, 0x5f0a, 0x0010, 0xe200, 0x098d, 0x4b18, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0013, + 0xe200, 0x0997, 0x4b18, 0xb901, 0xe500, 0x9019, 0x7980, + 0x09c9, 0x5f0a, 0x0011, 0xe200, 0x09a4, 0x4f18, 0xb905, + 0xe500, 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, + 0x5f0a, 0x0014, 0xe200, 0x09b1, 0x4c18, 0xb904, 0xe500, + 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, + 0x0012, 0xe200, 0x09be, 0x4d18, 0xb905, 0xe500, 0x9080, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0015, + 0xe200, 0x09c9, 0x4e18, 0xb904, 0xe500, 0x9080, 0xb901, + 0xe500, 0x9019, 0x8b8a, 0x4f19, 0xe200, 0x09d4, 0x4b80, + 0xe200, 0x09d6, 0x5d80, 0x0020, 0x7980, 0x09d9, 0x5d80, + 0x0010, 0x4a80, 0xe200, 0x0bca, 0x1001, 0xba01, 0x9001, + 0x1024, 0x2009, 0x8815, 0x8b89, 0x4d8d, 0xe200, 0x09f8, + 0x4f16, 0xe100, 0x09ed, 0x8b89, 0x1080, 0xbfc0, 0x000c, + 0x908c, 0x7980, 0x09f8, 0x4b89, 0x108d, 0xf600, 0xbfb0, + 0x0003, 0x4a89, 0x8b00, 0xf500, 0xbfc0, 0x0008, 0x908c, + 0x1022, 0x2009, 0x8811, 0x102e, 0x2008, 0x8812, 0x102f, + 0x2008, 0x8813, 0x1020, 0x200a, 0x8814, 0x101d, 0x200a, + 0x8815, 0x8b8a, 0x4f19, 0xe100, 0x0a11, 0x5e80, 0x0020, + 0x5d80, 0x0018, 0x7980, 0x0a3e, 0x4f80, 0xe200, 0x0a1e, + 0x8b8b, 0x108a, 0xbfa0, 0x7fc0, 0x8b00, 0xf704, 0x5c80, + 0x0003, 0x7980, 0x0a3e, 0x4e80, 0xe200, 0x0a36, 0x8b8c, + 0x178b, 0xbe01, 0xbfb7, 0x00f0, 0x308a, 0xe344, 0x0a3e, + 0x8b8d, 0x4a8a, 0x8b00, 0xe200, 0x0a32, 0x5c80, 0x0006, + 0x7980, 0x0a3e, 0x5c80, 0x000a, 0x7980, 0x0a3e, 0x4c80, + 0xe200, 0x0a3e, 0x4b80, 0x8b00, 0xf500, 0x5c80, 0x0019, + 0x4f80, 0xe200, 0x0a4d, 0x101f, 0x200a, 0x8816, 0x8b00, + 0x8b00, 0x8b8e, 0x1780, 0xbfb7, 0x00f0, 0x900b, 0x7980, + 0x0a64, 0x4e80, 0xe200, 0x0a5c, 0x101f, 0x200a, 0x8816, + 0x8b00, 0x8b00, 0x8b8e, 0x1b80, 0xbfbb, 0x000f, 0x900b, + 0x7980, 0x0a64, 0x4c80, 0xe200, 0x0a64, 0x8b8c, 0x1b80, + 0xbfbb, 0x000f, 0x900b, 0x8b89, 0x1880, 0xbfb8, 0x001c, + 0x4917, 0xe100, 0x0a6e, 0x4f80, 0x7980, 0x0a70, 0x4e80, + 0x8b00, 0xf500, 0xbf98, 0x0002, 0x8b8d, 0x4b89, 0x8b00, + 0xe600, 0xbfe1, 0x903e, 0xbe43, 0x6a0b, 0x613e, 0xbfe8, + 0x980c, 0xbe42, 0x7c10, 0x1080, 0xbfe5, 0xbe1e, 0x7810, + 0x1280, 0xbfb2, 0x001f, 0xbe11, 0x2027, 0x8811, 0x101e, + 0x200a, 0x8816, 0x8b00, 0x128e, 0x4980, 0xe100, 0x0a9b, + 0x4880, 0xe100, 0x0a98, 0xb900, 0x7980, 0x0a9f, 0xbe0a, + 0x7980, 0x0a9f, 0x4880, 0xe200, 0x0a9f, 0xbe09, 0xbe1e, + 0x158d, 0xbfb5, 0x003f, 0xbe11, 0x4889, 0xe200, 0x0aae, + 0xbe1e, 0x1010, 0x4818, 0x8b00, 0xe600, 0xbfe1, 0xbe11, + 0xbfe1, 0x8811, 0xbe1e, 0xb9ff, 0x8819, 0x8b00, 0x8b00, + 0xbf46, 0x8b00, 0xe600, 0xbe1f, 0xbe01, 0xbfb0, 0x00ff, + 0x202a, 0x8811, 0x8b00, 0x8b00, 0x108a, 0x900d, 0xb91f, + 0x8809, 0x0732, 0x730d, 0x4f80, 0xe200, 0x0ad8, 0x1028, + 0x200c, 0x8815, 0xbe43, 0x8b8b, 0x6a8d, 0xbec6, 0x0ad4, + 0x618b, 0x9880, 0x548f, 0x8dad, 0xbe42, 0x7980, 0x0b24, + 0x4e80, 0xe200, 0x0af9, 0x8b8c, 0x178b, 0xbe01, 0xbfb7, + 0x00f0, 0x903e, 0x1029, 0x200c, 0x8815, 0x108d, 0xbec6, + 0x0af6, 0x308b, 0xbe1e, 0x303e, 0x903f, 0x403f, 0xbe1f, + 0xe500, 0x103e, 0x9080, 0xbfe6, 0x202a, 0x8811, 0x8b00, + 0x1089, 0x548f, 0x8dad, 0x7980, 0x0b24, 0x4c8b, 0xe200, + 0x0b1b, 0x1029, 0x200c, 0x8815, 0xbf80, 0x007f, 0x903e, + 0x108d, 0xbec6, 0x0b14, 0x308b, 0xbe1e, 0x303e, 0x903f, + 0x403f, 0xbe1f, 0xe500, 0xb900, 0x9080, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x1089, 0x548f, 0x8dad, 0x8b8a, 0xf500, + 0x5e80, 0xffdf, 0x7980, 0x0b24, 0x1089, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x8b00, 0x548f, 0xbb1f, 0x8da0, 0x8b8f, + 0x0732, 0x1021, 0x2009, 0x8811, 0x8b89, 0x101d, 0x200a, + 0x8812, 0x1080, 0x7810, 0x8b00, 0xbe47, 0x288a, 0xbfb0, + 0x03ff, 0x4989, 0xe200, 0x0b3e, 0xbe1e, 0x1012, 0x4918, + 0x8b00, 0xe600, 0xbe0a, 0xbe11, 0x900e, 0xbe46, 0x108a, + 0xbfb0, 0x001c, 0xbfe1, 0x880d, 0x8b00, 0x6b0e, 0xbe0a, + 0x880c, 0x108c, 0xbfb0, 0x000f, 0x202d, 0x8814, 0x8b00, + 0x8b00, 0x5589, 0xbf03, 0x8c0e, 0xbf00, 0x1030, 0x2008, + 0x8811, 0xb91f, 0x8809, 0x108b, 0x0333, 0xbec6, 0x0b5f, + 0x200e, 0x90a0, 0x8b00, 0x8b89, 0x9080, 0x4a18, 0xe200, + 0x0b7a, 0x5f0a, 0x0011, 0xe200, 0x0b6c, 0x4f18, 0xe900, + 0x0b7c, 0x5f0a, 0x0014, 0xe200, 0x0b73, 0x4c18, 0xe900, + 0x0b9b, 0x5f0a, 0x0015, 0xe200, 0x0b7a, 0x4e18, 0xe900, + 0x0bb2, 0x7980, 0x009e, 0x0034, 0xb91f, 0x8809, 0x0333, + 0x8b8b, 0xbec6, 0x0b99, 0x1280, 0x6c80, 0xbfea, 0xbe1e, + 0x1580, 0x6c88, 0xbfec, 0xbe13, 0x903e, 0x6cab, 0x903f, + 0x4f3e, 0xb900, 0xf500, 0xbf80, 0x8000, 0x4f3f, 0xbf90, + 0x0d00, 0xf500, 0xbf90, 0x2700, 0x90a0, 0xef00, 0x0034, + 0xb91f, 0x8809, 0x0333, 0x8b88, 0xbec6, 0x0bb0, 0x1eab, + 0x6c80, 0xbfed, 0x903e, 0x4180, 0xb900, 0xf500, 0xbf80, + 0x8000, 0x4f3e, 0x8b00, 0xf500, 0xbf90, 0x4000, 0x90a8, + 0xef00, 0x0034, 0xb91f, 0x8809, 0x0333, 0x8b8b, 0xbec6, + 0x0bc8, 0x1280, 0x6c8b, 0xbfea, 0xbe1e, 0x1580, 0x6c80, + 0xbfec, 0xbe13, 0x903e, 0x4f3e, 0xbf80, 0x4000, 0xf500, + 0xbf90, 0x8000, 0x90a0, 0xef00, 0x0231, 0x8b8a, 0xb900, + 0xbb20, 0x90a0, 0x5f08, 0x0023, 0xe100, 0x0043, 0x1008, + 0xb801, 0x9008, 0x102b, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x900a, 0x102c, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x9009, 0x7980, 0x0952, 0x8148, 0x6946, 0xb801, + 0x9046, 0xb901, 0x9041, 0x6944, 0xba08, 0xe344, 0x0bfe, + 0x9044, 0x8b89, 0x0143, 0x694b, 0x881f, 0xbb0f, 0xada0, + 0x8143, 0x0811, 0x304a, 0xe308, 0x0bfe, 0x6949, 0x9043, + 0x0148, 0xbe3a +}; + +u16 asp_block_2[]={ + 0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0002, 0x0005, 0x0005, + 0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, + 0x0100, 0x0100, 0x0103, 0x0103, 0x0101, 0x0101, + 0x0104, 0x0104, 0x0102, 0x0102, 0x0105, 0x0105, + 0x0106, 0x0106, 0x0107, 0x0107, 0x0108, 0x0108 +}; + +u16 asp_block_3[]={ + 0x0000, 0x0000, 0x0000, 0x1200, 0x1200, 0x1280, 0x0000, 0x05d0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1104, 0x1105, 0x1008, 0x1020, 0x1040, 0x1060, + 0x1080, 0x10a0, 0x10b0, 0x100d, 0x1010, 0x10e0, 0x2000, 0x2980, + 0x2b00, 0x2b40, 0x2a00, 0x2b90, 0x13dc, 0x2b80, 0x11bc, 0x134c, + 0x1370, 0x12e0, 0x1240, 0x1260, 0x12c0, 0x009e, 0x0045, 0x10bc, + 0x1394, 0x13b8, 0x11f6, 0x10f6, 0x11b0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0815, 0x0956, 0x09df, 0x0be5, 0x0a19, 0x0a48, 0x0b37, + 0x0b5d, 0x0a8b, 0x0aae, 0x0ad2 }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/pci_legacy.c linux.ac/drivers/sound/pci_legacy.c --- linux.vanilla/drivers/sound/pci_legacy.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/pci_legacy.c Fri Feb 26 20:52:20 1999 @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + +/* + * Legacy initialisation tables + */ + +struct pci_legacy +{ + int vendor; + int device; + char *description; + int (*install)(struct pci_dev *, struct pci_legacy *); + int flags; +}; + +#define MAX_CARDS 8 + +static struct address_info pci_cards[MAX_CARDS]; +static int card_count=0; + +static int find_space(int *array, int len) +{ + int i; + for(i=0;array[i]!=0;i++) + { + if(check_region(array[i],len)==0) + return i; + } + return -1; +} + +static int find_dma(int *array) +{ + int i; + for(i=0;array[i]!= -1;i++) + { + if(request_dma(array[i],"pci_legacy")==0) + { + free_dma(array[i]); + return i; + } + } + return -1; +} + +/* + * Setup the Yamaha cards. For now don't do the MPU401/OPL3 ports. + * Does anyone actually use the glorified doorbell mode on an SB ? + */ + +static int ymf_init(struct pci_dev *pci_dev, struct pci_legacy *pl) +{ + u16 r; + int slot; + int dma; + static int ymf_sb[]={0x220, 0x240, 0x260, 0x280, 0}; + static int ymf_dma[]={0,1,3, -1}; + struct address_info *card; + + if((slot=find_space(ymf_sb, 16))==-1) + { + printk(KERN_WARNING "%s: no free soundblaster addresses.\n", + pl->description); + return 0; + } + if((dma=find_dma(ymf_dma))==-1) + { + printk(KERN_WARNING "%s: no free DMA channels.\n", + pl->description); + return 0; + } + + printk(KERN_INFO "Found a %s. Due to lack of documentation this card will\n", + pl->description); + printk(KERN_INFO "be configured as an 8bit soundblaster.\n"); + switch(pl->flags) + { + case 0: + case 1: + pci_read_config_word(pci_dev, 0x42, &r); + /* Set the I/O */ + r&=~0xC0; + r|=(slot<<2); + /* Serialized IRQ crap off */ + r|=(1<<15); + pci_write_config_word(pci_dev, 0x42, r); + pci_read_config_word(pci_dev, 0x40, &r); + /* Set DMA */ + r&=~0x00C0; + r|=(ymf_dma[dma])<<6; + /* SB port only */ + r&=0xF; + r|=1; + /* SIRQ off, I/O on */ + r&=~(1<<14); + r&=~(1<<15); + pci_write_config_word(pci_dev, 0x40, r); + + printk(KERN_INFO "%s: set to I/O 0x%03X DMA %d.\n", + pl->description, + ymf_sb[slot], ymf_dma[dma]); + break; + } + + card=&pci_cards[card_count]; + + card->dma = ymf_dma[dma]; + card->irq = pci_dev->irq; + card->io_base = ymf_sb[slot]; + card->dma2 = -1; + + if(sb_dsp_detect(card, SB_PCI_YAMAHA, 0)==-1) + { + printk(KERN_WARNING "pci_legacy: Sound blaster emulation not responding.\n"); + return 0; + } + + attach_sb_card(card); + card_count++; + return 1; +} + +/* + * Important; Put the less flexible cards first so that they get + * the SB emulation slots they need. + */ + +struct pci_legacy pci_legacy_table[]={ + { 0x107C, 0x0003, "Yamaha YMF-740C", ymf_init, 0 }, + { 0x107C, 0x000D, "Yamaha YMF-724F", ymf_init, 1 }, + { 0, 0, NULL, 0, 0} +}; + + +int init_legacy_pci(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + struct pci_legacy *pt=&pci_legacy_table[0]; + + if(!pci_present()) + return -ENODEV; + + while(pt->vendor) + { + pcidev = NULL; + + while((pcidev = pci_find_device(pt->vendor, pt->device, pcidev))!=NULL) + { + count+=pt->install(pcidev, pt); + if(count >= MAX_CARDS) + return 0; + } + pt++; + } + + if(count==0) + return -ENODEV; + + printk(KERN_INFO "pci_legacy: %d unsupported PCI card%s placed in legacy 8bit mode.\n", + card_count, + card_count==1?"s":""); + return 0; +} + + +int init_module(void) +{ + if(init_legacy_pci()<0) + { + printk(KERN_ERR "No supported devices found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + int i; + for(i=0;i * */ @@ -1646,7 +1648,7 @@ spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1659,7 +1661,7 @@ spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.total_bytes >> s->dma_dac.fragshift; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -2271,7 +2273,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.10 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.11 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/waveartist.c linux.ac/drivers/sound/waveartist.c --- linux.vanilla/drivers/sound/waveartist.c Sat Jan 9 21:50:46 1999 +++ linux.ac/drivers/sound/waveartist.c Wed Mar 17 23:18:15 1999 @@ -5,6 +5,7 @@ * codec chip used in the Corel Computer NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + * Tweaked for X86 by Alan Cox */ /* @@ -40,12 +41,19 @@ #include #include +#ifdef CONFIG_ARCH_NETWINDER #include +#define IS_VNC +#endif #include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" +#ifndef NO_DMA +#define NO_DMA 255 +#endif + #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec #define MIXER_PRIVATE3_RESET 0x53570000 @@ -203,7 +211,7 @@ } while (timeout--); if (timeout == 0) { - printk("WaveArtist: reset timeout "); + printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); @@ -222,7 +230,7 @@ unsigned int i; if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); + printk(KERN_DEBUG "waveartist_cmd: cmd="); for (i = 0; i < nr_cmd; i++) printk("%04X ", cmd[i]); @@ -239,7 +247,7 @@ old_data = inw(io_base + CMDR); if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); + printk(KERN_DEBUG "flushed %04X...", old_data); udelay(10); } @@ -272,14 +280,14 @@ if (debug_flg & DEBUG_CMD) { if (!timed_out) { - printk("waveartist_cmd: resp="); + printk(KERN_DEBUG "waveartist_cmd: resp="); for (i = 0; i < nr_resp; i++) printk("%04X ", resp[i]); printk("\n"); } else - printk("waveartist_cmd: timed out\n"); + printk(KERN_WARNING "waveartist_cmd: timed out\n"); } return timed_out ? 1 : 0; @@ -317,7 +325,7 @@ int count; if (debug_flg & DEBUG_CMD) - printk("waveartist_sendcmd: cmd=0x%04X...", cmd); + printk(KERN_DEBUG "waveartist_sendcmd: cmd=0x%04X...", cmd); udelay(10); @@ -330,7 +338,7 @@ udelay(10); if (debug_flg & DEBUG_CMD) - printk(" flushed %04X...", count); + printk(KERN_DEBUG " flushed %04X...", count); } /* @@ -350,7 +358,7 @@ /* ready BEFORE timeout? */ if (debug_flg & DEBUG_CMD) - printk(" %s\n", count ? "Done OK." : "Error!"); + printk(KERN_DEBUG " %s\n", count ? "Done OK." : "Error!"); udelay(10); @@ -455,7 +463,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: output block, buf=0x%lx, count=0x%x...\n", buf, count); /* * 16 bit data @@ -501,7 +509,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: start input, buf=0x%lx, count=0x%x...\n", buf, count); if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ @@ -604,26 +612,26 @@ cli(); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk("waveartist: error setting record to %d channels\n", + printk(KERN_WARNING "waveartist: error setting record to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk("waveartist: error setting the record speed " + printk(KERN_WARNING "waveartist: error setting the record speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk("waveartist: error setting the record data path " + printk(KERN_WARNING "waveartist: error setting the record data path " "to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -631,9 +639,9 @@ waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -658,19 +666,19 @@ if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk("waveartist: error setting the playback speed " + printk(KERN_WARNING "waveartist: error setting the playback speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk("waveartist: error setting the playback to" + printk(KERN_WARNING "waveartist: error setting the playback to" " %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk("waveartist: error setting the playback data path " + printk(KERN_WARNING "waveartist: error setting the playback data path " "to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk("waveartist: error setting the playback format to %d\n", + printk(KERN_WARNING "waveartist: error setting the playback format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -678,9 +686,9 @@ waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -775,7 +783,7 @@ unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); + printk(KERN_DEBUG "wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) @@ -883,15 +891,14 @@ status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", + printk(KERN_DEBUG "waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else - printk("waveartist: unexpected interrupt\n"); + printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -906,12 +913,11 @@ temp = 0; } if (temp) //default: - printk("WaveArtist: Unknown interrupt\n"); + printk(KERN_WARNING "WaveArtist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... - printk("WaveArtist: Unexpected SB interrupt...\n"); + printk(KERN_WARNING "WaveArtist: Unexpected SB interrupt...\n"); } /* ------------------------------------------------------------------------- @@ -1032,7 +1038,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); vals[1] &= ~0x03F; //kill current left/right mux input select @@ -1106,7 +1112,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, + printk(KERN_DEBUG "RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); #else @@ -1127,7 +1133,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1], vals[2]); /* @@ -1197,7 +1203,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", + printk(KERN_DEBUG "RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", level, vals[1], vals[2]); #endif /* @@ -1220,7 +1226,7 @@ right = (level & 0x7f00) >> 8; if (debug_flg & DEBUG_MIXER) - printk("wa_mixer_set(dev=%d, level=%X)\n", + printk(KERN_DEBUG "wa_mixer_set(dev=%d, level=%X)\n", whichDev, level); switch (whichDev) { @@ -1321,7 +1327,7 @@ int i; if (debug_flg & DEBUG_MIXER) - printk("%s: mixer_reset\n", devc->hw.name); + printk(KERN_DEBUG "%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd @@ -1615,20 +1621,20 @@ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk("%s: IRQ %d in use\n", + printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk("%s: Can't allocate DMA%d\n", + printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk("%s: can't allocate DMA%d\n", + printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } @@ -1660,6 +1666,14 @@ return -1; } +#ifndef IS_VNC + +static void vnc_mute(wavnc_info *devc, int mute) +{ +} + +#else + /* * Corel Netwinder specifics... */ @@ -1793,31 +1807,34 @@ mod_timer(&vnc_timer, jiffies + next_timeout); } +#endif + int probe_waveartist(struct address_info *hw_config) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk("waveartist: too many audio devices\n"); + printk(KERN_ERR "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { - printk("WaveArtist: I/O port conflict\n"); + printk(KERN_ERR "WaveArtist: I/O port conflict\n"); return 0; } +#ifdef IS_NW if (hw_config->irq > 31 || hw_config->irq < 16) { - printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + printk(KERN_ERR "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { - printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + printk(KERN_ERR "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } - +#endif hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; @@ -1854,12 +1871,13 @@ if (devc->dev_no < 0) release_region(hw->io_base, 15); else { +#ifdef IS_VNC init_timer(&vnc_timer); vnc_timer.function = vnc_slider_tick; vnc_timer.expires = jiffies; vnc_timer.data = nr_waveartist_devs; add_timer(&vnc_timer); - +#endif nr_waveartist_devs += 1; vnc_mute(devc, 0); @@ -1909,7 +1927,7 @@ for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else - printk("waveartist: can't find device to unload\n"); + printk(KERN_ERR "waveartist: can't find device to unload\n"); } #ifdef MODULE @@ -1919,10 +1937,10 @@ MODULE_PARM(dma, "i"); /* DMA */ MODULE_PARM(dma2, "i"); /* DMA2 */ -int io = CONFIG_WAVEARTIST_BASE; -int irq = CONFIG_WAVEARTIST_IRQ; -int dma = CONFIG_WAVEARTIST_DMA; -int dma2 = CONFIG_WAVEARTIST_DMA2; +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = NO_DMA; static int attached; @@ -1930,6 +1948,11 @@ int init_module(void) { + if(io == -1 || irq == -1 || dma == -1) + { + printk(KERN_ERR "waveartist:io, irq and dma are mandatory.\n"); + return -EINVAL; + } hw_config.io_base = io; hw_config.irq = irq; hw_config.dma = dma; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/Config.in linux.ac/fs/Config.in --- linux.vanilla/fs/Config.in Wed Mar 10 21:13:09 1999 +++ linux.ac/fs/Config.in Wed Feb 24 17:09:22 1999 @@ -70,7 +70,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'NFS server support' CONFIG_NFSD fi - if [ "$CONFIG_NFSD" != "n" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFSD" != "n" ]; then bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN fi if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/Makefile linux.ac/fs/Makefile --- linux.vanilla/fs/Makefile Sun Nov 8 15:06:31 1998 +++ linux.ac/fs/Makefile Fri Dec 4 17:15:07 1998 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o inode.o attr.o bad_inode.o $(BINFMTS) + dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/adfs/inode.c linux.ac/fs/adfs/inode.c --- linux.vanilla/fs/adfs/inode.c Sun Nov 8 15:06:41 1998 +++ linux.ac/fs/adfs/inode.c Sun Jan 24 21:01:01 1999 @@ -27,7 +27,7 @@ #define inode_dirindex(idx) (((idx) & 0xff) * 26 - 21) #define frag_id(x) (((x) >> 8) & 0x7fff) -#define off(x) (((x) & 0xff) ? ((x) & 0xff) - 1 : 0) +#define off(x) (((x) & 0xff) ? (((x) & 0xff) - 1) << sb->u.adfs_sb.s_dr->log2sharesize : 0) static inline int adfs_inode_validate_no (struct super_block *sb, unsigned int inode_no) { @@ -83,11 +83,20 @@ return 0; } + if (block < 0) { + adfs_error(sb, "adfs_bmap", "block(%d) < 0", block); + return 0; + } + + if (block > inode->i_blocks) + return 0; + + block += off(inode->u.adfs_i.file_id); + if (frag_id(inode->u.adfs_i.file_id) == ADFS_ROOT_FRAG) - blk = sb->u.adfs_sb.s_map_block + off(inode_frag (inode->i_ino)) + block; + blk = sb->u.adfs_sb.s_map_block + block; else - blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id), - off (inode->u.adfs_i.file_id) + block); + blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id), block); return blk; } @@ -105,13 +114,13 @@ fragment = inode_frag (inode->i_ino); if (frag_id (fragment) == ADFS_ROOT_FRAG) - blk = sb->u.adfs_sb.s_map_block + off (fragment) + block; + blk = sb->u.adfs_sb.s_map_block + off(fragment) + block; else - blk = adfs_map_lookup (sb, frag_id (fragment), off (fragment) + block); + blk = adfs_map_lookup (sb, frag_id (fragment), off(fragment) + block); return blk; } -static int adfs_atts2mode (unsigned char mode, unsigned int filetype) +static int adfs_atts2mode(struct super_block *sb, unsigned char mode, unsigned int filetype) { int omode = 0; @@ -120,24 +129,29 @@ S_IRGRP|S_IWGRP|S_IXGRP| S_IROTH|S_IWOTH|S_IXOTH; } else { - if (mode & ADFS_NDA_DIRECTORY) - omode |= S_IFDIR|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH; - else + if (mode & ADFS_NDA_DIRECTORY) { + omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask; + omode |= S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH; + } else omode |= S_IFREG; + if (mode & ADFS_NDA_OWNER_READ) { - omode |= S_IRUSR; + omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask; if (filetype == 0xfe6 /* UnixExec */) - omode |= S_IXUSR; + omode |= S_IXUGO & sb->u.adfs_sb.s_owner_mask; } + if (mode & ADFS_NDA_OWNER_WRITE) - omode |= S_IWUSR; + omode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask; + if (mode & ADFS_NDA_PUBLIC_READ) { - omode |= S_IRGRP | S_IROTH; - if (filetype == 0xfe6) - omode |= S_IXGRP | S_IXOTH; + omode |= S_IRUGO & sb->u.adfs_sb.s_other_mask; + if (filetype == 0xfe6 /* UnixExec */) + omode |= S_IXUGO & sb->u.adfs_sb.s_other_mask; } + if (mode & ADFS_NDA_PUBLIC_WRITE) - omode |= S_IWGRP | S_IWOTH; + omode |= S_IWUGO & sb->u.adfs_sb.s_other_mask; } return omode; } @@ -150,8 +164,8 @@ int buffers; sb = inode->i_sb; - inode->i_uid = 0; - inode->i_gid = 0; + inode->i_uid = sb->u.adfs_sb.s_uid; + inode->i_gid = sb->u.adfs_sb.s_gid; inode->i_version = ++event; if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) { @@ -186,7 +200,7 @@ goto bad; } adfs_dir_free (bh, buffers); - inode->i_mode = adfs_atts2mode (ide.mode, ide.filetype); + inode->i_mode = adfs_atts2mode(sb, ide.mode, ide.filetype); inode->i_nlink = 2; inode->i_size = ide.size; inode->i_blksize = PAGE_SIZE; @@ -204,13 +218,5 @@ return; bad: - inode->i_mode = 0; - inode->i_nlink = 1; - inode->i_size = 0; - inode->i_blksize = 0; - inode->i_blocks = 0; - inode->i_mtime = - inode->i_atime = - inode->i_ctime = 0; - inode->i_op = NULL; + make_bad_inode(inode); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/adfs/super.c linux.ac/fs/adfs/super.c --- linux.vanilla/fs/adfs/super.c Sun Nov 8 15:06:41 1998 +++ linux.ac/fs/adfs/super.c Sun Jan 24 21:01:01 1999 @@ -21,25 +21,26 @@ #include -static void adfs_put_super (struct super_block *sb); -static int adfs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz); -void adfs_read_inode (struct inode *inode); +static void adfs_put_super(struct super_block *sb); +static int adfs_remount(struct super_block *sb, int *flags, char *data); +static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +void adfs_read_inode(struct inode *inode); -void adfs_error (struct super_block *sb, const char *function, const char *fmt, ...) +void adfs_error(struct super_block *sb, const char *function, const char *fmt, ...) { char error_buf[128]; va_list args; - va_start (args, fmt); - vsprintf (error_buf, fmt, args); - va_end (args); + va_start(args, fmt); + vsprintf(error_buf, fmt, args); + va_end(args); - printk (KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n", - kdevname (sb->s_dev), function ? ": " : "", + printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n", + kdevname(sb->s_dev), function ? ": " : "", function ? function : "", error_buf); } -unsigned char adfs_calccrosscheck (struct super_block *sb, char *map) +static unsigned char adfs_calczonecheck(struct super_block *sb, char *map) { unsigned int v0, v1, v2, v3; int i; @@ -63,7 +64,7 @@ return v0 ^ v1 ^ v2 ^ v3; } -static int adfs_checkmap (struct super_block *sb) +static int adfs_checkmap(struct super_block *sb) { unsigned char crosscheck = 0, zonecheck = 1; int i; @@ -72,14 +73,14 @@ char *map; map = sb->u.adfs_sb.s_map[i]->b_data; - if (adfs_calccrosscheck (sb, map) != map[0]) { - adfs_error (sb, "adfs_checkmap", "zone %d fails zonecheck", i); + if (adfs_calczonecheck(sb, map) != map[0]) { + adfs_error(sb, "adfs_checkmap", "zone %d fails zonecheck", i); zonecheck = 0; } crosscheck ^= map[3]; } if (crosscheck != 0xff) - adfs_error (sb, "adfs_checkmap", "crosscheck != 0xff"); + adfs_error(sb, "adfs_checkmap", "crosscheck != 0xff"); return crosscheck == 0xff && zonecheck; } @@ -92,21 +93,73 @@ adfs_put_super, NULL, adfs_statfs, - NULL + adfs_remount }; -static void adfs_put_super (struct super_block *sb) +static void adfs_put_super(struct super_block *sb) { int i; for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) - brelse (sb->u.adfs_sb.s_map[i]); - kfree (sb->u.adfs_sb.s_map); - brelse (sb->u.adfs_sb.s_sbh); + brelse(sb->u.adfs_sb.s_map[i]); + kfree(sb->u.adfs_sb.s_map); + brelse(sb->u.adfs_sb.s_sbh); MOD_DEC_USE_COUNT; } -struct super_block *adfs_read_super (struct super_block *sb, void *data, int silent) +static int parse_options(struct super_block *sb, char *options) +{ + char *value, *opt; + + if (!options) + return 0; + + for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) { + value = strchr(opt, '='); + if (value) + *value++ = '\0'; + + if (!strcmp(opt, "uid")) { /* owner of all files */ + if (!value || !*value) + return -EINVAL; + sb->u.adfs_sb.s_uid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } else + if (!strcmp(opt, "gid")) { /* group owner of all files */ + if (!value || !*value) + return -EINVAL; + sb->u.adfs_sb.s_gid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } else + if (!strcmp(opt, "ownmask")) { /* owner permission mask */ + if (!value || !*value) + return -EINVAL; + sb->u.adfs_sb.s_owner_mask = simple_strtoul(value, &value, 8); + if (*value) + return -EINVAL; + } else + if (!strcmp(opt, "othmask")) { /* others permission mask */ + if (!value || !*value) + return -EINVAL; + sb->u.adfs_sb.s_other_mask = simple_strtoul(value, &value, 8); + if (*value) + return -EINVAL; + } else { /* eh? say again. */ + printk("ADFS-fs: unrecognised mount option %s\n", opt); + return -EINVAL; + } + } + return 0; +} + +static int adfs_remount(struct super_block *sb, int *flags, char *data) +{ + return parse_options(sb, data); +} + +struct super_block *adfs_read_super(struct super_block *sb, void *data, int silent) { struct adfs_discrecord *dr; struct buffer_head *bh; @@ -114,28 +167,30 @@ kdev_t dev = sb->s_dev; int i, j; + /* set default options */ + sb->u.adfs_sb.s_uid = 0; + sb->u.adfs_sb.s_gid = 0; + sb->u.adfs_sb.s_owner_mask = S_IRWXU; + sb->u.adfs_sb.s_other_mask = S_IRWXG | S_IRWXO; + + if (parse_options(sb, data)) + goto error; + MOD_INC_USE_COUNT; - lock_super (sb); - set_blocksize (dev, BLOCK_SIZE); - if (!(bh = bread (dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) { - unlock_super (sb); - adfs_error (sb, NULL, "unable to read superblock"); - MOD_DEC_USE_COUNT; - return NULL; + lock_super(sb); + set_blocksize(dev, BLOCK_SIZE); + if (!(bh = bread(dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) { + adfs_error(sb, NULL, "unable to read superblock"); + goto error_unlock; } b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE); - if (adfs_checkbblk (b_data)) { + if (adfs_checkbblk(b_data)) { if (!silent) - printk ("VFS: Can't find an adfs filesystem on dev " + printk("VFS: Can't find an adfs filesystem on dev " "%s.\n", kdevname(dev)); -failed_mount: - unlock_super (sb); - if (bh) - brelse (bh); - MOD_DEC_USE_COUNT; - return NULL; + goto error_free_bh; } dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET); @@ -145,26 +200,26 @@ (sb->s_blocksize == 512 || sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) { - brelse (bh); - set_blocksize (dev, sb->s_blocksize); - bh = bread (dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize); + brelse(bh); + set_blocksize(dev, sb->s_blocksize); + bh = bread(dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize); if (!bh) { - adfs_error (sb, NULL, "couldn't read superblock on " + adfs_error(sb, NULL, "couldn't read superblock on " "2nd try."); - goto failed_mount; + goto error_unlock; } b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize); - if (adfs_checkbblk (b_data)) { - adfs_error (sb, NULL, "disc record mismatch, very weird!"); - goto failed_mount; + if (adfs_checkbblk(b_data)) { + adfs_error(sb, NULL, "disc record mismatch, very weird!"); + goto error_free_bh; } dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET); } if (sb->s_blocksize != bh->b_size) { if (!silent) - printk (KERN_ERR "VFS: Unsupported blocksize on dev " - "%s.\n", kdevname (dev)); - goto failed_mount; + printk(KERN_ERR "VFS: Unsupported blocksize on dev " + "%s.\n", kdevname(dev)); + goto error_free_bh; } /* blocksize on this device should now be set to the adfs log2secsize */ @@ -202,71 +257,81 @@ else sb->u.adfs_sb.s_map_block >>= -sb->u.adfs_sb.s_map2blk; - printk (KERN_DEBUG "ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n", + printk(KERN_DEBUG "ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n", sb->u.adfs_sb.s_zone_size, sb->u.adfs_sb.s_ids_per_zone, sb->u.adfs_sb.s_map_block, sb->u.adfs_sb.s_map_size); - printk (KERN_DEBUG "ADFS: sector size %d, map bit size %d\n", - 1 << dr->log2secsize, 1 << dr->log2bpmb); + printk(KERN_DEBUG "ADFS: sector size %d, map bit size %d, share size %d\n", + 1 << dr->log2secsize, 1 << dr->log2bpmb, + 1 << (dr->log2secsize + dr->log2sharesize)); sb->s_magic = ADFS_SUPER_MAGIC; - sb->s_flags |= MS_RDONLY; /* we don't support writing yet */ - sb->u.adfs_sb.s_map = kmalloc (sb->u.adfs_sb.s_map_size * - sizeof (struct buffer_head *), GFP_KERNEL); + sb->u.adfs_sb.s_map = kmalloc(sb->u.adfs_sb.s_map_size * + sizeof(struct buffer_head *), GFP_KERNEL); if (sb->u.adfs_sb.s_map == NULL) { - adfs_error (sb, NULL, "not enough memory"); - goto failed_mount; + adfs_error(sb, NULL, "not enough memory"); + goto error_free_bh; } for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) { - sb->u.adfs_sb.s_map[i] = bread (dev, + sb->u.adfs_sb.s_map[i] = bread(dev, sb->u.adfs_sb.s_map_block + i, sb->s_blocksize); if (!sb->u.adfs_sb.s_map[i]) { for (j = 0; j < i; j++) - brelse (sb->u.adfs_sb.s_map[j]); - kfree (sb->u.adfs_sb.s_map); - adfs_error (sb, NULL, "unable to read map"); - goto failed_mount; + brelse(sb->u.adfs_sb.s_map[j]); + kfree(sb->u.adfs_sb.s_map); + adfs_error(sb, NULL, "unable to read map"); + goto error_free_bh; } } - if (!adfs_checkmap (sb)) { + if (!adfs_checkmap(sb)) { for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) - brelse (sb->u.adfs_sb.s_map[i]); - adfs_error (sb, NULL, "map corrupted"); - goto failed_mount; + brelse(sb->u.adfs_sb.s_map[i]); + adfs_error(sb, NULL, "map corrupted"); + goto error_free_bh; } dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0]->b_data + 4); - unlock_super (sb); + unlock_super(sb); /* * set up enough so that it can read an inode */ sb->s_op = &adfs_sops; - sb->u.adfs_sb.s_root = adfs_inode_generate (dr->root, 0); + sb->u.adfs_sb.s_root = adfs_inode_generate(dr->root, 0); sb->s_root = d_alloc_root(iget(sb, sb->u.adfs_sb.s_root), NULL); if (!sb->s_root) { - sb->s_dev = 0; for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) - brelse (sb->u.adfs_sb.s_map[i]); - brelse (bh); - adfs_error (sb, NULL, "get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; + brelse(sb->u.adfs_sb.s_map[i]); + brelse(bh); + adfs_error(sb, NULL, "get root inode failed\n"); + goto error_dec_use; } return sb; + +error_free_bh: + if (bh) + brelse(bh); +error_unlock: + unlock_super(sb); +error_dec_use: + MOD_DEC_USE_COUNT; +error: + sb->s_dev = 0; + return NULL; } -static int adfs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) +static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { struct statfs tmp; const unsigned int nidlen = sb->u.adfs_sb.s_idlen + 1; tmp.f_type = ADFS_SUPER_MAGIC; tmp.f_bsize = sb->s_blocksize; - tmp.f_blocks = (sb->u.adfs_sb.s_dr->disc_size) >> (sb->s_blocksize_bits); + tmp.f_blocks = sb->u.adfs_sb.s_dr->disc_size_high << (32 - sb->s_blocksize_bits) | + sb->u.adfs_sb.s_dr->disc_size >> sb->s_blocksize_bits; tmp.f_files = tmp.f_blocks >> nidlen; { unsigned int i, j = 0; @@ -305,35 +370,35 @@ if (freelink <= nidlen) break; } while (mapindex < 8 * sb->s_blocksize); if (mapindex > 8 * sb->s_blocksize) - adfs_error (sb, NULL, "oversized free fragment\n"); + adfs_error(sb, NULL, "oversized free fragment\n"); else if (freelink) - adfs_error (sb, NULL, "undersized free fragment\n"); + adfs_error(sb, NULL, "undersized free fragment\n"); } tmp.f_bfree = tmp.f_bavail = j << (sb->u.adfs_sb.s_dr->log2bpmb - sb->s_blocksize_bits); } tmp.f_ffree = tmp.f_bfree >> nidlen; tmp.f_namelen = ADFS_NAME_LEN; - return copy_to_user (buf, &tmp, bufsiz) ? -EFAULT : 0; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } static struct file_system_type adfs_fs_type = { "adfs", FS_REQUIRES_DEV, adfs_read_super, NULL }; -__initfunc(int init_adfs_fs (void)) +__initfunc(int init_adfs_fs(void)) { - return register_filesystem (&adfs_fs_type); + return register_filesystem(&adfs_fs_type); } #ifdef MODULE -int init_module (void) +int init_module(void) { return init_adfs_fs(); } -void cleanup_module (void) +void cleanup_module(void) { - unregister_filesystem (&adfs_fs_type); + unregister_filesystem(&adfs_fs_type); } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/attr.c linux.ac/fs/attr.c --- linux.vanilla/fs/attr.c Thu Nov 19 18:38:45 1998 +++ linux.ac/fs/attr.c Tue Feb 16 18:04:49 1999 @@ -28,10 +28,10 @@ goto error; /* Make sure caller can chgrp. */ - if ((ia_valid & ATTR_GID) && - (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && - !capable(CAP_CHOWN)) - goto error; + if ((ia_valid & ATTR_GID) && (attr->ia_gid != inode->i_gid) && + ((current->fsuid != inode->i_uid) || !in_group_p(attr->ia_gid)) && + !capable(CAP_CHOWN)) + goto error; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/buffer.c linux.ac/fs/buffer.c --- linux.vanilla/fs/buffer.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/buffer.c Wed Mar 24 18:06:04 1999 @@ -854,6 +854,7 @@ return; } remove_from_queues(buf); + buf->b_count = 0; put_last_free(buf); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/exec.c linux.ac/fs/exec.c --- linux.vanilla/fs/exec.c Tue Jan 19 02:57:34 1999 +++ linux.ac/fs/exec.c Tue Jan 19 03:11:17 1999 @@ -479,10 +479,10 @@ unsigned long set, i; i = j * __NFDBITS; - if (i >= files->max_fds) + if (i >= files->max_fds || i >= files->max_fdset) break; - set = files->close_on_exec.fds_bits[j]; - files->close_on_exec.fds_bits[j] = 0; + set = files->close_on_exec->fds_bits[j]; + files->close_on_exec->fds_bits[j] = 0; j++; for ( ; set ; i++,set >>= 1) { if (set & 1) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/fsync.c linux.ac/fs/ext2/fsync.c --- linux.vanilla/fs/ext2/fsync.c Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/ext2/fsync.c Thu Feb 4 18:01:28 1999 @@ -250,24 +250,14 @@ return err; } -/* - * File may be NULL when we are called. Perhaps we shouldn't - * even pass file to fsync ? - */ - -int ext2_sync_file(struct file * file, struct dentry *dentry) +static int sync_inode(struct inode *inode) { int wait, err = 0; - struct inode *inode = dentry->d_inode; - + if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) - /* - * Don't sync fast links! - */ - goto skip; + return 0; - for (wait=0; wait<=1; wait++) - { + for (wait=0; wait<=1; wait++) { err |= sync_direct (inode, wait); err |= sync_indirect (inode, inode->u.ext2_i.i_data+EXT2_IND_BLOCK, @@ -279,7 +269,23 @@ inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, wait); } -skip: err |= ext2_sync_inode (inode); + return err; +} + +/* + * File may be NULL when we are called by msync on a vma. In the + * future, the VFS layer should be changed to not pass the struct file + * parameter to the fsync function, since it's not used by any of the + * implementations (and the dentry parameter is all that we need). + */ +int ext2_sync_file(struct file * file, struct dentry *dentry) +{ + int err = 0; + + err = sync_inode(dentry->d_inode); + if (dentry->d_parent && dentry->d_parent->d_inode) + err |= sync_inode(dentry->d_parent->d_inode); + return err ? -EIO : 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/ialloc.c linux.ac/fs/ext2/ialloc.c --- linux.vanilla/fs/ext2/ialloc.c Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/ext2/ialloc.c Wed Mar 24 18:01:38 1999 @@ -268,21 +268,6 @@ } /* - * This function increments the inode version number - * - * This may be used one day by the NFS server - */ -static void inc_inode_version (struct inode * inode, - struct ext2_group_desc *gdp, - int mode) -{ - inode->u.ext2_i.i_version++; - mark_inode_dirty(inode); - - return; -} - -/* * There are two policies for allocating an inode. If the new inode is * a directory, then a forward search is made for a block group with both * free space and a low directory-to-inode ratio; if that fails, then of @@ -493,8 +478,9 @@ if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) inode->i_flags |= MS_SYNCHRONOUS; insert_inode_hash(inode); + inode->i_generation = inode_generation_count++; + inode->u.ext2_i.i_version = inode->i_generation; mark_inode_dirty(inode); - inc_inode_version (inode, gdp, mode); unlock_super (sb); if(DQUOT_ALLOC_INODE(sb, inode)) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/inode.c linux.ac/fs/ext2/inode.c --- linux.vanilla/fs/ext2/inode.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/ext2/inode.c Wed Mar 24 18:01:39 1999 @@ -51,6 +51,10 @@ inode->i_ino == EXT2_ACL_DATA_INO) return; inode->u.ext2_i.i_dtime = CURRENT_TIME; + /* When we delete an inode, we increment its i_version. If it + is ever read in from disk again, it will have a different + i_version. */ + inode->u.ext2_i.i_version++; mark_inode_dirty(inode); ext2_update_inode(inode, IS_SYNC(inode)); inode->i_size = 0; @@ -553,6 +557,7 @@ #endif } inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version); + inode->i_generation = inode->u.ext2_i.i_version; inode->u.ext2_i.i_block_group = block_group; inode->u.ext2_i.i_next_alloc_block = 0; inode->u.ext2_i.i_next_alloc_goal = 0; @@ -722,10 +727,11 @@ unsigned int flags; retval = -EPERM; - if ((iattr->ia_attr_flags & - (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^ - (inode->u.ext2_i.i_flags & - (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { + if (iattr->ia_valid & ATTR_ATTR_FLAG && + ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) != + !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) || + (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) != + !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) { if (!capable(CAP_LINUX_IMMUTABLE)) goto out; } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/ioctl.c linux.ac/fs/ext2/ioctl.c --- linux.vanilla/fs/ext2/ioctl.c Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/ext2/ioctl.c Wed Mar 24 18:01:39 1999 @@ -77,6 +77,7 @@ return -EROFS; if (get_user(inode->u.ext2_i.i_version, (int *) arg)) return -EFAULT; + inode->i_generation = inode->u.ext2_i.i_version; inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/fcntl.c linux.ac/fs/fcntl.c --- linux.vanilla/fs/fcntl.c Thu Nov 19 18:38:46 1998 +++ linux.ac/fs/fcntl.c Fri Dec 4 17:15:07 1998 @@ -12,14 +12,15 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); -static inline int dupfd(unsigned int fd, unsigned int arg) +static inline int dupfd(unsigned int fd, unsigned int start) { struct files_struct * files = current->files; struct file * file; + unsigned int newfd; int error; error = -EINVAL; - if (arg >= NR_OPEN) + if (start >= NR_OPEN) goto out; error = -EBADF; @@ -27,15 +28,39 @@ if (!file) goto out; +repeat: error = -EMFILE; - arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); - if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) + if (start < files->next_fd) + start = files->next_fd; + /* At this point, start MUST be <= max_fdset */ +#if 1 + if (start > files->max_fdset) + printk (KERN_ERR "dupfd: fd %d, max %d\n", + start, files->max_fdset); +#endif + newfd = find_next_zero_bit(files->open_fds->fds_bits, + files->max_fdset, + start); + if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out_putf; - FD_SET(arg, &files->open_fds); - FD_CLR(arg, &files->close_on_exec); - fd_install(arg, file); - error = arg; + + error = expand_files(files, newfd); + if (error < 0) + goto out_putf; + if (error) /* If we might have blocked, try again. */ + goto repeat; + + FD_SET(newfd, files->open_fds); + FD_CLR(newfd, files->close_on_exec); + if (start <= files->next_fd) + files->next_fd = newfd + 1; + fd_install(newfd, file); + error = newfd; out: +#ifdef FDSET_DEBUG + if (error < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", error); +#endif return error; out_putf: @@ -48,18 +73,30 @@ int err = -EBADF; lock_kernel(); +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " 0: oldfd = %d, newfd = %d\n", + oldfd, newfd); +#endif if (!fcheck(oldfd)) goto out; + if (newfd >= NR_OPEN) + goto out; /* following POSIX.1 6.2.1 */ + err = newfd; if (newfd == oldfd) goto out; - err = -EBADF; - if (newfd >= NR_OPEN) - goto out; /* following POSIX.1 6.2.1 */ + /* We must be able to do the fd setting inside dupfd() without + blocking after the sys_close(). */ + if ((err = expand_files(current->files, newfd)) < 0) + goto out; + sys_close(newfd); err = dupfd(oldfd, newfd); out: +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ ": return %d\n", err); +#endif unlock_kernel(); return err; } @@ -71,6 +108,10 @@ lock_kernel(); ret = dupfd(fildes, 0); unlock_kernel(); +#ifdef FDSET_DEBUG + if (ret < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", ret); +#endif return ret; } @@ -111,19 +152,20 @@ filp = fget(fd); if (!filp) goto out; + err = 0; switch (cmd) { case F_DUPFD: err = dupfd(fd, arg); break; case F_GETFD: - err = FD_ISSET(fd, ¤t->files->close_on_exec); + err = FD_ISSET(fd, current->files->close_on_exec); break; case F_SETFD: if (arg&1) - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); else - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case F_GETFL: err = filp->f_flags; @@ -151,7 +193,6 @@ err = filp->f_owner.pid; break; case F_SETOWN: - err = 0; filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; @@ -171,10 +212,9 @@ break; default: /* sockets need a few special fcntls. */ + err = -EINVAL; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, cmd, arg); - else - err = -EINVAL; break; } fput(filp); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/file.c linux.ac/fs/file.c --- linux.vanilla/fs/file.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/file.c Fri Dec 4 17:15:07 1998 @@ -0,0 +1,224 @@ +/* + * linux/fs/open.c + * + * Copyright (C) 1998, Stephen Tweedie and Bill Hawes + * + * Manage the dynamic fd arrays in the process files_struct. + */ + +#include +#include +#include +#include +#include + +#include + + +/* + * Allocate an fd array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +struct file ** alloc_fd_array(int num) +{ + struct file **new_fds; + int size = num * sizeof(struct file *); + + if (size < PAGE_SIZE) + new_fds = (struct file **) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fds = (struct file **) __get_free_page(GFP_KERNEL); + else + new_fds = (struct file **) vmalloc(size); + return new_fds; +} + +void free_fd_array(struct file **array, int num) +{ + int size = num * sizeof(struct file *); + + if (!array) { + printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num); + return; + } + + if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */ + return; + else if (size < PAGE_SIZE) + kfree(array); + else if (size == PAGE_SIZE) + free_page((unsigned long) array); + else + vfree(array); +} + +/* + * Expand the fd array in the files_struct. + */ + +int expand_fd_array(struct files_struct *files, int nr) +{ + struct file **new_fds; + int error, nfds; + + + error = -EMFILE; + if (files->max_fds >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fds; + + /* + * Expand to the max in easy steps, and keep expanding it until + * we have enough for the requested fd array size. + */ + + do { +#if NR_OPEN_DEFAULT < 256 + if (nfds < 256) + nfds = 256; + else +#endif + if (nfds < (PAGE_SIZE / sizeof(struct file *))) + nfds = PAGE_SIZE / sizeof(struct file *); + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_fds = alloc_fd_array(nfds); + if (!new_fds) + goto out; + + /* Copy the existing array and install the new pointer */ + + if (nfds > files->max_fds) { + struct file **old_fds; + int i = files->max_fds; + + old_fds = files->fd; + files->fd = new_fds; + files->max_fds = nfds; + /* Don't copy/clear the array if we are creating a new + fd array for fork() */ + if (i) { + memcpy(new_fds, old_fds, i * sizeof(struct file *)); + /* clear the remainder of the array */ + memset(&new_fds[i], 0, + (nfds-i) * sizeof(struct file *)); + free_fd_array(old_fds, i); + } + } else { + /* Somebody expanded the array while we slept ... */ + free_fd_array(new_fds, nfds); + } + error = 0; +out: + return error; +} + +/* + * Allocate an fdset array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +fd_set * alloc_fdset(int num) +{ + fd_set *new_fdset; + int size = num / 8; + + if (size < PAGE_SIZE) + new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fdset = (fd_set *) __get_free_page(GFP_KERNEL); + else + new_fdset = (fd_set *) vmalloc(size); + return new_fdset; +} + +void free_fdset(fd_set *array, int num) +{ + int size = num / 8; + + if (!array) { + printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num); + return; + } + + if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */ + return; + else if (size < PAGE_SIZE) + kfree(array); + else if (size == PAGE_SIZE) + free_page((unsigned long) array); + else + vfree(array); +} + +/* + * Expand the fdset in the files_struct. + */ +int expand_fdset(struct files_struct *files, int nr) +{ + fd_set *new_openset = 0, *new_execset = 0; + int error, nfds = 0; + + error = -EMFILE; + if (files->max_fdset >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fdset; + /* Expand to the max in easy steps */ + do { + if (nfds < (PAGE_SIZE * 8)) + nfds = PAGE_SIZE * 8; + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_openset = alloc_fdset(nfds); + new_execset = alloc_fdset(nfds); + if (!new_openset || !new_execset) + goto out; + + error = 0; + + /* Copy the existing tables and install the new pointers */ + if (nfds > files->max_fdset) { + int i = files->max_fdset / (sizeof(unsigned long) * 8); + int count = (nfds - files->max_fdset) / 8; + + /* + * Don't copy the entire array if the current fdset is + * not yet initialised. + */ + if (i) { + memcpy (new_openset, files->open_fds, files->max_fdset/8); + memcpy (new_execset, files->close_on_exec, files->max_fdset/8); + memset (&new_openset->fds_bits[i], 0, count); + memset (&new_execset->fds_bits[i], 0, count); + } + + free_fdset (files->close_on_exec, files->max_fdset); + free_fdset (files->open_fds, files->max_fdset); + files->max_fdset = nfds; + files->open_fds = new_openset; + files->close_on_exec = new_execset; + return 0; + } + /* Somebody expanded the array while we slept ... */ + +out: + if (new_openset) + free_fdset(new_openset, nfds); + if (new_execset) + free_fdset(new_execset, nfds); + return error; +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/inode.c linux.ac/fs/inode.c --- linux.vanilla/fs/inode.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/inode.c Wed Mar 24 18:01:39 1999 @@ -48,6 +48,8 @@ static LIST_HEAD(inode_unused); static struct list_head inode_hashtable[HASH_SIZE]; +__u32 inode_generation_count = 0; + /* * A simple spinlock to protect the list manipulations. * @@ -778,6 +780,10 @@ if (max > MAX_INODE) max = MAX_INODE; max_inodes = max; + + /* Get a random number. */ + get_random_bytes (&inode_generation_count, + sizeof (inode_generation_count)); } /* This belongs in file_table.c, not here... */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ioctl.c linux.ac/fs/ioctl.c --- linux.vanilla/fs/ioctl.c Thu Nov 19 18:38:46 1998 +++ linux.ac/fs/ioctl.c Thu Mar 11 12:22:49 1999 @@ -52,11 +52,11 @@ error = 0; switch (cmd) { case FIOCLEX: - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); break; case FIONCLEX: - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case FIONBIO: @@ -74,14 +74,20 @@ filp->f_flags &= ~flag; break; - case FIOASYNC: /* O_SYNC is not yet implemented, - but it's here for completeness. */ + case FIOASYNC: if ((error = get_user(on, (int *)arg)) != 0) break; + flag = on ? FASYNC : 0; + + /* Did FASYNC state change ? */ + if ((flag ^ filp->f_flags) & FASYNC) { + if (filp->f_op && filp->f_op->fasync) + filp->f_op->fasync(fd, filp, on); + } if (on) - filp->f_flags |= O_SYNC; + filp->f_flags |= FASYNC; else - filp->f_flags &= ~O_SYNC; + filp->f_flags &= ~FASYNC; break; default: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/clntproc.c linux.ac/fs/lockd/clntproc.c --- linux.vanilla/fs/lockd/clntproc.c Tue Feb 23 14:21:34 1999 +++ linux.ac/fs/lockd/clntproc.c Sun Mar 21 01:19:18 1999 @@ -328,7 +328,7 @@ status = req->a_res.status; if (status == NLM_LCK_GRANTED) { fl->fl_type = F_UNLCK; - } if (status == NLM_LCK_DENIED) { + } else if (status == NLM_LCK_DENIED) { /* * Report the conflicting lock back to the application. * FIXME: Is it OK to report the pid back as well? @@ -478,7 +478,7 @@ int status = req->a_res.status; if (RPC_ASSASSINATED(task)) - goto die; + return; if (task->tk_status < 0) { dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status); @@ -490,9 +490,6 @@ && status != NLM_LCK_DENIED_GRACE_PERIOD) { printk("lockd: unexpected unlock status: %d\n", status); } - -die: - rpc_release_task(task); } /* @@ -568,7 +565,6 @@ } die: - rpc_release_task(task); nlm_release_host(req->a_host); kfree(req); return; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/svclock.c linux.ac/fs/lockd/svclock.c --- linux.vanilla/fs/lockd/svclock.c Tue Feb 23 14:21:34 1999 +++ linux.ac/fs/lockd/svclock.c Tue Feb 16 17:02:53 1999 @@ -561,7 +561,6 @@ block->b_incall = 0; nlm_release_host(call->a_host); - rpc_release_task(task); } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/svcproc.c linux.ac/fs/lockd/svcproc.c --- linux.vanilla/fs/lockd/svcproc.c Tue Feb 23 14:21:34 1999 +++ linux.ac/fs/lockd/svcproc.c Tue Feb 16 17:03:01 1999 @@ -492,7 +492,6 @@ task->tk_pid, -task->tk_status); } nlm_release_host(call->a_host); - rpc_release_task(task); kfree(call); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/locks.c linux.ac/fs/locks.c --- linux.vanilla/fs/locks.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/locks.c Wed Mar 24 18:01:39 1999 @@ -339,7 +339,11 @@ error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) goto out_putf; - fl = &file_lock; + else if (error == LOCK_USE_CLNT) + /* Bypass for NFS with no locking - 2.0.36 compat */ + fl = posix_test_lock(filp, &file_lock); + else + fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); } else { fl = posix_test_lock(filp, &file_lock); } @@ -450,6 +454,10 @@ if (filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, &file_lock); + /* + * FUTURE: Watch out for return of LOCK_USE_CLNT here! + * See nfs_lock in fs/nfs/file.c + */ if (error < 0) goto out_putf; } @@ -609,7 +617,7 @@ /* Block for writes against a "read" lock, * and both reads and writes against a "write" lock. */ - if (posix_locks_conflict(fl, &tfl)) { + if (posix_locks_conflict(&tfl, fl)) { if (filp && (filp->f_flags & O_NONBLOCK)) return (-EAGAIN); if (signal_pending(current)) @@ -672,8 +680,11 @@ if (((start += l->l_start) < 0) || (l->l_len < 0)) return (0); + fl->fl_end = start + l->l_len - 1; + if (l->l_len > 0 && fl->fl_end < 0) + return (0); fl->fl_start = start; /* we record the absolute position */ - if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0)) + if (l->l_len == 0) fl->fl_end = OFFSET_MAX; fl->fl_file = filp; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/minix/file.c linux.ac/fs/minix/file.c --- linux.vanilla/fs/minix/file.c Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/minix/file.c Mon Mar 1 14:24:09 1999 @@ -25,7 +25,6 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) #include -#include static ssize_t minix_file_write(struct file *, const char *, size_t, loff_t *); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/namei.c linux.ac/fs/namei.c --- linux.vanilla/fs/namei.c Tue Jan 26 09:44:22 1999 +++ linux.ac/fs/namei.c Tue Jan 26 12:12:21 1999 @@ -194,6 +194,12 @@ void put_write_access(struct inode * inode) { +#ifdef DEBUG_WRITE_ACCESS + if(inode->i_writecount == 0) + printk(KERN_ERR "inode %p (%ld,%X), invalid write count!\n", + inode, inode->i_ino, inode->i_dev); + else +#endif inode->i_writecount--; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ncpfs/dir.c linux.ac/fs/ncpfs/dir.c --- linux.vanilla/fs/ncpfs/dir.c Thu Dec 3 14:12:00 1998 +++ linux.ac/fs/ncpfs/dir.c Mon Mar 1 14:24:09 1999 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ncpfs/sock.c linux.ac/fs/ncpfs/sock.c --- linux.vanilla/fs/ncpfs/sock.c Sun Nov 8 15:10:24 1998 +++ linux.ac/fs/ncpfs/sock.c Wed Mar 24 18:13:45 1999 @@ -94,7 +94,7 @@ poll_table wait_table; struct poll_table_entry entry; int init_timeout, max_timeout; - int timeout; long tmp_timeout; + int timeout; int retrans; int major_timeout_seen; int acknowledge_seen; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/Makefile linux.ac/fs/nfs/Makefile --- linux.vanilla/fs/nfs/Makefile Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/nfs/Makefile Mon Feb 1 22:06:55 1999 @@ -9,7 +9,7 @@ O_TARGET := nfs.o O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \ - nfs2xdr.o + nfs2xdr.o cluster.o ifdef CONFIG_ROOT_NFS O_OBJS += nfsroot.o mount_clnt.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/cluster.c linux.ac/fs/nfs/cluster.c --- linux.vanilla/fs/nfs/cluster.c Thu Jan 1 01:00:00 1970 +++ linux.ac/fs/nfs/cluster.c Wed Mar 24 18:01:47 1999 @@ -0,0 +1,1154 @@ +/* + * linux/fs/nfs/cluster.c + * + * Clustering of file data over NFS. + * + * The write-back code takes a two-level approach. At the lower level, + * there is a request associated with each dirty page. + * These pages are grouped in clusters in order to improve write scheduling. + * The benefits are: + * + * 1. If we write out clusters of pages simultaneously, the write-gathering + * code on the server side can optimize syncing the data (for NFSv2). + * 2. For NFSv3, we can schedule COMMIT calls more intelligently. + * 3. If the write block size is bigger than physical page size, we + * are able to group several pages into one write request. + * + * Clusters are linked into the inode so that the file sync code et. al. + * can conveniently loop over all dirty pages. There is also a hash table + * of clusters so that the write() code itself can locate the relevant + * cluster fairly quick. + * + * Each cluster holds a list of requests (struct nfs_page) that represent + * the dirty portion of a page. These can be considered as an equivalent + * to the buffer heads currently used in the VFS. A request struct holds + * a minimal set of information to keep memory overhead low; most of + * the state is in fact kept in the cluster. + * + * For each NFS mount, there is a separate cache object that contains + * a hash table of all clusters. With this cache, an async RPC task + * (`clusterd') is associated, which wakes up occasionally to inspect + * its list of dirty buffers. + * (Note that RPC tasks aren't kernel threads. Take a look at the + * rpciod code to understand what they are). + * + * Inside the cache object, we also maintain a count of the current number + * of dirty pages, which may not exceed a certain threshold. + * (FIXME: This threshold should be configurable). + * + * The code is streamlined for what I think is the prevalent case for + * NFS traffic, which is sequential write access without concurrent + * access by different processes. + * + * Copyright (C) 1996, 1997, Olaf Kirch + * + * Some parts + * Copyright (C) 1999, Trond Myklebust + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* + * Various constants + */ +#define NFS_WRITEBACK_DELAY (10 * HZ) +#define NFS_WRITEBACK_LOCKDELAY (120 * HZ) + +#define NFSDBG_FACILITY NFSDBG_PAGECACHE + +/* + * This is the per-mount writeback cache. + */ +struct nfs_reqlist { + unsigned int nr_requests; + struct wait_queue * request_wait; + + struct nfs_server * server; + /* The async RPC task that is responsible for scanning the + * clusters. + */ + struct rpc_task * task; /* cluster flush task */ + + /* Authentication flavor handle for this NFS client */ + struct rpc_auth * auth; + + /* The 'hash' table of all clusters. + * Technically, this needn't be a hash table; all we + * want is an even distribution of clusters across + * slots in this table. + */ + struct nfs_cluster * clusters[CLUSTER_HASH_SIZE]; + + /* Used by clusterd when scanning the hash table */ + unsigned int hand; +}; + +/* + * This is the wait queue all cluster daemons sleep on + */ +static struct rpc_wait_queue cluster_queue = RPC_INIT_WAITQ("clusterd"); + +/* + * Local function declarations. + */ +static void nfs_clusterd(struct rpc_task *); +static void nfs_clusterd_done(struct rpc_task *); + + +int +nfs_reqlist_init(struct nfs_server *server) +{ + struct nfs_reqlist *cache; + struct rpc_task *task; + + dprintk("NFS: writecache_init\n"); + cache = (struct nfs_reqlist *) kmalloc(sizeof(*cache), GFP_KERNEL); + if (cache == NULL) + return -ENOMEM; + memset(cache, 0, sizeof(*cache)); + + /* Create the RPC task */ + task = rpc_new_task(server->client, nfs_clusterd_done, 0); + if (task == NULL) { + kfree(cache); + return -ENOMEM; + } + task->tk_flags |= RPC_TASK_ASYNC; + task->tk_action = nfs_clusterd; + task->tk_calldata = cache; + + /* Put the task to sleep */ + task->tk_timeout = 60 * HZ; + rpc_sleep_on(&cluster_queue, task, NULL, NULL); + + cache->task = task; + cache->auth = server->client->cl_auth; + server->rw_requests = cache; + cache->server = server; + return 0; +} + +void +nfs_reqlist_exit(struct nfs_server *server) +{ + struct nfs_reqlist *cache; + struct rpc_task *task; + + if ((cache = server->rw_requests) == 0) + return; + + dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task); + + server->rw_requests = NULL; + task = cache->task; + task->tk_exit = NULL; + rpc_kill(task, 0); +} + +static void +nfs_clusterd_done(struct rpc_task *task) +{ + struct nfs_reqlist *cache = (struct nfs_reqlist *)task->tk_calldata; + struct nfs_server *server; + + if (cache) { + server = cache->server; + if (server) + server->rw_requests = NULL; + kfree(cache); + } +} + + +/* + * Check whether the file range we want to write to is locked by + * us. + */ +static int +region_locked(struct inode *inode, struct nfs_page *req) +{ + struct file_lock *fl; + + /* Don't optimize writes if we don't use NLM */ + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) + return 0; + + for (fl = inode->i_flock; fl; fl = fl->fl_next) { + if (fl->fl_owner == current->files && (fl->fl_flags & FL_POSIX) + && fl->fl_type == F_WRLCK + && fl->fl_start <= req->start && req->end <= fl->fl_end) { + return 1; + } + } + + return 0; +} + +/* + * Create a new cluster and associated RPC task. + * + * Clusters are created only in update_request, and we know the inode + * is nfs-locked when we get there. + */ +static struct nfs_cluster * +create_cluster(struct file *file, nfs_flush_req flush,__u64 rqstart, __u64 rqend, int *error) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); + struct nfs_cluster *cluster, *next; + unsigned int hash; + unsigned long flags; + + dprintk("NFS: create_cluster(%x/%ld, %ld)\n", + inode->i_dev, inode->i_ino, + (long) (rqstart & CLUSTER_MASK)); + + /* + * Did somebody recently kill RPCIOD? + */ + if (!cache) { + *error = nfs_reqlist_init(NFS_SERVER(inode)); + cache = NFS_REQUESTLIST(inode); + if (!cache) + return NULL; + } + /* Default error out of memory */ + *error = -ENOMEM; + + /* Should never fail */ + cluster = (struct nfs_cluster *) rpc_allocate(0, sizeof(*cluster)); + if (cluster == NULL) + return NULL; + + dprintk("NFS: allocated cluster %p\n", cluster); + memset(cluster, 0, sizeof(*cluster)); + + cluster->nextscan = jiffies + NFS_WRITEBACK_DELAY; + cluster->file = file; + file->f_count++; + cluster->flush = flush; + cluster->start = rqstart; + cluster->end = rqend; + cluster->auth = cache->auth; + cluster->cred = rpcauth_lookupcred(cache->auth, 0); +#ifdef NFSV3 + cluster->sequence = 1; +#endif + + /* should not happen */ + if (cluster->cred == 0) { + printk("NFS: couldn't get creds for write cluster.\n"); + kfree(cache); + return NULL; + } + + /* Note that we don't have to keep a reference on the + * inode as write_inode takes care of any pending writes. */ + + /* Attach cluster to the inode */ + cluster->count++; + + rpc_append_list(&NFS_CLUSTERS(inode), cluster); + + /* Insert the cluster into the hash table */ + hash = CLUSTER_HASH(inode->i_ino, rqstart); + if ((next = cache->clusters[hash]) != NULL) + next->hash_prev = cluster; + cluster->hash_next = next; + cluster->hash_prev = NULL; + cache->clusters[hash] = cluster; + + *error = 0; + return cluster; +} + +/* + * Delete an empty cluster + */ +void +delete_cluster(struct nfs_cluster *cluster) +{ + struct nfs_reqlist *cache; + struct nfs_cluster *prev, *next; + struct dentry *dentry = cluster->file->f_dentry; + struct inode *inode = dentry->d_inode; + unsigned int hash; + unsigned long flags; + + dprintk("NFS: delete_cluster(%p)\n", cluster); + + if (cluster->count) + return; + + if (cluster->pages) + printk("NFS: Arrgh! Cluster not empty!\n"); + + /* Remove from inode list of clusters */ + rpc_remove_list(&NFS_CLUSTERS(inode), cluster); + + /* Remove from cluster hash table */ + cache = NFS_REQUESTLIST(inode); + hash = CLUSTER_HASH(inode->i_ino, cluster->start); + prev = cluster->hash_prev; + next = cluster->hash_next; + if (prev != NULL) + prev->hash_next = next; + else + cache->clusters[hash] = next; + if (next != NULL) + next->hash_prev = prev; + + /* Free cluster memory */ + fput(cluster->file); + kfree(cluster); +} + + +/* + * Insert a write request into a cluster + */ +static inline void +nfs_insert_request(struct nfs_cluster *cluster, struct nfs_page *req) +{ + struct inode *inode = cluster->file->f_dentry->d_inode; + cluster->count++; + + if (cluster->request[REQUEST_NR(req->start)]) + printk("NFS: Uh oh! Overwriting existing request!\n"); + + cluster->request[REQUEST_NR(req->start)] = req; + cluster->pages++; + + /* Update the cluster region */ + if (req->start < cluster->start) + cluster->start = req->start; + if (cluster->end < req->end) + cluster->end = req->end; + + NFS_REQUESTLIST(inode)->nr_requests++; +} + +/* + * Remove a write request from a cluster. + * To avoid race conditions, this function should be called by + * nfs_clusterd only! + */ +static inline void +nfs_remove_request(struct nfs_cluster *cluster, struct nfs_page *req) +{ + struct inode *inode = cluster->file->f_dentry->d_inode; + struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); + + cluster->request[REQUEST_NR(req->start)] = NULL; + cluster->pages--; + release_cluster(cluster); + /* wake up anyone waiting to allocate a request */ + cache->nr_requests--; + wake_up(&cache->request_wait); +} + +/* + * Create a write request. + * Page must be locked by the caller. This makes sure we never create + * two different requests for the same page, and avoids possible deadlock + * when we reach the hard limit on the number of dirty pages. + */ +struct nfs_page * +nfs_create_request(struct nfs_cluster *cluster, struct page *page, + __u64 rqstart, __u64 rqend, int *error) +{ + struct inode *inode = cluster->file->f_dentry->d_inode; + struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); + struct nfs_page *req = NULL; + signed long timeout; + + /* Deal with hard/soft limits. + * Increment the reference count on the cluster to make sure it + * doesn't go away while we sleep. + */ + cluster->count++; + while (1) { + *error = 0; + + /* If we're over the soft limit, wake up some requests */ + if (cache->nr_requests >= MAX_REQUEST_SOFT + && !NFS_CONGESTED(inode)) { + dprintk("NFS: hit soft limit (%d requests)\n", + cache->nr_requests); + rpc_wake_up_task(cache->task); + } + + /* If we haven't reached the hard limit yet, + * try to allocate the request struct */ + if (cache->nr_requests < MAX_REQUEST_HARD) { + req = (struct nfs_page *) kmalloc(sizeof(*req), + GFP_KERNEL); + if (req != NULL) + break; + } + + /* We're over the hard limit. Wait for better times */ + dprintk("NFS: create_request sleeping (total %d pid %d)\n", + cache->nr_requests, current->pid); + timeout = jiffies + (HZ >> 2); + if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) { + interruptible_sleep_on_timeout(&cache->request_wait, timeout); + *error = -ERESTARTSYS; + if (signalled()) + goto done; + } else { + sleep_on(&cache->request_wait); + } + dprintk("NFS: create_request waking up (tot %d pid %d)\n", + cache->nr_requests, current->pid); + } + + /* Initialize the request struct. Initially, we assume a + * long write-back delay. This will be adjusted in + * update_nfs_request below if the region is not locked. */ + req->cluster = cluster; + req->page = page; + req->task = NULL; + req->start = rqstart; + req->end = rqend; + req->timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; + req->flags = 0; + req->commit = 0; + atomic_inc(&page->count); + + /* Insert the request into the cluster */ + nfs_insert_request(cluster, req); + +done: + release_cluster(cluster); + return req; +} + + +/* + * Try to update any existing write request, or create one if there is none. + * In order to match, the request's credentials must match those of + * the calling process. + * + * The inode is nfs-locked when we get here. + */ +int +nfs_update_request(struct file* file, struct page *page, + __u64 offset, __u64 bytes, + struct nfs_page **reqp, + nfs_flush_req flush) +{ + struct inode *inode = file->f_dentry->d_inode; + struct nfs_cluster *cluster = NULL, *head, *c; + struct nfs_page *req; + __u64 rqstart, rqend; + __u64 base; + unsigned int rqnr; + int status; + + base = page->offset & CLUSTER_MASK; + rqstart = page->offset + offset; + rqend = rqstart + bytes; + rqnr = REQUEST_NR(rqstart); + + /* Loop over all clusters and see if we find + * a. A cluster with matching region and creds + * b. A request for the page we wish to update + */ + + head = c = NFS_CLUSTERS(inode); + if (!c) + goto create; + + do { + if ((c->start & CLUSTER_MASK) != base) + continue; + /* If the cluster matches our creds and pid, remember it. + * We must match against the pid so errors can be reported + * to the correct process. + * XXX do we really care? + */ + if (c->file == file + && rpcauth_matchcred(c->auth, c->cred, 0) + && c->flush == flush) + cluster = c; + + if ((req = c->request[rqnr]) != NULL) { + /* We have a request for our page. + * If the cluster creds don't match, or the + * page addresses don't match (can that happen?), + * tell the caller to wait on the conflicting + * request. + */ + if (req->page != page || c != cluster || + rqstart > req->end || rqend < req->start) { + *reqp = req; + return 0; + } + + /* Okay, the request matches. Update the region */ + if (rqstart < req->start) { + if (rqstart < cluster->start) + cluster->start = rqstart; + req->start = rqstart; + } + if (req->end < rqend) { + if (cluster->end < rqend) + cluster->end = rqend; + req->end = rqend; + } + cluster->count++; + + goto doupdate; + } + } while ((c = CL_NEXT(c)) != head); + + if (cluster) + cluster->count++; + +create: + + /* No matching request found. + * Create a cluster if we don't have one. + */ + if (cluster == NULL) { + cluster = create_cluster(file, flush, rqstart, rqend, &status); + if (cluster == NULL) + goto out; + } + + /* Create the request. It's safe to sleep in this call because + * we only get here if the page is locked. + */ + req = nfs_create_request(cluster, page, rqstart, rqend, &status); + if (req == NULL) + goto out; + +doupdate: + status = 1; + + nfs_mark_request_dirty(cluster, req); + + /* If the region is not locked, adjust the timeout */ + if (!inode->i_flock || !region_locked(inode, req)) { + unsigned long timeout; + + timeout = jiffies + NFS_WRITEBACK_DELAY; + if (time_before(timeout, req->timeout)) { + if (time_before(timeout, cluster->nextscan)) + cluster->nextscan = timeout; + req->timeout = timeout; + } + } + *reqp = req; + +out: + release_cluster(cluster); + return status; +} + +/* + * Wait for a request to complete. + * + * Interruptible by signals only if mounted with intr flag. + */ +int +nfs_wait_on_request(struct nfs_page *req) +{ + struct inode *inode = req->cluster->file->f_dentry->d_inode; + struct rpc_clnt *clnt = NFS_CLIENT(inode); + struct wait_queue wait = { current, NULL }; + struct page *page = req->page; + sigset_t oldmask; + int retval, intr; + + intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR; + rpc_clnt_sigmask(clnt, &oldmask); + add_wait_queue(&page->wait, &wait); + atomic_inc(&page->count); + for(;;) { + current->state = (intr) ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE; + + retval = 0; + if (!PageLocked(page)) + break; + + retval = -ERESTARTSYS; + if (intr && signalled()) + break; + + schedule(); + } + + remove_wait_queue(&page->wait, &wait); + current->state = TASK_RUNNING; + rpc_clnt_sigunmask(clnt, &oldmask); + __free_page(page); + + return retval; +} + +/* + * Release all resources associated with a write request after it + * has been committed to stable storage + */ +void +nfs_release_request(struct nfs_page *req) +{ + struct page *page; + + /* Remove the request from the cluster */ + nfs_remove_request(req->cluster, req); + + if ((page = req->page) != NULL) { + if (req->flags & PG_INVALIDATE_AFTER) + clear_bit(PG_uptodate, &page->flags); + if (req->flags & PG_UNLOCK_AFTER) + nfs_unlock_page(page); + __free_page(page); + req->page = NULL; + } + kfree(req); +} + +/* + * Cancel a write request (called when truncating a file). + * + * This is tricky if you coalesce multiple pages into a single RPC call. + * Therefore you must make sure that when calling nfs_truncate_dirty_pages, + * you have either flushed all write requests after the truncation point, + * or you're truncating the entire file. + */ +void +nfs_cancel_request(struct nfs_cluster *cluster, struct nfs_page *req) +{ + struct rpc_task *task; + + /* If there is a task, kill it. */ + if ((task = req->task) != NULL) { + if (task->tk_calldata) { + kfree(task->tk_calldata); + task->tk_calldata = 0; + } + task->tk_exit = NULL; + rpc_kill(task, 0); + req->task = NULL; + } + /* Adjust book-keeping of dirty pages */ + if (IS_DIRTY(req)) + cluster->dirty--; + nfs_release_request(req); +} + +/* + * This is the strategy routine for NFS. + * It is called by nfs_updatepage whenever the user wrote up to the end + * of a page. + * + * We always try to submit a set of requests in parallel so that the + * server's write code can gather writes. This is mainly for the benefit + * of NFSv2. + * + * We never submit more requests than we think the remote can handle. + * For UDP sockets, we make sure we don't exceed the congestion window; + * for TCP, we limit the number of requests to 8. + * + * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that + * should be sent out in one go. This is for the benefit of NFSv2 servers + * that perform write gathering. + * + * FIXME: Different servers may have different sweet spots. + * Record the average congestion window in server struct? + */ +#define NFS_STRATEGY_PAGES 4 +int +nfs_strategy(struct nfs_cluster *cluster) +{ + struct inode *inode = cluster->file->f_dentry->d_inode; + struct rpc_xprt *xprt = NFS_CLIENT(inode)->cl_xprt; + struct nfs_page *req; + unsigned int j, nr, dirty, wpages; + + /* If we've reached the end of the cluster, flush everything */ + if ((cluster->end & ~CLUSTER_MASK) == 0) { + if (NFS_CONGESTED(inode)) + nfs_wait_on_congest(inode); + sync_cluster(cluster, FLUSH_SYNC); + return 0; + } + +#ifdef NFSV3 + /* If more than half of all pages are clean, schedule a commit + * call. */ + if (!cluster->committing) { + if (cluster->pages - cluster->dirty > CLUSTER_PAGES/2) + commit_cluster(cluster); + } + + dirty = cluster->dirty - cluster->pending; + wpages = NFS_SERVER(inode)->wsize / PAGE_SIZE; + if (NFS_PROTO(inode)->version == 2) { + if (dirty < NFS_STRATEGY_PAGES * wpages) + return 0; + } else { + if (dirty < wpages) + return 0; + } +#else + dirty = cluster->dirty - cluster->pending; + wpages = NFS_SERVER(inode)->wsize / PAGE_SIZE; + if (dirty < NFS_STRATEGY_PAGES * wpages) + return 0; +#endif + + for (j = nr = 0; j < CLUSTER_PAGES; j++) { + if (NFS_CONGESTED(inode)) + nfs_wait_on_congest(inode); + req = cluster->request[j]; + if (req && IS_DIRTY(req) && nfs_lock_page(req)) { + /* Fails if out of memory and unlocks the page */ + if (cluster->flush(req, FLUSH_SYNC) < 0) + break; + nr++; + } + } + + /* Make sure we yield the processor when a high-priority RPC task + * is ready. (This is most likely a writeback having received + * his reply). + * XXX: not clear whether that makes such a big difference. + */ +#if 0 + if (current->need_resched) + schedule(); +#endif + + return nr; +} + +/* + * Flush out all dirty pages. Called for + * + * - fsync, fclose, and when releasing a write lock. + * How is FLUSH_WAIT in this case. + * - nfs_invalidate_pages. + * How is FLUSH_INVALIDATE|FLUSH_STABLE in this case. + * + * The start/end arguments specify a file range to flush. To make the + * logic simpler, we flush the entire cluster even if it overlaps the + * file range only partially. + * + * The inode must be nfs-locked when we get here, in order to avoid + * that new write requests get created while we're busy flushing out + * the old ones. + */ +int +nfs_sync_file(struct inode *inode, struct file *file, __u64 start, __u64 end, int how) +{ + struct nfs_cluster *cluster, *last, *head; + int error = 0, wait, count; + + wait = how & FLUSH_WAIT; + how &= ~FLUSH_WAIT; + how |= FLUSH_SYNC; + + if (file && ! inode) + inode = file->f_dentry->d_inode; + + /* Do this repeatedly. We may write all pages to the server only + * to find out that it has rebooted when we get around to the + * commit call. + */ +again: + head = cluster = NFS_CLUSTERS(inode); + last = 0; + count = 0; + + if (cluster == NULL) + goto wait; + + head->count++; + + do { + if (cluster->pages && (file == 0 || file == cluster->file) + && cluster->start < end && start < cluster->end) { + + /* Cluster overlaps file region. + * Flush it out and remember pointer. */ + cluster->count++; + + release_cluster(last); + + if (wait && NFS_CONGESTED(inode)) + nfs_wait_on_congest(inode); + + error = sync_cluster(cluster, how); + last = cluster; + + if (error < 0) { + release_cluster(head); + goto out; + } + } + } while ((cluster = CL_NEXT(cluster)) && cluster != head); + +wait: + release_cluster(head); + + /* Wait for the last cluster to complete */ + if (wait && last) { + error = wait_cluster(last); + if (error < 0) + goto out; + release_cluster(last); + goto again; + } + +out: + release_cluster(last); + return error; +} + + +/* + * Send all dirty pages of a cluster to the server and lock them. + * + * When invalidating pages we must make sure every page gets locked + * down. Therefore we send even written but uncommitted pages to stable + * storage right away. + */ +int +sync_cluster(struct nfs_cluster *cluster, int how) +{ + struct nfs_page *req; + unsigned int nr, flushed = 0; + int error = 0; + + cluster->count++; + + for (nr = 0; nr < CLUSTER_PAGES; nr++) { + if (!(req = cluster->request[nr])) + continue; + + if (how & FLUSH_INVALIDATE) + req->flags |= PG_INVALIDATE_AFTER; + else if (!IS_DIRTY(req)) + continue; + + if (nfs_lock_page(req)) { + error = cluster->flush(req, how); + if (error < 0) + goto out; + + flushed++; + } + } + +out: + release_cluster(cluster); + + if (error == 0) + error = flushed; + return error; +} + +/* + * Scan cluster for dirty pages and send as many of them to the + * server as possible. + */ +int +scan_cluster(struct nfs_cluster *cluster, unsigned int max) +{ + struct nfs_page *req; + unsigned int nr, flushed = 0; + int error = 0; + + cluster->count++; + for (nr = 0; nr < CLUSTER_PAGES; nr++) { + + if (NFS_CONGESTED(cluster->file->f_dentry->d_inode)) + break; + + if (!(req = cluster->request[nr])) + continue; + + if (time_before(req->timeout, cluster->nextscan)) + cluster->nextscan = req->timeout; + if (time_after(req->timeout, jiffies)) + continue; + if (IS_DIRTY(req) && nfs_lock_page(req)) { + error = cluster->flush(req, FLUSH_AGING); + if (error < 0) + break; + if (max && ++flushed >= max) + break; + } + } + + release_cluster(cluster); + + if (error == 0) + error = flushed; + return error; +} + +/* + * Wait for all write requests to complete, and commit them when + * they're done. + */ +int +wait_cluster(struct nfs_cluster *cluster) +{ + struct nfs_page *last, *req; + unsigned int nr; + int intr, error = 0; + + cluster->count++; + while (cluster->pages && error >= 0) { + last = 0; + for (nr = 0; nr < CLUSTER_PAGES; nr++) { + if (!(req = cluster->request[nr])) + continue; + if (req->page && PageLocked(req->page) && req->task) + last = req; + } + + if (last != NULL) { + error = nfs_wait_on_request(last); + continue; + } + + /* Forget about committing if there remain dirty + * pages (e.g. due to a failed commit call). + */ + if (cluster->dirty) + break; + +#ifdef NFSV3 + /* If there's a commit call in process, we first + * wait for it to complete. Most likely it's the + * one that will sync all current pages anyway. + * We also must wait for it in order to make sure + * there aren't any clusters around after we + * close the file. + */ + intr = NFS_SERVER(cluster->inode)->flags & NFS_MOUNT_INTR; + rpc_clnt_sigmask(clnt, &oldmask); + add_wait_queue(&cluster->wait, &wait); + if (!cluster->committing) { + if (cluster->pages == 0) + break; + error = commit_cluster(cluster); + } + + if (!error) { + current->state = (intr) ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE; + + schedule(); + if (intr && signalled()) + error = -ERESTARTSYS; + } + + remove_wait_queue(&cluster->wait, &wait); + current->state = TASK_RUNNING; + rpc_clnt_sigunmask(clnt, &oldmask); +#endif + } + + release_cluster(cluster); + + return error; +} + +#ifdef NFSV3 +/* + * Commit cluster of dirty pages + */ +int +commit_cluster(struct nfs_cluster *cluster) +{ + struct nfs_write_data *data; + struct rpc_task *task; + struct inode *inode = cluster->inode; + int flags; + + if (NFS_PROTO(inode)->version == 2) { + printk("NFS: commit_cluster called for NFSv2\n"); + printk(" (dirty %d pages %d pending %d)\n", + cluster->dirty, cluster->pages, cluster->pending); + return -EIO; + } + + /* We give a COMMIT call a higher priority than ordinary RPC + * calls because it is so critical to our memory balance. + * (SWAPPER means it will always be inserted at the head of + * any wait queue; PRIORITY means that need_resched will be + * set whenever the task becomes runnable.) + */ + flags = RPC_TASK_SWAPPER|RPC_TASK_PRIORITY; + + /* Create a new RPC task and allocate RPC memory */ + task = rpc_new_task(NFS_CLIENT(inode), nfs_commit_done, flags); + data = nfs_write_rpcsetup(inode, cluster->start, cluster->end, flags); + + if (task == NULL || data == NULL) { + if (task) + rpc_release_task(task); + return -ENOMEM; + } + + /* Remember the commit sequence number. + * When the commit call completes, all requests with sequence + * number > data->commit are ignored because they're either + * dirty, or were marked clean only after the commit call + * was issued. + */ + cluster->committing = cluster->sequence; + data->commit = cluster->sequence; + data->cluster = cluster; + cluster->sequence++; + cluster->count++; + + /* Finalize the task */ + task->tk_flags |= RPC_TASK_ASYNC; + task->tk_calldata = data; + task->tk_cred = cluster->cred; + rpcauth_holdcred(task); + + dprintk("NFS: %4d initiated commit call\n", task->tk_pid); + rpc_call_setup(task, NFS3PROC_COMMIT, &data->args, &data->res, 0); + rpc_execute(task); + return 0; +} + +#endif + +/* + * This is the cluster scanner. + * - If there are pages due to be written, send them out now. + * - If the total number of dirty pages has exceeded the soft + * limit, sync the cluster now. + * - If the user has written past the end of the cluster, we + * also flush the remaining dirty pages and initiate a commit + * call. + */ +static void +nfs_clusterd(struct rpc_task *task) +{ + struct nfs_reqlist *cache; + struct nfs_cluster *cluster, *previous; + unsigned long delay = 60 * HZ; + unsigned int hand, nr; + int error = 0; + + dprintk("NFS: %4d clusterd starting\n", task->tk_pid); + cache = (struct nfs_reqlist *) task->tk_calldata; + + hand = cache->hand; + nr = 0; + do { + int cong = 0; + cluster = cache->clusters[hand]; + previous = 0; + while (cluster && error >= 0 + && ! (cong = NFS_CONGESTED(cluster->file->f_dentry->d_inode))) { + cluster->count++; + +#ifdef NFSV3 + if (!cluster->dirty && cluster->pages) { + /* Only initiate a commit call when we + * don't have one yet. Extremely important + * when the server hangs... + */ + if (!cluster->committing) + error = commit_cluster(cluster); + } else +#endif + if ((cluster->end & ~CLUSTER_MASK) == 0 + || cache->nr_requests >= MAX_REQUEST_SOFT) { + error = sync_cluster(cluster, 0); + } else if (time_before(cluster->nextscan, jiffies)) { + error = scan_cluster(cluster, 0); + } + + release_cluster(previous); + previous = cluster; + cluster = cluster->hash_next; + delay = 1 * HZ; + nr++; + } + release_cluster(previous); + + if (error < 0 || cong) { + delay = HZ >> 4; /* Not enough memory */ + break; + } + hand = (hand + 1) & (CLUSTER_HASH_SIZE - 1); + } while (hand != cache->hand && nr < 16); + + cache->hand = hand; + + dprintk("NFS: %4d clusterd back to sleep\n", task->tk_pid); + task->tk_timeout = delay; + rpc_sleep_on(&cluster_queue, task, NULL, NULL); +} + +/* + * Wait for the RPC backlog to clear. + * + * Interruptible by signals only if mounted with intr flag. + */ +int +nfs_wait_on_congest(struct inode *inode) +{ + struct rpc_clnt *clnt = NFS_CLIENT(inode); + struct rpc_xprt *xprt = clnt->cl_xprt; + struct wait_queue wait = { current, NULL }; + sigset_t oldmask; + int retval, intr; + + if (!NFS_CONGESTED(inode)) + return 0; + + intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR; + rpc_clnt_sigmask(clnt, &oldmask); + add_wait_queue(&xprt->cong_wait, &wait); + + for(;;) { + current->state = (intr) ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE; + + retval = 0; + if (!NFS_CONGESTED(inode)) + break; + + retval = -EINTR; + if (intr && signalled()) + break; + + schedule(); + } + + remove_wait_queue(&xprt->cong_wait, &wait); + current->state = TASK_RUNNING; + rpc_clnt_sigunmask(clnt, &oldmask); + + return retval; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/dir.c linux.ac/fs/nfs/dir.c --- linux.vanilla/fs/nfs/dir.c Wed Mar 10 21:13:09 1999 +++ linux.ac/fs/nfs/dir.c Wed Mar 24 18:03:12 1999 @@ -371,6 +371,8 @@ nfs_invalidate_dircache_sb(NULL); } +#define NFS_REVALIDATE_INTERVAL (5*HZ) + /* * Whenever an NFS operation succeeds, we know that the dentry * is valid, so we update the revalidation timestamp. @@ -380,7 +382,6 @@ dentry->d_time = jiffies; } -#define NFS_REVALIDATE_INTERVAL (5*HZ) /* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that @@ -438,15 +439,18 @@ if (fattr.fileid != inode->i_ino) goto out_bad; - /* Filehandle matches? */ - if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) - goto out_bad; + if (dentry->d_count < 2) { + /* Filehandle matches? */ + if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) + goto out_bad; + } /* Ok, remeber that we successfully checked it.. */ nfs_renew_times(dentry); nfs_refresh_inode(inode, &fattr); out_valid: + nfs_renew_times(dentry); return 1; out_bad: return 0; @@ -533,6 +537,7 @@ } #endif + static int nfs_lookup(struct inode *dir, struct dentry * dentry) { struct inode *inode; @@ -624,11 +629,11 @@ dfprintk(VFS, "NFS: create(%x/%ld, %s\n", dir->i_dev, dir->i_ino, dentry->d_name.name); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; + if (S_ISFIFO(mode)) + sattr.mode = (mode & ~S_IFMT) | S_IFCHR; + else + sattr.mode = mode; - sattr.mode = mode; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; @@ -638,6 +643,15 @@ nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); + /* + * Retry invalid FIFO creates as the original object + * to cover for NFS servers that don't cope. + */ + if (error == -EINVAL && (S_ISFIFO(mode))) { + sattr.mode = mode; + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name, &sattr, &fhandle, &fattr); + } if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error) @@ -659,10 +673,11 @@ dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n", dir->i_dev, dir->i_ino, dentry->d_name.name); - if (dentry->d_name.len > NFS_MAXNAMLEN) - return -ENAMETOOLONG; + if (S_ISFIFO(mode)) + sattr.mode = (mode & ~S_IFMT) | S_IFCHR; + else + sattr.mode = mode; - sattr.mode = mode; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; if (S_ISCHR(mode) || S_ISBLK(mode)) sattr.size = rdev; /* get out your barf bag */ @@ -671,6 +686,11 @@ nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); + if (error == -EINVAL && (S_ISFIFO(mode))) { + sattr.mode = mode; + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name, &sattr, &fhandle, &fattr); + } if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error) @@ -691,10 +711,6 @@ dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n", dir->i_dev, dir->i_ino, dentry->d_name.name); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - sattr.mode = mode | S_IFDIR; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; @@ -720,10 +736,6 @@ dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", dir->i_dev, dir->i_ino, dentry->d_name.name); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - #ifdef NFS_PARANOIA if (dentry->d_inode->i_count > 1) printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n", @@ -952,10 +964,6 @@ dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n", dir->i_dev, dir->i_ino, dentry->d_name.name); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - error = nfs_sillyrename(dir, dentry); if (error && error != -EBUSY) { error = nfs_safe_remove(dentry); @@ -976,10 +984,6 @@ dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n", dir->i_dev, dir->i_ino, dentry->d_name.name, symname); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - if (strlen(symname) > NFS_MAXPATHLEN) goto out; @@ -1026,10 +1030,6 @@ old_dentry->d_parent->d_name.name, old_dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name); - error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - /* * Drop the dentry in advance to force a new lookup. * Since nfs_proc_link doesn't return a file handle, @@ -1080,18 +1080,13 @@ struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL; - int error, rehash = 0, update = 1; + int error, rehash = 0; dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, new_dentry->d_count); - error = -ENAMETOOLONG; - if (old_dentry->d_name.len > NFS_MAXNAMLEN || - new_dentry->d_name.len > NFS_MAXNAMLEN) - goto out; - /* * First check whether the target is busy ... we can't * safely do _any_ rename if the target is in use. @@ -1135,13 +1130,6 @@ } /* - * Check for within-directory rename ... no complications. - */ - if (new_dir == old_dir) - goto do_rename; - /* - * Cross-directory move ... - * * ... prune child dentries and writebacks if needed. */ if (old_dentry->d_count > 1) { @@ -1149,17 +1137,6 @@ shrink_dcache_parent(old_dentry); } - /* - * Now check the use counts ... we can't safely do the - * rename unless we can drop the dentries first. - */ - if (old_dentry->d_count > 1) { -#ifdef NFS_PARANOIA -printk("nfs_rename: old dentry %s/%s busy, d_count=%d\n", -old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count); -#endif - goto out; - } if (new_dentry->d_count > 1 && new_inode) { #ifdef NFS_PARANOIA printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n", @@ -1169,9 +1146,7 @@ } d_drop(old_dentry); - update = 0; -do_rename: /* * To prevent any new references to the target during the rename, * we unhash the dentry and free the inode in advance. @@ -1185,7 +1160,7 @@ #endif if (!list_empty(&new_dentry->d_hash)) { d_drop(new_dentry); - rehash = update; + rehash = 1; } if (new_inode) { d_delete(new_dentry); @@ -1196,12 +1171,11 @@ error = nfs_proc_rename(NFS_DSERVER(old_dentry), NFS_FH(old_dentry->d_parent), old_dentry->d_name.name, NFS_FH(new_dentry->d_parent), new_dentry->d_name.name); - if (!error) { + if (!error && old_dentry->d_count > 1) { /* Update the dcache if needed */ if (rehash) d_add(new_dentry, NULL); - if (update) - d_move(old_dentry, new_dentry); + d_move(old_dentry, new_dentry); } out: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/file.c linux.ac/fs/nfs/file.c --- linux.vanilla/fs/nfs/file.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/nfs/file.c Wed Mar 24 18:01:52 1999 @@ -86,22 +86,11 @@ /* * Flush all dirty pages, and check for write errors. - * */ static int nfs_file_flush(struct file *file) { - struct inode *inode = file->f_dentry->d_inode; - int status; - - dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino); - - status = nfs_wb_file(inode, file); - if (!status) { - status = file->f_error; - file->f_error = 0; - } - return status; + return nfs_fsync(file, file->f_dentry); } static ssize_t @@ -230,7 +219,7 @@ * Flush all pending writes before doing anything * with locks.. */ - status = nfs_wb_all(inode); + status = nfs_sync_file(inode, 0, fl->fl_start, fl->fl_end, FLUSH_WAIT); if (status < 0) return status; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/inode.c linux.ac/fs/nfs/inode.c --- linux.vanilla/fs/nfs/inode.c Wed Mar 10 21:13:10 1999 +++ linux.ac/fs/nfs/inode.c Wed Mar 24 18:01:52 1999 @@ -100,26 +100,22 @@ /* * Flush out any pending write requests ... */ - if (NFS_WRITEBACK(inode) != NULL) { + if (NFS_CLUSTERS(inode) != NULL) { unsigned long timeout = jiffies + 5*HZ; #ifdef NFS_DEBUG_VERBOSE printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); #endif - nfs_inval(inode); - while (NFS_WRITEBACK(inode) != NULL && + nfs_invalidate_pages(inode); + while (NFS_CLUSTERS(inode) != NULL && time_before(jiffies, timeout)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); } current->state = TASK_RUNNING; - if (NFS_WRITEBACK(inode) != NULL) + if (NFS_CLUSTERS(inode) != NULL) printk("NFS: Arghhh, stuck RPC requests!\n"); } - failed = nfs_check_failed_request(inode); - if (failed) - printk("NFS: inode %ld had %d failed requests\n", - inode->i_ino, failed); clear_inode(inode); } @@ -129,6 +125,9 @@ struct nfs_server *server = &sb->u.nfs_sb.s_server; struct rpc_clnt *rpc; + /* First get rid of the request list */ + nfs_reqlist_exit(server); + if ((rpc = server->client) != NULL) rpc_shutdown_client(rpc); @@ -299,6 +298,12 @@ sb->s_root->d_op = &nfs_dentry_operations; sb->s_root->d_fsdata = root_fh; + /* Fire up the writeback cache */ + if (nfs_reqlist_init(server) < 0) { + printk("NFS: cannot initialize writeback cache.\n"); + goto failure_put_root; + } + /* We're airborne */ unlock_super(sb); @@ -308,6 +313,8 @@ return sb; /* Yargs. It didn't work out. */ +failure_put_root: + nfs_reqlist_exit(server); out_no_root: printk("nfs_read_super: get root inode failed\n"); iput(root_inode); @@ -639,6 +646,86 @@ } /* + * Zap the caches. + * Inode must be nfs-locked on entry. + */ +static int +nfs_zap_caches(struct inode *inode) +{ + int error = 0; + + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + + if (S_ISDIR(inode->i_mode)) { + nfs_invalidate_dircache(inode); + } else if (S_ISREG(inode->i_mode)) { + error = nfs_invalidate_pages(inode); + if (error < 0) { + /* If there was a problem flushing out all + * dirty pages (low on memory etc), we make sure + * the next revalidate_inode call picks up + * where we left. */ + NFS_CACHEINV(inode); + goto out; + } + invalidate_inode_pages(inode); + } +out: + return error; +} + +/* + * Wait for the inode to get unlocked. + * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING). + */ +int +__nfs_wait_on_inode(struct inode *inode, int flag) +{ + struct wait_queue wait = {current, NULL}; + int intr, error = 0; + + intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR; + + add_wait_queue(&inode->i_wait, &wait); + if (intr) { + repeat_intr: + current->state = TASK_INTERRUPTIBLE; + if (NFS_FLAGS(inode) & flag) { + if (!signal_pending(current)) { + schedule(); + goto repeat_intr; + } + error = -ERESTARTSYS; + } + } else { + repeat_nointr: + current->state = TASK_UNINTERRUPTIBLE; + if (NFS_FLAGS(inode) & flag) { + schedule(); + goto repeat_nointr; + } + } + + remove_wait_queue(&inode->i_wait, &wait); + current->state = TASK_RUNNING; + return error; +} + +/* + * Unlock the inode + */ +void +nfs_unlock_inode(struct inode *inode) +{ + if (NFS_FLAGS(inode) & NFS_INO_INVALIDATE) { + nfs_zap_caches(inode); + NFS_FLAGS(inode) &= ~NFS_INO_INVALIDATE; + } + NFS_FLAGS(inode) &= ~NFS_INO_LOCKED; + wake_up(&inode->i_wait); +} + +/* * Externally visible revalidation function */ int @@ -766,7 +853,7 @@ * to look at the size or the mtime the server sends us * too closely, as we're in the middle of modifying them. */ - if (NFS_WRITEBACK(inode)) + if (NFS_CLUSTERS(inode)) goto out; if (inode->i_size != fattr->size) { @@ -808,7 +895,7 @@ #endif fattr->mode = inode->i_mode; /* save mode */ make_bad_inode(inode); - nfs_inval(inode); + nfs_invalidate_pages(inode); inode->i_mode = fattr->mode; /* restore mode */ /* * No need to worry about unhashing the dentry, as the diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/nfs2xdr.c linux.ac/fs/nfs/nfs2xdr.c --- linux.vanilla/fs/nfs/nfs2xdr.c Wed Mar 10 21:13:10 1999 +++ linux.ac/fs/nfs/nfs2xdr.c Sun Mar 7 19:50:48 1999 @@ -5,6 +5,9 @@ * * Copyright (C) 1992, 1993, 1994 Rick Sladkey * Copyright (C) 1996 Olaf Kirch + * + * 04 Aug 1998 Ion Badulescu + * FIFO's need special handling in NFSv2 */ #define NFS_NEED_XDR_TYPES @@ -62,6 +65,7 @@ #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz #define NFS_readlinkres_sz 1+NFS_path_sz #define NFS_readres_sz 1+NFS_fattr_sz+1 +#define NFS_writeres_sz NFS_attrstat_sz #define NFS_stat_sz 1 #define NFS_readdirres_sz 1 #define NFS_statfsres_sz 1+NFS_info_sz @@ -91,7 +95,7 @@ if (*len > maxlen) return NULL; *string = (char *) p; - return p + QUADLEN(*len); + return p + XDR_QUADLEN(*len); } static inline u32 * @@ -114,6 +118,11 @@ fattr->mtime.useconds = ntohl(*p++); fattr->ctime.seconds = ntohl(*p++); fattr->ctime.useconds = ntohl(*p++); + if (fattr->type == NFCHR && fattr->rdev == NFS_FIFO_DEV) { + fattr->type = NFFIFO; + fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; + fattr->rdev = 0; + } return p; } @@ -190,6 +199,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; + unsigned int nr; int replen, buflen; p = xdr_encode_fhandle(p, args->fh); @@ -198,21 +208,25 @@ *p++ = htonl(args->count); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); -#if 1 + /* Get the number of buffers in the receive iovec */ + nr = args->nriov; + + if (nr + 2 > MAX_IOVEC) { + printk("NFS: Bad number of iov's in xdr_readargs\n"); + return -EINVAL; + } + /* set up reply iovec */ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2; buflen = req->rq_rvec[0].iov_len; req->rq_rvec[0].iov_len = replen; - req->rq_rvec[1].iov_base = args->buffer; - req->rq_rvec[1].iov_len = args->count; - req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen; - req->rq_rvec[2].iov_len = buflen - replen; + /* Copy the iovec */ + memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec)); + + req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen; + req->rq_rvec[nr+1].iov_len = buflen - replen; req->rq_rlen = args->count + buflen; - req->rq_rnr = 3; -#else - replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2; - req->rq_rvec[0].iov_len = replen; -#endif + req->rq_rnr = nr+2; return 0; } @@ -234,7 +248,7 @@ count = ntohl(*p++); hdrlen = (u8 *) p - (u8 *) iov->iov_base; recvd = req->rq_rlen - hdrlen; - if (p != iov[2].iov_base) { + if (p != iov[req->rq_rnr-1].iov_base) { /* Unexpected reply header size. Punt. * XXX: Move iovec contents to align data on page * boundary and adjust RPC header size guess */ @@ -248,8 +262,10 @@ } dprintk("RPC: readres OK count %d\n", count); +#if 0 if (count < res->count) memset((u8 *)(iov[1].iov_base+count), 0, res->count-count); +#endif return count; } @@ -261,6 +277,7 @@ static int nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) { + unsigned int nr; u32 count = args->count; p = xdr_encode_fhandle(p, args->fh); @@ -270,10 +287,18 @@ *p++ = htonl(count); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - req->rq_svec[1].iov_base = (void *) args->buffer; - req->rq_svec[1].iov_len = count; + nr = args->nriov; + + if (nr > MAX_IOVEC) { + printk("NFS: Bad number of iov's in xdr_writeargs " + "(nr %d max %d)\n", nr, MAX_IOVEC); + return -EINVAL; + } + + /* Copy the iovec */ + memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec)); req->rq_slen += count; - req->rq_snr = 2; + req->rq_snr += nr; #ifdef NFS_PAD_WRITES /* @@ -286,10 +311,10 @@ printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n", req->rq_svec[1].iov_len, req->rq_slen, count); #endif - req->rq_svec[2].iov_base = (void *) "\0\0\0"; - req->rq_svec[2].iov_len = count; + req->rq_svec[req->rq_snr].iov_base = (void *) "\0\0\0"; + req->rq_svec[req->rq_snr].iov_len = count; req->rq_slen += count; - req->rq_snr = 3; + req->rq_snr++; } #endif @@ -445,8 +470,8 @@ printk(KERN_WARNING "NFS: server %s, readdir reply truncated\n", clnt->cl_server); - printk(KERN_WARNING "NFS: nr=%d, slots=%d, len=%d\n", - nr, (end - p), len); + printk(KERN_WARNING "NFS: nr=%d, slots=%ld, len=%d\n", + nr, (long)(end - p), len); clnt->cl_flags |= NFS_CLNTF_BUFSIZE; break; } @@ -571,6 +596,15 @@ } /* + * Decode WRITE reply + */ +static int +nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) +{ + return nfs_xdr_attrstat(req, p, res->fattr); +} + +/* * Decode STATFS reply */ static int @@ -656,7 +690,7 @@ PROC(readlink, fhandle, readlinkres), PROC(read, readargs, readres), PROC(writecache, enc_void, dec_void), - PROC(write, writeargs, attrstat), + PROC(write, writeargs, writeres), PROC(create, createargs, diropres), PROC(remove, diropargs, stat), PROC(rename, renameargs, stat), diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/proc.c linux.ac/fs/nfs/proc.c --- linux.vanilla/fs/nfs/proc.c Sun Nov 8 15:06:33 1998 +++ linux.ac/fs/nfs/proc.c Mon Feb 1 22:06:55 1999 @@ -113,7 +113,9 @@ unsigned long offset, unsigned int count, void *buffer, struct nfs_fattr *fattr) { - struct nfs_readargs arg = { fhandle, offset, count, buffer }; + struct nfs_readargs arg = { fhandle, offset, count, 1, + {{ buffer, count }, {0,0}, {0,0}, {0,0}, + {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count }; int status; @@ -129,11 +131,14 @@ unsigned long offset, unsigned int count, const void *buffer, struct nfs_fattr *fattr) { - struct nfs_writeargs arg = { fhandle, offset, count, buffer }; + struct nfs_writeargs arg = { fhandle, offset, count, 1, + {{ buffer, count }, {0,0}, {0,0}, {0,0}, + {0,0}, {0,0}, {0,0}, {0,0}} }; + struct nfs_writeres res = { fattr, 0, count }; int status; dprintk("NFS call write %d @ %ld\n", count, offset); - status = rpc_call(server->client, NFSPROC_WRITE, &arg, fattr, + status = rpc_call(server->client, NFSPROC_WRITE, &arg, &res, swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0); dprintk("NFS reply read: %d\n", status); return status < 0? status : count; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/read.c linux.ac/fs/nfs/read.c --- linux.vanilla/fs/nfs/read.c Tue Dec 22 23:20:01 1998 +++ linux.ac/fs/nfs/read.c Wed Feb 3 22:22:57 1999 @@ -56,7 +56,9 @@ req->ra_args.fh = fh; req->ra_args.offset = offset; req->ra_args.count = rsize; - req->ra_args.buffer = buffer; + req->ra_args.nriov = 1; + req->ra_args.iov[0].iov_base = buffer; + req->ra_args.iov[0].iov_len = rsize; req->ra_res.fattr = &req->ra_fattr; req->ra_res.count = rsize; } @@ -159,7 +161,6 @@ free_page(address); - rpc_release_task(task); kfree(req); } @@ -230,33 +231,33 @@ dprintk("NFS: nfs_readpage (%p %ld@%ld)\n", page, PAGE_SIZE, page->offset); atomic_inc(&page->count); - set_bit(PG_locked, &page->flags); /* * Try to flush any pending writes to the file.. - * - * NOTE! Because we own the page lock, there cannot - * be any new pending writes generated at this point - * for this page (other pages can be written to). */ +again: error = nfs_wb_page(inode, page); if (error) - goto out_error; + goto out_free; + + if (test_and_set_bit(PG_locked, &page->flags)) + goto again; error = -1; if (!IS_SWAPFILE(inode) && !PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_SIZE) error = nfs_readpage_async(dentry, inode, page); - if (error >= 0) + + if (error >= 0) { + if (NFS_CONGESTED(inode)) + nfs_wait_on_congest(inode); goto out; + } error = nfs_readpage_sync(dentry, inode, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); - goto out_free; -out_error: - clear_bit(PG_locked, &page->flags); out_free: free_page(page_address(page)); out: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/write.c linux.ac/fs/nfs/write.c --- linux.vanilla/fs/nfs/write.c Wed Mar 10 21:13:10 1999 +++ linux.ac/fs/nfs/write.c Wed Mar 24 18:01:52 1999 @@ -44,36 +44,58 @@ * buffer_heads with a b_ops-> field. * * Copyright (C) 1996, 1997, Olaf Kirch + * + * Some parts + * Copyright (C) 1999, Trond Myklebust */ #include #include #include #include -#include +#include #include #include +#include #include #define NFS_PARANOIA 1 #define NFSDBG_FACILITY NFSDBG_PAGECACHE -static void nfs_wback_begin(struct rpc_task *task); -static void nfs_wback_result(struct rpc_task *task); -static void nfs_cancel_request(struct nfs_wreq *req); +/* + * NFSv3 constants + */ +#define NFS_COMMIT_DELAY (10 * HZ) /* - * Cache parameters + * This is the struct where the WRITE/COMMIT arguments go. */ -#define NFS_WRITEBACK_DELAY (10 * HZ) -#define NFS_WRITEBACK_MAX 64 +struct nfs_write_data { + struct nfs_cluster * cluster; /* cluster */ + unsigned short index; /* request index */ + unsigned short count; /* # of coalesced pages */ + struct nfs_writeargs args; /* argument struct */ + struct nfs_writeres res; /* result struct */ + struct nfs_fattr fattr; +#ifdef NFSV3 + struct nfs_writeverf verf; +#endif + unsigned int commit; /* commit id */ +}; /* - * Limit number of delayed writes + * Local function declarations */ -static int nr_write_requests = 0; -static struct rpc_wait_queue write_queue = RPC_INIT_WAITQ("write_chain"); +static void nfs_writeback_done(struct rpc_task *); +static struct nfs_write_data * nfs_write_rpcsetup(struct dentry*, + struct inode *inode, + __u64 start, __u64 end, int flags); +static void nfs_writeback_attrs(struct inode *inode, + struct nfs_fattr *fattr); +static int flush_wrequest(struct nfs_page *, int); + + /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE @@ -153,243 +175,11 @@ inode->i_ino, fattr.fileid); } + nfs_unlock_page(page); return written? written : result; } /* - * Append a writeback request to a list - */ -static inline void -append_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq) -{ - dprintk("NFS: append_write_request(%p, %p)\n", q, wreq); - rpc_append_list(q, wreq); -} - -/* - * Remove a writeback request from a list - */ -static inline void -remove_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq) -{ - dprintk("NFS: remove_write_request(%p, %p)\n", q, wreq); - rpc_remove_list(q, wreq); -} - -/* - * Find a non-busy write request for a given page to - * try to combine with. - */ -static inline struct nfs_wreq * -find_write_request(struct inode *inode, struct page *page) -{ - pid_t pid = current->pid; - struct nfs_wreq *head, *req; - - dprintk("NFS: find_write_request(%x/%ld, %p)\n", - inode->i_dev, inode->i_ino, page); - if (!(req = head = NFS_WRITEBACK(inode))) - return NULL; - do { - /* - * We can't combine with canceled requests or - * requests that have already been started.. - */ - if (req->wb_flags & (NFS_WRITE_CANCELLED | NFS_WRITE_INPROGRESS)) - continue; - - if (req->wb_page == page && req->wb_pid == pid) - return req; - - /* - * Ehh, don't keep too many tasks queued.. - */ - rpc_wake_up_task(&req->wb_task); - - } while ((req = WB_NEXT(req)) != head); - return NULL; -} - -/* - * Find and release all failed requests for this inode. - */ -int -nfs_check_failed_request(struct inode * inode) -{ - /* FIXME! */ - return 0; -} - -/* - * Try to merge adjacent write requests. This works only for requests - * issued by the same user. - */ -static inline int -update_write_request(struct nfs_wreq *req, unsigned int first, - unsigned int bytes) -{ - unsigned int rqfirst = req->wb_offset, - rqlast = rqfirst + req->wb_bytes, - last = first + bytes; - - dprintk("nfs: trying to update write request %p\n", req); - - /* not contiguous? */ - if (rqlast < first || last < rqfirst) - return 0; - - if (first < rqfirst) - rqfirst = first; - if (rqlast < last) - rqlast = last; - - req->wb_offset = rqfirst; - req->wb_bytes = rqlast - rqfirst; - req->wb_count++; - - return 1; -} - -static inline void -free_write_request(struct nfs_wreq * req) -{ - if (!--req->wb_count) - kfree(req); -} - -/* - * Create and initialize a writeback request - */ -static inline struct nfs_wreq * -create_write_request(struct file * file, struct page *page, unsigned int offset, unsigned int bytes) -{ - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - struct rpc_clnt *clnt = NFS_CLIENT(inode); - struct nfs_wreq *wreq; - struct rpc_task *task; - - dprintk("NFS: create_write_request(%s/%s, %ld+%d)\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - page->offset + offset, bytes); - - /* FIXME: Enforce hard limit on number of concurrent writes? */ - wreq = (struct nfs_wreq *) kmalloc(sizeof(*wreq), GFP_KERNEL); - if (!wreq) - goto out_fail; - memset(wreq, 0, sizeof(*wreq)); - - task = &wreq->wb_task; - rpc_init_task(task, clnt, nfs_wback_result, RPC_TASK_NFSWRITE); - task->tk_calldata = wreq; - task->tk_action = nfs_wback_begin; - - rpcauth_lookupcred(task); /* Obtain user creds */ - if (task->tk_status < 0) - goto out_req; - - /* Put the task on inode's writeback request list. */ - wreq->wb_file = file; - wreq->wb_pid = current->pid; - wreq->wb_page = page; - wreq->wb_offset = offset; - wreq->wb_bytes = bytes; - wreq->wb_count = 2; /* One for the IO, one for us */ - - append_write_request(&NFS_WRITEBACK(inode), wreq); - - if (nr_write_requests++ > NFS_WRITEBACK_MAX*3/4) - rpc_wake_up_next(&write_queue); - - return wreq; - -out_req: - rpc_release_task(task); - kfree(wreq); -out_fail: - return NULL; -} - -/* - * Schedule a writeback RPC call. - * If the server is congested, don't add to our backlog of queued - * requests but call it synchronously. - * The function returns whether we should wait for the thing or not. - * - * FIXME: Here we could walk the inode's lock list to see whether the - * page we're currently writing to has been write-locked by the caller. - * If it is, we could schedule an async write request with a long - * delay in order to avoid writing back the page until the lock is - * released. - */ -static inline int -schedule_write_request(struct nfs_wreq *req, int sync) -{ - struct rpc_task *task = &req->wb_task; - struct file *file = req->wb_file; - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - - if (NFS_CONGESTED(inode) || nr_write_requests >= NFS_WRITEBACK_MAX) - sync = 1; - - if (sync) { - sigset_t oldmask; - struct rpc_clnt *clnt = NFS_CLIENT(inode); - dprintk("NFS: %4d schedule_write_request (sync)\n", - task->tk_pid); - /* Page is already locked */ - rpc_clnt_sigmask(clnt, &oldmask); - rpc_execute(task); - rpc_clnt_sigunmask(clnt, &oldmask); - } else { - dprintk("NFS: %4d schedule_write_request (async)\n", - task->tk_pid); - task->tk_flags |= RPC_TASK_ASYNC; - task->tk_timeout = NFS_WRITEBACK_DELAY; - rpc_sleep_on(&write_queue, task, NULL, NULL); - } - - return sync; -} - -/* - * Wait for request to complete. - */ -static int -wait_on_write_request(struct nfs_wreq *req) -{ - struct file *file = req->wb_file; - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - struct rpc_clnt *clnt = NFS_CLIENT(inode); - struct wait_queue wait = { current, NULL }; - sigset_t oldmask; - int retval; - - /* Make sure it's started.. */ - if (!WB_INPROGRESS(req)) - rpc_wake_up_task(&req->wb_task); - - rpc_clnt_sigmask(clnt, &oldmask); - add_wait_queue(&req->wb_wait, &wait); - for (;;) { - current->state = TASK_INTERRUPTIBLE; - retval = 0; - if (req->wb_flags & NFS_WRITE_COMPLETE) - break; - retval = -ERESTARTSYS; - if (signalled()) - break; - schedule(); - } - remove_wait_queue(&req->wb_wait, &wait); - current->state = TASK_RUNNING; - rpc_clnt_sigunmask(clnt, &oldmask); - return retval; -} - -/* * Write a page to the server. This will be used for NFS swapping only * (for now), and we currently do this synchronously only. */ @@ -407,31 +197,56 @@ * things with a page scheduled for an RPC call (e.g. invalidate it). */ int -nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count, int sync) +nfs_updatepage(struct file *file, struct page *page, const char *buf, unsigned long offset, unsigned int count, int sync) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - struct nfs_wreq *req; - int synchronous = sync; - int retval; + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + struct nfs_page *req; + struct nfs_cluster *cluster; + int status; dprintk("NFS: nfs_updatepage(%s/%s %d@%ld, sync=%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, count, page->offset+offset, sync); - /* - * Try to find a corresponding request on the writeback queue. - * If there is one, we can be sure that this request is not - * yet being processed, because we hold a lock on the page. - * - * If the request was created by us, update it. Otherwise, - * transfer the page lock and flush out the dirty page now. - * After returning, generic_file_write will wait on the - * page and retry the update. - */ - req = find_write_request(inode, page); - if (req && req->wb_file == file && update_write_request(req, offset, count)) - goto updated; + + set_bit(PG_locked, &page->flags); + + /* + * Try to find an NFS request corresponding to this page + * and update it. + * If there is one, we can be sure it is not yet being processed + * because *we* hold the lock on the page. + * If the request was not created by the calling process (or the + * process was running under a different uid when creating it), + * we must flush it out now. Lend it the page lock and perform + * a synchronous RPC WRITE call. + */ +again: + status = nfs_update_request(file, page, offset, count, &req, flush_wrequest); + req->flags &= ~PG_UNLOCK_AFTER; + if (status == 0) { + status = req->cluster->flush(req, FLUSH_SYNC|FLUSH_WAIT|FLUSH_STABLE); + if (status >= 0) + goto again; + /* XXX: when the server returned an error, check that it is + * propagated to the proper process (it should be). + */ + } + if (status < 0) { + /* Error when allocating cluster or request, or when + * copying used data. + */ + nfs_unlock_page(page); + goto done; + } + + if (copy_from_user((u8*)page_address(page) + offset, buf, count)) { + status = -EFAULT; + clear_bit(PG_uptodate, &page->flags); + nfs_unlock_page(page); + goto done; + } /* * If wsize is smaller than page size, update and write @@ -440,241 +255,534 @@ if (NFS_SERVER(inode)->wsize < PAGE_SIZE) return nfs_writepage_sync(dentry, inode, page, offset, count); - /* Create the write request. */ - req = create_write_request(file, page, offset, count); - if (!req) - return -ENOBUFS; + if ((req->start & ~PAGE_MASK) == 0 && req->end >= (req->start + PAGE_SIZE)) + set_bit(PG_uptodate, &page->flags); - /* - * Ok, there's another user of this page with the new request.. - * The IO completion will then free the page and the dentry. - */ - atomic_inc(&page->count); - file->f_count++; + cluster = req->cluster; + status = count; /* unless we detect an error */ - /* Schedule request */ - synchronous = schedule_write_request(req, sync); + /* If the user requested a sync write, do it now */ + if (sync) { + int error; -updated: - if (req->wb_bytes == PAGE_SIZE) - set_bit(PG_uptodate, &page->flags); + error = flush_wrequest(req, FLUSH_SYNC|FLUSH_WAIT|FLUSH_STABLE); + if (error >= 0 && (error = file->f_error) < 0) + status = error; + nfs_unlock_page(page); + } else { + cluster->count++; + nfs_unlock_page(page); - retval = count; - if (synchronous) { - int status = wait_on_write_request(req); - if (status) { - nfs_cancel_request(req); - retval = status; - } else { - status = req->wb_status; - if (status < 0) - retval = status; - } + /* If we wrote past the end of the page. + * Call the strategy routine so it can send out a bunch + * of requests. + */ + if (offset + count >= PAGE_SIZE) + nfs_strategy(cluster); - if (retval < 0) - clear_bit(PG_uptodate, &page->flags); - } + release_cluster(cluster); + } - free_write_request(req); - return retval; -} + /* Cluster may have gone at this point */ + +done: + dprintk("NFS: nfs_updatepage returns %d (isize %ld)\n", + status, inode->i_size); + return status; -/* - * Cancel a write request. We always mark it cancelled, - * but if it's already in progress there's no point in - * calling rpc_exit, and we don't want to overwrite the - * tk_status field. - */ -static void -nfs_cancel_request(struct nfs_wreq *req) -{ - req->wb_flags |= NFS_WRITE_CANCELLED; - if (!WB_INPROGRESS(req)) { - rpc_exit(&req->wb_task, 0); - rpc_wake_up_task(&req->wb_task); - } } /* - * Cancel all writeback requests, both pending and in progress. + * Coalesce adjacent write requests */ static void -nfs_cancel_dirty(struct inode *inode, pid_t pid) +coalesce(struct nfs_page *req, struct nfs_write_data *data) { - struct nfs_wreq *head, *req; - - req = head = NFS_WRITEBACK(inode); - while (req != NULL) { - if (pid == 0 || req->wb_pid == pid) - nfs_cancel_request(req); - if ((req = WB_NEXT(req)) == head) - break; - } + struct nfs_cluster *cluster = req->cluster; + unsigned int wpages, index, count, total; + struct iovec *iov; + __u64 pos, offset; + + /* Fixme: put this in the server struct one day */ + wpages = NFS_SERVER(cluster->file->f_dentry->d_inode)->wsize / PAGE_SIZE; + if (wpages > NFS_WRITE_MAXIOV) + wpages = NFS_WRITE_MAXIOV; + + /* Index of first request in this write call */ + pos = req->end; + index = REQUEST_NR(req->start); + data->index = index; + data->count = 0; + offset = req->start & ~PAGE_MASK; + total = 0; + + goto first; + + while (index < CLUSTER_PAGES && data->count < wpages) { + req = cluster->request[index]; + if (req == 0 || req->start != pos + || !IS_DIRTY(req) || !nfs_lock_page(req)) + break; + first: + count = req->end - req->start; + iov = data->args.iov + data->count; + iov->iov_base = (u8 *) page_address(req->page) + offset; + iov->iov_len = count; + total += count; + data->count++; + index++; + + pos = req->end; + offset = 0; + + } + + dprintk("NFS: coalesce gathered %d pages (first %d)\n", + data->count, data->index); + data->args.nriov = data->count; + data->args.count = total; + +#if NFSV3 + /* When there aren't any other pages than those we're + * writing, just sync them to disk right away. + * This ensures that files smaller than wsize get written + * to disk in one RPC call. */ + if (data->count == cluster->pages + && (offset & CLUSTER_MASK) != 0) + data->args.stable = 1; +#endif } /* - * If we're waiting on somebody else's request - * we need to increment the counter during the - * wait so that the request doesn't disappear - * from under us during the wait.. + * Create an RPC task for the given write request and kick it. + * The page must have been locked by the caller. + * + * It may happen that the page we're passed is not marked dirty. + * This is the case if nfs_updatepage detects a conflicting request + * that has been written but not committed. + * + * This routine should always succeed when given FLUSH_SYNC. */ -static int FASTCALL(wait_on_other_req(struct nfs_wreq *)); -static int wait_on_other_req(struct nfs_wreq *req) +static int +flush_wrequest(struct nfs_page *req, int how) { - int retval; - req->wb_count++; - retval = wait_on_write_request(req); - free_write_request(req); - return retval; -} + struct nfs_write_data *data; + struct nfs_cluster *cluster; + struct dentry *dentry; + struct rpc_clnt *clnt; + struct rpc_task *task; + struct inode *inode; + int flags = 0; + u32 proc; + sigset_t oldset; -/* - * This writes back a set of requests according to the condition. - * - * If this ever gets much more convoluted, use a fn pointer for - * the condition.. - */ -#define NFS_WB(inode, cond) { int retval = 0 ; \ - do { \ - struct nfs_wreq *req = NFS_WRITEBACK(inode); \ - struct nfs_wreq *head = req; \ - if (!req) break; \ - for (;;) { \ - if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \ - if (cond) break; \ - req = WB_NEXT(req); \ - if (req == head) goto out; \ - } \ - retval = wait_on_other_req(req); \ - } while (!retval); \ -out: return retval; \ -} +#if 0 + dprintk("NFS: flush_wrequest(%d, how=%d)\n", req->nr, how); +#endif + cluster = req->cluster; + cluster->count++; + dentry = cluster->file->f_dentry; + inode = dentry->d_inode; + clnt = NFS_CLIENT(inode); + + if (!IS_DIRTY(req)) { + if (!(how & FLUSH_STABLE)) { + printk("NFS: flush_wrequest called for clean page!\n"); + how |= FLUSH_STABLE; + } + + /* Make sure we mark the page dirty so that our book- + * keeping is consistent */ + nfs_mark_request_dirty(cluster, req); + } + + /* Set the initial flags for the task. PRIORITY means that + * the RPC code will set need_resched whenever the task becomes + * runnable. ASYNC means that the task will be asynchronously. + * In addition to that, this means that rpc_allocate will not + * block when it can't get any memory. Without ASYNC, rpc_new_task + * may block while allocating memory. + * That's bad for swapping, but good for general sanity. + * + * (We also set ASYNC later when we see that the caller doesn't + * want to wait for the task's completion). + */ + flags = (how & FLUSH_SYNC)? RPC_TASK_PRIORITY : RPC_TASK_ASYNC; + + rpc_clnt_sigmask(clnt, &oldset); + + task = rpc_new_task(clnt, nfs_writeback_done, flags); + data = nfs_write_rpcsetup(dentry, inode, req->start, req->end, flags); + + if (task == NULL || data == NULL) { + /* We failed to allocate the task. To avoid any hassle + * in the upper layers, release the page lock if we own it. */ + if (req->flags & PG_UNLOCK_AFTER) { + req->flags &= ~PG_UNLOCK_AFTER; + nfs_unlock_page(req->page); + } + if (task) + rpc_release_task(task); + release_cluster(cluster); + rpc_clnt_sigunmask(clnt, &oldset); + return -ENOMEM; + } + req->task = task; + + /* Unless the caller wants to wait on the request, make the RPC + * task async now. */ + if (!(how & FLUSH_WAIT)) + task->tk_flags |= RPC_TASK_ASYNC; + +#ifdef NFSV3 + /* Set up the argument struct */ + data->args.stable = (how & FLUSH_STABLE)? 1 : 0; +#endif + data->cluster = cluster; -int -nfs_wb_all(struct inode *inode) -{ - NFS_WB(inode, 1); + /* Put one or more pages of data into call */ + coalesce(req, data); + cluster->pending += data->count; + + /* Hack for NFSv2 as it never returns the size written */ + data->res.count = data->args.count; + + /* Finalize the task. */ + task->tk_calldata = data; + + task->tk_cred = cluster->cred; + rpcauth_holdcred(task); + +#ifdef NFSV3 + if (NFS_PROTO(inode)->version == 3) + proc = NFS3PROC_WRITE; + else +#endif + proc = NFSPROC_WRITE; + + dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n", + task->tk_pid, + dentry->d_parent->d_name.name, + dentry->d_name.name, + data->args.count, data->args.nriov); + rpc_call_setup(task, proc, &data->args, &data->res, 0); + rpc_execute(task); + + rpc_clnt_sigunmask(clnt, &oldset); + return 0; } + /* - * Write back all requests on one page - we do this before reading it. + * Allocate the argument/result storage required for the RPC call. */ -int -nfs_wb_page(struct inode *inode, struct page *page) +static struct nfs_write_data * +nfs_write_rpcsetup(struct dentry * dentry, struct inode *inode, + __u64 start, __u64 end, int flags) { - NFS_WB(inode, req->wb_page == page); + struct nfs_write_data *data; + void *ptr; + + if (!(ptr = rpc_allocate(flags, sizeof(*data)))) + return NULL; + + /* Set up the RPC argument and reply structs */ + data = (struct nfs_write_data *) ptr; + data->args.fh = NFS_FH(dentry); + data->res.fattr = &data->fattr; + data->res.count = end - start; + data->args.offset = start; + data->args.count = end - start; +#ifdef NFSV3 + data->res.verf = &data->verf; + data->fattr.valid = 0; + data->verf.committed = 1; +#endif + + return data; } + /* - * Write back all pending writes from one file descriptor.. + * This function is called when the WRITE call is complete. */ -int -nfs_wb_file(struct inode *inode, struct file *file) +static void +nfs_writeback_done(struct rpc_task *task) { - NFS_WB(inode, req->wb_file == file); -} + struct nfs_cluster *cluster; + struct nfs_write_data *data; + struct nfs_writeargs *argp; + struct nfs_writeres *resp; + struct nfs_page *req; + struct inode *inode; + unsigned int nr, count; + + dprintk("NFS: %4d nfs_writeback_done (status %d)\n", + task->tk_pid, task->tk_status); + + if (!(data = (struct nfs_write_data *) task->tk_calldata)) { + printk("NFS: no write data for RPC task?!\n"); + return; + } + + cluster = data->cluster; + argp = &data->args; + resp = &data->res; + inode = cluster->file->f_dentry->d_inode; + + /* Update attributes as result of writeback. */ + nfs_writeback_attrs(inode, resp->fattr); + +#ifdef RPC_DEBUG + for (nr = data->index, count = data->count; count--; nr++) { + if ((req = cluster->request[nr]) != NULL) + continue; + printk("NFS: request disappeared in write callback.\n"); + task->tk_status = -EIO; + break; + } +#endif + /* We can't handle that yet but we check for it nevertheless */ + if (resp->count < argp->count && task->tk_status >= 0) { + static unsigned long complain = 0; + if (time_before(complain, jiffies)) { + printk("NFS: Server wrote less than requested.\n"); + complain = jiffies + 300 * HZ; + } + /* Can't do anything about it right now except throw + * an error. */ + task->tk_status = -EIO; + } + + + if (task->tk_status < 0) { + /* A WRITE error occurred. Report the error back to the + * application. */ + cluster->file->f_error = task->tk_status; + for (nr = data->index, count = data->count; count--; nr++) { + if ((req = cluster->request[nr]) != NULL) + clear_bit(PG_uptodate, &req->page->flags); + } + goto out_release; + } + +#ifdef NFSV3 + /* If data has been committed, we're all done. + * We always take this branch for NFSv2 as the XDR routine always + * sets the committed flag. + */ + if (resp->verf->committed) + goto out_release; + + if (data->args.stable) { + /* We tried a write call, but the server did not + * commit data to stable storage even though we + * requested it. + */ + static unsigned long complain = 0; + + if (time_before(complain, jiffies)) { + printk(KERN_NOTICE + "NFS: faulty NFSv3 server %s\n", + NFS_SERVER(inode)->hostname); + complain = jiffies + 300 * HZ; + } + goto out_release; + } + + /* If there was an nfs_invalidate_pages, re-send request with + * stable flag turned on. */ + for (nr = data->index, count = data->count; count--; nr++) { + req = cluster->request[nr]; + if (req && (req->flags & PG_INVALIDATE_AFTER)) + goto out_resend; + } + + /* Normal NFSv3 operation. Save the verifier, + * and unlock the page. Don't release the request. + */ + rverf = resp->verf->verifier; + for (nr = data->index, count = data->count; count--; nr++) { + if (!(req = cluster->request[nr])) + continue; + req->verifier[0] = rverf[0]; + req->verifier[1] = rverf[1]; + if (req->flags & PG_UNLOCK_AFTER) { + req->flags &= ~PG_UNLOCK_AFTER; + nfs_unlock_page(req->page); + } + /* Update commit sequence number. + * This implicitly marks the page clean + */ + req->commit = cluster->sequence; + req->timeout = jiffies + NFS_COMMIT_DELAY; + if (time_before(req->timeout, cluster->nextscan)) + cluster->nextscan = req->timeout; + req->task = 0; + } + goto out_norelease; + +out_resend: + /* Re-send all pages, this time requesting a write to stable + * storage. + */ + dprintk("NFS: %4d re-initiated write call\n", task->tk_pid); + data->args.stable = 1; + rpc_restart_call(task); + return; +#endif -void -nfs_inval(struct inode *inode) -{ - nfs_cancel_dirty(inode,0); +out_release: + /* Release requests */ + for (nr = data->index, count = data->count; count--; nr++) { + if (!(req = cluster->request[nr])) + continue; + req->task = NULL; + nfs_release_request(req); + } + +out_norelease: + /* Cluster book-keeping. */ + cluster->dirty -= data->count; + + /* + * If all write requests for that cluster have completed, commit. + */ + cluster->pending -= data->count; +#ifdef NFSV3 + if (cluster->dirty == 0 && cluster->pages != 0) + commit_cluster(cluster); +#endif + + kfree(task->tk_calldata); + release_cluster(cluster); } +#ifdef NFSV3 /* - * The following procedures make up the writeback finite state machinery: - * - * 1. Try to lock the page if not yet locked by us, - * set up the RPC call info, and pass to the call FSM. + * COMMIT call returned */ static void -nfs_wback_begin(struct rpc_task *task) +nfs_commit_done(struct rpc_task *task) { - struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata; - struct page *page = req->wb_page; - struct file *file = req->wb_file; - struct dentry *dentry = file->f_dentry; - - dprintk("NFS: %4d nfs_wback_begin (%s/%s, status=%d flags=%x)\n", - task->tk_pid, dentry->d_parent->d_name.name, - dentry->d_name.name, task->tk_status, req->wb_flags); - - task->tk_status = 0; - - /* Setup the task struct for a writeback call */ - req->wb_flags |= NFS_WRITE_INPROGRESS; - req->wb_args.fh = NFS_FH(dentry); - req->wb_args.offset = page->offset + req->wb_offset; - req->wb_args.count = req->wb_bytes; - req->wb_args.buffer = (void *) (page_address(page) + req->wb_offset); - - rpc_call_setup(task, NFSPROC_WRITE, &req->wb_args, &req->wb_fattr, 0); - - return; + struct nfs_write_data *data; + struct nfs_cluster *cluster; + struct nfs_writeres *resp; + struct nfs_page *req; + unsigned int nr; + int stable = 0; + + dprintk("NFS: %4d nfs_commit_done (status %d)\n", + task->tk_pid, task->tk_status); + + data = (struct nfs_write_data *) task->tk_calldata; + cluster = data->cluster; + resp = &data->res; + + if (task->tk_status < 0) { + /* A COMMIT error occurred. Just reschedule all pages + * for sync writing. */ + for (nr = 0; nr < CLUSTER_PAGES; nr++) { + req = cluster->request[nr]; + if (req && req->commit <= data->commit) { + mark_request_dirty(cluster, req); + } + } + stable |= FLUSH_STABLE; + } else { + /* Okay, COMMIT succeeded, apparently. Check the verifier + * returned by the server against all stored verfs. */ + u32 *rverf = resp->verf->verifier; + + dprintk("NFS: %4d scan committed (clu=%ld seq=%d)\n", + task->tk_pid, cluster->_id, cluster->sequence); + for (nr = 0; nr < CLUSTER_PAGES; nr++) { + if (!(req = cluster->request[nr])) + continue; + + dprintk("NFS: inspect req %d (seq %d)\n", + req->nr, req->commit); + + /* Ignore dirty pages and pages written to + * the server after this commit call. + * (not that req->commit is 0xFFFF if page dirty) + */ + if (req->commit > data->commit) + continue; + + if (!memcmp(req->verifier, rverf, 8)) { + /* We have a match */ + nfs_release_request(req); + } else { + /* We have a mismatch. Write the page again, + * this time to stable storage right away */ + dprintk("NFS: verf mismatch...\n"); + mark_request_dirty(cluster, req); + stable |= FLUSH_STABLE; + } + } + } + if (cluster->committing == data->commit) + cluster->committing = 0; + wake_up(&cluster->wait); + + /* We must update the attributes _after_ inspecting all + * pages. Otherwise bad/incomplete attributes might force + * a full cache flush. + */ + nfs_writeback_attrs(cluster->inode, resp->fattr); + + if (cluster->dirty) + sync_cluster(cluster, stable); + release_cluster(cluster); + kfree(task->tk_calldata); } +#endif /* - * 2. Collect the result + * Handle the file attributes returned in a WRITE response. + * Beware: Normally, the reply to an async write requests arrives + * after the user process has written a lot more data to the + * cache, hence the file size returned by the server is completely + * bogus. We therefore fake the returned file size. + * + * Also, the pre-op inode size returned by the server reflects the + * current length of the file on the server, not our local copy. Hence + * NFSv3 will always flush the caches, potentially sending off + * huge amounts of data to stable storage. Therefore, we also fake + * the returned pre-op size. + * + * The inode number check tries to avoid a possible + * Solaris 2.4/2.5 server bug. */ static void -nfs_wback_result(struct rpc_task *task) +nfs_writeback_attrs(struct inode *inode, struct nfs_fattr *fattr) { - struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata; - struct file *file = req->wb_file; - struct page *page = req->wb_page; - int status = task->tk_status; - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - - dprintk("NFS: %4d nfs_wback_result (%s/%s, status=%d, flags=%x)\n", - task->tk_pid, dentry->d_parent->d_name.name, - dentry->d_name.name, status, req->wb_flags); - - /* Set the WRITE_COMPLETE flag, but leave WRITE_INPROGRESS set */ - req->wb_flags |= NFS_WRITE_COMPLETE; - req->wb_status = status; - - if (status < 0) { - req->wb_flags |= NFS_WRITE_INVALIDATE; - file->f_error = status; - } else if (!WB_CANCELLED(req)) { - struct nfs_fattr *fattr = &req->wb_fattr; - /* Update attributes as result of writeback. - * Beware: when UDP replies arrive out of order, we - * may end up overwriting a previous, bigger file size. - * - * When the file size shrinks we cancel all pending - * writebacks. - */ - if (fattr->mtime.seconds >= inode->i_mtime) { - if (fattr->size < inode->i_size) - fattr->size = inode->i_size; - - /* possible Solaris 2.5 server bug workaround */ - if (inode->i_ino == fattr->fileid) { - /* - * We expect these values to change, and - * don't want to invalidate the caches. - */ - inode->i_size = fattr->size; - inode->i_mtime = fattr->mtime.seconds; - nfs_refresh_inode(inode, fattr); - } - else - printk("nfs_wback_result: inode %ld, got %u?\n", - inode->i_ino, fattr->fileid); - } - } - rpc_release_task(task); + if (fattr->size < inode->i_size) + fattr->size = inode->i_size; +#ifdef NFSV3 + if ((fattr->valid & NFS_ATTR_FATTR) + && inode->i_ino != fattr->fileid) + return; + + /* Try to fake wcc data for NFSv2 in order to avoid + * invalidating the caches. */ + if (NFS_PROTO(inode)->version == 2 + && (fattr->valid & NFS_ATTR_FATTR)) { + fattr->valid |= NFS_ATTR_WCC; + fattr->pre_mtime = NFS_OLDMTIME(inode); + } + fattr->pre_size = inode->i_size; +#else + if (inode->i_ino != fattr->fileid) + return; - if (WB_INVALIDATE(req)) - clear_bit(PG_uptodate, &page->flags); - - __free_page(page); - remove_write_request(&NFS_WRITEBACK(inode), req); - nr_write_requests--; - fput(req->wb_file); + inode->i_size = fattr->size; + inode->i_mtime = fattr->mtime.seconds; +#endif - wake_up(&req->wb_wait); - free_write_request(req); + /* Now refresh the inode */ + nfs_refresh_inode(inode, fattr); } + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfs3xdr.c linux.ac/fs/nfsd/nfs3xdr.c --- linux.vanilla/fs/nfsd/nfs3xdr.c Sun Nov 8 15:06:38 1998 +++ linux.ac/fs/nfsd/nfs3xdr.c Tue Feb 23 21:14:53 1999 @@ -667,6 +667,7 @@ *p++ = xdr_zero; /* file id (64 bit) */ *p++ = htonl((u32) ino); *p++ = htonl((u32) namlen); /* name length & name */ + p[slen - 1] = 0 /* Dont leak kernel data */ memcpy(p, name, namlen); p += slen; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsfh.c linux.ac/fs/nfsd/nfsfh.c --- linux.vanilla/fs/nfsd/nfsfh.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/nfsd/nfsfh.c Wed Mar 24 18:01:39 1999 @@ -4,6 +4,7 @@ * NFS server file handle treatment. * * Copyright (C) 1995, 1996 Olaf Kirch + * Portions Copyright (C) 1999 G. Allen Morris III */ #include @@ -21,6 +22,7 @@ #define NFSDDBG_FACILITY NFSDDBG_FH #define NFSD_PARANOIA 1 /* #define NFSD_DEBUG_VERBOSE 1 */ +/* #define NFSD_DEBUG_VERY_VERBOSE 1 */ extern unsigned long max_mapnr; @@ -50,15 +52,16 @@ static int nfsd_nr_fixups = 0; static int nfsd_nr_paths = 0; #define NFSD_MAX_PATHS 500 -#define NFSD_MAX_FIXUPAGE 60*HZ +#define NFSD_MAX_FIXUPS 500 +#define NFSD_MAX_FIXUP_AGE 30*HZ struct nfsd_fixup { struct list_head lru; - ino_t dir; + unsigned long reftime; + ino_t dirino; ino_t ino; kdev_t dev; - struct dentry *dentry; - unsigned long reftime; + ino_t new_dirino; }; struct nfsd_path { @@ -70,7 +73,8 @@ char name[1]; }; -static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino) +static struct nfsd_fixup * +find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino) { struct list_head *tmp = fixup_head.next; @@ -78,32 +82,43 @@ struct nfsd_fixup *fp; fp = list_entry(tmp, struct nfsd_fixup, lru); +#ifdef NFSD_DEBUG_VERY_VERBOSE +printk("fixup %lu %lu, %lu %lu %s %s\n", + fp->ino, ino, + fp->dirino, dirino, + kdevname(fp->dev), kdevname(dev)); +#endif if (fp->ino != ino) continue; - if (fp->dir != dir) + if (fp->dirino != dirino) continue; if (fp->dev != dev) continue; + fp->reftime = jiffies; list_del(tmp); list_add(tmp, &fixup_head); - fp->reftime = jiffies; return fp; } return NULL; } /* - * Save the dentry pointer from a successful lookup. + * Save the dirino from a rename. */ -static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh) +void +add_to_rename_cache(ino_t new_dirino, + kdev_t dev, ino_t dirino, ino_t ino) { struct nfsd_fixup *fp; - fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev), - u32_to_ino_t(fh->fh_dirino), - u32_to_ino_t(fh->fh_ino)); + if (dirino == new_dirino) + return; + + fp = find_cached_lookup(dev, + dirino, + ino); if (fp) { - fp->dentry = dentry; + fp->new_dirino = new_dirino; return; } @@ -114,19 +129,30 @@ */ fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL); if (fp) { - fp->dir = u32_to_kdev_t(fh->fh_dirino); - fp->ino = u32_to_ino_t(fh->fh_ino); - fp->dev = u32_to_ino_t(fh->fh_dev); - fp->dentry = dentry; - fp->reftime = jiffies; + fp->dirino = dirino; + fp->ino = ino; + fp->dev = dev; + fp->new_dirino = new_dirino; list_add(&fp->lru, &fixup_head); nfsd_nr_fixups++; } } +/* + * Save the dentry pointer from a successful lookup. + */ + static void free_fixup_entry(struct nfsd_fixup *fp) { list_del(&fp->lru); +#ifdef NFSD_DEBUG_VERY_VERBOSE +printk("free_rename_entry: %lu->%lu %lu/%s\n", + fp->dirino, + fp->new_dirino, + fp->ino, + kdevname(fp->dev), + (jiffies - fp->reftime)); +#endif kfree(fp); nfsd_nr_fixups--; } @@ -211,9 +237,9 @@ if (new) { new->users = 0; new->reftime = jiffies; - new->ino = inode->i_ino; - new->dev = inode->i_dev; - result = copy_path(new->name, dentry, len); + new->ino = inode->i_ino; + new->dev = inode->i_dev; + result = copy_path(new->name, dentry, len); if (!result) goto retry; list_add(&new->lru, &path_inuse); @@ -300,8 +326,8 @@ int result = 0; buf->sequence++; -#ifdef NFSD_DEBUG_VERBOSE -printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name); +#ifdef NFSD_DEBUG_VERY_VERBOSE +printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name); #endif if (buf->sequence == 2) { buf->dirino = ino; @@ -310,7 +336,7 @@ if (dirent->ino == ino) { dirent->len = len; memcpy(dirent->name, name, len); - dirent->name[len] = 0; + dirent->name[len] = '\0'; buf->found = 1; result = -1; } @@ -520,7 +546,8 @@ struct dentry *dentry = empty->dentry; #ifdef NFSD_DEBUG_VERBOSE -printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n", +printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n", +(cache == NFSD_FILE_CACHE) ? "file" : "dir", dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino); #endif empty->dentry = NULL; /* no dentry */ @@ -575,11 +602,10 @@ */ static void expire_old(int cache, int age) { - struct list_head *tmp; struct fh_entry *fhe; int i; -#ifdef NFSD_DEBUG_VERBOSE +#ifdef NFSD_DEBUG_VERY_VERBOSE printk("expire_old: expiring %s older than %d\n", (cache == NFSD_FILE_CACHE) ? "file" : "dir", age); #endif @@ -592,12 +618,12 @@ } /* - * Remove old entries from the patch-up cache. + * Trim the fixup cache ... */ - while ((tmp = fixup_head.prev) != &fixup_head) { + while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) { struct nfsd_fixup *fp; - fp = list_entry(tmp, struct nfsd_fixup, lru); - if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE) + fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru); + if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE) break; free_fixup_entry(fp); } @@ -756,6 +782,8 @@ */ static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh) { +/* FIXME: this must use the dev/ino/dir_ino triple. */ +#if 0 struct fh_entry * fhe; fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL); @@ -793,6 +821,7 @@ return dentry; } out: +#endif return NULL; } @@ -841,13 +870,12 @@ dentry = NULL; out: return dentry; - } /* * Search the fix-up list for a dentry from a prior lookup. */ -static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh) +static ino_t nfsd_cached_lookup(struct knfs_fh *fh) { struct nfsd_fixup *fp; @@ -855,8 +883,8 @@ u32_to_ino_t(fh->fh_dirino), u32_to_ino_t(fh->fh_ino)); if (fp) - return fp->dentry; - return NULL; + return fp->new_dirino; + return 0; } void @@ -915,8 +943,12 @@ static struct dentry * find_fh_dentry(struct knfs_fh *fh) { + struct super_block *sb; struct dentry *dentry, *parent; + struct inode * inode; + struct list_head *lst; int looked_up = 0, retry = 0; + ino_t dirino; /* * Stage 1: Look for the dentry in the short-term fhcache. @@ -926,50 +958,67 @@ nfsdstats.fh_cached++; goto out; } - /* - * Stage 2: Attempt to validate the dentry in the file handle. + * Stage 2: Attempt to find the inode. */ - dentry = fh->fh_dcookie; + sb = get_super(fh->fh_dev); + if (NULL == sb) { + printk("find_fh_dentry: No SuperBlock for device %s.", + kdevname(fh->fh_dev)); + dentry = NULL; + goto out; + } + + dirino = u32_to_ino_t(fh->fh_dirino); + inode = iget(sb, fh->fh_ino); recheck: - if (nfsd_d_validate(dentry)) { - struct inode * dir = dentry->d_parent->d_inode; + if (!inode) { + dprintk(": No inode found.\n"); + goto out_three; + } + for (lst = inode->i_dentry.next; + lst != &inode->i_dentry; + lst = lst->next) { + dentry = list_entry(lst, struct dentry, d_alias); + +/* if we are looking up a directory then we don't need the parent! */ + if (!dentry || + !dentry->d_parent || + !dentry->d_parent->d_inode) { +printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino); + continue; + } + if (dentry->d_parent->d_inode->i_ino != dirino) + continue; - if (dir->i_ino == u32_to_ino_t(fh->fh_dirino) && - dir->i_dev == u32_to_kdev_t(fh->fh_dev)) { - struct inode * inode = dentry->d_inode; - /* - * NFS file handles must always have an inode, - * so we won't accept a negative dentry. - */ - if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) { - dget(dentry); + dget(dentry); + iput(inode); #ifdef NFSD_DEBUG_VERBOSE -printk("find_fh_dentry: validated %s/%s, ino=%ld\n", -dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino); + printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n", + retry ? " Renamed" : "", + dentry->d_parent->d_name.name, + dentry->d_name.name, + dentry->d_parent->d_inode->i_ino, + dirino); #endif - if (!retry) - nfsdstats.fh_valid++; - else { - nfsdstats.fh_fixup++; -#ifdef NFSD_DEBUG_VERBOSE -printk("find_fh_dentry: retried validation successful\n"); -#endif - } - goto out; - } - } - } + goto out; + } /* for inode->i_dentry */ /* - * Before proceeding to a lookup, check whether we cached a - * prior lookup. If so, try to validate that dentry ... + * Before proceeding to a lookup, check for a rename */ - if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) { + if (!retry && (dirino = nfsd_cached_lookup(fh))) { + dprintk("find_fh_dentry: retry with %lu\n", dirino); retry = 1; goto recheck; } + iput(inode); + + dprintk("find_fh_dentry: dirino not found %lu\n", dirino); + +out_three: + /* * Stage 3: Look up the dentry based on the inode and parent inode * numbers. This should work for all Unix-like filesystems. @@ -982,7 +1031,7 @@ struct inode * inode = dentry->d_inode; #ifdef NFSD_DEBUG_VERBOSE printk("find_fh_dentry: looked up %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); #endif if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) { nfsdstats.fh_lookup++; @@ -990,7 +1039,7 @@ } #ifdef NFSD_PARANOIA printk("find_fh_dentry: %s/%s lookup mismatch!\n", -dentry->d_parent->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); #endif dput(dentry); } @@ -1014,17 +1063,13 @@ * Stage 5: Search the whole volume. */ #ifdef NFSD_PARANOIA -printk("find_fh_dentry: %s, %u/%u not found -- need full search!\n", -kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_dirino, fh->fh_ino); +printk("find_fh_dentry: %s/%u dir/%u not found!\n", + kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino); #endif dentry = NULL; nfsdstats.fh_stale++; out: - if (looked_up && dentry) { - add_to_lookup_cache(dentry, fh); - } - expire_all(); return dentry; @@ -1045,8 +1090,12 @@ struct inode *inode; u32 error = 0; - dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n", - fh->fh_xdev, fh->fh_xino, fh->fh_dcookie); + dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n", + kdevname(fh->fh_xdev), + fh->fh_xino, + kdevname(fh->fh_dev), + fh->fh_ino, + fh->fh_dirino); if (fhp->fh_dverified) goto check_type; @@ -1055,8 +1104,8 @@ */ error = nfserr_stale; exp = exp_get(rqstp->rq_client, - u32_to_kdev_t(fh->fh_xdev), - u32_to_ino_t(fh->fh_xino)); + u32_to_kdev_t(fh->fh_xdev), + u32_to_ino_t(fh->fh_xino)); if (!exp) /* export entry revoked */ goto out; @@ -1078,8 +1127,13 @@ */ error = nfserr_noent; dentry = find_fh_dentry(fh); - if (!dentry) + if (!dentry) { + goto out; + } + if (IS_ERR(dentry)) { + error = nfserrno(-PTR_ERR(dentry)); goto out; + } /* * Note: it's possible the returned dentry won't be the one in the @@ -1101,6 +1155,21 @@ check_type: dentry = fhp->fh_dentry; inode = dentry->d_inode; + error = nfserr_stale; +/* is to keep from breaking the nfs filehandles until june */ + +#define FIXME_IN_JUNE_1999 1 + + if (inode->i_generation != fh->fh_generation) { + dprintk("fh_verify: Bad version %u %u %u\n", + inode->i_ino, + inode->i_generation, + fh->fh_generation); +#ifdef FIXME_IN_JUNE_1999 + if (fh->fh_dcookie == 0xfeebbaca) +#endif + goto out; + } exp = fhp->fh_export; if (type > 0 && (inode->i_mode & S_IFMT) != type) { error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir; @@ -1116,8 +1185,8 @@ */ error = 0; if (fh->fh_dev != fh->fh_xdev) { - printk("fh_verify: Security: export on other device" - " (%d, %d).\n", fh->fh_dev, fh->fh_xdev); + printk("fh_verify: Security: export on other device (%s, %s).\n", + kdevname(fh->fh_dev), kdevname(fh->fh_xdev)); error = nfserr_stale; } else if (exp->ex_dentry != dentry) { struct dentry *tdentry = dentry; @@ -1127,13 +1196,13 @@ if (exp->ex_dentry == tdentry) break; /* executable only by root and we can't be root */ - if (current->fsuid && - !(tdentry->d_inode->i_uid && - (tdentry->d_inode->i_mode & S_IXUSR)) && - !(tdentry->d_inode->i_gid && - (tdentry->d_inode->i_mode & S_IXGRP)) && - !(tdentry->d_inode->i_mode & S_IXOTH) && - (exp->ex_flags & NFSEXP_ROOTSQUASH)) { + if (current->fsuid + && !(tdentry->d_inode->i_uid + && (tdentry->d_inode->i_mode & S_IXUSR)) + && !(tdentry->d_inode->i_gid + && (tdentry->d_inode->i_mode & S_IXGRP)) + && !(tdentry->d_inode->i_mode & S_IXOTH) + && (exp->ex_flags & NFSEXP_ROOTSQUASH)) { error = nfserr_stale; dprintk("fh_verify: no root_squashed access.\n"); } @@ -1189,9 +1258,10 @@ } fh_init(fhp); - fhp->fh_handle.fh_dcookie = dentry; + fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca; if (inode) { fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino); + fhp->fh_handle.fh_generation = inode->i_generation; } fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino); fhp->fh_handle.fh_dev = kdev_t_to_u32(parent->d_inode->i_dev); @@ -1223,6 +1293,7 @@ if (!inode) goto out_negative; fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino); + fhp->fh_handle.fh_generation = inode->i_generation; out: return; @@ -1335,7 +1406,7 @@ } /* - * Free the dentry and path caches. + * Free the rename and path caches. */ void nfsd_fh_free(void) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsproc.c linux.ac/fs/nfsd/nfsproc.c --- linux.vanilla/fs/nfsd/nfsproc.c Tue Feb 23 14:21:34 1999 +++ linux.ac/fs/nfsd/nfsproc.c Wed Mar 24 18:01:39 1999 @@ -270,7 +270,7 @@ rdev = (dev_t) size; if (type != S_IFBLK && type != S_IFCHR) { rdev = 0; - } else if (type == S_IFCHR && size == ~(u32) 0) { + } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { /* If you think you've seen the worst, grok this. */ attr->ia_mode = S_IFIFO | mode; type = S_IFIFO; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfssvc.c linux.ac/fs/nfsd/nfssvc.c --- linux.vanilla/fs/nfsd/nfssvc.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/nfsd/nfssvc.c Wed Mar 24 18:01:39 1999 @@ -5,7 +5,7 @@ * * Authors: Olaf Kirch (okir@monad.swb.de) * - * Copyright (C) 1995, 1996, 1997 Olaf Kirch + * Copyright (C) 1995-1999 Olaf Kirch */ #define __NO_VERSION__ @@ -72,15 +72,16 @@ if (serv == NULL) goto out; - error = svc_makesock(serv, IPPROTO_UDP, port); - if (error < 0) - goto failure; - #if 0 /* Don't even pretend that TCP works. It doesn't. */ error = svc_makesock(serv, IPPROTO_TCP, port); if (error < 0) goto failure; #endif + + error = svc_makesock(serv, IPPROTO_UDP, port); + if (error < 0) + goto failure; + while (nrservs--) { error = svc_create_thread(nfsd, serv); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsxdr.c linux.ac/fs/nfsd/nfsxdr.c --- linux.vanilla/fs/nfsd/nfsxdr.c Sun Nov 8 15:06:38 1998 +++ linux.ac/fs/nfsd/nfsxdr.c Wed Feb 24 01:17:51 1999 @@ -449,6 +449,7 @@ *p++ = xdr_one; /* mark entry present */ *p++ = htonl((u32) ino); /* file id */ *p++ = htonl((u32) namlen); /* name length & name */ + p[slen - 1] = 0; memcpy(p, name, namlen); p += slen; cd->offset = p; /* remember pointer */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/vfs.c linux.ac/fs/nfsd/vfs.c --- linux.vanilla/fs/nfsd/vfs.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/nfsd/vfs.c Wed Mar 24 18:01:39 1999 @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -554,7 +553,7 @@ /* clear setuid/setgid flag after write */ if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) { struct iattr ia; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; ia.ia_valid = ATTR_MODE; ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); @@ -658,10 +657,6 @@ if (IS_ERR(dchild)) goto out_nfserr; fh_compose(resfhp, fhp->fh_export, dchild); - /* Lock the parent and check for errors ... */ - err = fh_lock_parent(fhp, dchild); - if (err) - goto out; } else { dchild = resfhp->fh_dentry; if (!fhp->fh_locked) @@ -670,6 +665,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name); } + err = nfserr_exist; + if (dchild->d_inode) + goto out; + if (!fhp->fh_locked) { + /* Lock the parent and check for errors ... */ + err = fh_lock_parent(fhp, dchild); + if (err) + goto out; + } /* * Make sure the child dentry is still negative ... */ @@ -695,8 +699,7 @@ case S_IFCHR: case S_IFBLK: /* The client is _NOT_ required to do security enforcement */ - if(!capable(CAP_SYS_ADMIN)) - { + if(!capable(CAP_SYS_ADMIN)) { err = -EPERM; goto out; } @@ -759,7 +762,7 @@ struct inode *inode; struct iattr newattrs; int err; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC); if (err) @@ -899,6 +902,7 @@ /* Compose the fh so the dentry will be freed ... */ out_compose: fh_compose(resfhp, fhp->fh_export, dnew); + out: return err; @@ -1091,6 +1095,15 @@ DQUOT_DROP(tdir); nfsd_double_up(&tdir->i_sem, &fdir->i_sem); + + if (!err && odentry->d_inode) { + add_to_rename_cache(tdir->i_ino, + odentry->d_inode->i_dev, + fdir->i_ino, + odentry->d_inode->i_ino); + } else { + printk(": no inode in rename or err: %d.\n", err); + } dput(ndentry); out_dput_old: @@ -1132,15 +1145,12 @@ err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; - if (!rdentry->d_inode) { dput(rdentry); err = nfserr_noent; goto out; } - expire_by_dentry(rdentry); - if (type != S_IFDIR) { /* It's UNLINK */ @@ -1154,11 +1164,10 @@ fh_unlock(fhp); dput(rdentry); - + expire_by_dentry(rdentry); } else { /* It's RMDIR */ /* See comments in fs/namei.c:do_rmdir */ - rdentry->d_count++; nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem); if (!fhp->fh_pre_mtime) @@ -1183,6 +1192,7 @@ goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) write_inode_now(dirp); + out: return err; @@ -1314,7 +1324,7 @@ { struct inode *inode = dentry->d_inode; int err; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; if (acc == MAY_NOP) return 0; @@ -1334,7 +1344,7 @@ inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); #endif #ifndef CONFIG_NFSD_SUN - if (dentry->d_mounts != dentry) { + if (dentry->d_mounts != dentry) { return nfserr_perm; } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/attr.c linux.ac/fs/ntfs/attr.c --- linux.vanilla/fs/ntfs/attr.c Sun Jan 3 03:52:02 1999 +++ linux.ac/fs/ntfs/attr.c Tue Feb 16 17:17:04 1999 @@ -19,7 +19,8 @@ /* Look if an attribute already exists in the inode, and if not, create it */ static int -new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found) +new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found, + int do_search ) { int do_insert=0; int i; @@ -28,15 +29,17 @@ { int n=min(namelen,ino->attrs[i].namelen); int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n); - /* - * We assume that each attribute can be uniquely - * identified by inode - * number, attribute type and attribute name. - */ - if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ - *found=1; - *pos=i; - return 0; + if( do_search ) { + /* + * We assume that each attribute can be uniquely + * identified by inode + * number, attribute type and attribute name. + */ + if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ + *found=1; + *pos=i; + return 0; + } } /* attributes are ordered by type, then by name */ if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){ @@ -48,17 +51,21 @@ /* re-allocate space */ if(ino->attr_count % 8 ==0) { - ntfs_attribute* old=ino->attrs; - ino->attrs = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* + ntfs_attribute* new; + new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* sizeof(ntfs_attribute)); - if(old){ - ntfs_memcpy(ino->attrs,old,ino->attr_count*sizeof(ntfs_attribute)); - ntfs_free(old); + if( !new ) + return ENOMEM; + if( ino->attrs ) { + ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) ); + ntfs_free( ino->attrs ); } + ino->attrs = new; } if(do_insert) ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)* sizeof(ntfs_attribute)); + ino->attr_count++; ino->attrs[i].type=type; ino->attrs[i].namelen=namelen; @@ -86,14 +93,16 @@ { /* (re-)allocate space if necessary */ if(attr->d.r.len % 8 == 0) { - ntfs_runlist* old; - old=attr->d.r.runlist; - attr->d.r.runlist=ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); - if(old) { - ntfs_memcpy(attr->d.r.runlist,old,attr->d.r.len + ntfs_runlist* new; + new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); + if( !new ) + return; + if( attr->d.r.runlist ) { + ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len *sizeof(ntfs_runlist)); - ntfs_free(old); + ntfs_free( attr->d.r.runlist ); } + attr->d.r.runlist = new; } if(attr->d.r.len>cnum) ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum, @@ -208,8 +217,10 @@ v=attr->d.data; if(newsize){ attr->d.data=ntfs_malloc(newsize); - if(!attr->d.data) + if(!attr->d.data) { + ntfs_free(v); return ENOMEM; + } if(newsize>oldsize) ntfs_bzero((char*)attr->d.data+oldsize, newsize-oldsize); @@ -279,12 +290,20 @@ if(aname){ namelen=strlen(aname); name=ntfs_malloc(2*namelen); + if( !name ) + return ENOMEM; ntfs_ascii2uni(name,aname,namelen); }else{ name=0; namelen=0; } - new_attr(ino,anum,name,namelen,&i,&found); + + error = new_attr(ino,anum,name,namelen,&i,&found,1); + if( error ) { + ntfs_free( name ); + return error; + } + if(found){ ntfs_free(name); return EEXIST; @@ -309,6 +328,10 @@ }else attr->indexed=0; attr->d.data=ntfs_malloc(dsize); + + if( !attr->d.data ) + return ENOMEM; + ntfs_memcpy(attr->d.data,data,dsize); return 0; } @@ -366,6 +389,7 @@ int namelen; void *data; ntfs_attribute *attr; + int error; type = NTFS_GETU32(attrdata); namelen = NTFS_GETU8(attrdata+9); @@ -376,15 +400,30 @@ { /* 1 Unicode character fits in 2 bytes */ name=ntfs_malloc(2*namelen); + if( !name ) + return ENOMEM; + ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen); } - new_attr(ino,type,name,namelen,&i,&found); + + error = new_attr(ino,type,name,namelen,&i,&found,1); + if( error ) { + if( name ) ntfs_free( name ); + return error; + } + /* We can have in one inode two attributes with type 0x00000030 (File Name) and without name */ if(found && /*FIXME*/type!=ino->vol->at_file_name) { ntfs_process_runs(ino,ino->attrs+i,attrdata); return 0; + } else if( found ) { + /* Don't understand the above, but I know it leaks memory below + as it overwrites a found entry without freeing it. So here we + call new_attr again but this time ask it to always allocate a + new entry */ + new_attr(ino,type,name,namelen,&i,&found,0); } attr=ino->attrs+i; attr->resident=NTFS_GETU8(attrdata+8)==0; @@ -395,6 +434,8 @@ attr->size=NTFS_GETU16(attrdata+0x10); data=attrdata+NTFS_GETU16(attrdata+0x14); attr->d.data = (void*)ntfs_malloc(attr->size); + if( !attr->d.data ) + return ENOMEM; ntfs_memcpy(attr->d.data,data,attr->size); attr->indexed=NTFS_GETU16(attrdata+0x16); }else{ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/dir.c linux.ac/fs/ntfs/dir.c --- linux.vanilla/fs/ntfs/dir.c Sun Jan 3 03:52:02 1999 +++ linux.ac/fs/ntfs/dir.c Tue Feb 16 17:17:04 1999 @@ -166,6 +166,8 @@ int nr_fix = s1/vol->blocksize+1; int hsize; char *record=ntfs_malloc(s1); + if( !record ) + return ENOMEM; ntfs_bzero(record,s1); /* magic */ ntfs_memcpy(record,"INDX",4); @@ -395,8 +397,9 @@ goto out; } index = ntfs_malloc(ino->vol->index_recordsize); - if(!index) - goto out; + if(!index) { + error = ENOMEM; goto out; + } walk.dir = ino; walk.block = -1; walk.result = walk.new_entry = 0; @@ -485,6 +488,9 @@ int oldblock; ntfs_io io; + if( !record ) + return ENOMEM; + io.fn_put=ntfs_put; io.param=record; io.size=length; @@ -683,6 +689,9 @@ char *root=ntfs_malloc(length); ntfs_io io; + if( !root ) + return ENOMEM; + io.fn_put=ntfs_put; io.param=root; io.size=length; @@ -747,6 +756,8 @@ /* are we still in the index root */ if(*p_high==0){ buf=ntfs_malloc(length=vol->mft_recordsize); + if( !buf ) + return ENOMEM; io.fn_put=ntfs_put; io.param=buf; io.size=length; @@ -762,6 +773,8 @@ }else{ /* we are in an index record */ length=ino->u.index.recordsize; buf=ntfs_malloc(length); + if( !buf ) + return ENOMEM; io.fn_put=ntfs_put; io.param=buf; io.size=length; @@ -821,6 +834,9 @@ return 0; } buf=ntfs_malloc(length=attr->size); + if( !buf ) + return ENOMEM; + io.param=buf; io.size=length; error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/fs.c linux.ac/fs/ntfs/fs.c --- linux.vanilla/fs/ntfs/fs.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/ntfs/fs.c Mon Mar 22 15:44:50 1999 @@ -387,6 +387,8 @@ if(error) return error; item=ntfs_malloc(ITEM_SIZE); + if( !item ) + return ENOMEM; /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; @@ -709,6 +711,7 @@ #ifdef NTFS_IN_LINUX_KERNEL ino=&inode->u.ntfs_i; #else + /* FIXME: check for ntfs_malloc failure */ ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); inode->u.generic_ip=ino; #endif @@ -818,6 +821,7 @@ struct statfs fs; struct inode *mft; ntfs_volume *vol; + int error; ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n"); vol=NTFS_SB2VOL(sb); @@ -825,7 +829,9 @@ fs.f_type=NTFS_SUPER_MAGIC; fs.f_bsize=vol->clustersize; - fs.f_blocks=ntfs_get_volumesize(NTFS_SB2VOL(sb)); + error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks ); + if( error ) + return error; fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap); fs.f_bavail=fs.f_bfree; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/inode.c linux.ac/fs/ntfs/inode.c --- linux.vanilla/fs/ntfs/inode.c Fri Feb 26 02:53:20 1999 +++ linux.ac/fs/ntfs/inode.c Tue Mar 16 19:03:03 1999 @@ -10,6 +10,7 @@ #include "ntfstypes.h" #include "struct.h" #include "inode.h" +#include "ntfsendian.h" #include #include "macros.h" @@ -165,13 +166,16 @@ /* (re-)allocate space if necessary */ if(ino->record_count % 8==0) { - int *old=ino->records; - ino->records=ntfs_malloc((ino->record_count+8)*sizeof(int)); - if(old) { + int *new; + new = ntfs_malloc((ino->record_count+8)*sizeof(int)); + if( !new ) + return; + if( ino->records ) { for(i=0;irecord_count;i++) - ino->records[i]=old[i]; - ntfs_free(old); + new[i] = ino->records[i]; + ntfs_free( ino->records ); } + ino->records = new; } ino->records[ino->record_count]=mftno; ino->record_count++; @@ -179,8 +183,10 @@ do{ type=NTFS_GETU32(it); len=NTFS_GETU32(it+4); - if(type!=-1) + if(type!=-1) { + /* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */ ntfs_insert_attribute(ino,it); + } it+=len; }while(type!=-1); /* attribute list ends with type -1 */ } @@ -195,6 +201,8 @@ int last_mft=-1; int len=*plen; mft=ntfs_malloc(ino->vol->mft_recordsize); + if( !mft ) + return ENOMEM; while(len>8) { l=NTFS_GETU16(alist+4); @@ -239,6 +247,8 @@ return; } buf=ntfs_malloc(1024); + if( !buf ) + return; delta=0; for(offset=0;datasize;datasize-=len) { @@ -271,6 +281,8 @@ ino->i_number=inum; ino->vol=vol; ino->attr=buf=ntfs_malloc(vol->mft_recordsize); + if( !buf ) + return ENOMEM; error=ntfs_read_mft_record(vol,inum,ino->attr); if(error){ ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum); @@ -1108,6 +1120,8 @@ /* work out the size */ size = 0x42 + 2 * length; data = ntfs_malloc(size); + if( !data ) + return ENOMEM; ntfs_bzero(data,size); /* search for a position */ @@ -1191,7 +1205,7 @@ { ntfs_io io; int error; - ntfs_u8 buffer[1]; + ntfs_u8 buffer[2]; ntfs_volume* vol=dir->vol; int byte,bit; @@ -1230,7 +1244,7 @@ */ /* get the sequence number */ io.param = buffer; - io.size = 0x10; + io.size = 2; error = ntfs_read_attr(vol->mft_ino, vol->at_data, 0, result->i_number*vol->mft_recordsize+0x10,&io); if(error) @@ -1238,10 +1252,17 @@ result->sequence_number=NTFS_GETU16(buffer)+1; result->vol=vol; result->attr=ntfs_malloc(vol->mft_recordsize); + if( !result->attr ) + return ENOMEM; result->attr_count=0; result->attrs=0; result->record_count=1; result->records=ntfs_malloc(8*sizeof(int)); + if( !result->records ) { + ntfs_free( result->attr ); + result->attr = NULL; + return ENOMEM; + } result->records[0]=result->i_number; error=add_mft_header(result); if(error) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/super.c linux.ac/fs/ntfs/super.c --- linux.vanilla/fs/ntfs/super.c Sun Jan 3 03:52:02 1999 +++ linux.ac/fs/ntfs/super.c Tue Feb 16 17:17:04 1999 @@ -113,6 +113,8 @@ ntfs_io io; #define UPCASE_LENGTH 256 upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH); + if( !upcase->vol->upcase ) + return; upcase->vol->upcase_length = UPCASE_LENGTH; io.fn_put=ntfs_put; io.fn_get=0; @@ -246,11 +248,22 @@ return 0; } -int ntfs_get_volumesize(ntfs_volume *vol) +/* + * Writes the volume size into vol_size. Returns 0 if successful + * or error. + */ +int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size ) { ntfs_io io; - char *cluster0=ntfs_malloc(vol->clustersize); ntfs_u64 size; + char *cluster0; + + if( !vol_size ) + return EFAULT; + + cluster0=ntfs_malloc(vol->clustersize); + if( !cluster0 ) + return ENOMEM; io.fn_put=ntfs_put; io.fn_get=ntfs_get; @@ -262,7 +275,8 @@ ntfs_free(cluster0); /* FIXME: more than 2**32 cluster */ /* FIXME: gcc will emit udivdi3 if we don't truncate it */ - return ((unsigned int)size)/vol->clusterfactor; + *vol_size = ((unsigned long)size)/vol->clusterfactor; + return 0; } static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0}; @@ -460,6 +474,8 @@ int start; bits=ntfs_malloc(2048); + if( !bits ) + return ENOMEM; io.fn_put=ntfs_put; io.fn_get=ntfs_get; io.param=bits; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/super.h linux.ac/fs/ntfs/super.h --- linux.vanilla/fs/ntfs/super.h Sun Jan 3 03:52:02 1999 +++ linux.ac/fs/ntfs/super.h Tue Feb 16 17:17:04 1999 @@ -10,7 +10,7 @@ #define ALLOC_REQUIRE_SIZE 2 int ntfs_get_free_cluster_count(ntfs_inode *bitmap); -int ntfs_get_volumesize(ntfs_volume *vol); +int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size ); int ntfs_init_volume(ntfs_volume *vol,char *boot); int ntfs_load_special_files(ntfs_volume *vol); int ntfs_release_volume(ntfs_volume *vol); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/support.c linux.ac/fs/ntfs/support.c --- linux.vanilla/fs/ntfs/support.c Sun Jan 3 03:52:02 1999 +++ linux.ac/fs/ntfs/support.c Tue Feb 16 17:17:04 1999 @@ -246,6 +246,10 @@ if(!(vol->nct & nct_uni_xlate))goto inval; /* realloc */ buf=ntfs_malloc(*out_len+3); + if( !buf ) { + ntfs_free( result ); + return ENOMEM; + } memcpy(buf,result,o); ntfs_free(result); result=buf; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/open.c linux.ac/fs/open.c --- linux.vanilla/fs/open.c Wed Mar 24 10:55:24 1999 +++ linux.ac/fs/open.c Wed Mar 24 11:04:47 1999 @@ -682,9 +682,13 @@ { struct files_struct * files = current->files; int fd, error; - + +repeat: error = -EMFILE; - fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + + fd = find_next_zero_bit(files->open_fds, + current->files->max_fdset, + files->next_fd); /* * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. @@ -692,10 +696,27 @@ if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; - /* Check here for fd > files->max_fds to do dynamic expansion */ + /* Do we need to expand the fdset array? */ + if (fd >= current->files->max_fdset) { + error = expand_fdset(files, 0); + if (!error) + goto repeat; + goto out; + } + + /* + * Check whether we need to expand the fd array. + */ + if (fd >= files->max_fds) { + error = expand_fd_array(files, 0); + if (!error) + goto repeat; + goto out; + } - FD_SET(fd, &files->open_fds); - FD_CLR(fd, &files->close_on_exec); + FD_SET(fd, files->open_fds); + FD_CLR(fd, files->close_on_exec); + files->next_fd = fd + 1; #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { @@ -706,12 +727,18 @@ error = fd; out: +#ifdef FDSET_DEBUG + if (error < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", error); +#endif return error; } inline void put_unused_fd(unsigned int fd) { - FD_CLR(fd, ¤t->files->open_fds); + FD_CLR(fd, current->files->open_fds); + if (fd < current->files->next_fd) + current->files->next_fd = fd; } asmlinkage int sys_open(const char * filename, int flags, int mode) @@ -811,8 +838,8 @@ struct files_struct * files = current->files; files->fd[fd] = NULL; put_unused_fd(fd); - FD_CLR(fd, &files->close_on_exec); - error = filp_close(filp, files); + FD_CLR(fd, files->close_on_exec); + error = filp_close(filp, files); } unlock_kernel(); return error; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/inode.c linux.ac/fs/proc/inode.c --- linux.vanilla/fs/proc/inode.c Sun Nov 8 15:06:32 1998 +++ linux.ac/fs/proc/inode.c Tue Feb 23 21:25:44 1999 @@ -38,13 +38,9 @@ return; } - if (!--de->count) { - if (de->deleted) { - printk("de_put: deferred delete of %s\n", - de->name); - free_proc_entry(de); - } - } + /* free entries that had deletion deferred */ + if (!--de->count && de->deleted) + free_proc_entry(de); } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/link.c linux.ac/fs/proc/link.c --- linux.vanilla/fs/proc/link.c Sun Nov 8 15:06:32 1998 +++ linux.ac/fs/proc/link.c Wed Mar 24 18:14:32 1999 @@ -158,7 +158,7 @@ path = tmp; } else { path = d_path(dentry, tmp, PAGE_SIZE); - len = tmp + PAGE_SIZE - path; + len = tmp + PAGE_SIZE - 1 - path; } if (len < buflen) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/mem.c linux.ac/fs/proc/mem.c --- linux.vanilla/fs/proc/mem.c Sun Nov 8 15:06:32 1998 +++ linux.ac/fs/proc/mem.c Wed Dec 30 01:32:41 1998 @@ -2,6 +2,7 @@ * linux/fs/proc/mem.c * * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1998 Andi Kleen */ #include @@ -16,15 +17,9 @@ #include #include -/* - * mem_write isn't really a good idea right now. It needs - * to check a lot more: if the process we try to write to - * dies in the middle right now, mem_write will overwrite - * kernel memory.. This disables it altogether. - */ -#define mem_write NULL - -static int check_range(struct mm_struct * mm, unsigned long addr, int count) +/* Must be called with the mm semaphore held. */ +static int check_range(struct mm_struct * mm, unsigned long addr, int count, + int flags) { struct vm_area_struct *vma; int retval; @@ -34,15 +29,16 @@ return -EACCES; if (vma->vm_start > addr) return -EACCES; - if (!(vma->vm_flags & VM_READ)) + if ((vma->vm_flags & flags) != flags) return -EACCES; + while ((retval = vma->vm_end - addr) < count) { struct vm_area_struct *next = vma->vm_next; if (!next) break; if (vma->vm_end != next->vm_start) break; - if (!(next->vm_flags & VM_READ)) + if ((next->vm_flags & flags) != flags) break; vma = next; } @@ -53,24 +49,74 @@ static struct task_struct * get_task(int pid) { - struct task_struct * tsk = current; + struct task_struct * tsk; - if (pid != tsk->pid) { - tsk = find_task_by_pid(pid); + tsk = find_task_by_pid(pid); - /* Allow accesses only under the same circumstances - * that we would allow ptrace to work. - */ - if (tsk) { - if (!(tsk->flags & PF_PTRACED) - || tsk->state != TASK_STOPPED - || tsk->p_pptr != current) - tsk = NULL; - } + /* + * Allow accesses only under the same circumstances + * that we would allow ptrace to work. + */ + if (tsk && tsk!=current) { + if (!(tsk->flags & PF_PTRACED) + || tsk->state != TASK_STOPPED + || tsk->p_pptr != current) + tsk = NULL; } return tsk; } +struct mm_struct *get_mm(int pid, int *err) +{ + struct task_struct *tsk; + struct mm_struct *mm = NULL; + + read_lock(&tasklist_lock); + tsk = get_task(pid); + *err = -ESRCH; + if (tsk) { + *err = -EINVAL; + /* + * Access of current vm: it could be special cased, + * but is it worth it? + */ + if ((mm = tsk->mm) == current->mm) + mm = NULL; + else { + mmget(mm); + *err = 0; + } + } + read_unlock(&tasklist_lock); + return mm; +} + +static int make_page_present(int pid, unsigned long addr, struct mm_struct *mm, + int write_flag) +{ + struct task_struct *tsk; + struct vm_area_struct *vma; + + /* + * Caller may have slept, thus recheck. + */ + read_lock(&tasklist_lock); + tsk = get_task(pid); + read_unlock(&tasklist_lock); + if (!tsk || tsk->mm != mm) + return -ESRCH; + + /* + * The kernel lock ensures that the task does not go away. + * find_vma should not fail here because the mm semaphore is held. + */ + vma = find_vma(mm, addr); + if (!handle_mm_fault(tsk, vma, addr, write_flag)) + return -ENOMEM; + + return 0; +} + static ssize_t mem_read(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -79,25 +125,30 @@ pmd_t *page_middle; pte_t pte; char * page; - struct task_struct * tsk; unsigned long addr; - char *tmp; + char *dst; ssize_t scount, i; + int err; + struct mm_struct *mm; + + mm = get_mm(inode->i_ino >> 16, &err); + if (!mm) + return err; + err = 0; - read_lock(&tasklist_lock); - tsk = get_task(inode->i_ino >> 16); - read_unlock(&tasklist_lock); /* FIXME: This should really be done only afetr not using tsk any more!!! */ - if (!tsk) - return -ESRCH; addr = *ppos; - scount = check_range(tsk->mm, addr, count); - if (scount < 0) - return scount; - tmp = buf; + down(&mm->mmap_sem); + scount = check_range(mm, addr, count, VM_READ); + if (scount < 0) + err = scount; + dst = buf; while (scount > 0) { - if (signal_pending(current)) + /* XXX Is a current->need_resched check needed too? */ + if (signal_pending(current)) { + err = -ERESTARTSYS; break; - page_dir = pgd_offset(tsk->mm,addr); + } + page_dir = pgd_offset(mm,addr); if (pgd_none(*page_dir)) break; if (pgd_bad(*page_dir)) { @@ -114,24 +165,42 @@ break; } pte = *pte_offset(page_middle,addr); - if (!pte_present(pte)) + if (!pte_present(pte)) { + err = make_page_present(inode->i_ino >> 16, addr, mm, 0); + if (err) + break; + continue; + } + /* check_range should have catched this, but be paranoid */ + if (!pte_read(pte)) { + err = -EACCES; break; + } + page = (char *) pte_page(pte) + (addr & ~PAGE_MASK); + if (MAP_NR(page) >= max_mapnr) + break; i = PAGE_SIZE-(addr & ~PAGE_MASK); if (i > scount) i = scount; - copy_to_user(tmp, page, i); + /* Assumes that current->mm != mm */ + err = copy_to_user(dst, page, i); + if (err) { + err = -EFAULT; + break; + } + addr += i; - tmp += i; + dst += i; scount -= i; } + up(&mm->mmap_sem); + mmput(mm); *ppos = addr; - return tmp-buf; + return err ? err : dst-buf; } -#ifndef mem_write - -static ssize_t mem_write(struct file * file, char * buf, +static ssize_t mem_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; @@ -139,20 +208,29 @@ pmd_t *page_middle; pte_t pte; char * page; - struct task_struct * tsk; + struct mm_struct *mm; unsigned long addr; - char *tmp; + const char *src; long i; + int err; addr = *ppos; - tsk = get_task(inode->i_ino >> 16); - if (!tsk) - return -ESRCH; - tmp = buf; + mm = get_mm(inode->i_ino >> 16, &err); + if (!mm) + return err; + + down(&mm->mmap_sem); + count = check_range(mm, addr, count, VM_WRITE); + if (count < 0) + err = count; + + src = buf; while (count > 0) { - if (signal_pending(current)) + if (signal_pending(current)) { + err = -ERESTARTSYS; break; - page_dir = pgd_offset(tsk,addr); + } + page_dir = pgd_offset(mm,addr); if (pgd_none(*page_dir)) break; if (pgd_bad(*page_dir)) { @@ -169,29 +247,40 @@ break; } pte = *pte_offset(page_middle,addr); - if (!pte_present(pte)) - break; - if (!pte_write(pte)) - break; + if (!pte_present(pte) || !pte_write(pte)) { + err = make_page_present(inode->i_ino>>16, addr, mm, 1); + if (err) + break; + continue; + } + page = (char *) pte_page(pte) + (addr & ~PAGE_MASK); + if (MAP_NR(page) > max_mapnr) + break; + i = PAGE_SIZE-(addr & ~PAGE_MASK); if (i > count) i = count; - copy_from_user(page, tmp, i); + /* Assumes current->mm != mm */ + if (copy_from_user(page, src, i)) { + err = -EFAULT; + break; + } + set_pte(pte_offset(page_middle,addr), pte_mkdirty(pte)); + flush_tlb_mm(mm); + addr += i; - tmp += i; + src += i; count -= i; } + up(&mm->mmap_sem); + mmput(mm); *ppos = addr; - if (tmp != buf) - return tmp-buf; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; + if (err) + return err; + return src-buf; } -#endif - static long long mem_lseek(struct file * file, long long offset, int orig) { switch (orig) { @@ -206,93 +295,124 @@ } } -/* - * This isn't really reliable by any means.. - */ +static inline struct mm_struct *grab_mm(int pid, int *err) +{ + struct mm_struct *mm; + /* + * Mmaping its own memory is a highly dubious feature, + * it would be better to forbid it, because it violates some + * assumptions elsewhere in the MM system + */ + if (pid == current->pid) { + mm = current->mm; + mmget(mm); + } else { + mm = get_mm(pid, err); + } + return mm; +} + int mem_mmap(struct file * file, struct vm_area_struct * vma) { - struct task_struct *tsk; pgd_t *src_dir, *dest_dir; pmd_t *src_middle, *dest_middle; pte_t *src_table, *dest_table; unsigned long stmp, dtmp, mapnr; struct vm_area_struct *src_vma = NULL; struct inode *inode = file->f_dentry->d_inode; - - /* Get the source's task information */ - - tsk = get_task(inode->i_ino >> 16); - - if (!tsk) - return -ESRCH; + struct mm_struct *mm; + int err; - /* Ensure that we have a valid source area. (Has to be mmap'ed and - have valid page information.) We can't map shared memory at the - moment because working out the vm_area_struct & nattach stuff isn't - worth it. */ + mm = grab_mm(inode->i_ino >> 16, &err); + if (!mm) + return err; + + /* + * This relies on the kernel lock to make sure that there are + * no races between the aquisition of the current mm lock in the caller + * and the locking here. + */ + if (mm != current->mm) + down(&mm->mmap_sem); + + /* + * Ensure that we have a valid source area: has to be mmap'ed and + * have valid page information. Mapping shared memory is not supported + * ATM because working out the vm_area_struct & nattach stuff isn't + * worth it. + */ - src_vma = tsk->mm->mmap; + src_vma = mm->mmap; stmp = vma->vm_offset; while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) { while (src_vma && stmp > src_vma->vm_end) src_vma = src_vma->vm_next; + err = -EINVAL; if (!src_vma || (src_vma->vm_flags & VM_SHM)) - return -EINVAL; + goto out; - src_dir = pgd_offset(tsk->mm, stmp); + src_dir = pgd_offset(mm, stmp); if (pgd_none(*src_dir)) - return -EINVAL; + goto out; if (pgd_bad(*src_dir)) { printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir)); - return -EINVAL; + goto out; } src_middle = pmd_offset(src_dir, stmp); if (pmd_none(*src_middle)) - return -EINVAL; + goto out; if (pmd_bad(*src_middle)) { printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle)); - return -EINVAL; + goto out; } src_table = pte_offset(src_middle, stmp); if (pte_none(*src_table)) - return -EINVAL; + goto out; if (stmp < src_vma->vm_start) { if (!(src_vma->vm_flags & VM_GROWSDOWN)) - return -EINVAL; + goto out; if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur) - return -EINVAL; + goto out; } stmp += PAGE_SIZE; } - src_vma = tsk->mm->mmap; + src_vma = mm->mmap; stmp = vma->vm_offset; dtmp = vma->vm_start; flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end); flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end); + while (dtmp < vma->vm_end) { while (src_vma && stmp > src_vma->vm_end) src_vma = src_vma->vm_next; - src_dir = pgd_offset(tsk->mm, stmp); + src_dir = pgd_offset(mm, stmp); src_middle = pmd_offset(src_dir, stmp); src_table = pte_offset(src_middle, stmp); dest_dir = pgd_offset(current->mm, dtmp); + + /* Next two might sleep */ dest_middle = pmd_alloc(dest_dir, dtmp); + err = -ENOMEM; if (!dest_middle) - return -ENOMEM; + break; dest_table = pte_alloc(dest_middle, dtmp); if (!dest_table) - return -ENOMEM; + break; - if (!pte_present(*src_table)) - handle_mm_fault(tsk, src_vma, stmp, 1); + if (!pte_present(*src_table) || + ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table)) ) { + err = make_page_present(inode->i_ino >> 16, stmp, mm, + vma->vm_flags & VM_WRITE); + if (err) + break; + } - if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table)) - handle_mm_fault(tsk, src_vma, stmp, 1); + err = 0; set_pte(src_table, pte_mkdirty(*src_table)); set_pte(dest_table, *src_table); @@ -306,7 +426,12 @@ flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end); flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end); - return 0; + +out: + if (mm != current->mm) + up(&mm->mmap_sem); + mmput(mm); + return err; } static struct file_operations proc_mem_operations = { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/qnx4/file.c linux.ac/fs/qnx4/file.c --- linux.vanilla/fs/qnx4/file.c Fri Nov 13 01:37:16 1998 +++ linux.ac/fs/qnx4/file.c Mon Mar 1 14:24:09 1999 @@ -33,8 +33,6 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -#include -#include static int qnx4_readpage(struct file *file, struct page *page); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/select.c linux.ac/fs/select.c --- linux.vanilla/fs/select.c Sun Jan 24 19:55:38 1999 +++ linux.ac/fs/select.c Sun Jan 24 20:31:02 1999 @@ -107,7 +107,7 @@ /* handle last in-complete long-word first */ set = ~(~0UL << (n & (__NFDBITS-1))); n /= __NFDBITS; - open_fds = current->files->open_fds.fds_bits+n; + open_fds = current->files->open_fds->fds_bits+n; max = 0; if (set) { set &= BITS(fds, n); @@ -264,19 +264,31 @@ if ((unsigned long) sec < MAX_SELECT_SECONDS) { timeout = ROUND_UP(usec, 1000000/HZ); timeout += sec * (unsigned long) HZ; + + if (timeout < 0) { + ret = -EINVAL; + goto out_nofds; + } } } ret = -EINVAL; - if (n < 0 || n > KFDS_NR) + + /* + * We ought to optimise the n=0 case - it is used enough.. + */ + + if (n < 0 || n > current->files->max_fdset + 1) goto out_nofds; + /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), * since we used fdset we need to allocate memory in units of - * long-words. + * long-words. */ + ret = -ENOMEM; - size = FDS_BYTES(n); + size = (n + 8 * sizeof(long) - 1) / (8 * sizeof(long)) * sizeof(long); bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; @@ -379,13 +391,13 @@ lock_kernel(); /* Do a sanity check on nfds ... */ err = -EINVAL; - if (nfds > NR_OPEN) + if (nfds > current->files->max_fds) goto out; if (timeout) { - /* Carefula about overflow in the intermediate values */ + /* Careful about overflow in the intermediate values */ if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) - timeout = (unsigned long)(timeout*HZ+999)/1000+1; + timeout = (timeout*HZ+999)/1000+1; else /* Negative or overflow */ timeout = MAX_SCHEDULE_TIMEOUT; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/smbfs/file.c linux.ac/fs/smbfs/file.c --- linux.vanilla/fs/smbfs/file.c Tue Feb 23 14:21:34 1999 +++ linux.ac/fs/smbfs/file.c Sat Feb 27 02:12:39 1999 @@ -144,7 +144,7 @@ result = smb_proc_write(dentry, offset, wsize, buffer); if (result < 0) - break; + goto io_error; /* N.B. what if result < wsize?? */ #ifdef SMBFS_PARANOIA if (result < wsize) @@ -162,7 +162,15 @@ inode->i_size = offset; inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE; } while (count); + +out: + smb_unlock_page(page); return written ? written : result; + +io_error: + /* Must mark the page invalid after I/O error */ + clear_bit(PG_uptodate, &page->flags); + goto out; } /* @@ -182,20 +190,27 @@ set_bit(PG_locked, &page->flags); atomic_inc(&page->count); result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE); - smb_unlock_page(page); free_page(page_address(page)); return result; } static int -smb_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count, int sync) +smb_updatepage(struct file *file, struct page *page, const char *buf, unsigned long offset, unsigned int count, int sync) { struct dentry *dentry = file->f_dentry; + set_bit(PG_locked, &page->flags); + pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld, sync=%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, count, page->offset+offset, sync); + if (copy_from_user((u8*)page_address(page) + offset, buf, count)) { + clear_bit(PG_uptodate, &page->flags); + smb_unlock_page(page); + return -EFAULT; + } + return smb_writepage_sync(dentry, page, offset, count); } @@ -215,8 +230,8 @@ if (status) { #ifdef SMBFS_PARANOIA -printk("smb_file_read: %s/%s validation failed, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, status); +printk("smb_file_read: %s/%s validation failed, error=%ld\n", +dentry->d_parent->d_name.name, dentry->d_name.name, (long)status); #endif goto out; } @@ -275,8 +290,8 @@ if (result) { #ifdef SMBFS_PARANOIA -printk("smb_file_write: %s/%s validation failed, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, result); +printk("smb_file_write: %s/%s validation failed, error=%ld\n", +dentry->d_parent->d_name.name, dentry->d_name.name, (long)result); #endif goto out; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/CHANGES linux.ac/fs/sysv/CHANGES --- linux.vanilla/fs/sysv/CHANGES Thu Dec 31 18:10:46 1998 +++ linux.ac/fs/sysv/CHANGES Mon Mar 1 00:18:47 1999 @@ -43,3 +43,6 @@ * inode.c (detect_sysv4): Added detection of expanded s_type field (0x10, 0x20 and 0x30). Forced read-only access in this case. +Sun Feb 21 1999 JSN + * all + Added V7 Unix filesystem support. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/INTRO linux.ac/fs/sysv/INTRO --- linux.vanilla/fs/sysv/INTRO Sun Nov 8 15:06:35 1998 +++ linux.ac/fs/sysv/INTRO Mon Mar 1 00:18:47 1999 @@ -4,6 +4,7 @@ Xenix FS Doug Evans June 1992 SystemV FS Paul B. Monday March-June 1993 Coherent FS B. Haible June 1993 + V7 FS Jonathan Naylor February 1999 and was merged together in July 1993. @@ -13,12 +14,14 @@ - Minix FS 0x81 Linux/Minix - Xenix FS ?? - SystemV FS ?? + - V7 FS ?? - Coherent FS 0x08 AIX bootable * Size of a block or zone (data allocation unit on disk) - Minix FS 1024 - Xenix FS 1024 (also 512 ??) - SystemV FS 1024 (also 512 and 2048) + - V7 FS 512 - Coherent FS 512 * General layout: all have one boot block, one super block and @@ -30,6 +33,7 @@ - Minix FS little endian 0 1 - Xenix FS little endian 0 1 - SystemV FS little endian 0 1 + - V7 FS PDP-11 0 1 - Coherent FS little endian 0 1 Of course, this affects only the file system, not the data of files on it! @@ -37,28 +41,30 @@ - Minix FS little endian 0 1 2 3 - Xenix FS little endian 0 1 2 3 - SystemV FS little endian 0 1 2 3 + - V7 FS PDP-11 2 3 0 1 - Coherent FS PDP-11 2 3 0 1 Of course, this affects only the file system, not the data of files on it! * Inode on disk: "short", 0 means non-existent, the root dir ino is: - - Minix FS 1 - - Xenix FS, SystemV FS, Coherent FS 2 + - Minix FS 1 + - Xenix FS, SystemV FS, V7 FS, Coherent FS 2 * Maximum number of hard links to a file: - Minix FS 250 - Xenix FS ?? - SystemV FS ?? + - V7 FS ?? - Coherent FS >=10000 * Free inode management: - Minix FS a bitmap - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS There is a cache of a certain number of free inodes in the super-block. When it is exhausted, new free inodes are found using a linear search. * Free block management: - Minix FS a bitmap - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS Free blocks are organized in a "free list". Maybe a misleading term, since it is not true that every free block contains a pointer to the next free block. Rather, the free blocks are organized in chunks @@ -71,6 +77,7 @@ - Minix FS block 1 = bytes 1024..2047 - Xenix FS block 1 = bytes 1024..2047 - SystemV FS bytes 512..1023 + - V7 FS block 1 = bytes 512..1023 - Coherent FS block 1 = bytes 512..1023 * Super-block layout: @@ -99,7 +106,7 @@ unsigned long s_free_zones; unsigned short s_free_inodes; short s_dinfo[4]; -- Xenix FS only - unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only + unsigned short s_interleave_m,s_interleave_n; -- V7 FS and Coherent FS only char s_fname[6]; char s_fpack[6]; then they differ considerably: @@ -115,7 +122,7 @@ long s_type; Coherent FS unsigned long s_unique; - Note that Coherent FS has no magic. + Note that V7 FS and Coherent FS have no magic number. * Inode layout: - Minix FS @@ -126,7 +133,7 @@ unsigned char i_gid; unsigned char i_nlinks; unsigned short i_zone[7+1+1]; - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS unsigned short i_mode; unsigned short i_nlink; unsigned short i_uid; @@ -142,7 +149,7 @@ 7 direct blocks 1 indirect block (pointers to blocks) 1 double-indirect block (pointer to pointers to blocks) - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS 10 direct blocks 1 indirect block (pointers to blocks) 1 double-indirect block (pointer to pointers to blocks) @@ -152,13 +159,14 @@ - Minix FS 32 32 - Xenix FS 64 16 - SystemV FS 64 16 + - V7 FS 64 8 - Coherent FS 64 8 * Directory entry on disk - Minix FS unsigned short inode; char name[14/30]; - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS unsigned short inode; char name[14]; @@ -166,12 +174,14 @@ - Minix FS 16/32 64/32 - Xenix FS 16 64 - SystemV FS 16 64 + - V7 FS 16 32 - Coherent FS 16 32 * How to implement symbolic links such that the host fsck doesn't scream: - Minix FS normal - Xenix FS kludge: as regular files with chmod 1000 - SystemV FS ?? + - V7 FS none - Coherent FS kludge: as regular files with chmod 1000 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/balloc.c linux.ac/fs/sysv/balloc.c --- linux.vanilla/fs/sysv/balloc.c Sun Nov 8 15:06:35 1998 +++ linux.ac/fs/sysv/balloc.c Mon Mar 1 00:18:47 1999 @@ -79,6 +79,10 @@ flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; + break; default: panic("sysv_free_block: invalid fs type\n"); } *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ @@ -182,6 +186,10 @@ flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; + break; default: panic("sysv_new_block: invalid fs type\n"); } if (*flc_count > sb->sv_flc_size) { @@ -275,6 +283,10 @@ case FSTYPE_COH: flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; break; default: panic("sysv_count_free_blocks: invalid fs type\n"); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/dir.c linux.ac/fs/sysv/dir.c --- linux.vanilla/fs/sysv/dir.c Fri Nov 13 01:37:17 1998 +++ linux.ac/fs/sysv/dir.c Mon Mar 1 00:18:47 1999 @@ -10,7 +10,7 @@ * sysv/dir.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent directory handling functions + * SystemV/V7/Coherent directory handling functions */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/file.c linux.ac/fs/sysv/file.c --- linux.vanilla/fs/sysv/file.c Sun Nov 8 15:06:35 1998 +++ linux.ac/fs/sysv/file.c Mon Mar 1 14:24:09 1999 @@ -10,7 +10,7 @@ * sysv/file.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent regular file handling primitives + * SystemV/V7/Coherent regular file handling primitives */ #include @@ -30,8 +30,6 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -#include -#include static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/fsync.c linux.ac/fs/sysv/fsync.c --- linux.vanilla/fs/sysv/fsync.c Sun Nov 8 15:06:35 1998 +++ linux.ac/fs/sysv/fsync.c Mon Mar 1 00:18:47 1999 @@ -11,7 +11,7 @@ * sysv/fsync.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent fsync primitive + * SystemV/V7/Coherent fsync primitive */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/inode.c linux.ac/fs/sysv/inode.c --- linux.vanilla/fs/sysv/inode.c Wed Mar 24 10:55:25 1999 +++ linux.ac/fs/sysv/inode.c Mon Mar 22 15:44:59 1999 @@ -80,6 +80,7 @@ * - Xenix FS by its magic number. * - SystemV FS by its magic number. * - Coherent FS by its funny fname/fpack field. + * - V7 FS has no distinguishing features. * We discriminate among SystemV4 and SystemV2 FS by the assumption that * the time stamp is not < 01-01-1980. */ @@ -304,6 +305,7 @@ sb->sv_type = FSTYPE_COH; return "Coherent"; } + static struct super_block * detected_coherent (struct super_block *sb, struct buffer_head *bh) { struct coh_super_block * sbd; @@ -518,6 +520,101 @@ return sb; } +struct super_block *v7_read_super(struct super_block *sb,void *data, + int silent) +{ + struct v7_super_block *sbd; + struct buffer_head *bh; + kdev_t dev = sb->s_dev; + struct inode *root_inode; + unsigned long blocknr; + + if (440 != sizeof (struct v7_super_block)) + panic("V7 FS: bad super-block size"); + if (64 != sizeof (struct sysv_inode)) + panic("sysv fs: bad i-node size"); + MOD_INC_USE_COUNT; + lock_super(sb); + set_blocksize(dev,BLOCK_SIZE); + sb->sv_block_base = 0; + + if ((bh = bread(dev, 0, BLOCK_SIZE)) == NULL) { + sb->s_dev = 0; + unlock_super(sb); + if (!silent) + printk("VFS: unable to read V7 FS superblock on device " + "%s\n", kdevname(dev)); + goto failed; + } + + detected_bs(1, sb); + sb->sv_type = FSTYPE_V7; + /* Change to 512 byte block mode */ + blocknr = (bh->b_blocknr << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; + brelse(bh); + set_blocksize(dev,sb->sv_block_size); + + if ((bh = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) { + set_blocksize(sb->s_dev,BLOCK_SIZE); + sb->s_dev = 0; + unlock_super(sb); + printk("SysV FS: cannot read superblock in 512 byte mode\n"); + goto failed; + } + + sbd = (struct v7_super_block *)bh->b_data; + + sb->sv_convert = 1; + sb->sv_kludge_symlinks = 1; /* V7 doesn't have them at all */ + sb->sv_truncate = 1; /* or 0 ? */ + sb->sv_link_max = V7_LINK_MAX; + sb->sv_fic_size = V7_NICINOD; + sb->sv_flc_size = V7_NICFREE; + sb->sv_bh1 = bh; + sb->sv_bh2 = bh; + sb->sv_sbd1 = (char *)sbd; + sb->sv_sbd2 = (char *)sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = from_coh_ulong(sbd->s_fsize); + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; + if (!silent) + printk("VFS: Found a V7 FS (block size = %d) on device %s\n", + sb->sv_block_size, kdevname(dev)); + sb->s_magic = SYSV_MAGIC_BASE + FSTYPE_V7; + /* The buffer code now supports block size 512 as well as 1024. */ + sb->s_blocksize = sb->sv_block_size; + sb->s_blocksize_bits = sb->sv_block_size_bits; + /* set up enough so that it can read an inode */ + sb->s_dev = dev; + sb->s_op = &sysv_sops; + root_inode = iget(sb,SYSV_ROOT_INO); + sb->s_root = d_alloc_root(root_inode, NULL); + if (!sb->s_root) { + printk("SysV FS: get V7 FS root inode failed\n"); + sysv_put_super(sb); + sb->s_dev = 0; + unlock_super(sb); + return NULL; + } + unlock_super(sb); + sb->s_dirt = 1; + /* brelse(bh); occurs when the disk is unmounted. */ + return sb; + +failed: + MOD_DEC_USE_COUNT; + return NULL; +} + /* This is only called on sync() and umount(), when s_dirt=1. */ void sysv_write_super (struct super_block *sb) { @@ -1010,10 +1107,11 @@ /* Every kernel module contains stuff like this. */ -static struct file_system_type sysv_fs_type[3] = { +static struct file_system_type sysv_fs_type[4] = { {"xenix", FS_REQUIRES_DEV, sysv_read_super, NULL}, {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL}, - {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL} + {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}, + {"v7", FS_REQUIRES_DEV, v7_read_super, NULL} }; __initfunc(int init_sysv_fs(void)) @@ -1021,7 +1119,7 @@ int i; int ouch; - for (i = 0; i < 3; i++) { + for (i = 0; i < 4; i++) { if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0) break; } @@ -1040,7 +1138,7 @@ { int i; - for (i = 0; i < 3; i++) + for (i = 0; i < 4; i++) /* No error message if this breaks... that's OK... */ unregister_filesystem(&sysv_fs_type[i]); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/sysv/symlink.c linux.ac/fs/sysv/symlink.c --- linux.vanilla/fs/sysv/symlink.c Sun Nov 8 15:06:35 1998 +++ linux.ac/fs/sysv/symlink.c Mon Mar 1 00:18:47 1999 @@ -10,7 +10,7 @@ * sysv/symlink.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent symlink handling code + * SystemV/V7/Coherent symlink handling code */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/umsdos/file.c linux.ac/fs/umsdos/file.c --- linux.vanilla/fs/umsdos/file.c Sun Nov 8 15:06:34 1998 +++ linux.ac/fs/umsdos/file.c Mon Mar 1 14:24:09 1999 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/core_cia.h linux.ac/include/asm-alpha/core_cia.h --- linux.vanilla/include/asm-alpha/core_cia.h Thu Jan 14 01:25:27 1999 +++ linux.ac/include/asm-alpha/core_cia.h Tue Mar 16 18:57:45 1999 @@ -77,14 +77,14 @@ #define CIA_MEM_R2_MASK 0x07ffffff /* SPARSE Mem region 2 mask is 27 bits */ #define CIA_MEM_R3_MASK 0x03ffffff /* SPARSE Mem region 3 mask is 26 bits */ -#define CIA_DMA_WIN_BASE_DEFAULT (1024*1024*1024) -#define CIA_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) +#define CIA_DMA_WIN_BASE_DEFAULT (2UL*1024*1024*1024) +#define CIA_DMA_WIN_SIZE_DEFAULT (2UL*1024*1024*1024) #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) #define CIA_DMA_WIN_BASE alpha_mv.dma_win_base #define CIA_DMA_WIN_SIZE alpha_mv.dma_win_size #else -#define CIA_DMA_WIN_BASE CIA_DMA_WIN_SIZE_DEFAULT +#define CIA_DMA_WIN_BASE CIA_DMA_WIN_BASE_DEFAULT #define CIA_DMA_WIN_SIZE CIA_DMA_WIN_SIZE_DEFAULT #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/core_pyxis.h linux.ac/include/asm-alpha/core_pyxis.h --- linux.vanilla/include/asm-alpha/core_pyxis.h Mon Dec 28 23:09:47 1998 +++ linux.ac/include/asm-alpha/core_pyxis.h Tue Mar 16 18:57:45 1999 @@ -74,8 +74,8 @@ #define PYXIS_MEM_R2_MASK 0x07ffffff /* SPARSE Mem region 2 mask is 27 bits */ #define PYXIS_MEM_R3_MASK 0x03ffffff /* SPARSE Mem region 3 mask is 26 bits */ -#define PYXIS_DMA_WIN_BASE_DEFAULT (1024*1024*1024) -#define PYXIS_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) +#define PYXIS_DMA_WIN_BASE_DEFAULT (2UL*1024*1024*1024) +#define PYXIS_DMA_WIN_SIZE_DEFAULT (2UL*1024*1024*1024) #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) #define PYXIS_DMA_WIN_BASE alpha_mv.dma_win_base diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/resource.h linux.ac/include/asm-alpha/resource.h --- linux.vanilla/include/asm-alpha/resource.h Sun Nov 8 15:06:56 1998 +++ linux.ac/include/asm-alpha/resource.h Fri Dec 4 17:15:34 1998 @@ -28,7 +28,7 @@ {_STK_LIM, _STK_LIM}, /* RLIMIT_STACK */ \ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-arc/hardware.h linux.ac/include/asm-arm/arch-arc/hardware.h --- linux.vanilla/include/asm-arm/arch-arc/hardware.h Sat Jan 9 21:50:47 1999 +++ linux.ac/include/asm-arm/arch-arc/hardware.h Sat Feb 6 23:18:52 1999 @@ -20,7 +20,6 @@ * source. */ #define HAS_IOC -#include #define HAS_MEMC #include #define HAS_MEMC1A @@ -56,6 +55,12 @@ * for use with inb/outb */ #define IO_VIDC_BASE 0x80100000 +#ifdef CONFIG_ARCH_A5K +#define IOEB_VID_CTL 0x800d4012 +#define IOEB_PRESENT 0x800d4014 +#define IOEB_PSCLR 0x800d4016 +#define IOEB_MONTYPE 0x800d401c +#endif #ifdef CONFIG_ARCH_ARC #define LATCHAADDR 0x80094010 #define LATCHBADDR 0x80094006 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-arc/irq.h linux.ac/include/asm-arm/arch-arc/irq.h --- linux.vanilla/include/asm-arm/arch-arc/irq.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-arc/irq.h Wed Feb 17 20:56:22 1999 @@ -10,6 +10,9 @@ * 11-01-1998 RMK Added mask_and_ack_irq * 22-08-1998 RMK Restructured IRQ routines */ +#include + +#define fixup_irq(x) (x) static void arc_mask_irq_ack_a(unsigned int irq) { @@ -108,10 +111,17 @@ outb(0, IOC_FIQMASK); for (irq = 0; irq < NR_IRQS; irq++) { - switch (irq & 0xf8) { + switch (irq) { case 0 ... 6: irq_desc[irq].probe_ok = 1; + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = arc_mask_irq_ack_a; + irq_desc[irq].mask = arc_mask_irq_a; + irq_desc[irq].unmask = arc_unmask_irq_a; + break; + case 7: + irq_desc[irq].noautoenable = 1; irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = arc_mask_irq_ack_a; irq_desc[irq].mask = arc_mask_irq_a; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-arc/oldlatches.h linux.ac/include/asm-arm/arch-arc/oldlatches.h --- linux.vanilla/include/asm-arm/arch-arc/oldlatches.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-arc/oldlatches.h Mon Feb 22 21:52:36 1999 @@ -34,6 +34,8 @@ /* newval=(oldval & mask)|newdata */ void oldlatch_aupdate(unsigned char mask,unsigned char newdata); +void oldlatch_init(void); + #elif defined(CONFIG_ARCH_A5K) #ifdef __need_oldlatches diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-arc/processor.h linux.ac/include/asm-arm/arch-arc/processor.h --- linux.vanilla/include/asm-arm/arch-arc/processor.h Sat Jan 9 21:50:47 1999 +++ linux.ac/include/asm-arm/arch-arc/processor.h Wed Jan 20 11:37:31 1999 @@ -28,7 +28,4 @@ */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } - #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-arc/time.h linux.ac/include/asm-arm/arch-arc/time.h --- linux.vanilla/include/asm-arm/arch-arc/time.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-arc/time.h Fri Jan 22 09:40:32 1999 @@ -8,6 +8,7 @@ * 10-Oct-1996 RMK Brought up to date with arch-sa110eval * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ +#include extern __inline__ unsigned long gettimeoffset (void) { @@ -51,21 +52,24 @@ return offset; } -/* - * No need to reset the timer at every irq - */ -#define reset_timer() 1 +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); +} -/* - * Updating of the RTC. We don't currently write the time to the - * CMOS clock. - */ -#define update_rtc() +static struct irqaction timerirq = { + timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; /* * Set up timer interrupt, and return the current time in seconds. */ -extern __inline__ unsigned long setup_timer (void) +extern __inline__ void setup_timer(void) { extern int iic_control (unsigned char, int, char *, int); unsigned int year, mon, day, hour, min, sec; @@ -92,5 +96,7 @@ BCD_TO_BIN(min); BCD_TO_BIN(sec); - return mktime(year, mon, day, hour, min, sec); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + + setup_arm_irq(IRQ_TIMER, &timerirq); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/hardware.h linux.ac/include/asm-arm/arch-ebsa110/hardware.h --- linux.vanilla/include/asm-arm/arch-ebsa110/hardware.h Sat Jan 9 21:50:47 1999 +++ linux.ac/include/asm-arm/arch-ebsa110/hardware.h Sat Jan 9 17:13:57 1999 @@ -9,11 +9,6 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -/* - * What hardware must be present - */ -#define HAS_PCIO - #ifndef __ASSEMBLER__ /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/irq.h linux.ac/include/asm-arm/arch-ebsa110/irq.h --- linux.vanilla/include/asm-arm/arch-ebsa110/irq.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-ebsa110/irq.h Fri Jan 22 09:51:31 1999 @@ -11,6 +11,8 @@ #define IRQ_MSET ((volatile unsigned char *)0xf2c00000) #define IRQ_MASK ((volatile unsigned char *)0xf2c00000) +#define fixup_irq(x) (x) + static void ebsa110_mask_and_ack_irq(unsigned int irq) { *IRQ_MCLR = 1 << irq; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/mm-init.h linux.ac/include/asm-arm/arch-ebsa110/mm-init.h --- linux.vanilla/include/asm-arm/arch-ebsa110/mm-init.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-ebsa110/mm-init.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/mmap.h - * - * Copyright (C) 1996,1997,1998 Russell King - */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/oldlatches.h linux.ac/include/asm-arm/arch-ebsa110/oldlatches.h --- linux.vanilla/include/asm-arm/arch-ebsa110/oldlatches.h Sun Nov 8 15:07:06 1998 +++ linux.ac/include/asm-arm/arch-ebsa110/oldlatches.h Thu Jan 1 01:00:00 1970 @@ -1,9 +0,0 @@ -/* - * Dummy oldlatches.h - * - * Copyright (C) 1996 Russell King - */ - -#ifdef __need_oldlatches -#error "Old latches not present in this (rpc) machine" -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/processor.h linux.ac/include/asm-arm/arch-ebsa110/processor.h --- linux.vanilla/include/asm-arm/arch-ebsa110/processor.h Sat Jan 9 21:50:47 1999 +++ linux.ac/include/asm-arm/arch-ebsa110/processor.h Wed Jan 20 11:37:31 1999 @@ -25,7 +25,4 @@ */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } - #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa110/time.h linux.ac/include/asm-arm/arch-ebsa110/time.h --- linux.vanilla/include/asm-arm/arch-ebsa110/time.h Sat Jan 9 21:50:47 1999 +++ linux.ac/include/asm-arm/arch-ebsa110/time.h Wed Feb 3 23:01:40 1999 @@ -38,63 +38,67 @@ return 0; } -#ifndef DIVISOR -extern __inline__ int reset_timer (void) +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { *PIT_T1 = (PIT1_COUNT) & 0xff; *PIT_T1 = (PIT1_COUNT) >> 8; - return 1; -} -#else -extern __inline__ int reset_timer (void) -{ - static unsigned int divisor; -#ifdef CONFIG_LEDS - static int count = 50; -#endif - - *PIT_T1 = (PIT1_COUNT) & 0xff; - *PIT_T1 = (PIT1_COUNT) >> 8; #ifdef CONFIG_LEDS - if (--count == 0) { - count = 50; - leds_event(led_timer); + { + static int count = 50; + if (--count == 0) { + count = 50; + leds_event(led_timer); + } } #endif - if (divisor == 0) { - divisor = DIVISOR - 1; - return 1; + { +#ifdef DIVISOR + static unsigned int divisor; + + if (divisor-- == 0) { + divisor = DIVISOR - 1; +#else + { +#endif + do_timer(regs); + } } - divisor -= 1; - return 0; } -#endif -/* - * We don't have a RTC to update! - */ -#define update_rtc() +static struct irqaction timerirq = { + timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; /* * Set up timer interrupt, and return the current time in seconds. */ -extern __inline__ unsigned long setup_timer (void) +extern __inline__ void setup_timer(void) { /* * Timer 1, mode 0, 16-bit, autoreload */ *PIT_CTRL = 0x70; + /* * Refresh counter clocked at 47.8MHz/7 = 146.4ns * We want centi-second interrupts */ - reset_timer (); + *PIT_T1 = (PIT1_COUNT) & 0xff; + *PIT_T1 = (PIT1_COUNT) >> 8; + /* * Default the date to 1 Jan 1970 0:0:0 * You will have to run a time daemon to set the * clock correctly at bootup */ - return mktime(1970, 1, 1, 0, 0, 0); + xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0); + + setup_arm_irq(IRQ_TIMER, &timerirq); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/hardware.h linux.ac/include/asm-arm/arch-ebsa285/hardware.h --- linux.vanilla/include/asm-arm/arch-ebsa285/hardware.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/hardware.h Thu Jan 21 22:41:23 1999 @@ -20,11 +20,9 @@ * */ -#include - -#define IO_BASE 0xe0000000 #define PCIO_BASE 0xffe00000 -#define PCI_IACK 0xfc000000 +#define ARMCSR_BASE 0xfe000000 +#define PCI_IACK 0xfc000000 #define XBUS_LEDS ((volatile unsigned char *)0xfff12000) #define XBUS_LED_AMBER (1 << 0) @@ -44,4 +42,36 @@ #define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET) #define FLUSH_BASE_PHYS 0x50000000 + + +/* PIC irq control */ +#define PIC_LO 0x20 +#define PIC_MASK_LO 0x21 +#define PIC_HI 0xA0 +#define PIC_MASK_HI 0xA1 + +/* GPIO pins */ +#define GPIO_CCLK 0x800 +#define GPIO_DSCLK 0x400 +#define GPIO_E2CLK 0x200 +#define GPIO_IOLOAD 0x100 +#define GPIO_RED_LED 0x080 +#define GPIO_WDTIMER 0x040 +#define GPIO_DATA 0x020 +#define GPIO_IOCLK 0x010 +#define GPIO_DONE 0x008 +#define GPIO_FAN 0x004 +#define GPIO_GREEN_LED 0x002 +#define GPIO_RESET 0x001 + +/* CPLD pins */ +#define CPLD_DSRESET 8 +#define CPLD_UNMUTE 2 + +#ifndef __ASSEMBLY__ +extern void gpio_modify_op(int mask, int set); +extern void gpio_modify_io(int mask, int in); +extern int gpio_read(void); +extern void cpld_modify(int mask, int set); +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/io.h linux.ac/include/asm-arm/arch-ebsa285/io.h --- linux.vanilla/include/asm-arm/arch-ebsa285/io.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/io.h Thu Jan 21 10:21:08 1999 @@ -155,18 +155,15 @@ */ #define IO_FUDGE_FACTOR 0xe0000000 -extern inline void *ioremap(unsigned long iomem_addr, unsigned long size) -{ - unsigned long phys_addr; - - if (!valid_ioaddr(iomem_addr, size)) - return NULL; - - phys_addr = io_to_phys(iomem_addr & PAGE_MASK); - - return (void *)((unsigned long)__ioremap(phys_addr, size, 0) - - IO_FUDGE_FACTOR); -} +#define ioremap(iomem_addr,size) \ + ({ \ + unsigned long _addr = (iomem_addr), _size = (size); \ + void *_ret = NULL; \ + if (valid_ioaddr(_addr, _size)) { \ + _addr = io_to_phys(_addr); \ + _ret = __ioremap(_addr, _size, 0) - IO_FUDGE_FACTOR; \ + } \ + _ret; }) #define ioremap_nocache(iomem_addr,size) ioremap((iomem_addr),(size)) @@ -202,7 +199,7 @@ *(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr)) = b; } -static inline unsigned short readl(unsigned int addr) +static inline unsigned long readl(unsigned int addr) { return *(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr)); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/irq.h linux.ac/include/asm-arm/arch-ebsa285/irq.h --- linux.vanilla/include/asm-arm/arch-ebsa285/irq.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/irq.h Sun Feb 7 20:00:49 1999 @@ -4,136 +4,198 @@ * Copyright (C) 1996-1998 Russell King * * Changelog: - * 22-08-1998 RMK Restructured IRQ routines - * 03-09-1998 PJB Merged CATS support + * 22-Aug-1998 RMK Restructured IRQ routines + * 03-Sep-1998 PJB Merged CATS support + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder + * 26-Jan-1999 PJB Don't use IACK on CATS */ -#include +#include +#include +#include -static void ebsa285_mask_irq(unsigned int irq) +/* + * Footbridge IRQ translation table + * Converts from our IRQ numbers into FootBridge masks + */ +static int dc21285_irq_mask[] = { + IRQ_MASK_UART_RX, /* 0 */ + IRQ_MASK_UART_TX, /* 1 */ + IRQ_MASK_TIMER1, /* 2 */ + IRQ_MASK_TIMER2, /* 3 */ + IRQ_MASK_TIMER3, /* 4 */ + IRQ_MASK_IN0, /* 5 */ + IRQ_MASK_IN1, /* 6 */ + IRQ_MASK_IN2, /* 7 */ + IRQ_MASK_IN3, /* 8 */ + IRQ_MASK_DOORBELLHOST, /* 9 */ + IRQ_MASK_DMA1, /* 10 */ + IRQ_MASK_DMA2, /* 11 */ + IRQ_MASK_PCI, /* 12 */ + IRQ_MASK_SDRAMPARITY, /* 13 */ + IRQ_MASK_I2OINPOST, /* 14 */ + IRQ_MASK_PCI_ERR /* 15 */ +}; + +static int isa_irq; + +static inline int fixup_irq(unsigned int irq) +{ + if (irq == isa_irq) { + if (machine_is_cats()) { + unsigned int status = inb(0x20) | (inb(0xa0) << 8); + status &= ~(1<<2); + for (irq = 16; irq < 32; irq++) { + if (status & 1) + break; + status >>= 1; + } + } else + irq = *(unsigned char *)PCI_IACK; + } + + return irq; +} + +static void dc21285_mask_irq(unsigned int irq) { - *CSR_IRQ_DISABLE = 1 << irq; + *CSR_IRQ_DISABLE = dc21285_irq_mask[irq]; } -static void ebsa285_unmask_irq(unsigned int irq) +static void dc21285_unmask_irq(unsigned int irq) { - *CSR_IRQ_ENABLE = 1 << irq; + *CSR_IRQ_ENABLE = dc21285_irq_mask[irq]; } -#ifdef CONFIG_CATS +static void isa_mask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); -/* - * This contains the irq mask for both 8259A irq controllers, - */ -static unsigned int isa_irq_mask = 0xffff; + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); +} -#define cached_21 (isa_irq_mask & 0xff) -#define cached_A1 ((isa_irq_mask >> 8) & 0xff) +static void isa_mask_ack_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); -#define update_8259(_irq) \ - if ((_irq) & 8) \ - outb(cached_A1, 0xa1); \ - else \ - outb(cached_21, 0x21); - -static void isa_interrupt(int irq, void *h, struct pt_regs *regs) -{ - asmlinkage void do_IRQ(int irq, struct pt_regs * regs); - unsigned int irqbits = inb(0x20) | (inb(0xa0) << 8), irqnr = 0; - irqbits &= ~(1<<2); /* don't try to service the cascade */ - while (irqbits) { - if (irqbits & 1) - do_IRQ(32 + irqnr, regs); - irqbits >>= 1; - irqnr++; - } + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); + outb(0x20, PIC_LO); } -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +static void isa_unmask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); -static struct irqaction irq_isa = - { isa_interrupt, SA_INTERRUPT, 0, "ISA PIC", NULL, NULL }; -static struct irqaction irq_cascade = - { no_action, 0, 0, "cascade", NULL, NULL }; - -static void cats_mask_and_ack_isa_irq(unsigned int irq) -{ - isa_irq_mask |= (1 << (irq - 32)); - update_8259(irq); - if (irq & 8) { - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x62,0x20); /* Specific EOI to cascade */ - outb(0x20,0xA0); - } else { - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); - } + outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); +} + +static void isa_mask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); +} + +static void isa_mask_ack_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); + outb(0x62, PIC_LO); + outb(0x20, PIC_HI); } -static void cats_mask_isa_irq(unsigned int irq) +static void isa_unmask_pic_hi_irq(unsigned int irq) { - isa_irq_mask |= (1 << (irq - 32)); - update_8259(irq); + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); } -static void cats_unmask_isa_irq(unsigned int irq) +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { - isa_irq_mask &= ~(1 << (irq - 32)); - update_8259(irq); } - -#endif + +static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; static __inline__ void irq_init_irq(void) { - int irq; + int irq, nr_irqs = 0; *CSR_IRQ_DISABLE = -1; *CSR_FIQ_DISABLE = -1; - for (irq = 0; irq < NR_IRQS; irq++) { + switch (machine_type) { + case MACH_TYPE_EBSA285: + nr_irqs = NR_DC21285_IRQS; + isa_irq = -1; + break; + + case MACH_TYPE_CATS: + nr_irqs = NR_IRQS; + + outb(0x11, PIC_LO); + outb(0, PIC_MASK_LO); /* IRQ IACK not used */ + outb(0x04, PIC_MASK_LO); + outb(0x01, PIC_MASK_LO); + outb(0xff, PIC_MASK_LO); + outb(0x68, PIC_LO); + outb(0x0a, PIC_LO); + + outb(0x11, PIC_HI); + outb(0, PIC_MASK_HI); /* IRQ IACK not used */ + outb(0x02, PIC_MASK_HI); + outb(0x01, PIC_MASK_HI); + outb(0xff, PIC_MASK_HI); + outb(0x68, PIC_HI); + outb(0x0a, PIC_HI); + + isa_irq = IRQ_IN2; + break; + + case MACH_TYPE_NETWINDER: + nr_irqs = NR_IRQS; + + outb(0x11, PIC_LO); + outb(0x10, PIC_MASK_LO); /* IRQ_IACK starts at 16 */ + outb(0x04, PIC_MASK_LO); + outb(0x01, PIC_MASK_LO); + outb(0xff, PIC_MASK_LO); + + outb(0x11, PIC_HI); + outb(0x18, PIC_MASK_HI); /* IRQ_IACK starts at 24 */ + outb(0x02, PIC_MASK_HI); + outb(0x01, PIC_MASK_HI); + outb(0xff, PIC_MASK_HI); + + isa_irq = IRQ_IN3; + break; + } + + for (irq = 0; irq < nr_irqs; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 1; -#ifdef CONFIG_CATS - if (machine_is_cats() && IRQ_IS_ISA(irq)) { - irq_desc[irq].mask_ack = cats_mask_and_ack_isa_irq; - irq_desc[irq].mask = cats_mask_isa_irq; - irq_desc[irq].unmask = cats_unmask_isa_irq; - } else -#endif - { - irq_desc[irq].mask_ack = ebsa285_mask_irq; - irq_desc[irq].mask = ebsa285_mask_irq; - irq_desc[irq].unmask = ebsa285_unmask_irq; + + if (irq >= NR_DC21285_IRQS + 8) { + irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq; + irq_desc[irq].mask = isa_mask_pic_hi_irq; + irq_desc[irq].unmask = isa_unmask_pic_hi_irq; + } else if (irq >= NR_DC21285_IRQS) { + irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq; + irq_desc[irq].mask = isa_mask_pic_lo_irq; + irq_desc[irq].unmask = isa_unmask_pic_lo_irq; + } else { + irq_desc[irq].mask_ack = dc21285_mask_irq; + irq_desc[irq].mask = dc21285_mask_irq; + irq_desc[irq].unmask = dc21285_unmask_irq; } } -#ifdef CONFIG_CATS - if (machine_is_cats()) { - request_region(0x20, 2, "pic1"); - request_region(0xa0, 2, "pic2"); - - /* set up master 8259 */ - outb(0x11, 0x20); - outb(0, 0x21); - outb(1<<2, 0x21); - outb(0x1, 0x21); - outb(0xff, 0x21); - outb(0x68, 0x20); - outb(0xa, 0x20); - - /* set up slave 8259 */ - outb(0x11, 0xa0); - outb(0, 0xa1); - outb(2, 0xa1); - outb(0x1, 0xa1); - outb(0xff, 0xa1); - outb(0x68, 0xa0); - outb(0xa, 0xa0); - - setup_arm_irq(IRQ_ISA_PIC, &irq_isa); + if (nr_irqs == NR_IRQS) { + request_region(PIC_LO, 2, "pic1"); + request_region(PIC_HI, 2, "pic2"); setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade); } -#endif + + if (isa_irq != -1) + setup_arm_irq(isa_irq, &irq_cascade); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/irqs.h linux.ac/include/asm-arm/arch-ebsa285/irqs.h --- linux.vanilla/include/asm-arm/arch-ebsa285/irqs.h Tue Dec 22 23:20:05 1998 +++ linux.ac/include/asm-arm/arch-ebsa285/irqs.h Sat Jan 23 14:31:13 1999 @@ -3,55 +3,94 @@ * * Copyright (C) 1998 Russell King * Copyright (C) 1998 Phil Blundell + * + * Changelog: + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder */ -#define NR_IRQS 48 +#define NR_IRQS 32 +#define NR_DC21285_IRQS 16 /* * This is a list of all interrupts that the 21285 - * can generate + * can generate and we handle. */ -#define IRQ_RESERVED 0 -#define IRQ_SOFTIRQ 1 -#define IRQ_CONRX 2 -#define IRQ_CONTX 3 -#define IRQ_TIMER1 4 -#define IRQ_TIMER2 5 -#define IRQ_TIMER3 6 -#define IRQ_TIMER4 7 -#define IRQ_IN0 8 -#define IRQ_IN1 9 -#define IRQ_IN2 10 -#define IRQ_IN3 11 -#define IRQ_XCS0 12 -#define IRQ_XCS1 13 -#define IRQ_XCS2 14 -#define IRQ_DOORBELLHOST 15 -#define IRQ_DMA1 16 -#define IRQ_DMA2 17 -#define IRQ_PCI 18 -#define IRQ_BIST 22 -#define IRQ_SERR 23 -#define IRQ_SDRAMPARITY 24 -#define IRQ_I2OINPOST 25 -#define IRQ_DISCARDTIMER 27 -#define IRQ_PCIDATAPARITY 28 -#define IRQ_PCIMASTERABORT 29 -#define IRQ_PCITARGETABORT 30 -#define IRQ_PCIPARITY 31 - -/* IRQs 32-47 are the 16 ISA interrupts on a CATS board. */ -#define IRQ_ISA_PIC IRQ_IN2 -#define IRQ_IS_ISA(_x) (((_x) >= 32) && ((_x) <= 47)) -#define IRQ_ISA(_x) ((_x) + 0x20) -#define IRQ_ISA_CASCADE IRQ_ISA(2) +#define IRQ_CONRX 0 +#define IRQ_CONTX 1 +#define IRQ_TIMER1 2 +#define IRQ_TIMER2 3 +#define IRQ_TIMER3 4 +#define IRQ_IN0 5 +#define IRQ_IN1 6 +#define IRQ_IN2 7 +#define IRQ_IN3 8 +#define IRQ_DOORBELLHOST 9 +#define IRQ_DMA1 10 +#define IRQ_DMA2 11 +#define IRQ_PCI 12 +#define IRQ_SDRAMPARITY 13 +#define IRQ_I2OINPOST 14 +#define IRQ_PCI_ERR 15 + +#define IRQ_ISA_TIMER 16 +#define IRQ_ISA_KEYBOARD 17 +#define IRQ_ISA_CASCADE 18 +#define IRQ_ISA_UART2 19 +#define IRQ_ISA_UART 20 +#define IRQ_ISA_FLOPPY 22 +#define IRQ_ISA_PRINTER 23 +#define IRQ_ISA_RTC_ALARM 24 +#define IRQ_ISA_2 25 +#define IRQ_ISA_HARDDISK1 30 +#define IRQ_ISA_HARDDISK2 31 + +#define IRQ_MASK_UART_RX (1 << 2) +#define IRQ_MASK_UART_TX (1 << 3) +#define IRQ_MASK_TIMER1 (1 << 4) +#define IRQ_MASK_TIMER2 (1 << 5) +#define IRQ_MASK_TIMER3 (1 << 6) +#define IRQ_MASK_IN0 (1 << 8) +#define IRQ_MASK_IN1 (1 << 9) +#define IRQ_MASK_IN2 (1 << 10) +#define IRQ_MASK_IN3 (1 << 11) +#define IRQ_MASK_DOORBELLHOST (1 << 15) +#define IRQ_MASK_DMA1 (1 << 16) +#define IRQ_MASK_DMA2 (1 << 17) +#define IRQ_MASK_PCI (1 << 18) +#define IRQ_MASK_SDRAMPARITY (1 << 24) +#define IRQ_MASK_I2OINPOST (1 << 25) +#define IRQ_MASK_PCI_ERR ((1 <<23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31)) + +/* + * EBSA285 interrupt allocations + */ +#define IRQ_EBSA285_TIMER IRQ_TIMER1 /* - * Now map them to the Linux interrupts + * Netwinder interrupt allocations */ -#define IRQ_TIMER IRQ_TIMER1 -#define IRQ_FLOPPYDISK IRQ_ISA(6) -#define IRQ_HARDDISK IRQ_ISA(14) -#define IRQ_HARDDISK_SECONDARY IRQ_ISA(15) +#define IRQ_NETWINDER_ETHER10 IRQ_IN0 +#define IRQ_NETWINDER_ETHER100 IRQ_IN1 +#define IRQ_NETWINDER_VIDCOMP IRQ_IN2 +#define IRQ_NETWINDER_TIMER IRQ_ISA_TIMER +#define IRQ_NETWINDER_MOUSE 21 +#define IRQ_NETWINDER_IR 22 +#define IRQ_NETWINDER_BUTTON 26 +#define IRQ_NETWINDER_VGA 27 +#define IRQ_NETWINDER_SOUND 28 +#define IRQ_NETWINDER_IDE IRQ_ISA_HARDDISK1 + +/* + * CATS interrupt allocations + */ +#define IRQ_CATS_TIMER IRQ_TIMER1 +#define IRQ_CATS_FLOPPYDISK IRQ_ISA_FLOPPY +#define IRQ_CATS_HARDDISK IRQ_ISA_HARDDISK1 +#define IRQ_CATS_HARDDISK_SECONDARY IRQ_ISA_HARDDISK2 + +#undef RTC_IRQ +#define RTC_IRQ IRQ_ISA_RTC_ALARM +#undef AUX_IRQ +#define AUX_IRQ IRQ_NETWINDER_MOUSE -#define irq_cannonicalize(_i) (((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA(9) : _i) +#define irq_cannonicalize(_i) (((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/keyboard.h linux.ac/include/asm-arm/arch-ebsa285/keyboard.h --- linux.vanilla/include/asm-arm/arch-ebsa285/keyboard.h Tue Dec 22 23:20:05 1998 +++ linux.ac/include/asm-arm/arch-ebsa285/keyboard.h Sun Feb 7 20:00:59 1999 @@ -6,17 +6,9 @@ * (C) 1998 Russell King * (C) 1998 Phil Blundell */ - -#include #include #include -#define NR_SCANCODES 128 - -#ifdef CONFIG_CATS - -#define KEYBOARD_IRQ IRQ_ISA(1) - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); @@ -27,46 +19,55 @@ extern void pckbd_init_hw(void); extern unsigned char pckbd_sysrq_xlate[128]; -#define kbd_setkeycode pckbd_setkeycode -#define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate -#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \ - pckbd_translate(sc & 0x7f, kcp, rm);}) +#define KEYBOARD_IRQ IRQ_ISA_KEYBOARD -#define kbd_unexpected_up pckbd_unexpected_up -#define kbd_leds pckbd_leds -#define kbd_init_hw() \ - do { if (machine_is_cats()) pckbd_init_hw(); } while (0) -#define kbd_sysrq_xlate pckbd_sysrq_xlate -#define kbd_disable_irq() -#define kbd_enable_irq() +#define NR_SCANCODES 128 -#define SYSRQ_KEY 0x54 +#define kbd_setkeycode(sc,kc) \ + ({ \ + int __ret; \ + if (!machine_is_ebsa285()) \ + __ret = pckbd_setkeycode(sc,kc);\ + else \ + __ret = -EINVAL; \ + __ret; \ + }) + +#define kbd_getkeycode(sc) \ + ({ \ + int __ret; \ + if (!machine_is_ebsa285()) \ + __ret = pckbd_getkeycode(sc); \ + else \ + __ret = -EINVAL; \ + __ret; \ + }) -#else +#define kbd_pretranslate pckbd_pretranslate -/* Dummy keyboard definitions */ +#define kbd_translate(sc, kcp, ufp, rm) \ + ({ \ + *ufp = sc & 0200; \ + pckbd_translate(sc & 0x7f, kcp, rm); \ + }) + +#define kbd_unexpected_up pckbd_unexpected_up -#define kbd_setkeycode(sc,kc) (-EINVAL) -#define kbd_getkeycode(sc) (-EINVAL) +#define kbd_leds(leds) \ + do { \ + if (!machine_is_ebsa285()) \ + pckbd_leds(leds); \ + } while (0) + +#define kbd_init_hw() \ + do { \ + if (!machine_is_ebsa285()) \ + pckbd_init_hw(); \ + } while (0) + +#define kbd_sysrq_xlate pckbd_sysrq_xlate -/* Prototype: int kbd_pretranslate(scancode, raw_mode) - * Returns : 0 to ignore scancode - */ -#define kbd_pretranslate(sc,rm) (1) - -/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode) - * Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag - * set to 0200 if scancode indicates release - */ -#define kbd_translate(sc, kcp, ufp, rm) (1) -#define kbd_unexpected_up(kc) (0200) -#define kbd_leds(leds) -#define kbd_init_hw() -//#define kbd_sysrq_xlate ps2kbd_sysrq_xlate #define kbd_disable_irq() #define kbd_enable_irq() -#define SYSRQ_KEY 13 - -#endif +#define SYSRQ_KEY 0x54 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/mm-init.h linux.ac/include/asm-arm/arch-ebsa285/mm-init.h --- linux.vanilla/include/asm-arm/arch-ebsa285/mm-init.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-ebsa285/mm-init.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/mmap.h - * - * Copyright (C) 1996,1997,1998 Russell King - */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/mmu.h linux.ac/include/asm-arm/arch-ebsa285/mmu.h --- linux.vanilla/include/asm-arm/arch-ebsa285/mmu.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/mmu.h Sat Jan 9 17:00:13 1999 @@ -13,7 +13,7 @@ #define __ASM_ARCH_MMU_H /* - * On ebsa285, the dram is contiguous + * On DEC21285-based machines, the dram is contiguous */ #define __virt_to_phys__is_a_macro #define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/oldlatches.h linux.ac/include/asm-arm/arch-ebsa285/oldlatches.h --- linux.vanilla/include/asm-arm/arch-ebsa285/oldlatches.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-ebsa285/oldlatches.h Thu Jan 1 01:00:00 1970 @@ -1,9 +0,0 @@ -/* - * Dummy oldlatches.h - * - * Copyright (C) 1996 Russell King - */ - -#ifdef __need_oldlatches -#error "Old latches not present in this (rpc) machine" -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/processor.h linux.ac/include/asm-arm/arch-ebsa285/processor.h --- linux.vanilla/include/asm-arm/arch-ebsa285/processor.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/processor.h Wed Jan 20 11:37:32 1999 @@ -25,7 +25,4 @@ */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } - #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/serial.h linux.ac/include/asm-arm/arch-ebsa285/serial.h --- linux.vanilla/include/asm-arm/arch-ebsa285/serial.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/serial.h Sun Feb 7 20:01:10 1999 @@ -10,8 +10,6 @@ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H -#include - #include /* @@ -23,13 +21,8 @@ */ #define BASE_BAUD (1843200 / 16) -#ifdef CONFIG_CATS -#define _SER_IRQ0 IRQ_ISA(4) -#define _SER_IRQ1 IRQ_ISA(3) -#else -#define _SER_IRQ0 0 -#define _SER_IRQ1 0 -#endif +#define _SER_IRQ0 IRQ_ISA_UART +#define _SER_IRQ1 IRQ_ISA_UART2 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/system.h linux.ac/include/asm-arm/arch-ebsa285/system.h --- linux.vanilla/include/asm-arm/arch-ebsa285/system.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/system.h Fri Jan 22 11:14:18 1999 @@ -3,6 +3,8 @@ * * Copyright (c) 1996,1997,1998 Russell King. */ +#include +#include #include #include @@ -16,14 +18,37 @@ mov r0, #0x130 mcr p15, 0, r0, c1, c0 @ MMU off mcr p15, 0, ip, c7, c7 @ flush caches - mov pc, lr"); + mov pc, lr" : : : "cc"); } else { - /* To reboot, we set up the 21285 watchdog and enable it. - * We then wait for it to timeout. - */ - *CSR_TIMER4_LOAD = 0x8000; - *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; - *CSR_SA110_CNTL |= 1 << 13; + if (machine_is_ebsa285()) { + /* To reboot, we set up the 21285 watchdog and + * enable it. We then wait for it to timeout. + */ + *CSR_TIMER4_LOAD = 0x8000; + *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | + TIMER_CNTL_AUTORELOAD | + TIMER_CNTL_DIV16; + *CSR_SA110_CNTL |= 1 << 13; + } else if (machine_is_netwinder()) { + /* open up the SuperIO chip + */ + outb(0x87, 0x370); + outb(0x87, 0x370); + + /* aux function group 1 (logical device 7) + */ + outb(0x07, 0x370); + outb(0x07, 0x371); + + /* set GP16 for WD-TIMER output + */ + outb(0xe6, 0x370); + outb(0x00, 0x371); + + /* set a RED LED and toggle WD_TIMER for rebooting + */ + outb(0xc4, 0x338); + } } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/time.h linux.ac/include/asm-arm/arch-ebsa285/time.h --- linux.vanilla/include/asm-arm/arch-ebsa285/time.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-ebsa285/time.h Sun Jan 24 11:47:01 1999 @@ -10,116 +10,341 @@ * 21-Mar-1998 RMK Created * 27-Aug-1998 PJB CATS support * 28-Dec-1998 APH Made leds optional + * 20-Jan-1999 RMK Started merge of EBSA285, CATS and NetWinder */ #define RTC_PORT(x) (0x72+(x)) #define RTC_ALWAYS_BCD 1 #include +#include + +#include #include #include -#include -extern __inline__ unsigned long gettimeoffset (void) +static unsigned long (*gettimeoffset)(void); +static int (*set_rtc_mmss)(unsigned long nowtime); +static long last_rtc_update = 0; /* last time the cmos clock got updated */ + +#ifdef CONFIG_LEDS +static void do_leds(void) +{ + static unsigned int count = 50; + static int last_pid; + + if (current->pid != last_pid) { + last_pid = current->pid; + if (last_pid) + leds_event(led_idle_end); + else + leds_event(led_idle_start); + } + + if (--count == 0) { + count = 50; + leds_event(led_timer); + } +} +#else +#define do_leds() +#endif + +#ifdef CONFIG_ARCH_EBSA285 + +static int __ebsa285_text set_dummy_time(unsigned long secs) +{ + return 1; +} + +#endif + +#ifdef CONFIG_ARCH_NETWINDER + +#define mSEC_10_from_14 ((14318180 + 100) / 200) + +static unsigned long __netwinder_text isa_gettimeoffset(void) +{ + int count; + + static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* timer count may underflow right here */ + outb_p(0x00, 0x43); /* latch the count ASAP */ + + count = inb_p(0x40); /* read the latched count */ + + /* + * We do this guaranteed double memory access instead of a _p + * postfix in the previous port access. Wheee, hackady hack + */ + jiffies_t = jiffies; + + count |= inb_p(0x40) << 8; + + /* Detect timer underflows. If we haven't had a timer tick since + the last time we were called, and time is apparently going + backwards, the counter must have wrapped during this routine. */ + if ((jiffies_t == jiffies_p) && (count > count_p)) + count -= (mSEC_10_from_14/6); + else + jiffies_p = jiffies_t; + + count_p = count; + + count = (((mSEC_10_from_14/6)-1) - count) * tick; + count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); + + return count; +} + +static void __netwinder_text isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_leds(); + do_timer(regs); + + /* If we have an externally synchronized linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 50000 - (tick >> 1) && + xtime.tv_usec < 50000 + (tick >> 1)) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +} + +static struct irqaction __netwinder_data isa_timer_irq = { + isa_timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; + +#endif + +#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_CATS) + +static unsigned long __ebsa285_text timer1_gettimeoffset (void) { unsigned long value = LATCH - *CSR_TIMER1_VALUE; return (tick * value) / LATCH; } -extern __inline__ int reset_timer (void) +static void __ebsa285_text timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { *CSR_TIMER1_CLR = 0; -#ifdef CONFIG_LEDS - /* - * Do the LEDs thing on EBSA-285 hardware. + /* Do the LEDs things on non-CATS hardware. */ - if (!machine_is_cats()) { - static unsigned int count = 50; - static int last_pid; - - if (current->pid != last_pid) { - last_pid = current->pid; - if (last_pid) - leds_event(led_idle_end); - else - leds_event(led_idle_start); - } - - if (--count == 0) { - count = 50; - leds_event(led_timer); - } + if (!machine_is_cats()) + do_leds(); + + do_timer(regs); + + /* If we have an externally synchronized linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 50000 - (tick >> 1) && + xtime.tv_usec < 50000 + (tick >> 1)) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } -#endif - - return 1; } -/* - * We don't have a RTC to update! - */ -#define update_rtc() +static struct irqaction __ebsa285_data timer1_irq = { + timer1_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; -/* - * Set up timer interrupt, and return the current time in seconds. - */ -extern __inline__ unsigned long setup_timer (void) +#endif + +#if defined(CONFIG_CATS) || defined(CONFIG_ARCH_NETWINDER) +__initfunc(static unsigned long +get_cmos_time(void)) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + // check to see if the RTC makes sense..... + if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0) + return mktime(1970, 1, 1, 0, 0, 0); + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + return mktime(year, mon, day, hour, min, sec); +} + +static int set_cmos_time(unsigned long nowtime) { - int year, mon, day, hour, min, sec; + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); /* - * Default the date to 1 Jan 1970 0:0:0 + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else + retval = -1; + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn */ - year = 1970; mon = 1; day = 1; - hour = 0; min = 0; sec = 0; + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} +#endif - *CSR_TIMER1_CLR = 0; - *CSR_TIMER1_LOAD = LATCH; - *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; - - if (machine_is_cats()) - { - int i; +/* + * Set up timer interrupt, and return the current time in seconds. + */ +extern __inline__ void setup_timer(void) +{ + switch (machine_type) { +#ifdef CONFIG_ARCH_EBSA285 + case MACH_TYPE_EBSA285: /* - * Read the real time from the Dallas chip. (Code borrowed - * from arch/i386/kernel/time.c). - */ - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. + * Default the date to 1 Jan 1970 0:0:0 */ + xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0); + set_rtc_mmss = set_dummy_time; + gettimeoffset = timer1_gettimeoffset; - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + *CSR_TIMER1_CLR = 0; + *CSR_TIMER1_LOAD = LATCH; + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; + + setup_arm_irq(IRQ_EBSA285_TIMER, &timer1_irq); + + break; +#endif +#ifdef CONFIG_CATS + case MACH_TYPE_CATS: + xtime.tv_sec = get_cmos_time(); + set_rtc_mmss = set_cmos_time; + gettimeoffset = timer1_gettimeoffset; + + *CSR_TIMER1_CLR = 0; + *CSR_TIMER1_LOAD = LATCH; + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; + + setup_arm_irq(IRQ_CATS_TIMER, &timer1_irq); + + break; +#endif +#ifdef CONFIG_ARCH_NETWINDER + case MACH_TYPE_NETWINDER: + /* Turn on the RTC */ + outb(13, 0x70); + if ((inb(0x71) & 0x80) == 0) + printk("RTC: *** warning: CMOS battery bad\n"); + + outb(10, 0x70); /* select control reg */ + outb(32, 0x71); /* make sure the divider is set */ + outb(11, 0x70); /* select other control reg */ { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); + char c; + c = inb(0x71) & 0xfb; /* read it */ + outb(11, 0x70); + outb(c | 2, 0x71); /* turn on BCD counting and 24 hour clock mode */ } - if ((year += 1900) < 1970) - year += 100; - } - return mktime(year, mon, day, hour, min, sec); + /* enable PIT timer */ + /* set for periodic (4) and LSB/MSB write (0x30) */ + outb(0x34, 0x43); + outb((mSEC_10_from_14/6) & 0xFF, 0x40); + outb((mSEC_10_from_14/6) >> 8, 0x40); + + xtime.tv_sec = get_cmos_time(); + set_rtc_mmss = set_cmos_time; + gettimeoffset = isa_gettimeoffset; + + setup_arm_irq(IRQ_NETWINDER_TIMER, &isa_timer_irq); + + break; +#endif + } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-ebsa285/timex.h linux.ac/include/asm-arm/arch-ebsa285/timex.h --- linux.vanilla/include/asm-arm/arch-ebsa285/timex.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-ebsa285/timex.h Sat Jan 9 17:03:45 1999 @@ -7,8 +7,7 @@ */ /* - * On the EBSA, the clock ticks at weird rates. - * This is therefore not used to calculate the - * divisor. + * On the EBSA285, the clock runs at 50MHz and is divided + * by a 4-bit prescaler. */ #define CLOCK_TICK_RATE (50000000 / 16) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-nexuspci/hardware.h linux.ac/include/asm-arm/arch-nexuspci/hardware.h --- linux.vanilla/include/asm-arm/arch-nexuspci/hardware.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-nexuspci/hardware.h Sat Jan 9 17:30:41 1999 @@ -18,16 +18,9 @@ #define __ASM_ARCH_HARDWARE_H /* - * What hardware must be present - */ - -#define HAS_PCIO -#define PCIO_BASE 0xfe000000 - -/* * Mapping areas */ -#define IO_BASE 0xfe000000 +#define PCIO_BASE 0xfe000000 /* * RAM definitions diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-nexuspci/irq.h linux.ac/include/asm-arm/arch-nexuspci/irq.h --- linux.vanilla/include/asm-arm/arch-nexuspci/irq.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-nexuspci/irq.h Fri Jan 22 09:51:31 1999 @@ -9,6 +9,8 @@ #include +#define fixup_irq(x) (x) + #define INTCONT 0xffe00000 extern unsigned long soft_irq_mask; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-nexuspci/mm-init.h linux.ac/include/asm-arm/arch-nexuspci/mm-init.h --- linux.vanilla/include/asm-arm/arch-nexuspci/mm-init.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-nexuspci/mm-init.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-nexuspci/mmap.h - * - * Copyright (C) 1998 Philip Blundell - */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-nexuspci/processor.h linux.ac/include/asm-arm/arch-nexuspci/processor.h --- linux.vanilla/include/asm-arm/arch-nexuspci/processor.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-nexuspci/processor.h Wed Jan 20 12:05:28 1999 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-ebsa110/processor.h + * linux/include/asm-arm/arch-nexuspci/processor.h * from linux/include/asm-arm/arch-ebsa110/processor.h * * Copyright (C) 1996,1997,1998 Russell King @@ -25,8 +25,5 @@ * space during mmap's. */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) - -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-nexuspci/time.h linux.ac/include/asm-arm/arch-nexuspci/time.h --- linux.vanilla/include/asm-arm/arch-nexuspci/time.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-nexuspci/time.h Fri Jan 22 09:49:10 1999 @@ -17,37 +17,53 @@ return 0; } -extern __inline__ int reset_timer (void) +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { static int count = 50; + writeb(0x90, UART_BASE + 8); - if (--count == 0) - { + + if (--count == 0) { static int state = 1; state ^= 1; writeb(0x1a + state, INTCONT); count = 50; } + readb(UART_BASE + 0x14); readb(UART_BASE + 0x14); readb(UART_BASE + 0x14); readb(UART_BASE + 0x14); readb(UART_BASE + 0x14); readb(UART_BASE + 0x14); - return 1; + + do_timer(regs); } -extern __inline__ unsigned long setup_timer (void) +static struct irqaction timerirq = { + timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; + +extern __inline__ void setup_timer(void) { int tick = 3686400 / 16 / 2 / 100; + writeb(tick & 0xff, UART_BASE + 0x1c); writeb(tick >> 8, UART_BASE + 0x18); writeb(0x80, UART_BASE + 8); writeb(0x10, UART_BASE + 0x14); + /* * Default the date to 1 Jan 1970 0:0:0 * You will have to run a time daemon to set the * clock correctly at bootup */ - return mktime(1970, 1, 1, 0, 0, 0); + xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0); + + setup_arm_irq(IRQ_TIMER, &timerirq); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/hardware.h linux.ac/include/asm-arm/arch-rpc/hardware.h --- linux.vanilla/include/asm-arm/arch-rpc/hardware.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-rpc/hardware.h Sun Jan 10 22:10:48 1999 @@ -13,7 +13,6 @@ * What hardware must be present */ #define HAS_IOMD -#include #define HAS_VIDC20 /* Hardware addresses of major areas. @@ -26,7 +25,7 @@ #define EASI_SIZE 0x08000000 /* EASI I/O */ #define EASI_START 0x08000000 -#define EASI_BASE 0xe8000000 +#define EASI_BASE 0xe5000000 #define IO_START 0x03000000 /* I/O */ #define IO_SIZE 0x01000000 @@ -47,8 +46,9 @@ #define IO_VIDC_AUDIO_BASE 0x80140000 #define IO_VIDC_BASE 0x80100000 #define IO_IOMD_BASE 0x80080000 +#define IOC_BASE 0x80080000 -#define IO_EC_EASI_BASE 0x82000000 +#define IO_EC_EASI_BASE 0x81400000 #define IO_EC_IOC4_BASE 0x8009c000 #define IO_EC_IOC_BASE 0x80090000 #define IO_EC_MEMC8_BASE 0x8000ac00 @@ -59,7 +59,7 @@ */ #define EXPMASK_BASE ((volatile unsigned char *)0xe0360000) #define IOEB_BASE ((volatile unsigned char *)0xe0350050) -#define IOC_BASE ((volatile unsigned char *)0xe0200000) +/*#define IOC_BASE ((volatile unsigned char *)0xe0200000)*/ #define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) #define PCIO_BASE 0xe0010000 @@ -83,7 +83,7 @@ #define KERNEL_BASE (PAGE_OFFSET + KERNEL_OFFSET) #define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET) #define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) -#define SAFE_ADDR 0x00000000 /* ROM */ +#define FLUSH_BASE_PHYS 0x00000000 /* ROM */ #else diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/irq.h linux.ac/include/asm-arm/arch-rpc/irq.h --- linux.vanilla/include/asm-arm/arch-rpc/irq.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-rpc/irq.h Fri Jan 22 09:51:31 1999 @@ -7,6 +7,9 @@ * 10-10-1996 RMK Brought up to date with arch-sa110eval * 22-08-1998 RMK Restructured IRQ routines */ +#include + +#define fixup_irq(x) (x) static void rpc_mask_irq_ack_a(unsigned int irq) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/oldlatches.h linux.ac/include/asm-arm/arch-rpc/oldlatches.h --- linux.vanilla/include/asm-arm/arch-rpc/oldlatches.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-rpc/oldlatches.h Thu Jan 1 01:00:00 1970 @@ -1,9 +0,0 @@ -/* - * Dummy oldlatches.h - * - * Copyright (C) 1996 Russell King - */ - -#ifdef __need_oldlatches -#error "Old latches not present in this (rpc) machine" -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/processor.h linux.ac/include/asm-arm/arch-rpc/processor.h --- linux.vanilla/include/asm-arm/arch-rpc/processor.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-rpc/processor.h Wed Jan 20 11:37:32 1999 @@ -28,7 +28,4 @@ */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } - #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/system.h linux.ac/include/asm-arm/arch-rpc/system.h --- linux.vanilla/include/asm-arm/arch-rpc/system.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-rpc/system.h Sat Jan 9 16:42:29 1999 @@ -7,6 +7,7 @@ #define __ASM_ARCH_SYSTEM_H #include +#include #define arch_reset(mode) { \ extern void ecard_reset (int card); \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/time.h linux.ac/include/asm-arm/arch-rpc/time.h --- linux.vanilla/include/asm-arm/arch-rpc/time.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-rpc/time.h Fri Jan 22 09:48:55 1999 @@ -8,6 +8,7 @@ * 10-Oct-1996 RMK Brought up to date with arch-sa110eval * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ +#include extern __inline__ unsigned long gettimeoffset (void) { @@ -51,21 +52,24 @@ return offset; } -/* - * No need to reset the timer at every irq - */ -#define reset_timer() 1 +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); +} -/* - * Updating of the RTC. We don't currently write the time to the - * CMOS clock. - */ -#define update_rtc() +static struct irqaction timerirq = { + timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; /* * Set up timer interrupt, and return the current time in seconds. */ -extern __inline__ unsigned long setup_timer (void) +extern __inline__ void setup_timer(void) { extern int iic_control (unsigned char, int, char *, int); unsigned int year, mon, day, hour, min, sec; @@ -92,5 +96,7 @@ BCD_TO_BIN(min); BCD_TO_BIN(sec); - return mktime(year, mon, day, hour, min, sec); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + + setup_arm_irq(IRQ_TIMER, &timerirq); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-rpc/uncompress.h linux.ac/include/asm-arm/arch-rpc/uncompress.h --- linux.vanilla/include/asm-arm/arch-rpc/uncompress.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/arch-rpc/uncompress.h Wed Feb 24 23:50:43 1999 @@ -5,7 +5,6 @@ */ #define VIDMEM ((char *)SCREEN_START) -#include "../arch/arm/drivers/char/font.h" #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/a.out.h linux.ac/include/asm-arm/arch-vnc/a.out.h --- linux.vanilla/include/asm-arm/arch-vnc/a.out.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-vnc/a.out.h Thu Jan 1 01:00:00 1970 @@ -1,14 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/a.out.h - * - * Copyright (C) 1996 Russell King - */ - -#ifndef __ASM_ARCH_A_OUT_H -#define __ASM_ARCH_A_OUT_H - -#ifdef __KERNEL__ -#define STACK_TOP ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000) -#endif - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/dma.h linux.ac/include/asm-arm/arch-vnc/dma.h --- linux.vanilla/include/asm-arm/arch-vnc/dma.h Sat Jan 9 21:50:48 1999 +++ linux.ac/include/asm-arm/arch-vnc/dma.h Thu Jan 1 01:00:00 1970 @@ -1,19 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/dma.h - * - * Architecture DMA routes - * - * Copyright (C) 1997.1998 Russell King - */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -/* - * This is the maximum DMA address that can be DMAd to. - * There should not be more than (0xd0000000 - 0xc0000000) - * bytes of RAM. - */ -#define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 8 - -#endif /* _ASM_ARCH_DMA_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/hardware.h linux.ac/include/asm-arm/arch-vnc/hardware.h --- linux.vanilla/include/asm-arm/arch-vnc/hardware.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/hardware.h Thu Jan 1 01:00:00 1970 @@ -1,74 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/hardware.h - * - * Copyright (C) 1998 Corel Computer/Russell King. - * - * This file contains the hardware definitions of the VNC. - */ - -/* Logical Physical - * 0xffe00000 0x7c000000 PCI I/O space - * 0xfe000000 0x42000000 CSR - * 0xfd000000 0x78000000 Outbound write flush - * 0xfc000000 0x79000000 PCI IACK/special space - * 0xf9000000 0x7a000000 PCI Config type 1 - * 0xf8000000 0x7b000000 PCI Config type 0 - * - */ - -#include - -#define IO_BASE_ARM_CSR 0xfe000000 -#define PCI_IACK 0xfc000000 - -/* LEDs */ -#define XBUS_LEDS ((volatile unsigned char *)0xfff12000) -#define XBUS_LED_AMBER (1 << 0) -#define XBUS_LED_GREEN (1 << 1) -#define XBUS_LED_RED (1 << 2) -#define XBUS_LED_TOGGLE (1 << 8) - -/* PIC irq control */ -#define PIC_LO 0x20 -#define PIC_MASK_LO 0x21 -#define PIC_HI 0xA0 -#define PIC_MASK_HI 0xA1 - -#define IO_END 0xffffffff -#define IO_BASE 0xe0000000 -#define IO_SIZE (IO_END - IO_BASE) - -#define HAS_PCIO -#define PCIO_BASE 0xffe00000 - -#define KERNTOPHYS(a) ((unsigned long)(&a)) - -//#define PARAMS_OFFSET 0x0100 -//#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET) - -#define FLUSH_BASE_PHYS 0x50000000 - -/* GPIO pins */ -#define GPIO_CCLK 0x800 -#define GPIO_DSCLK 0x400 -#define GPIO_E2CLK 0x200 -#define GPIO_IOLOAD 0x100 -#define GPIO_RED_LED 0x080 -#define GPIO_WDTIMER 0x040 -#define GPIO_DATA 0x020 -#define GPIO_IOCLK 0x010 -#define GPIO_DONE 0x008 -#define GPIO_FAN 0x004 -#define GPIO_GREEN_LED 0x002 -#define GPIO_RESET 0x001 - -/* CPLD pins */ -#define CPLD_DSRESET 8 -#define CPLD_UNMUTE 2 - -#ifndef __ASSEMBLY__ -extern void gpio_modify_op(int mask, int set); -extern void gpio_modify_io(int mask, int in); -extern int gpio_read(void); -extern void cpld_modify(int mask, int set); -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/ide.h linux.ac/include/asm-arm/arch-vnc/ide.h --- linux.vanilla/include/asm-arm/arch-vnc/ide.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/arch-vnc/ide.h Thu Jan 1 01:00:00 1970 @@ -1,42 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/ide.h - * - * Copyright (c) 1998 Russell King - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - */ -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) -{ - ide_ioreg_t reg = (ide_ioreg_t) data_port; - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ - hw_regs_t hw; - - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK); - ide_register_hw(&hw, NULL); -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/io.h linux.ac/include/asm-arm/arch-vnc/io.h --- linux.vanilla/include/asm-arm/arch-vnc/io.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/io.h Thu Jan 1 01:00:00 1970 @@ -1,176 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/io.h - * - * Copyright (C) 1997,1998 Russell King - * - * Modifications: - * 06-Dec-1997 RMK Created. - */ -#ifndef __ASM_ARM_ARCH_IO_H -#define __ASM_ARM_ARCH_IO_H - -/* - * This architecture does not require any delayed IO, and - * has the constant-optimised IO - */ -#undef ARCH_IO_DELAY - -/* - * Dynamic IO functions - let the compiler - * optimize the expressions - */ -#define DECLARE_DYN_OUT(fnsuffix,instr,typ) \ -extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port) \ -{ \ - __asm__ __volatile__( \ - "str%?" ##instr## " %0, [%1, %2] @ out"###fnsuffix \ - : \ - : "r" (value), "r" (PCIO_BASE), typ (port)); \ -} - -#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ) \ -extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \ -{ \ - unsigned long value; \ - __asm__ __volatile__( \ - "ldr%?" ##instr## " %0, [%1, %2] @ in"###fnsuffix \ - : "=&r" (value) \ - : "r" (PCIO_BASE), typ (port)); \ - return (unsigned sz)value; \ -} - -extern __inline__ unsigned int __ioaddr (unsigned int port) \ -{ \ - return (unsigned int)(PCIO_BASE + port); \ -} - -#define DECLARE_IO(sz,fnsuffix,instr,typ) \ - DECLARE_DYN_OUT(fnsuffix,instr,typ) \ - DECLARE_DYN_IN(sz,fnsuffix,instr,typ) - -DECLARE_IO(char,b,"b","Jr") -DECLARE_IO(short,w,"h","r") -DECLARE_IO(long,l,"","Jr") - -#undef DECLARE_IO -#undef DECLARE_DYN_OUT -#undef DECLARE_DYN_IN - -/* - * Constant address IO functions - * - * These have to be macros for the 'J' constraint to work - - * +/-4096 immediate operand. - */ -#define __outbc(value,port) \ -({ \ - __asm__ __volatile__( \ - "strb %0, [%1, %2] @ outbc" \ - : \ - : "r" (value), "r" (PCIO_BASE), "Jr" (port)); \ -}) - -#define __inbc(port) \ -({ \ - unsigned char result; \ - __asm__ __volatile__( \ - "ldrb %0, [%1, %2] @ inbc" \ - : "=r" (result) \ - : "r" (PCIO_BASE), "Jr" (port)); \ - result; \ -}) - -#define __outwc(value,port) \ -({ \ - __asm__ __volatile__( \ - "strh %0, [%1, %2] @ outwc" \ - : \ - : "r" (value), "r" (PCIO_BASE), "r" (port)); \ -}) - -#define __inwc(port) \ -({ \ - unsigned short result; \ - __asm__ __volatile__( \ - "ldrh %0, [%1, %2] @ inwc" \ - : "=r" (result) \ - : "r" (PCIO_BASE), "r" (port)); \ - result & 0xffff; \ -}) - -#define __outlc(value,port) \ -({ \ - __asm__ __volatile__( \ - "str %0, [%1, %2] @ outlc" \ - : \ - : "r" (value), "r" (PCIO_BASE), "Jr" (port)); \ -}) - -#define __inlc(port) \ -({ \ - unsigned long result; \ - __asm__ __volatile__( \ - "ldr %0, [%1, %2] @ inlc" \ - : "=r" (result) \ - : "r" (PCIO_BASE), "Jr" (port)); \ - result; \ -}) - -#define __ioaddrc(port) \ -({ \ - unsigned long addr; \ - addr = PCIO_BASE + port; \ - addr; \ -}) - -/* - * Translated address IO functions - * - * IO address has already been translated to a virtual address - */ -#define outb_t(v,p) \ - (*(volatile unsigned char *)(p) = (v)) - -#define inb_t(p) \ - (*(volatile unsigned char *)(p)) - -#define outl_t(v,p) \ - (*(volatile unsigned long *)(p) = (v)) - -#define inl_t(p) \ - (*(volatile unsigned long *)(p)) - -/* - * This is not sufficient... (and it's a hack anyway) - */ -static inline void writeb(unsigned char b, unsigned int addr) -{ - *(volatile unsigned char *)(0xe0000000 + (addr)) = b; -} - -static inline unsigned char readb(unsigned int addr) -{ - return *(volatile unsigned char *)(0xe0000000 + (addr)); -} - -static inline void writew(unsigned short b, unsigned int addr) -{ - *(volatile unsigned short *)(0xe0000000 + (addr)) = b; -} - -static inline unsigned short readw(unsigned int addr) -{ - return *(volatile unsigned short *)(0xe0000000 + (addr)); -} - -static inline void writel(unsigned long b, unsigned int addr) -{ - *(volatile unsigned long *)(0xe0000000 + (addr)) = b; -} - -static inline unsigned long readl(unsigned int addr) -{ - return *(volatile unsigned long *)(0xe0000000 + (addr)); -} - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/irq.h linux.ac/include/asm-arm/arch-vnc/irq.h --- linux.vanilla/include/asm-arm/arch-vnc/irq.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/arch-vnc/irq.h Thu Jan 1 01:00:00 1970 @@ -1,156 +0,0 @@ -/* - * include/asm-arm/arch-vnc/irq.h - * - * Copyright (C) 1998 Russell King - * - * Changelog: - * 22-08-1998 RMK Restructured IRQ routines - */ - -#include -#include - -/* - * FootBridge IRQ translation table - * Converts form our IRQ numbers into FootBridge masks (defined in irqs.h) - */ -static int fb_irq_mask[16] = { - 0, - IRQ_MASK_SOFTIRQ, - IRQ_MASK_UART_DEBUG, - 0, - IRQ_MASK_TIMER0, - IRQ_MASK_TIMER1, - IRQ_MASK_TIMER2, - IRQ_MASK_WATCHDOG, - IRQ_MASK_ETHER10, - IRQ_MASK_ETHER100, - IRQ_MASK_VIDCOMP, - IRQ_MASK_EXTERN_IRQ, - IRQ_MASK_DMA1, - 0, - 0, - IRQ_MASK_PCI_ERR -}; - -static void vnc_mask_csr_irq(unsigned int irq) -{ - *CSR_IRQ_DISABLE = fb_irq_mask[irq]; -} - -static void vnc_unmask_csr_irq(unsigned int irq) -{ - *CSR_IRQ_ENABLE = fb_irq_mask[irq]; -} - -static void vnc_mask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); -} - -static void vnc_mask_ack_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); - outb(0x20, PIC_LO); -} - -static void vnc_unmask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = ~(1 << (irq & 7)); - - outb(inb(PIC_MASK_LO) & mask, PIC_MASK_LO); -} - -static void vnc_mask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); -} - -static void vnc_mask_ack_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); - outb(0x62, PIC_LO); - outb(0x20, PIC_HI); -} - -static void vnc_unmask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); -} - -static void no_action(int irq, void *dev_id, struct pt_regs *regs) -{ -} - -static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; - -static __inline__ void irq_init_irq(void) -{ - unsigned int irq; - - outb(0x11, PIC_LO); - outb(0x10, PIC_MASK_LO); - outb(0x04, PIC_MASK_LO); - outb(1, PIC_MASK_LO); - - outb(0x11, PIC_HI); - outb(0x18, PIC_MASK_HI); - outb(0x02, PIC_MASK_HI); - outb(1, PIC_MASK_HI); - - *CSR_IRQ_DISABLE = ~IRQ_MASK_EXTERN_IRQ; - *CSR_IRQ_ENABLE = IRQ_MASK_EXTERN_IRQ; - *CSR_FIQ_DISABLE = -1; - - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - - if (irq < 16) { - irq_desc[irq].mask_ack = vnc_mask_csr_irq; - irq_desc[irq].mask = vnc_mask_csr_irq; - irq_desc[irq].unmask = vnc_unmask_csr_irq; - } else if (irq < 24) { -irq_desc[irq].probe_ok = 0; - irq_desc[irq].mask_ack = vnc_mask_ack_pic_lo_irq; - irq_desc[irq].mask = vnc_mask_pic_lo_irq; - irq_desc[irq].unmask = vnc_unmask_pic_lo_irq; - } else { -irq_desc[irq].probe_ok = 0; - irq_desc[irq].mask_ack = vnc_mask_ack_pic_hi_irq; - irq_desc[irq].mask = vnc_mask_pic_hi_irq; - irq_desc[irq].unmask = vnc_unmask_pic_hi_irq; - } - } - - irq_desc[0].probe_ok = 0; - irq_desc[IRQ_SOFTIRQ].probe_ok = 0; - irq_desc[IRQ_CONRX].probe_ok = 0; - irq_desc[IRQ_CONTX].probe_ok = 0; - irq_desc[IRQ_TIMER0].probe_ok = 0; - irq_desc[IRQ_TIMER1].probe_ok = 0; - irq_desc[IRQ_TIMER2].probe_ok = 0; - irq_desc[IRQ_WATCHDOG].probe_ok = 0; - irq_desc[IRQ_DMA1].probe_ok = 0; - irq_desc[13].probe_ok = 0; - irq_desc[14].probe_ok = 0; - irq_desc[IRQ_PCI_ERR].probe_ok = 0; - irq_desc[IRQ_PIC_HI].probe_ok = 0; - irq_desc[29].probe_ok = 0; - irq_desc[31].probe_ok = 0; - - outb(0xff, PIC_MASK_LO); - outb(0xff, PIC_MASK_HI); - - setup_arm_irq(IRQ_PIC_HI, &irq_cascade); -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/irqs.h linux.ac/include/asm-arm/arch-vnc/irqs.h --- linux.vanilla/include/asm-arm/arch-vnc/irqs.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/irqs.h Thu Jan 1 01:00:00 1970 @@ -1,67 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/irqs.h - * - * Copyright (C) 1998 Russell King - */ - -#define NR_IRQS 32 - -/* - * This is a list of all interrupts that the 21285 - * can generate - */ -#define IRQ_SOFTIRQ 1 /* from FB.1 */ -#define IRQ_CONRX 2 /* from FB.2 */ -#define IRQ_CONTX 3 /* from FB.3 */ -#define IRQ_TIMER0 4 /* from FB.4 */ -#define IRQ_TIMER1 5 /* from FB.5 */ -#define IRQ_TIMER2 6 /* from FB.6 */ -#define IRQ_WATCHDOG 7 /* from FB.7 */ -#define IRQ_ETHER10 8 /* from FB.8 */ -#define IRQ_ETHER100 9 /* from FB.9 */ -#define IRQ_VIDCOMP 10 /* from FB.10 */ -#define IRQ_EXTERN_IRQ 11 /* from FB.11: chain to IDE irq's */ -#define IRQ_DMA1 12 /* from future */ -#define IRQ_PCI_ERR 15 /* from FB.[28:31] */ - -#define IRQ_TIMER4 16 /* from 553.0 */ -#define IRQ_KEYBOARD 17 /* from 553.1 */ -#define IRQ_PIC_HI 18 /* from 533.2: chained to 553.[8:15] */ -#define IRQ_UART2 19 /* from 553.3 */ -#define IRQ_UART 20 /* from 553.4 */ -#define IRQ_MOUSE 21 /* from 553.5 */ -#define IRQ_UART_IR 22 /* from 553.6 */ -#define IRQ_PRINTER 23 /* from 553.7 */ -#define IRQ_RTC_ALARM 24 /* from 553.8 */ -#define IRQ_POWERLOW 26 /* from 553.10 */ -#define IRQ_VGA 27 /* from 553.11 */ -#define IRQ_SOUND 28 /* from 553.12 */ -#define IRQ_HARDDISK 30 /* from 553.14 */ - -/* These defines handle the translation from the above FB #defines - * into physical bits for the FootBridge IRQ registers - */ -#define IRQ_MASK_SOFTIRQ 0x00000002 -#define IRQ_MASK_UART_DEBUG 0x0000000C -#define IRQ_MASK_TIMER0 0x00000010 -#define IRQ_MASK_TIMER1 0x00000020 -#define IRQ_MASK_TIMER2 0x00000040 -#define IRQ_MASK_WATCHDOG 0x00000080 -#define IRQ_MASK_ETHER10 0x00000100 -#define IRQ_MASK_ETHER100 0x00000200 -#define IRQ_MASK_VIDCOMP 0x00000400 -#define IRQ_MASK_EXTERN_IRQ 0x00000800 -#define IRQ_MASK_DMA1 0x00030000 -#define IRQ_MASK_PCI_ERR 0xf8800000 - -/* - * Now map them to the Linux interrupts - */ -#undef IRQ_TIMER -#define IRQ_TIMER IRQ_TIMER0 -#undef RTC_IRQ -#define RTC_IRQ IRQ_RTC_ALARM -#undef AUX_IRQ -#define AUX_IRQ IRQ_MOUSE - -#define irq_cannonicalize(i) (i) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/keyboard.h linux.ac/include/asm-arm/arch-vnc/keyboard.h --- linux.vanilla/include/asm-arm/arch-vnc/keyboard.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/arch-vnc/keyboard.h Thu Jan 1 01:00:00 1970 @@ -1,38 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/keyboard.h - * - * Keyboard driver definitions for VNC architecture - * - * (C) 1998 Russell King - */ - -#include - -#define NR_SCANCODES 128 - -#define KEYBOARD_IRQ IRQ_KEYBOARD - -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); -extern unsigned char pckbd_sysrq_xlate[128]; - -#define kbd_setkeycode pckbd_setkeycode -#define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate -#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \ - pckbd_translate(sc & 0x7f, kcp, rm);}) - -#define kbd_unexpected_up pckbd_unexpected_up -#define kbd_leds pckbd_leds -#define kbd_init_hw() pckbd_init_hw() -#define kbd_sysrq_xlate pckbd_sysrq_xlate -#define kbd_disable_irq() -#define kbd_enable_irq() - -#define SYSRQ_KEY 0x54 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/mm-init.h linux.ac/include/asm-arm/arch-vnc/mm-init.h --- linux.vanilla/include/asm-arm/arch-vnc/mm-init.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/mm-init.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/mmap.h - * - * Copyright (C) 1996,1997,1998 Russell King - */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/mmu.h linux.ac/include/asm-arm/arch-vnc/mmu.h --- linux.vanilla/include/asm-arm/arch-vnc/mmu.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/arch-vnc/mmu.h Thu Jan 1 01:00:00 1970 @@ -1,26 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/mmu.h - * - * Copyright (c) 1996,1997,1998 Russell King. - * - * Changelog: - * 20-10-1996 RMK Created - * 31-12-1997 RMK Fixed definitions to reduce warnings - */ -#ifndef __ASM_ARCH_MMU_H -#define __ASM_ARCH_MMU_H - -/* - * On ebsa, the dram is contiguous - */ -#define __virt_to_phys__is_a_macro -#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) -#define __phys_to_virt__is_a_macro -#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) - -#define __virt_to_bus__is_a_macro -#define __virt_to_bus(x) (x - 0xe0000000) -#define __bus_to_virt__is_a_macro -#define __bus_to_virt(x) (x + 0xe0000000) - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/oldlatches.h linux.ac/include/asm-arm/arch-vnc/oldlatches.h --- linux.vanilla/include/asm-arm/arch-vnc/oldlatches.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/oldlatches.h Thu Jan 1 01:00:00 1970 @@ -1,9 +0,0 @@ -/* - * Dummy oldlatches.h - * - * Copyright (C) 1996 Russell King - */ - -#ifdef __need_oldlatches -#error "Old latches not present in this (rpc) machine" -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/param.h linux.ac/include/asm-arm/arch-vnc/param.h --- linux.vanilla/include/asm-arm/arch-vnc/param.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/param.h Thu Jan 1 01:00:00 1970 @@ -1,8 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/param.h - * - * Copyright (C) 1996 Russell King - * Copyright (C) 1998 Philip Blundell - */ - -#define HZ 100 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/processor.h linux.ac/include/asm-arm/arch-vnc/processor.h --- linux.vanilla/include/asm-arm/arch-vnc/processor.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/processor.h Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/processor.h - * - * Copyright (C) 1996,1997,1998 Russell King - */ - -#ifndef __ASM_ARCH_PROCESSOR_H -#define __ASM_ARCH_PROCESSOR_H - -/* - * Bus types - */ -#define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ -#define MCA_bus 0 -#define MCA_bus__is_a_macro /* for versions in ksyms.c */ - -/* - * User space: 3GB - */ -#define TASK_SIZE (0xc0000000UL) - -/* This decides where the kernel will search for a free chunk of vm - * space during mmap's. - */ -#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) - -#define INIT_MMAP \ -{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/serial.h linux.ac/include/asm-arm/arch-vnc/serial.h --- linux.vanilla/include/asm-arm/arch-vnc/serial.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/serial.h Thu Jan 1 01:00:00 1970 @@ -1,43 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/serial.h - * - * Copyright (c) 1996 Russell King. - * - * Changelog: - * 15-10-1996 RMK Created - * 03-05-1998 RMK Modified for Corel Video NC - */ -#ifndef __ASM_ARCH_SERIAL_H -#define __ASM_ARCH_SERIAL_H - -#include - -/* - * This assumes you have a 1.8432 MHz clock for your UART. - * - * It'd be nice if someone built a serial card with a 24.576 MHz - * clock, since the 16550A is capable of handling a top speed of 1.5 - * megabits/second; but this requires the faster clock. - */ -#define BASE_BAUD (1843200 / 16) - -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) - - /* UART CLK PORT IRQ FLAGS */ -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, 0x3F8, IRQ_UART , STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, IRQ_UART2, STD_COM_FLAGS }, /* ttyS1 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS2 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS3 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS4 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS5 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS6 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS7 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS8 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS9 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS10 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS11 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS12 */ \ - { 0, BASE_BAUD, 0 , 0 , STD_COM_FLAGS }, /* ttyS13 */ - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/shmparam.h linux.ac/include/asm-arm/arch-vnc/shmparam.h --- linux.vanilla/include/asm-arm/arch-vnc/shmparam.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/shmparam.h Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/shmparam.h - * - * Copyright (c) 1996 Russell King. - */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/system.h linux.ac/include/asm-arm/arch-vnc/system.h --- linux.vanilla/include/asm-arm/arch-vnc/system.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/system.h Thu Jan 1 01:00:00 1970 @@ -1,37 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/system.h - * - * Copyright (c) 1996,1997,1998 Russell King. - * Copyright (c) 1998 Corel Computer Corp. - */ -#include -#include -#include -#include - -extern __inline__ void arch_reset(char mode) -{ - cli(); - - /* open up the SuperIO chip - */ - outb(0x87, 0x370); - outb(0x87, 0x370); - - /* aux function group 1 (Logical Device 7) - */ - outb(0x07, 0x370); - outb(0x07, 0x371); - - /* set GP16 for WD-TIMER output - */ - outb(0xE6, 0x370); - outb(0x00, 0x371); - - /* set a RED LED and toggle WD_TIMER for rebooting... - */ - outb(0xC4, 0x338); -} - -#define arch_start_idle() leds_event(led_idle_start) -#define arch_end_idle() leds_event(led_idle_end) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/time.h linux.ac/include/asm-arm/arch-vnc/time.h --- linux.vanilla/include/asm-arm/arch-vnc/time.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/arch-vnc/time.h Thu Jan 1 01:00:00 1970 @@ -1,232 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/time.h - * - * Copyright (c) 1997 Corel Computer Corp. - * Slight modifications to bring in line with ebsa285 port. - * -- Russell King. - * Added LED driver (based on the ebsa285 code) - Alex Holden 28/12/98. - */ - -#include -#include - -#include -#include - -#undef IRQ_TIMER -#define IRQ_TIMER IRQ_TIMER4 - -#define mSEC_10_from_14 ((14318180 + 100) / 200) - -extern __inline__ unsigned long gettimeoffset (void) -{ - int count; - - static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* timer count may underflow right here */ - outb_p(0x00, 0x43); /* latch the count ASAP */ - - count = inb_p(0x40); /* read the latched count */ - - /* - * We do this guaranteed double memory access instead of a _p - * postfix in the previous port access. Wheee, hackady hack - */ - jiffies_t = jiffies; - - count |= inb_p(0x40) << 8; - - /* Detect timer underflows. If we haven't had a timer tick since - the last time we were called, and time is apparently going - backwards, the counter must have wrapped during this routine. */ - if ((jiffies_t == jiffies_p) && (count > count_p)) - count -= (mSEC_10_from_14/6); - else - jiffies_p = jiffies_t; - - count_p = count; - - count = (((mSEC_10_from_14/6)-1) - count) * tick; - count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); - - return count; -} - -extern __inline__ int reset_timer (void) -{ -#ifdef CONFIG_LEDS - static unsigned int count = 50; - static int last_pid; - - if (current->pid != last_pid) { - last_pid = current->pid; - if (last_pid) - leds_event(led_idle_end); - else - leds_event(led_idle_start); - } - - if (--count == 0) { - count = 50; - leds_event(led_timer); - } -#endif - return 1; -} - -unsigned long set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else - retval = -1; - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return retval; -} - -/* - * We don't have a RTC to update! - */ -extern __inline__ void update_rtc(void) -{ - static long last_rtc_update = 0; /* last time the cmos clock got updated */ - - /* If we have an externally synchronized linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 50000 - (tick >> 1) && - xtime.tv_usec < 50000 + (tick >> 1)) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ - } -} - -extern __inline__ unsigned long get_cmos_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - int i; - - // check to see if the RTC makes sense..... - if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0) - return mktime(1970, 1, 1, 0, 0, 0); - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - - do { /* Isn't this overkill ? UIP above should guarantee consistency */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - if ((year += 1900) < 1970) - year += 100; - return mktime(year, mon, day, hour, min, sec); -} - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -extern __inline__ unsigned long setup_timer (void) -{ - unsigned int c; - - /* Turn on the RTC */ - outb(13, 0x70); - if ((inb(0x71) & 0x80) == 0) - printk("RTC: *** warning: CMOS battery bad\n"); - - outb(10, 0x70); /* select control reg */ - outb(32, 0x71); /* make sure the divider is set */ - outb(11, 0x70); /* select other control reg */ - c = inb(0x71) & 0xfb; /* read it */ - outb(11, 0x70); - outb(c | 2, 0x71); /* turn on BCD counting and 24 hour clock mode */ - - /* enable PIT timer */ - /* set for periodic (4) and LSB/MSB write (0x30) */ - outb(0x34, 0x43); - outb((mSEC_10_from_14/6) & 0xFF, 0x40); - outb((mSEC_10_from_14/6) >> 8, 0x40); - - /* - * Default the date to 1 Jan 1970 00:00:00 - * You will have to run a time daemon to set the - * clock correctly at bootup - */ - return get_cmos_time(); -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/timex.h linux.ac/include/asm-arm/arch-vnc/timex.h --- linux.vanilla/include/asm-arm/arch-vnc/timex.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/timex.h Thu Jan 1 01:00:00 1970 @@ -1,13 +0,0 @@ -/* - * linux/include/asm-arm/arch-vnc/timex.h - * - * Corel Video NC architecture timex specifications - * - * Copyright (C) 1998 Corel Computer/Russell King - */ - -/* - * On the VNC, the clock runs at 66MHz and is divided - * by a 4-bit prescaler. - */ -#define CLOCK_TICK_RATE (66000000 / 16) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/arch-vnc/uncompress.h linux.ac/include/asm-arm/arch-vnc/uncompress.h --- linux.vanilla/include/asm-arm/arch-vnc/uncompress.h Sun Nov 8 15:07:08 1998 +++ linux.ac/include/asm-arm/arch-vnc/uncompress.h Thu Jan 1 01:00:00 1970 @@ -1,34 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/uncompress.h - * - * Copyright (C) 1996,1997,1998 Russell King - */ - -/* - * This does not append a newline - */ -static void puts(const char *s) -{ - __asm__ __volatile__(" - ldrb %0, [%2], #1 - teq %0, #0 - beq 3f -1: strb %0, [%3] -2: ldrb %1, [%3, #0x14] - and %1, %1, #0x60 - teq %1, #0x60 - bne 2b - teq %0, #'\n' - moveq %0, #'\r' - beq 1b - ldrb %0, [%2], #1 - teq %0, #0 - bne 1b -3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); -} - -/* - * nothing to do - */ -#define arch_decomp_setup() -#define arch_decomp_wdog() diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/dec21285.h linux.ac/include/asm-arm/dec21285.h --- linux.vanilla/include/asm-arm/dec21285.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/dec21285.h Tue Feb 23 16:17:12 1999 @@ -15,7 +15,8 @@ #define DC21285_PCI_MEM 0x80000000 #ifndef __ASSEMBLY__ -#define DC21285_IO(x) ((volatile unsigned long *)(0xfe000000+(x))) +#include +#define DC21285_IO(x) ((volatile unsigned long *)(ARMCSR_BASE+(x))) #else #define DC21285_IO(x) (x) #endif @@ -44,6 +45,33 @@ #define CSR_I2O_OUTPOSTCOUNT DC21285_IO(0x0134) #define CSR_I2O_INPOSTCOUNT DC21285_IO(0x0138) #define CSR_SA110_CNTL DC21285_IO(0x013c) +#define SA110_CNTL_INITCMPLETE (1 << 0) +#define SA110_CNTL_ASSERTSERR (1 << 1) +#define SA110_CNTL_RXSERR (1 << 3) +#define SA110_CNTL_SA110DRAMPARITY (1 << 4) +#define SA110_CNTL_PCISDRAMPARITY (1 << 5) +#define SA110_CNTL_DMASDRAMPARITY (1 << 6) +#define SA110_CNTL_DISCARDTIMER (1 << 8) +#define SA110_CNTL_PCINRESET (1 << 9) +#define SA110_CNTL_I2O_256 (0 << 10) +#define SA110_CNTL_I20_512 (1 << 10) +#define SA110_CNTL_I2O_1024 (2 << 10) +#define SA110_CNTL_I2O_2048 (3 << 10) +#define SA110_CNTL_I2O_4096 (4 << 10) +#define SA110_CNTL_I2O_8192 (5 << 10) +#define SA110_CNTL_I2O_16384 (6 << 10) +#define SA110_CNTL_I2O_32768 (7 << 10) +#define SA110_CNTL_WATCHDOG (1 << 13) +#define SA110_CNTL_ROMWIDTH_UNDEF (0 << 14) +#define SA110_CNTL_ROMWIDTH_16 (1 << 14) +#define SA110_CNTL_ROMWIDTH_32 (2 << 14) +#define SA110_CNTL_ROMWIDTH_8 (3 << 14) +#define SA110_CNTL_ROMACCESSTIME(x) ((x)<<16) +#define SA110_CNTL_ROMBURSTTIME(x) ((x)<<20) +#define SA110_CNTL_ROMTRISTATETIME(x) ((x)<<24) +#define SA110_CNTL_XCSDIR(x) ((x)<<28) +#define SA110_CNTL_PCICFN (1 << 31) + #define CSR_PCIADDR_EXTN DC21285_IO(0x0140) #define CSR_PREFETCHMEMRANGE DC21285_IO(0x0144) #define CSR_XBUS_CYCLE DC21285_IO(0x0148) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/dma.h linux.ac/include/asm-arm/dma.h --- linux.vanilla/include/asm-arm/dma.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/dma.h Tue Feb 2 20:29:26 1999 @@ -11,15 +11,16 @@ #include /* - * DMA modes - we have two, IN and OUT + * DMA modes */ typedef unsigned int dmamode_t; -#define DMA_MODE_MASK 1 +#define DMA_MODE_MASK 3 -#define DMA_MODE_READ 0 -#define DMA_MODE_WRITE 1 -#define DMA_AUTOINIT 2 +#define DMA_MODE_READ 0 +#define DMA_MODE_WRITE 1 +#define DMA_MODE_CASCADE 2 +#define DMA_AUTOINIT 4 typedef struct { unsigned long address; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/ecard.h linux.ac/include/asm-arm/ecard.h --- linux.vanilla/include/asm-arm/ecard.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/ecard.h Sun Feb 28 09:54:04 1999 @@ -47,6 +47,9 @@ #define MANU_ICS 0x003c #define PROD_ICS_IDE 0x00ae +#define MANU_ICS2 0x003d +#define PROD_ICS2_IDE 0x00ae + #define MANU_SERPORT 0x003f #define PROD_SERPORT_DSPORT 0x00b9 @@ -76,7 +79,7 @@ #define CONST const #endif -#define MAX_ECARDS 8 +#define MAX_ECARDS 9 typedef enum { /* Cards address space */ ECARD_IOC, @@ -116,14 +119,18 @@ typedef struct { /* Card handler routines */ void (*irqenable)(ecard_t *ec, int irqnr); void (*irqdisable)(ecard_t *ec, int irqnr); + int (*irqpending)(ecard_t *ec); void (*fiqenable)(ecard_t *ec, int fiqnr); void (*fiqdisable)(ecard_t *ec, int fiqnr); + int (*fiqpending)(ecard_t *ec); } expansioncard_ops_t; /* * This contains all the info needed on an expansion card */ struct expansion_card { + struct expansion_card *next; + /* Public data */ volatile unsigned char *irqaddr; /* address of IRQ register */ volatile unsigned char *fiqaddr; /* address of FIQ register */ @@ -135,10 +142,10 @@ void *fiq_data; /* Data for use for FIQ by card */ expansioncard_ops_t *ops; /* Enable/Disable Ops for card */ - CONST unsigned char slot_no; /* Slot number */ - CONST unsigned char dma; /* DMA number (for request_dma) */ - CONST unsigned char irq; /* IRQ number (for request_irq) */ - CONST unsigned char fiq; /* FIQ number (for request_irq) */ + CONST unsigned int slot_no; /* Slot number */ + CONST unsigned int dma; /* DMA number (for request_dma) */ + CONST unsigned int irq; /* IRQ number (for request_irq) */ + CONST unsigned int fiq; /* FIQ number (for request_irq) */ CONST card_type_t type; /* Type of card */ CONST struct in_ecid cid; /* Card Identification */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/fiq.h linux.ac/include/asm-arm/fiq.h --- linux.vanilla/include/asm-arm/fiq.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/fiq.h Tue Feb 2 20:27:00 1999 @@ -30,5 +30,6 @@ extern void release_fiq(struct fiq_handler *f); extern void set_fiq_handler(void *start, unsigned int length); extern void set_fiq_regs(struct pt_regs *regs); +extern void get_fiq_regs(struct pt_regs *regs); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/init.h linux.ac/include/asm-arm/init.h --- linux.vanilla/include/asm-arm/init.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/init.h Sun Jan 24 10:59:47 1999 @@ -5,7 +5,7 @@ /* C routines */ -#ifdef CONFIG_TEXT_INIT_SECTION +#ifdef CONFIG_TEXT_SECTIONS #define __init __attribute__ ((__section__ (".text.init"))) #define __initfunc(__arginit) \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/io.h linux.ac/include/asm-arm/io.h --- linux.vanilla/include/asm-arm/io.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/io.h Fri Jan 22 11:14:18 1999 @@ -12,6 +12,27 @@ #ifndef __ASM_ARM_IO_H #define __ASM_ARM_IO_H +#ifdef __KERNEL__ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); + +/* + * String version of IO memory access ops: + */ +extern void _memcpy_fromio(void *, unsigned long, unsigned long); +extern void _memcpy_toio(unsigned long, void *, unsigned long); +extern void _memset_io(unsigned long, int, unsigned long); + +#define memcpy_fromio(to,from,len) _memcpy_fromio((to),(unsigned long)(from),(len)) +#define memcpy_toio(to,from,len) _memcpy_toio((unsigned long)(to),(from),(len)) +#define memset_io(addr,c,len) _memset_io((unsigned long)(addr),(c),(len)) + +#endif + #include #include #include @@ -170,23 +191,6 @@ #undef ARCH_IO_DELAY #undef ARCH_IO_CONSTANT - -#ifdef __KERNEL__ - -extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); - -/* - * String version of IO memory access ops: - */ -extern void _memcpy_fromio(void *, unsigned long, unsigned long); -extern void _memcpy_toio(unsigned long, void *, unsigned long); -extern void _memset_io(unsigned long, int, unsigned long); - -#define memcpy_fromio(to,from,len) _memcpy_fromio((to),(unsigned long)(from),(len)) -#define memcpy_toio(to,from,len) _memcpy_toio((unsigned long)(to),(from),(len)) -#define memset_io(addr,c,len) _memset_io((unsigned long)(addr),(c),(len)) - -#endif #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/ioc.h linux.ac/include/asm-arm/ioc.h --- linux.vanilla/include/asm-arm/ioc.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/ioc.h Sun Jan 10 22:37:52 1999 @@ -3,6 +3,8 @@ * read/write. */ +#ifndef IOC_CONTROL + #ifndef __ASSEMBLER__ #define __IOC(offset) (IOC_BASE + (offset >> 2)) #else @@ -54,3 +56,4 @@ #define IOC_T3GO __IOC(0x78) #define IOC_T3LATCH __IOC(0x7c) +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/iomd.h linux.ac/include/asm-arm/iomd.h --- linux.vanilla/include/asm-arm/iomd.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/iomd.h Sun Jan 10 22:37:57 1999 @@ -125,6 +125,8 @@ #define DMA_ST_OFL 4 #define DMA_ST_INT 2 #define DMA_ST_AB 1 + +#ifndef IOC_CONTROL /* * IOC compatability */ @@ -155,6 +157,7 @@ #define IOC_T1LTCHH IOMD_T1LTCHH #define IOC_T1GO IOMD_T1GO #define IOC_T1LATCH IOMD_T1LATCH +#endif /* * DMA (MEMC) compatability diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/irq.h linux.ac/include/asm-arm/irq.h --- linux.vanilla/include/asm-arm/irq.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/irq.h Sun Feb 7 19:27:02 1999 @@ -16,7 +16,7 @@ * capability */ #ifndef NO_IRQ -#define NO_IRQ 255 +#define NO_IRQ ((unsigned int)(-1)) #endif extern void disable_irq(unsigned int); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/memc.h linux.ac/include/asm-arm/memc.h --- linux.vanilla/include/asm-arm/memc.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/memc.h Sat Feb 6 23:09:20 1999 @@ -4,6 +4,9 @@ #define VDMA_START 1 #define VDMA_END 2 +#ifndef __ASSEMBLER__ +extern void memc_write(unsigned int reg, unsigned long val); + #define video_set_dma(start,end,offset) \ do { \ memc_write (VDMA_START, (start >> 2)); \ @@ -11,3 +14,4 @@ memc_write (VDMA_INIT, (offset >> 2)); \ } while (0) +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/mm-init.h linux.ac/include/asm-arm/mm-init.h --- linux.vanilla/include/asm-arm/mm-init.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/mm-init.h Thu Jan 1 01:00:00 1970 @@ -1,46 +0,0 @@ -/* - * linux/include/asm-arm/mm-init.h - * - * Copyright (C) 1997,1998 Russell King - * - * Contained within are structures to describe how to set up the - * initial memory map. It includes both a processor-specific header - * for parsing these structures, and an architecture-specific header - * to fill out the structures. - */ -#ifndef __ASM_MM_INIT_H -#define __ASM_MM_INIT_H - -typedef enum { - // physical address is absolute - init_mem_map_absolute, - /* physical address is relative to start_mem - * as passed in paging_init - */ - init_mem_map_relative_start_mem -} init_memmap_type_t; - -typedef struct { - init_memmap_type_t type; - unsigned long physical_address; - unsigned long virtual_address; - unsigned long size; -} init_memmap_t; - -#define INIT_MEM_MAP_SENTINEL { init_mem_map_absolute, 0, 0, 0 } -#define INIT_MEM_MAP_ABSOLUTE(p,l,s) { init_mem_map_absolute,p,l,s } -#define INIT_MEM_MAP_RELATIVE(o,l,s) { init_mem_map_relative_start_mem,o,l,s } - -/* - * Within this file, initialise an array of init_mem_map_t's - * to describe your initial memory mapping structure. - */ -#include - -/* - * Contained within this file is code to read the array - * of init_mem_map_t's created above. - */ -#include - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armo/mm-init.h linux.ac/include/asm-arm/proc-armo/mm-init.h --- linux.vanilla/include/asm-arm/proc-armo/mm-init.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/proc-armo/mm-init.h Sun Feb 7 19:27:18 1999 @@ -8,8 +8,6 @@ * some more work to get it to fit into our separate processor and * architecture structure. */ -extern unsigned long phys_screen_end; -extern unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update); int page_nr; #define setup_processor_functions() @@ -20,10 +18,11 @@ set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep)); } -static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem) +static inline unsigned long +setup_pagetables(unsigned long start_mem, unsigned long end_mem) { unsigned int i; - union {unsigned long l; pte_t *pte; } u; + union { unsigned long l; pte_t *pte; } u; page_nr = MAP_NR(end_mem); @@ -37,14 +36,11 @@ for (i = 1; i < PTRS_PER_PGD; i++) pgd_val(swapper_pg_dir[i]) = 0; - /* now map screen mem in */ - phys_screen_end = SCREEN2_END; - map_screen_mem (SCREEN1_END - 480*1024, 0, 0); - return start_mem; } -static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem) +static inline void +mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem) { unsigned long smem; @@ -54,7 +50,4 @@ clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags); smem += PAGE_SIZE; } - - for (smem = phys_screen_end; smem < SCREEN2_END; smem += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armo/pgtable.h linux.ac/include/asm-arm/proc-armo/pgtable.h --- linux.vanilla/include/asm-arm/proc-armo/pgtable.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/proc-armo/pgtable.h Tue Feb 9 22:27:47 1999 @@ -7,6 +7,7 @@ #ifndef __ASM_PROC_PGTABLE_H #define __ASM_PROC_PGTABLE_H +#include #include #include #include /* For TASK_SIZE */ @@ -280,13 +281,17 @@ return __phys_to_virt(pte_val(pte) & PAGE_MASK); } -extern __inline__ pmd_t mk_pmd (pte_t *ptep) +extern __inline__ pmd_t mk_pmd(pte_t *ptep) { pmd_t pmd; pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_TABLE; return pmd; } +/* these are aliases for the above function */ +#define mk_user_pmd(ptep) mk_pmd(ptep) +#define mk_kernel_pmd(ptep) mk_pmd(ptep) + #define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd)) extern __inline__ unsigned long pmd_page(pmd_t pmd) @@ -319,6 +324,7 @@ */ #ifndef __SMP__ +#ifndef CONFIG_NO_PGT_CACHE extern struct pgtable_cache_struct { unsigned long *pgd_cache; unsigned long *pte_cache; @@ -329,13 +335,16 @@ #define pte_quicklist (quicklists.pte_cache) #define pgd_quicklist (quicklists.pgd_cache) #define pgtable_cache_size (quicklists.pgtable_cache_sz) +#endif #else #error Pgtable caches have to be per-CPU, so that no locking is needed. #endif extern pgd_t *get_pgd_slow(void); +extern void free_table(void *table); +#ifndef CONFIG_NO_PGT_CACHE extern __inline__ pgd_t *get_pgd_fast(void) { unsigned long *ret; @@ -355,14 +364,17 @@ pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; } +#endif +/* keep this as an inline so we get type checking */ extern __inline__ void free_pgd_slow(pgd_t *pgd) { - kfree(pgd); + free_table((void *)pgd); } extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +#ifndef CONFIG_NO_PGT_CACHE extern __inline__ pte_t *get_pte_fast(void) { unsigned long *ret; @@ -381,10 +393,12 @@ pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } +#endif +/* keep this as an inline so we get type checking */ extern __inline__ void free_pte_slow(pte_t *pte) { - kfree(pte); + free_table((void *)pte); } /* We don't use pmd cache, so this is a dummy routine */ @@ -404,6 +418,26 @@ extern void __bad_pmd(pmd_t *pmd); extern void __bad_pmd_kernel(pmd_t *pmd); +#ifdef CONFIG_NO_PGT_CACHE +#define pte_free_kernel(pte) free_pte_slow(pte) +#define pte_free(pte) free_pte_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_slow() + +extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + + if (pmd_none (*pmd)) { + return get_pte_slow(pmd, address); + } + if (pmd_bad (*pmd)) { + __bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} +#else #define pte_free_kernel(pte) free_pte_fast(pte) #define pte_free(pte) free_pte_fast(pte) #define pgd_free(pgd) free_pgd_fast(pgd) @@ -427,6 +461,7 @@ } return (pte_t *) pmd_page(*pmd) + address; } +#endif /* * allocating and freeing a pmd is trivial: the 1-entry pmd is @@ -448,7 +483,6 @@ extern __inline__ void set_pgdir(unsigned long address, pgd_t entry) { struct task_struct * p; - pgd_t *pgd; read_lock(&tasklist_lock); for_each_task(p) { @@ -457,8 +491,14 @@ *pgd_offset(p->mm,address) = entry; } read_unlock(&tasklist_lock); - for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) - pgd[address >> PGDIR_SHIFT] = entry; +#ifndef CONFIG_NO_PGT_CACHE + { + pgd_t *pgd; + for (pgd = (pgd_t *)pgd_quicklist; pgd; + pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; + } +#endif } extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armo/processor.h linux.ac/include/asm-arm/proc-armo/processor.h --- linux.vanilla/include/asm-arm/proc-armo/processor.h Tue Dec 22 23:20:06 1998 +++ linux.ac/include/asm-arm/proc-armo/processor.h Sun Feb 7 19:34:45 1999 @@ -14,8 +14,6 @@ #ifndef __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H -#ifdef __KERNEL__ - #include #include @@ -32,6 +30,8 @@ unsigned long pc; }; +#define INIT_CSS (struct context_save_struct){ 0, 0, 0, 0, 0, 0, 0, SVC26_MODE } + typedef struct { void (*put_byte)(void); /* Special calling convention */ void (*get_byte)(void); /* Special calling convention */ @@ -50,50 +50,13 @@ #define EXTRA_THREAD_STRUCT \ uaccess_t *uaccess; /* User access functions*/ \ - struct context_save_struct *save; \ - unsigned long memmap; \ unsigned long memcmap[256]; #define EXTRA_THREAD_STRUCT_INIT \ - &uaccess_kernel, \ - 0, \ - (unsigned long) swapper_pg_dir, \ + ,&uaccess_kernel, \ { 0, } -DECLARE_THREAD_STRUCT; - -/* - * Return saved PC of a blocked thread. - */ -extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t) -{ - if (t->save) - return t->save->pc & ~PCMASK; - else - return 0; -} - -extern __inline__ unsigned long get_css_fp (struct thread_struct *t) -{ - if (t->save) - return t->save->fp; - else - return 0; -} - -asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); - -extern __inline__ void copy_thread_css (struct context_save_struct *save) -{ - save->r4 = - save->r5 = - save->r6 = - save->r7 = - save->r8 = - save->r9 = - save->fp = 0; - save->pc = ((unsigned long)ret_from_sys_call) | SVC26_MODE; -} +#define SWAPPER_PG_DIR ((unsigned long)swapper_pg_dir) #define start_thread(regs,pc,sp) \ ({ \ @@ -105,18 +68,16 @@ regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ regs->ARM_r1 = stack[1]; /* r1 (argv) */ \ regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ - flush_tlb_mm(current->mm); \ }) /* Allocation and freeing of basic task resources. */ /* * NOTE! The task struct and the stack go together */ -#define alloc_task_struct() \ - ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) -#define free_task_struct(p) free_pages((unsigned long)(p),1) - +extern unsigned long get_page_8k(int priority); +extern void free_page_8k(unsigned long page); -#endif +#define ll_alloc_task_struct() ((struct task_struct *)get_page_8k(GFP_KERNEL)) +#define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/mm-init.h linux.ac/include/asm-arm/proc-armv/mm-init.h --- linux.vanilla/include/asm-arm/proc-armv/mm-init.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/proc-armv/mm-init.h Tue Feb 23 16:02:41 1999 @@ -156,9 +156,21 @@ *start_mem = smem = PAGE_ALIGN(*start_mem); + /* + * Mark all of memory from the end of kernel to end of memory + */ while (smem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags); - smem += PAGE_SIZE; + clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags); + smem += PAGE_SIZE; + } + + /* + * Mark memory from page 1 to start of the swapper page directory + */ + smem = PAGE_OFFSET + PAGE_SIZE; + while (smem < (unsigned long)&swapper_pg_dir) { + clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags); + smem += PAGE_SIZE; } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/pgtable.h linux.ac/include/asm-arm/proc-armv/pgtable.h --- linux.vanilla/include/asm-arm/proc-armv/pgtable.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/proc-armv/pgtable.h Sun Feb 28 12:18:40 1999 @@ -258,14 +258,20 @@ #define PAGE_PTR(address) \ ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) -/* to set the page-dir */ +/* to set the page-dir + * Note that we need to flush the cache and TLBs + * if we are affecting the current task. + */ #define SET_PAGE_DIR(tsk,pgdir) \ do { \ tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir); \ - if ((tsk) == current) \ + if ((tsk) == current) { \ + flush_cache_all(); \ __asm__ __volatile__( \ "mcr%? p15, 0, %0, c2, c0, 0\n" \ : : "r" (tsk->tss.memmap)); \ + flush_tlb_all(); \ + } \ } while (0) extern __inline__ int pte_none(pte_t pte) @@ -518,8 +524,8 @@ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); } -extern unsigned long get_small_page(int priority); -extern void free_small_page(unsigned long page); +extern unsigned long get_page_1k(int priority); +extern void free_page_1k(unsigned long page); /* * Allocate and free page tables. The xxx_kernel() versions are @@ -593,7 +599,7 @@ extern __inline__ void free_pte_slow(pte_t *pte) { - free_small_page((unsigned long)pte); + free_page_1k((unsigned long)pte); } /* We don't use pmd cache, so this is a dummy routine */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/processor.h linux.ac/include/asm-arm/proc-armv/processor.h --- linux.vanilla/include/asm-arm/proc-armv/processor.h Tue Dec 22 23:20:07 1998 +++ linux.ac/include/asm-arm/proc-armv/processor.h Fri Jan 22 19:21:42 1999 @@ -12,8 +12,6 @@ #ifndef __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H -#ifdef __KERNEL__ - #define KERNEL_STACK_SIZE PAGE_SIZE struct context_save_struct { @@ -28,56 +26,18 @@ unsigned long pc; }; -#define EXTRA_THREAD_STRUCT \ - struct context_save_struct *save; \ - unsigned long memmap; +#define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0 } -#define EXTRA_THREAD_STRUCT_INIT \ - 0, \ - ((unsigned long) swapper_pg_dir) - PAGE_OFFSET - -DECLARE_THREAD_STRUCT; - -/* - * Return saved PC of a blocked thread. - */ -extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t) -{ - if (t->save) - return t->save->pc; - else - return 0; -} - -extern __inline__ unsigned long get_css_fp (struct thread_struct *t) -{ - if (t->save) - return t->save->fp; - else - return 0; -} - -asmlinkage void ret_from_sys_call(void) __asm__ ("ret_from_sys_call"); - -extern __inline__ void copy_thread_css (struct context_save_struct *save) -{ - save->cpsr = SVC_MODE; - save->r4 = - save->r5 = - save->r6 = - save->r7 = - save->r8 = - save->r9 = - save->fp = 0; - save->pc = (unsigned long) ret_from_sys_call; -} +#define EXTRA_THREAD_STRUCT +#define EXTRA_THREAD_STRUCT_INIT +#define SWAPPER_PG_DIR (((unsigned long)swapper_pg_dir) - PAGE_OFFSET) #define start_thread(regs,pc,sp) \ ({ \ unsigned long *stack = (unsigned long *)sp; \ set_fs(USER_DS); \ memzero(regs->uregs, sizeof(regs->uregs)); \ - if (current->personality == PER_LINUX_32BIT) \ + if (current->personality & ADDR_LIMIT_32BIT) \ regs->ARM_cpsr = USR_MODE; \ else \ regs->ARM_cpsr = USR26_MODE; \ @@ -92,10 +52,7 @@ /* * NOTE! The task struct and the stack go together */ -#define alloc_task_struct() \ - ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) -#define free_task_struct(p) free_pages((unsigned long)(p),1) - -#endif +#define ll_alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) +#define ll_free_task_struct(p) free_pages((unsigned long)(p),1) #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/ptrace.h linux.ac/include/asm-arm/proc-armv/ptrace.h --- linux.vanilla/include/asm-arm/proc-armv/ptrace.h Sun Nov 8 15:07:07 1998 +++ linux.ac/include/asm-arm/proc-armv/ptrace.h Sat Jan 9 16:50:36 1999 @@ -52,9 +52,14 @@ #define CC_Z_BIT (1 << 30) #define CC_N_BIT (1 << 31) +#if 0 /* GCC/egcs should be able to optimise this, IMHO */ #define user_mode(regs) \ ((((regs)->ARM_cpsr & MODE_MASK) == USR_MODE) || \ (((regs)->ARM_cpsr & MODE_MASK) == USR26_MODE)) +#else +#define user_mode(regs) \ + (((regs)->ARM_cpsr & 0xf) == 0) +#endif #define processor_mode(regs) \ ((regs)->ARM_cpsr & MODE_MASK) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/semaphore.h linux.ac/include/asm-arm/proc-armv/semaphore.h --- linux.vanilla/include/asm-arm/proc-armv/semaphore.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/proc-armv/semaphore.h Tue Feb 23 22:48:20 1999 @@ -60,6 +60,32 @@ return temp; } +extern inline int down_trylock(struct semaphore *sem) +{ + unsigned int cpsr, temp; + + __asm__ __volatile__ (" + @ atomic down try lock operation + mrs %0, cpsr + orr %1, %0, #128 @ disable IRQs + bic %0, %0, #0x80000000 @ clear N + msr cpsr, %1 + ldr %1, [%2] + subs %1, %1, #1 + orrmi %0, %0, #0x80000000 @ set N + str %1, [%2] + msr cpsr, %0 + movmi r0, %2 + movpl r0, #0 + blmi " SYMBOL_NAME_STR(__down_trylock_failed) " + mov %1, r0" + : "=&r" (cpsr), "=&r" (temp) + : "r" (sem) + : "r0", "lr", "cc"); + + return temp; +} + /* * Note! This is subtle. We jump to wake people up only if * the semaphore was negative (== somebody was waiting on it). diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/proc-armv/uaccess.h linux.ac/include/asm-arm/proc-armv/uaccess.h --- linux.vanilla/include/asm-arm/proc-armv/uaccess.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/proc-armv/uaccess.h Sun Feb 28 09:24:11 1999 @@ -133,6 +133,7 @@ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ "3: mvn %0, %3\n" \ + " mov %1, #0\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -153,6 +154,7 @@ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ "4: mvn %0, %5\n" \ + " mov %1, #0\n" \ " b 3b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -173,6 +175,7 @@ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ "3: mvn %0, %3\n" \ + " mov %1, #0\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/processor.h linux.ac/include/asm-arm/processor.h --- linux.vanilla/include/asm-arm/processor.h Tue Jan 19 02:57:36 1999 +++ linux.ac/include/asm-arm/processor.h Sun Jan 24 10:59:47 1999 @@ -7,12 +7,14 @@ #ifndef __ASM_ARM_PROCESSOR_H #define __ASM_ARM_PROCESSOR_H +#define FP_SIZE 35 + struct fp_hard_struct { - unsigned int save[140/4]; /* as yet undefined */ + unsigned int save[FP_SIZE]; /* as yet undefined */ }; struct fp_soft_struct { - unsigned int save[140/4]; /* undefined information */ + unsigned int save[FP_SIZE]; /* undefined information */ }; union fp_state { @@ -22,28 +24,59 @@ typedef unsigned long mm_segment_t; /* domain register */ -#define NR_DEBUGS 5 +#ifdef __KERNEL__ -#define DECLARE_THREAD_STRUCT \ -struct thread_struct { \ - unsigned long address; /* Address of fault */ \ - unsigned long trap_no; /* Trap number */ \ - unsigned long error_code; /* Error code of trap */ \ - union fp_state fpstate; /* FPE save state */ \ - unsigned long debug[NR_DEBUGS]; /* Debug/ptrace */ \ - EXTRA_THREAD_STRUCT \ -} +#include + +#define NR_DEBUGS 5 #include #include -#define INIT_TSS { \ - 0, \ - 0, \ - 0, \ - { { { 0, }, }, }, \ - { 0, }, \ - EXTRA_THREAD_STRUCT_INIT \ +struct thread_struct { + unsigned long address; /* Address of fault */ + unsigned long trap_no; /* Trap number */ + unsigned long error_code; /* Error code of trap */ + union fp_state fpstate; /* FPE save state */ + unsigned long debug[NR_DEBUGS]; /* Debug/ptrace */ + struct context_save_struct *save; /* context save */ + unsigned long memmap; /* page tables */ + EXTRA_THREAD_STRUCT +}; + +#define INIT_MMAP \ +{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } + +#define INIT_TSS { \ + 0, \ + 0, \ + 0, \ + { { { 0, }, }, }, \ + { 0, }, \ + (struct context_save_struct *)0, \ + SWAPPER_PG_DIR \ + EXTRA_THREAD_STRUCT_INIT \ +} + +/* + * Return saved PC of a blocked thread. + */ +extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t) +{ + return t->save ? t->save->pc & ~PCMASK : 0; +} + +extern __inline__ unsigned long get_css_fp(struct thread_struct *t) +{ + return t->save ? t->save->fp : 0; +} + +asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); + +extern __inline__ void init_thread_css(struct context_save_struct *save) +{ + *save = INIT_CSS; + save->pc |= (unsigned long)ret_from_sys_call; } /* Forward declaration, a strange C thing */ @@ -57,7 +90,12 @@ #define release_segments(mm) do { } while (0) #define forget_segments() do { } while (0) +extern struct task_struct *alloc_task_struct(void); +extern void free_task_struct(struct task_struct *); + #define init_task (init_task_union.task) #define init_stack (init_task_union.stack) + +#endif #endif /* __ASM_ARM_PROCESSOR_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/semaphore-helper.h linux.ac/include/asm-arm/semaphore-helper.h --- linux.vanilla/include/asm-arm/semaphore-helper.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-arm/semaphore-helper.h Wed Feb 24 23:51:02 1999 @@ -0,0 +1,84 @@ +#ifndef ASMARM_SEMAPHORE_HELPER_H +#define ASMARM_SEMAPHORE_HELPER_H + +/* + * These two _must_ execute atomically wrt each other. + */ +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 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_try_lock: + * 1 failed to lock + * 0 got the lock + * + * We must undo the sem->count down_interruptible() increment while we are + * protected by the spinlock in order to make 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/semaphore.h linux.ac/include/asm-arm/semaphore.h --- linux.vanilla/include/asm-arm/semaphore.h Tue Jan 19 02:57:37 1999 +++ linux.ac/include/asm-arm/semaphore.h Wed Feb 24 23:51:11 1999 @@ -19,49 +19,15 @@ asmlinkage void __down_failed (void /* special register calling convention */); asmlinkage int __down_interruptible_failed (void /* special register calling convention */); +asmlinkage int __down_failed_trylock(void /* params in registers */); asmlinkage void __up_wakeup (void /* special register calling convention */); extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); +extern int __down_trylock(struct semaphore * sem); extern void __up(struct semaphore * sem); #define sema_init(sem, val) atomic_set(&((sem)->count), (val)) - -/* - * 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. - * Currently this is just the global interrupt lock, - * bah. Go for a smaller spinlock some day. - * - * (On the other hand this shouldn't be in any critical - * path, so..) - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - save_flags(flags); - cli(); - sem->waking++; - restore_flags(flags); -} - -static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - save_flags(flags); - cli(); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - restore_flags(flags); - return ret; -} #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/system.h linux.ac/include/asm-arm/system.h --- linux.vanilla/include/asm-arm/system.h Tue Dec 22 23:20:07 1998 +++ linux.ac/include/asm-arm/system.h Sun Jan 24 10:59:46 1999 @@ -14,13 +14,24 @@ #define MACH_TYPE_TBOX 7 #ifdef CONFIG_ARCH_EBSA285 -#define machine_is_ebsa285() (1) +#define machine_is_ebsa285() (machine_type == MACH_TYPE_EBSA285) #else #define machine_is_ebsa285() (0) #endif -#ifdef CONFIG_ARCH_VNC -#define machine_is_netwinder() (1) +#define __ebsa285_data __attribute__((__section__(".data.ebsa285"))) +#define __netwinder_data __attribute__((__section__(".data.netwinder"))) + +#ifdef CONFIG_TEXT_SECTIONS +#define __ebsa285_text __attribute__((__section__(".text.ebsa285"))) +#define __netwinder_text __attribute__((__section__(".text.netwinder"))) +#else +#define __ebsa285_text +#define __netwinder_text +#endif + +#ifdef CONFIG_ARCH_NETWINDER +#define machine_is_netwinder() (machine_type == MACH_TYPE_NETWINDER) #else #define machine_is_netwinder() (0) #endif @@ -29,11 +40,6 @@ #define machine_is_cats() (machine_type == MACH_TYPE_CATS) #else #define machine_is_cats() (0) -#endif - -#if 0 -#define machine_is_ebsa285() (machine_type == MACH_TYPE_EBSA285) -#define machine_is_netwinder() (machine_type == MACH_TYPE_NETWINDER) #endif #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/unistd.h linux.ac/include/asm-arm/unistd.h --- linux.vanilla/include/asm-arm/unistd.h Sat Jan 9 21:50:49 1999 +++ linux.ac/include/asm-arm/unistd.h Sun Jan 17 11:31:06 1999 @@ -364,7 +364,7 @@ static inline int _exit(int exitcode) { - extern int sys_exit(int); + extern int sys_exit(int) __attribute__((noreturn)); return sys_exit(exitcode); } @@ -400,30 +400,22 @@ * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ -static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - long retval; +#define kernel_thread(fn,arg,flags) \ + ({ extern int sys_exit(int) __attribute__((noreturn)); \ + pid_t __ret; \ + __asm__ __volatile__( \ + "mov r0, %1 @ kernel_thread sys_clone\n" \ +" mov r1, #0\n" \ + __syscall(clone)"\n" \ +" mov %0, r0" \ + : "=r" (__ret) \ + : "Ir" (flags | CLONE_VM) : "r0", "r1"); \ + if (__ret == 0) \ + sys_exit((fn)(arg)); \ + __ret; }) - __asm__ __volatile__(" - mov r0,%1 - mov r1,%2 - "__syscall(clone)" - teq r0, #0 - bne 1f - mov r0,%4 - mov lr, pc - mov pc, %3 - "__syscall(exit)" -1: mov %0,r0" - : "=r" (retval) - : "Ir" (flags | CLONE_VM), "Ir" (NULL), "r" (fn), "Ir" (arg) - : "r0","r1","r2","r3","lr"); - - return retval; -} #endif - #endif /* __ASM_ARM_UNISTD_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/bugs.h linux.ac/include/asm-i386/bugs.h --- linux.vanilla/include/asm-i386/bugs.h Sat Jan 2 19:39:25 1999 +++ linux.ac/include/asm-i386/bugs.h Mon Mar 22 16:23:08 1999 @@ -19,6 +19,7 @@ #include #include +#include #define CONFIG_BUGi386 @@ -173,10 +174,10 @@ n = K6_BUG_LOOP; f_vide = vide; - __asm__ ("rdtsc" : "=a" (d)); + rdtscl(d); while (n--) f_vide(); - __asm__ ("rdtsc" : "=a" (d2)); + rdtscl(d2); d = d2-d; /* Knock these two lines out if it debugs out ok */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/msr.h linux.ac/include/asm-i386/msr.h --- linux.vanilla/include/asm-i386/msr.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/msr.h Mon Mar 22 16:23:05 1999 @@ -0,0 +1,30 @@ +/* + * Access to machine-specific registers (available on 586 and better only) + * Note: the rd* operations modify the parameters directly (without using + * pointer indirection), this allows gcc to optimize better + */ + +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + +#define wrmsr(msr,val1,val2) \ + __asm__ __volatile__("wrmsr" \ + : /* no outputs */ \ + : "c" (msr), "a" (val1), "d" (val2)) + +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdtscl(low) \ + __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "dx") + +#define rdtscll(val) \ + __asm__ __volatile__ ("rdtsc" : "=A" (val)) + +#define rdpmc(counter,low,high) \ + __asm__ __volatile__("rdpmc" \ + : "=a" (low), "=d" (high) \ + : "c" (counter)) + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/resource.h linux.ac/include/asm-i386/resource.h --- linux.vanilla/include/asm-i386/resource.h Thu Nov 19 18:38:47 1998 +++ linux.ac/include/asm-i386/resource.h Fri Dec 4 17:15:34 1998 @@ -29,7 +29,7 @@ { 0, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/timex.h linux.ac/include/asm-i386/timex.h --- linux.vanilla/include/asm-i386/timex.h Sat Jan 2 19:39:25 1999 +++ linux.ac/include/asm-i386/timex.h Mon Mar 22 16:23:08 1999 @@ -7,6 +7,7 @@ #define _ASMi386_TIMEX_H #include +#include #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ @@ -39,7 +40,7 @@ #else unsigned long eax, edx; - __asm__("rdtsc":"=a" (eax), "=d" (edx)); + rdtsc(eax,edx); return eax; #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-m68k/resource.h linux.ac/include/asm-m68k/resource.h --- linux.vanilla/include/asm-m68k/resource.h Wed Jan 6 23:02:29 1999 +++ linux.ac/include/asm-m68k/resource.h Wed Jan 6 23:16:34 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ - {NR_OPEN, NR_OPEN}, \ + {INR_OPEN, INR_OPEN}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX} \ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/resource.h linux.ac/include/asm-mips/resource.h --- linux.vanilla/include/asm-mips/resource.h Sun Nov 8 15:06:55 1998 +++ linux.ac/include/asm-mips/resource.h Fri Dec 4 17:15:34 1998 @@ -35,7 +35,7 @@ {LONG_MAX, LONG_MAX}, \ {_STK_LIM, _STK_LIM}, \ { 0, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, \ + {INR_OPEN, INR_OPEN}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/resource.h linux.ac/include/asm-ppc/resource.h --- linux.vanilla/include/asm-ppc/resource.h Tue Dec 22 23:20:10 1998 +++ linux.ac/include/asm-ppc/resource.h Wed Dec 23 00:20:27 1998 @@ -25,7 +25,7 @@ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/resource.h linux.ac/include/asm-sparc/resource.h --- linux.vanilla/include/asm-sparc/resource.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/asm-sparc/resource.h Sat Mar 20 23:07:45 1999 @@ -31,7 +31,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/resource.h linux.ac/include/asm-sparc64/resource.h --- linux.vanilla/include/asm-sparc64/resource.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/asm-sparc64/resource.h Sat Mar 20 23:08:38 1999 @@ -30,7 +30,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/adfs_fs_sb.h linux.ac/include/linux/adfs_fs_sb.h --- linux.vanilla/include/linux/adfs_fs_sb.h Sun Nov 8 15:06:51 1998 +++ linux.ac/include/linux/adfs_fs_sb.h Sun Jan 24 21:01:01 1999 @@ -15,6 +15,10 @@ struct adfs_sb_info { struct buffer_head *s_sbh; /* buffer head containing disc record */ struct adfs_discrecord *s_dr; /* pointer to disc record in s_sbh */ + uid_t s_uid; /* owner uid */ + gid_t s_gid; /* owner gid */ + int s_owner_mask; /* ADFS Owner perm -> unix perm */ + int s_other_mask; /* ADFS Other perm -> unix perm */ __u16 s_zone_size; /* size of a map zone in bits */ __u16 s_ids_per_zone; /* max. no ids in one zone */ __u32 s_idlen; /* length of ID in map */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/blk.h linux.ac/include/linux/blk.h --- linux.vanilla/include/linux/blk.h Sun Nov 8 15:06:49 1998 +++ linux.ac/include/linux/blk.h Wed Mar 24 18:21:52 1999 @@ -348,11 +348,28 @@ #define DEVICE_ON(device) #define DEVICE_OFF(device) +#elif (MAJOR_NR == MFM_ACORN_MAJOR) + +#define DEVICE_NAME "mfm disk" +#define DEVICE_INTR do_mfm +#define DEVICE_REQUEST do_mfm_request +#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + #elif (MAJOR_NR == NBD_MAJOR) #define DEVICE_NAME "nbd" #define DEVICE_REQUEST do_nbd_request #define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == I2O_MAJOR) + +#define DEVICE_NAME "I2O block" +#define DEVICE_REQUEST do_i2ob_request +#define DEVICE_NR(device) (MINOR(device)>>4) #define DEVICE_ON(device) #define DEVICE_OFF(device) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/fs.h linux.ac/include/linux/fs.h --- linux.vanilla/include/linux/fs.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/linux/fs.h Wed Mar 24 18:01:39 1999 @@ -27,17 +27,19 @@ /* - * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix - * that later. Anyway, now the file code is no longer dependent - * on bitmaps in unsigned longs, but uses the new fd_set structure.. + * It's silly to have NR_OPEN bigger than NR_FILE, but you can change + * the file limit at runtime and only root can increase the per-process + * nr_file rlimit, so it's safe to set up a ridiculously high absolute + * upper limit on files-per-process. * * Some programs (notably those using select()) may have to be - * recompiled to take full advantage of the new limits.. + * recompiled to take full advantage of the new limits.. */ /* Fixed constants first: */ #undef NR_OPEN -#define NR_OPEN 1024 +#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ +#define INR_OPEN 1024 /* Initial setting for nfile rlimits */ #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1< #include + +extern __u32 inode_generation_count; #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/hippidevice.h linux.ac/include/linux/hippidevice.h --- linux.vanilla/include/linux/hippidevice.h Sun Nov 8 15:06:51 1998 +++ linux.ac/include/linux/hippidevice.h Tue Mar 16 18:59:42 1999 @@ -52,6 +52,7 @@ void hippi_setup(struct device *dev); extern struct device *init_hippi_dev(struct device *, int); +extern void unregister_hipdev(struct device *dev); #endif #endif /* _LINUX_HIPPIDEVICE_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/i2o.h linux.ac/include/linux/i2o.h --- linux.vanilla/include/linux/i2o.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/i2o.h Tue Mar 16 15:57:52 1999 @@ -0,0 +1,351 @@ +/* + * Tunable parameters first + */ + +/* How many different OSM's are we allowing */ +#define MAX_I2O_MODULES 64 +/* How many controllers are we allowing */ +#define MAX_I2O_CONTROLLERS 32 + + +/* + * I2O Interface Objects + */ + +#include +#include + +/* + * message structures + */ + +#define TID_SZ 12 +#define FUNCTION_SZ 8 + + +struct i2o_message +{ + u32 version_size; + u32 function_addr; + u32 initiator_context; + /* List follows */ +}; + + +/* + * Each I2O device entity has one or more of these. There is one + * per device. *FIXME* how to handle multiple types on one unit. + */ + +struct i2o_device +{ + int type; /* Block, Net, SCSI etc (from spec) */ + int id; /* I2O ID assigned by the controller */ + int parent; /* Parent device */ + int flags; /* Control flags */ + struct i2o_driver *owner; /* Owning device */ + struct i2o_controller *controller; /* Controlling IOP */ + struct i2o_device *next; /* Chain */ +}; + +/* + * Resource data for each PCI I2O controller + */ + +struct i2o_pci +{ + int irq; +}; + +/* + * Each I2O controller has one of these objects + */ + +struct i2o_controller +{ + char name[8]; + int unit; + int status; /* I2O status */ + int type; +#define I2O_TYPE_PCI 0x01 /* PCI I2O controller */ + struct notifier_block *event_notifer; /* Events */ + atomic_t users; + struct i2o_device *devices; /* I2O device chain */ + struct i2o_controller *next; /* Controller chain */ + volatile u32 *post_port; /* Messaging ports */ + volatile u32 *read_port; + volatile u32 *irq_mask; /* Interrupt port */ + u32 mem_offset; /* MFA offset */ + u32 mem_phys; /* MFA physical */ + union + { /* Bus information */ + struct i2o_pci pci; + } bus; + void (*destructor)(struct i2o_controller *); /* Bus specific destructor */ + int (*bind)(struct i2o_controller *, struct i2o_device *); /* Bus specific attach/detach */ + int (*unbind)(struct i2o_controller *, struct i2o_device *); + void *page_frame; /* Message buffers */ + int inbound_size; /* Inbound queue size */ +}; + +struct i2o_handler +{ + void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *); + char *name; + int context; /* Low 8 bits of the transaction info */ + /* User data follows */ +}; + +/* + * Messenger inlines + */ + +extern inline void i2o_post_message(struct i2o_controller *c, u32 m) +{ + /* The second line isnt spurious - thats forcing PCI posting */ + *c->post_port=m; + *c->irq_mask; +} + +extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m) +{ + *c->read_port=m; +} + +struct i2o_controller *i2o_controller_chain; + +extern int i2o_install_controller(struct i2o_controller *); +extern int i2o_delete_controller(struct i2o_controller *); +extern int i2o_activate_controller(struct i2o_controller *); +extern void i2o_unlock_controller(struct i2o_controller *); +extern struct i2o_controller *i2o_find_controller(int); + + +extern int i2o_install_handler(struct i2o_handler *); +extern int i2o_remove_handler(struct i2o_handler *); + +extern int i2o_install_device(struct i2o_controller *, struct i2o_device *); +extern int i2o_delete_device(struct i2o_device *); +extern int i2o_claim_device(struct i2o_device *, struct i2o_driver *); +extern int i2o_release_device(struct i2o_device *); + +extern int i2o_post_this(struct i2o_controller *c, int tid, u32 *data, int len); +extern int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *flag); +extern int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag); +extern int i2o_query_scalar(struct i2o_controller *c, int tid, int context, + int table, int field, void *buf, int buflen, int *flag); + + + +extern void i2o_run_queue(struct i2o_controller *); + +/* RedCreek's OSM default LAN receive Initiator */ +#define DEFAULT_RECV_INIT_CONTEXT 0xA17 + +/* Transaction Reply Lists (TRL) Control Word structure */ + +#define TRL_SINGLE_FIXED_LENGTH 0x00 +#define TRL_SINGLE_VARIABLE_LENGTH 0x40 +#define TRL_MULTIPLE_FIXED_LENGTH 0x80 + +/* LAN Class specific functions */ + +#define LAN_PACKET_SEND 0x3B +#define LAN_SDU_SEND 0x3D +#define LAN_RECEIVE_POST 0x3E +#define LAN_RESET 0x35 +#define LAN_SHUTDOWN 0x37 + +/* + * Messaging API values + */ + +#define I2O_CMD_ADAPTER_ASSIGN 0xB3 +#define I2O_CMD_ADAPTER_READ 0xB2 +#define I2O_CMD_ADAPTER_RELEASE 0xB5 +#define I2O_CMD_BIOS_INFO_SET 0xA5 +#define I2O_CMD_BOOT_DEVICE_SET 0xA7 +#define I2O_CMD_CONFIG_VALIDATE 0xBB +#define I2O_CMD_CONN_SETUP 0xCA +#define I2O_CMD_DEVICE_ASSIGN 0xB7 +#define I2O_CMD_DEVICE_RELEASE 0xB9 +#define I2O_CMD_HRT_GET 0xA8 +#define I2O_CMD_ADAPTER_CLEAR 0xBE +#define I2O_CMD_ADAPTER_CONNECT 0xC9 +#define I2O_CMD_ADAPTER_RESET 0xBD +#define I2O_CMD_LCT_NOTIFY 0xA2 +#define I2O_CMD_OUTBOUND_INIT 0xA1 +#define I2O_CMD_PATH_ENABLE 0xD3 +#define I2O_CMD_PATH_QUIESCE 0xC5 +#define I2O_CMD_PATH_RESET 0xD7 +#define I2O_CMD_STATIC_MF_CREATE 0xDD +#define I2O_CMD_STATIC_MF_RELEASE 0xDF +#define I2O_CMD_STATUS_GET 0xA0 +#define I2O_CMD_SW_DOWNLOAD 0xA9 +#define I2O_CMD_SW_UPLOAD 0xAB +#define I2O_CMD_SW_REMOVE 0xAD +#define I2O_CMD_SYS_ENABLE 0xD1 +#define I2O_CMD_SYS_MODIFY 0xC1 +#define I2O_CMD_SYS_QUIESCE 0xC3 +#define I2O_CMD_SYS_TAB_SET 0xA3 + +#define I2O_CMD_UTIL_NOP 0x00 +#define I2O_CMD_UTIL_CLAIM 0x09 +#define I2O_CMD_UTIL_RELEASE 0x0B +#define I2O_CMD_UTIL_PARAMS_GET 0x06 +#define I2O_CMD_UTIL_CONFIG_DIALOG 0x10 + +#define I2O_CMD_SCSI_EXEC 0x81 +#define I2O_CMD_SCSI_ABORT 0x83 +#define I2O_CMD_SCSI_BUSRESET 0x27 + +#define I2O_CMD_BLOCK_READ 0x30 +#define I2O_CMD_BLOCK_WRITE 0x31 +#define I2O_CMD_BLOCK_CFLUSH 0x37 +#define I2O_CMD_BLOCK_MLOCK 0x49 +#define I2O_CMD_BLOCK_MUNLOCK 0x4B +#define I2O_CMD_BLOCK_MMOUNT 0x41 +#define I2O_CMD_BLOCK_MEJECT 0x43 + +/* + * Init Outbound Q status + */ + +#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01 +#define I2O_CMD_OUTBOUND_INIT_REJECTED 0x02 +#define I2O_CMD_OUTBOUND_INIT_FAILED 0x03 +#define I2O_CMD_OUTBOUND_INIT_COMPLETE 0x04 + +/* + * I2O Get Status State values + */ + +#define ADAPTER_STATE_INITIALIZING 0x01 +#define ADAPTER_STATE_RESET 0x02 +#define ADAPTER_STATE_HOLD 0x04 +#define ADAPTER_STATE_READY 0x05 +#define ADAPTER_STATE_OPERATIONAL 0x08 +#define ADAPTER_STATE_FAILED 0x10 +#define ADAPTER_STATE_FAULTED 0x11 + +/* I2O API function return values */ + +#define I2O_RTN_NO_ERROR 0 +#define I2O_RTN_NOT_INIT 1 +#define I2O_RTN_FREE_Q_EMPTY 2 +#define I2O_RTN_TCB_ERROR 3 +#define I2O_RTN_TRANSACTION_ERROR 4 +#define I2O_RTN_ADAPTER_ALREADY_INIT 5 +#define I2O_RTN_MALLOC_ERROR 6 +#define I2O_RTN_ADPTR_NOT_REGISTERED 7 +#define I2O_RTN_MSG_REPLY_TIMEOUT 8 +#define I2O_RTN_NO_STATUS 9 +#define I2O_RTN_NO_FIRM_VER 10 +#define I2O_RTN_NO_LINK_SPEED 11 + +/* Reply message status defines */ + +#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03 +#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04 +#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05 +#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06 +#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07 +#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08 +#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09 +#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A +#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80 + +/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/ + +#define I2O_DS_SUCCESS 0x0000 +#define I2O_DS_BAD_KEY 0x0001 +#define I2O_DS_CHAIN_BUFFER_TOO_LARGE 0x0002 +#define I2O_DS_DEVICE_BUSY 0x0003 +#define I2O_DS_DEVICE_LOCKED 0x0004 +#define I2O_DS_DEVICE_NOT_AVAILABLE 0x0005 +#define I2O_DS_DEVICE_RESET 0x0006 +#define I2O_DS_INAPPROPRIATE_FUNCTION 0x0007 +#define I2O_DS_INSUFFICIENT_RESOURCE_HARD 0x0008 +#define I2O_DS_INSUFFICIENT_RESOURCE_SOFT 0x0009 +#define I2O_DS_INVALID_INITIATOR_ADDRESS 0x000A +#define I2O_DS_INVALID_MESSAGE_FLAGS 0x000B +#define I2O_DS_INVALID_OFFSET 0x000C +#define I2O_DS_INVALID_PARAMETER 0x000D +#define I2O_DS_INVALID_REQUEST 0x000E +#define I2O_DS_INVALID_TARGET_ADDRESS 0x000F +#define I2O_DS_MESSAGE_TOO_LARGE 0x0010 +#define I2O_DS_MESSAGE_TOO_SMALL 0x0011 +#define I2O_DS_MISSING_PARAMETER 0x0012 +#define I2O_DS_NO_SUCH_PAGE 0x0013 +#define I2O_DS_REPLY_BUFFER_FULL 0x0014 +#define I2O_DS_TCL_ERROR 0x0015 +#define I2O_DS_TIMEOUT 0x0016 +#define I2O_DS_UNKNOWN_ERROR 0x0017 +#define I2O_DS_UNKNOWN_FUNCTION 0x0018 +#define I2O_DS_UNSUPPORTED_FUNCTION 0x0019 +#define I2O_DS_UNSUPPORTED_VERSION 0x001A + +/* DetailedStatusCode defines */ + +#define I2O_DSC_SUCCESS 0x0000 +#define I2O_DSC_DEVICE_FAILURE 0x0001 +#define I2O_DSC_DESTINATION_NOT_FOUND 0x0002 +#define I2O_DSC_TRANSMIT_ERROR 0x0003 +#define I2O_DSC_TRANSMIT_ABORTED 0x0004 +#define I2O_DSC_RECEIVE_ERROR 0x0005 +#define I2O_DSC_RECEIVE_ABORTED 0x0006 +#define I2O_DSC_DMA_ERROR 0x0007 +#define I2O_DSC_BAD_PACKET_DETECTED 0x0008 +#define I2O_DSC_OUT_OF_MEMORY 0x0009 +#define I2O_DSC_BUCKET_OVERRUN 0x000A +#define I2O_DSC_IOP_INTERNAL_ERROR 0x000B +#define I2O_DSC_CANCELED 0x000C +#define I2O_DSC_INVALID_TRANSACTION_CONTEXT 0x000D +#define I2O_DSC_DESTINATION_ADDRESS_DETECTED 0x000E +#define I2O_DSC_DESTINATION_ADDRESS_OMITTED 0x000F +#define I2O_DSC_PARTIAL_PACKET_RETURNED 0x0010 + +/* Message header defines for VersionOffset */ +#define RCMSGVER_1 0x0001 +#define SGL_OFFSET_0 RCMSGVER_1 +#define SGL_OFFSET_4 (0x0040 | RCMSGVER_1) +#define SGL_OFFSET_5 (0x0050 | RCMSGVER_1) +#define SGL_OFFSET_6 (0x0060 | RCMSGVER_1) +#define SGL_OFFSET_8 (0x0080 | RCMSGVER_1) +#define SGL_OFFSET_10 (0x00A0 | RCMSGVER_1) + +#define TRL_OFFSET_5 (0x0050 | RCMSGVER_1) +#define TRL_OFFSET_6 (0x0060 | RCMSGVER_1) + + /* msg header defines for MsgFlags */ +#define MSG_STATIC 0x0100 +#define MSG_64BIT_CNTXT 0x0200 +#define MSG_MULTI_TRANS 0x1000 +#define MSG_FAIL 0x2000 +#define MSG_LAST 0x4000 +#define MSG_REPLY 0x8000 + + /* normal LAN request message MsgFlags and VersionOffset (0x1041) */ +#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4) + + /* minimum size msg */ +#define THREE_WORD_MSG_SIZE 0x00030000 +#define FOUR_WORD_MSG_SIZE 0x00040000 +#define FIVE_WORD_MSG_SIZE 0x00050000 +#define SIX_WORD_MSG_SIZE 0x00060000 +#define SEVEN_WORD_MSG_SIZE 0x00070000 +#define EIGHT_WORD_MSG_SIZE 0x00080000 +#define NINE_WORD_MSG_SIZE 0x00090000 +#define TEN_WORD_MSG_SIZE 0x000A0000 +#define I2O_MESSAGE_SIZE(x) ((x)<<16) + + +/* Special TID Assignments */ + +#define ADAPTER_TID 0 +#define HOST_TID 1 + +#define MSG_FRAME_SIZE 128 +#define NMBR_MSG_FRAMES 128 + +#define MSG_POOL_SIZE 16384 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/major.h linux.ac/include/linux/major.h --- linux.vanilla/include/linux/major.h Sun Nov 8 15:06:48 1998 +++ linux.ac/include/linux/major.h Mon Mar 15 19:21:51 1999 @@ -89,6 +89,8 @@ #define SCSI_DISK6_MAJOR 70 #define SCSI_DISK7_MAJOR 71 +#define I2O_MAJOR 80 /* 80->87 */ + #define SPECIALIX_NORMAL_MAJOR 75 #define SPECIALIX_CALLOUT_MAJOR 76 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/mca.h linux.ac/include/linux/mca.h --- linux.vanilla/include/linux/mca.h Sun Nov 8 15:06:49 1998 +++ linux.ac/include/linux/mca.h Wed Mar 24 18:05:28 1999 @@ -39,27 +39,27 @@ specify a starting slot beyond zero, to deal with detecting multiple devices. Returns MCA_NOTFOUND if id not found. Also checks the integrated adapters. */ -extern int mca_find_adapter( int id, int start ); -extern int mca_find_unused_adapter( int id, int start ); +extern int mca_find_adapter(int id, int start); +extern int mca_find_unused_adapter(int id, int start); /* adapter state info - returns 0 if no */ -extern int mca_isadapter( int slot ); -extern int mca_isenabled( int slot ); +extern int mca_isadapter(int slot); +extern int mca_isenabled(int slot); -extern int mca_is_adapter_used( int slot ); -extern int mca_mark_as_used( int slot ); -extern void mca_mark_as_unused( int slot ); +extern int mca_is_adapter_used(int slot); +extern int mca_mark_as_used(int slot); +extern void mca_mark_as_unused(int slot); /* gets a byte out of POS register (stored in memory) */ -extern unsigned char mca_read_stored_pos( int slot, int reg ); +extern unsigned char mca_read_stored_pos(int slot, int reg); /* This can be expanded later. Right now, it gives us a way of getting meaningful information into the MCA_info structure, so we can have a more interesting /proc/mca. */ -extern void mca_set_adapter_name( int slot, char* name ); -extern char* mca_get_adapter_name( int slot ); +extern void mca_set_adapter_name(int slot, char* name); +extern char* mca_get_adapter_name(int slot); /* This sets up an information callback for /proc/mca/slot?. The @@ -73,8 +73,8 @@ unregisters, thus preventing kernel crashes and other such nastiness. */ -typedef int (*MCA_ProcFn)( char* buf, int slot, void* dev ); -extern void mca_set_adapter_procfn( int slot, MCA_ProcFn, void* dev ); +typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev); +extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev); /* These routines actually mess with the hardware POS registers. They temporarily disable the device (and interrupts), so make sure you know @@ -88,13 +88,13 @@ */ /* read a byte from the specified POS register. */ -extern unsigned char mca_read_pos( int slot, int reg ); +extern unsigned char mca_read_pos(int slot, int reg); /* write a byte to the specified POS register. */ -extern void mca_write_pos( int slot, int reg, unsigned char byte ); +extern void mca_write_pos(int slot, int reg, unsigned char byte); /* Should only be called by the NMI interrupt handler, this will do some fancy stuff to figure out what might have generated a NMI. */ -extern void mca_handle_nmi( void ); +extern void mca_handle_nmi(void); #endif /* _LINUX_MCA_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfs.h linux.ac/include/linux/nfs.h --- linux.vanilla/include/linux/nfs.h Wed Mar 10 21:13:11 1999 +++ linux.ac/include/linux/nfs.h Sun Mar 7 19:53:26 1999 @@ -93,6 +93,16 @@ #define NFS_MNT_PORT 627 #define NFS_MNTPROC_MNT 1 #define NFS_MNTPROC_UMNT 3 + +/* + * This is really a general kernel constant, but since nothing like + * this is defined in the kernel headers, I have to do it here. + */ +#ifndef LONG_LONG_MAX +#define LONG_LONG_MAX 9223372036854775807LL +#endif +#define NFS_OFFSET_MAX LONG_LONG_MAX + #endif #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES) @@ -139,11 +149,23 @@ __u32 bavail; }; +/* Arguments to the write call. + * Note that NFS_WRITE_MAXIOV must be <= MAX_IOVEC from sunrpc/xprt.h + */ +#define NFS_WRITE_MAXIOV 8 + struct nfs_writeargs { struct nfs_fh * fh; __u32 offset; __u32 count; - const void * buffer; + unsigned int nriov; + struct iovec iov[NFS_WRITE_MAXIOV]; +}; + +struct nfs_writeres { + struct nfs_fattr * fattr; + struct nfs_writeverf * verf; + __u32 count; }; #ifdef NFS_NEED_XDR_TYPES @@ -158,11 +180,22 @@ const char * name; }; +/* Arguments to the read call. + * Note that NFS_READ_MAXIOV must be < MAX_IOVEC from sunrpc/xprt.h + */ +#define NFS_READ_MAXIOV 7 + struct nfs_readargs { struct nfs_fh * fh; __u32 offset; __u32 count; - void * buffer; + unsigned int nriov; + struct iovec iov[NFS_READ_MAXIOV]; +}; + +struct nfs_readres { + struct nfs_fattr * fattr; + unsigned int count; }; struct nfs_createargs { @@ -203,11 +236,6 @@ struct nfs_fattr * fattr; }; -struct nfs_readres { - struct nfs_fattr * fattr; - unsigned int count; -}; - struct nfs_readlinkres { char ** string; unsigned int * lenp; @@ -219,6 +247,8 @@ void * buffer; unsigned int bufsiz; }; + +typedef __u64 off64; #endif /* NFS_NEED_XDR_TYPES */ #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfs_cluster.h linux.ac/include/linux/nfs_cluster.h --- linux.vanilla/include/linux/nfs_cluster.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/nfs_cluster.h Wed Mar 24 18:01:52 1999 @@ -0,0 +1,170 @@ +#ifndef NFS_CLUSTER_H +#define NFS_CLUSTER_H + + +/* + * Valid flags for a dirty buffer + */ +#define PG_UNLOCK_AFTER 0x0001 +#define PG_CANCELLED 0x0002 +#define PG_INVALIDATE_AFTER 0x0004 + +#ifdef __KERNEL__ +struct nfs_page { + struct page * page; + unsigned short flags; + + struct nfs_cluster * cluster; /* Back pointer to cluster */ + struct rpc_task * task; + u64 start; + u64 end; + + unsigned long timeout; /* when to write/commit */ + + unsigned short commit; /* batch of commit pages */ + +#ifdef NFSV3 + u32 verifier[2]; /* NFSv3 write verifier */ +#endif +}; + + +typedef int (*nfs_flush_req)(struct nfs_page *, int); + + +/* + * Counters of total number and pending number of requests. + * When the total number of requests exceeds the soft limit, we start + * flushing out requests. If it exceeds the hard limit, we stall until + * it drops again. + */ +#define MAX_REQUEST_SOFT 128 +#define MAX_REQUEST_HARD 1024 + +/* + * Maximum number of requests per write cluster. + * 32 requests per cluster account for 128K of data on an intel box. + * Note: it's a good idea to make this number smaller than MAX_REQUEST_SOFT. + * + * For 100Mbps Ethernet, 128 pages (i.e. 256K) per cluster gives much + * better performance. + */ +#define CLUSTER_SHIFT 7 +#define CLUSTER_PAGES (1 << CLUSTER_SHIFT) +#define CLUSTER_SIZE (CLUSTER_PAGES * PAGE_SIZE) +#define CLUSTER_MASK (~(CLUSTER_SIZE - 1)) +#define CLUSTER_NR(off) ((off) >> (CLUSTER_SHIFT + PAGE_SHIFT)) +#define CLUSTER_HASH_SIZE 16 +#define CLUSTER_HASH(ino, off) (((ino) ^ CLUSTER_NR(off)) & (CLUSTER_HASH_SIZE - 1)) +#define REQUEST_NR(off) (((off) >> PAGE_SHIFT) & (CLUSTER_PAGES - 1)) + + +/* + * This is a cluster of read/write requests that should be sent to + * the server together. + * + * Note that there may be more than one cluster for the same file + * region, but with different credentials and pid. + */ +struct nfs_cluster { + struct rpc_listitem cl_list; /* list of clusters per inode */ + struct nfs_cluster * hash_prev; /* hash chains */ + struct nfs_cluster * hash_next; + + /* List of requests */ + struct nfs_page * request[CLUSTER_PAGES]; + nfs_flush_req flush; + + struct rpc_auth * auth; /* RPC credentials */ + struct rpc_cred * cred; + struct file * file; /* file */ + __u64 start; /* file range covered */ + __u64 end; + unsigned long nextscan; /* when to flush aged bufs */ + unsigned short count; /* # of references */ + unsigned short pages; /* # of requests total */ + unsigned short dirty; /* # of dirty requests */ + unsigned short pending; /* # of pending WRITE calls */ +#ifdef NFSV3 + unsigned short sequence; /* next commit sequence # */ + unsigned short committing; /* pending commit sequence # */ +#define MAX_COMMIT_SEQ 0xFFFF +#define IS_DIRTY(req) ((req)->commit == MAX_COMMIT_SEQ) + struct wait_queue * wait; +#else +#define MAX_COMMIT_SEQ 0xFFFF +#define IS_DIRTY(req) ((req)->commit == MAX_COMMIT_SEQ) +#endif +}; + + +#define CL_NEXT(c) ((struct nfs_cluster *)((c)->cl_list.next)) + +/* + * Functions + */ +extern int sync_cluster(struct nfs_cluster *, int); +extern int scan_cluster(struct nfs_cluster *, unsigned int); +extern int wait_cluster(struct nfs_cluster *); +extern void delete_cluster(struct nfs_cluster *); + +extern int nfs_strategy(struct nfs_cluster *); + +static inline void +release_cluster(struct nfs_cluster *cluster) +{ + if (cluster && --(cluster->count) == 0) + delete_cluster(cluster); +} + +/* Request functions */ +extern struct nfs_page * nfs_create_request(struct nfs_cluster *, + struct page *, + __u64, __u64, int *); +extern void nfs_release_request(struct nfs_page *); +extern int nfs_update_request(struct file *, + struct page *, + __u64, __u64, + struct nfs_page **, + nfs_flush_req); +extern int nfs_wait_on_request(struct nfs_page *); +extern void nfs_cancel_request(struct nfs_cluster *, + struct nfs_page *); + +/* + * Mark a request dirty. + */ +static inline void +nfs_mark_request_dirty(struct nfs_cluster *cluster, struct nfs_page *req) +{ + mark_inode_dirty(cluster->file->f_dentry->d_inode); + if (req->commit != MAX_COMMIT_SEQ) + cluster->dirty++; + req->commit = MAX_COMMIT_SEQ; +} + +/* + * Lock the page of an asynchronous request + */ +static inline int +nfs_lock_page(struct nfs_page *req) +{ + struct page *page = req->page; + + if (test_and_set_bit(PG_locked, &page->flags)) + return 0; + req->flags |= PG_UNLOCK_AFTER; + return 1; +} + +static inline void +nfs_unlock_page(struct page *page) +{ + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); +} +#endif + + + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfs_fs.h linux.ac/include/linux/nfs_fs.h --- linux.vanilla/include/linux/nfs_fs.h Wed Mar 10 21:13:11 1999 +++ linux.ac/include/linux/nfs_fs.h Wed Mar 24 18:22:12 1999 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ #define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server) #define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server) #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) +#define NFS_REQUESTLIST(inode) (NFS_SERVER(inode)->rw_requests) #define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode))) #define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode))) @@ -78,7 +80,7 @@ #define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags) #define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATE) -#define NFS_WRITEBACK(inode) ((inode)->u.nfs_i.writeback) +#define NFS_CLUSTERS(inode) ((inode)->u.nfs_i.dirty) /* * These are the default flags for swap requests @@ -91,43 +93,15 @@ #ifdef __KERNEL__ /* - * This struct describes a file region to be written. - * It's kind of a pity we have to keep all these lists ourselves, rather - * than sticking an extra pointer into struct page. - */ -struct nfs_wreq { - struct rpc_listitem wb_list; /* linked list of req's */ - struct rpc_task wb_task; /* RPC task */ - struct file * wb_file; /* dentry referenced */ - struct page * wb_page; /* page to be written */ - struct wait_queue * wb_wait; /* wait for completion */ - unsigned int wb_offset; /* offset within page */ - unsigned int wb_bytes; /* dirty range */ - unsigned int wb_count; /* user count */ - int wb_status; - pid_t wb_pid; /* owner process */ - unsigned short wb_flags; /* status flags */ - - struct nfs_writeargs wb_args; /* NFS RPC stuff */ - struct nfs_fattr wb_fattr; /* file attributes */ -}; - -#define WB_NEXT(req) ((struct nfs_wreq *) ((req)->wb_list.next)) - -/* - * Various flags for wb_flags - */ -#define NFS_WRITE_CANCELLED 0x0004 /* has been cancelled */ -#define NFS_WRITE_UNCOMMITTED 0x0008 /* written but uncommitted (NFSv3) */ -#define NFS_WRITE_INVALIDATE 0x0010 /* invalidate after write */ -#define NFS_WRITE_INPROGRESS 0x0100 /* RPC call in progress */ -#define NFS_WRITE_COMPLETE 0x0200 /* RPC call completed */ - -#define WB_CANCELLED(req) ((req)->wb_flags & NFS_WRITE_CANCELLED) -#define WB_UNCOMMITTED(req) ((req)->wb_flags & NFS_WRITE_UNCOMMITTED) -#define WB_INVALIDATE(req) ((req)->wb_flags & NFS_WRITE_INVALIDATE) -#define WB_INPROGRESS(req) ((req)->wb_flags & NFS_WRITE_INPROGRESS) -#define WB_COMPLETE(req) ((req)->wb_flags & NFS_WRITE_COMPLETE) + * When flushing a cluster of dirty pages, there can be different + * strategies: + */ +#define FLUSH_AGING 0 /* only flush old buffers */ +#define FLUSH_SYNC 1 /* file being synced, or contention */ +#define FLUSH_INVALIDATE 2 /* pages will be invalidated */ +#define FLUSH_WAIT 4 /* wait for completion */ +#define FLUSH_STABLE 8 /* commit to stable storage */ + /* * linux/fs/nfs/proc.c @@ -182,6 +156,8 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_revalidate(struct dentry *); extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *); +extern int __nfs_wait_on_inode(struct inode *, int flag); +extern void nfs_unlock_inode(struct inode *inode); /* * linux/fs/nfs/file.c @@ -211,22 +187,54 @@ * linux/fs/nfs/write.c */ extern int nfs_writepage(struct file *, struct page *); -extern int nfs_check_failed_request(struct inode *); +extern int nfs_updatepage(struct file *, struct page *, const char *, + unsigned long, unsigned int, int); + /* * Try to write back everything synchronously (but check the * return value!) */ -extern int nfs_wb_all(struct inode *); -extern int nfs_wb_page(struct inode *, struct page *); -extern int nfs_wb_file(struct inode *, struct file *); +extern int nfs_sync_file(struct inode *, struct file *, __u64, __u64, int); + +static inline int +nfs_wb_all(struct inode *inode) +{ + return nfs_sync_file(inode, 0, 0, NFS_OFFSET_MAX, + FLUSH_WAIT|FLUSH_STABLE); +} + +/* + * Write back all requests on one page - we do this before reading it. + */ +static inline int +nfs_wb_page(struct inode *inode, struct page* page) +{ + return nfs_sync_file(inode, 0, page->offset, page->offset + PAGE_SIZE, + FLUSH_WAIT|FLUSH_STABLE); +} + + +/* + * Write back all pending writes for one user.. + */ +static inline int +nfs_wb_file(struct inode *inode, struct file *file) +{ + return nfs_sync_file(inode, file, 0, NFS_OFFSET_MAX, + FLUSH_WAIT|FLUSH_STABLE); +} /* * Invalidate write-backs, possibly trying to write them * back first.. */ -extern void nfs_inval(struct inode *); -extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int); +static inline int +nfs_invalidate_pages(struct inode *inode) +{ + return nfs_sync_file(inode, 0, 0, NFS_OFFSET_MAX, + FLUSH_INVALIDATE|FLUSH_STABLE); +} /* * linux/fs/nfs/read.c @@ -250,6 +258,49 @@ return 0; return _nfs_revalidate_inode(server, dentry); } + +static inline int +nfs_lock_inode(struct inode *inode) +{ + int error = 0; + + if (NFS_FLAGS(inode) & NFS_INO_LOCKED) + error = __nfs_wait_on_inode(inode, NFS_INO_LOCKED); + if (error >= 0) + NFS_FLAGS(inode) |= NFS_INO_LOCKED; + return error; +} + +static inline int +__nfs_flush_dirty_pages(struct inode *inode, struct file * file, loff_t start, loff_t end) +{ + return nfs_sync_file(inode, file, start, end, FLUSH_WAIT|FLUSH_STABLE); +} + +/* + * Sync a file or file region. + * While syncing, we make sure the inode is locked against further + * write() calls and revalidation. + * + * We don't distinguish between pages written by the current process or + * someone else, because people may do weird things like + * write a lot, fork, and fsync() in the child. + */ +static inline int +nfs_flush_dirty_pages(struct inode *inode , struct file *file, loff_t start, loff_t end) +{ + int error; + if ((error = nfs_lock_inode(inode)) >= 0) { + error = __nfs_flush_dirty_pages(inode, file, start, end); + nfs_unlock_inode(inode); + } + + return error; +} + + +/* NFS cluster */ +extern int nfs_wait_on_congest(struct inode *); /* NFS root */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfs_fs_i.h linux.ac/include/linux/nfs_fs_i.h --- linux.vanilla/include/linux/nfs_fs_i.h Sun Nov 8 15:06:47 1998 +++ linux.ac/include/linux/nfs_fs_i.h Sun Mar 7 22:07:00 1999 @@ -42,18 +42,21 @@ unsigned long attrtimeo; /* - * This is the list of dirty unwritten pages. - * NFSv3 will want to add a list for written but uncommitted - * pages. + * This is the list of clusters of dirty pages. */ - struct nfs_wreq * writeback; + struct nfs_cluster * dirty; }; /* * Legal inode flag values */ -#define NFS_INO_REVALIDATE 0x0001 /* revalidating attrs */ -#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */ +#define NFS_INO_LOCKED 0x0001 /* locked for revalidation */ +#define NFS_INO_ACCESSOK 0x0002 /* have called ACCES */ +#define NFS_INO_WRITE_ERROR 0x0004 /* a write error occurred */ +#define NFS_INO_ADVISE_RDPLUS 0x0008 /* advise readdirplus */ +#define NFS_INO_REVALIDATING 0x0010 /* in nfs_revalidate() */ +#define NFS_INO_INVALIDATE 0x0020 /* zap cache on next occasion */ +#define NFS_IS_SNAPSHOT 0x0040 /* a snapshot file */ /* * NFS lock info diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfs_fs_sb.h linux.ac/include/linux/nfs_fs_sb.h --- linux.vanilla/include/linux/nfs_fs_sb.h Sun Nov 8 15:06:47 1998 +++ linux.ac/include/linux/nfs_fs_sb.h Mon Mar 22 16:18:29 1999 @@ -18,6 +18,7 @@ unsigned int acdirmin; unsigned int acdirmax; char * hostname; /* remote hostname */ + struct nfs_reqlist * rw_requests; /* async read/write requests */ }; /* @@ -27,5 +28,9 @@ struct nfs_server s_server; struct nfs_fh s_root; }; + +/* Server writeback cache */ +int nfs_reqlist_init(struct nfs_server *); +void nfs_reqlist_exit(struct nfs_server *); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfsd/nfsfh.h linux.ac/include/linux/nfsd/nfsfh.h --- linux.vanilla/include/linux/nfsd/nfsfh.h Sun Nov 8 15:06:49 1998 +++ linux.ac/include/linux/nfsd/nfsfh.h Wed Mar 24 18:39:00 1999 @@ -33,6 +33,7 @@ __u32 fb_dev; /* our device */ __u32 fb_xdev; __u32 fb_xino; + __u32 fb_generation; }; #define NFS_FH_PADDING (NFS_FHSIZE - sizeof(struct nfs_fhbase)) @@ -47,6 +48,7 @@ #define fh_dev fh_base.fb_dev #define fh_xdev fh_base.fb_xdev #define fh_xino fh_base.fb_xino +#define fh_generation fh_base.fb_generation #ifdef __KERNEL__ @@ -106,6 +108,9 @@ void nfsd_fh_flush(kdev_t); void nfsd_fh_init(void); void nfsd_fh_free(void); +void expire_all(void); +void expire_by_dentry(struct dentry *); + static __inline__ struct svc_fh * fh_copy(struct svc_fh *dst, struct svc_fh *src) @@ -178,32 +183,9 @@ } /* - * Release an inode + * This is a long term cache to help find renamed files. */ -#if 0 -#define fh_put(fhp) __fh_put(fhp, __FILE__, __LINE__) - -static inline void -__fh_put(struct svc_fh *fhp, char *file, int line) -{ - struct dentry *dentry; - - if (!fhp->fh_dverified) - return; - - dentry = fhp->fh_dentry; - if (!dentry->d_count) { - printk("nfsd: trying to free free dentry in %s:%d\n" - " file %s/%s\n", - file, line, - dentry->d_parent->d_name.name, dentry->d_name.name); - } else { - fh_unlock(fhp); - fhp->fh_dverified = 0; - dput(dentry); - } -} -#endif +void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino); #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/pci.h linux.ac/include/linux/pci.h --- linux.vanilla/include/linux/pci.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/linux/pci.h Sat Mar 20 23:09:09 1999 @@ -273,6 +273,9 @@ #define PCI_CLASS_SERIAL_USB 0x0c03 #define PCI_CLASS_SERIAL_FIBER 0x0c04 +#define PCI_BASE_CLASS_INTELLIGENT 0x0e +#define PCI_CLASS_INTELLIGENT_I2O 0x0e00 + #define PCI_CLASS_OTHERS 0xff /* @@ -676,6 +679,8 @@ #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004 +#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV 0x0005 +#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS 0x0083 #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_ABP940 0x1200 @@ -946,6 +951,7 @@ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI 0x5000 +#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 #define PCI_VENDOR_ID_ALTEON 0x12ae #define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001 @@ -1072,6 +1078,7 @@ #define PCI_VENDOR_ID_ADAPTEC2 0x9005 #define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010 +#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011 #define PCI_DEVICE_ID_ADAPTEC2_78902 0x0013 #define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f #define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/poll.h linux.ac/include/linux/poll.h --- linux.vanilla/include/linux/poll.h Sun Jan 24 19:55:40 1999 +++ linux.ac/include/linux/poll.h Wed Mar 24 18:21:59 1999 @@ -59,9 +59,6 @@ unsigned long *res_in, *res_out, *res_ex; } fd_set_bits; -/* - * How many longwords for "nr" bits? - */ #define FDS_BITPERLONG (8*sizeof(long)) #define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG) #define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) @@ -90,14 +87,17 @@ static inline void set_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset) { - if (ufdset) - __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); + if (ufdset) { + nr = (nr + 8*sizeof(long) - 1) / (8*sizeof(long))*sizeof(long); + __copy_to_user(ufdset, fdset, nr); + } } static inline void zero_fd_set(unsigned long nr, unsigned long *fdset) { - memset(fdset, 0, FDS_BYTES(nr)); + nr = (nr + 8*sizeof(long) - 1) / (8*sizeof(long)) * sizeof(long); + memset(fdset, 0, nr); } extern int do_select(int n, fd_set_bits *fds, long *timeout); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/proc_fs.h linux.ac/include/linux/proc_fs.h --- linux.vanilla/include/linux/proc_fs.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/linux/proc_fs.h Wed Mar 24 18:21:52 1999 @@ -203,8 +203,9 @@ PROC_SCSI_53C94, PROC_SCSI_PLUTO, PROC_SCSI_INI9100U, - PROC_SCSI_INIA100, + PROC_SCSI_INIA100, PROC_SCSI_FCAL, + PROC_SCSI_I2O, PROC_SCSI_SCSI_DEBUG, PROC_SCSI_NOT_PRESENT, PROC_SCSI_FILE, /* I'm assuming here that we */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sched.h linux.ac/include/linux/sched.h --- linux.vanilla/include/linux/sched.h Wed Mar 10 21:13:11 1999 +++ linux.ac/include/linux/sched.h Wed Mar 24 18:21:51 1999 @@ -112,6 +112,7 @@ * a separate lock). */ extern rwlock_t tasklist_lock; +extern spinlock_t runqueue_lock; extern spinlock_t scheduler_lock; extern void sched_init(void); @@ -123,22 +124,38 @@ asmlinkage void schedule(void); /* + * The default fd array needs to be at least BITS_PER_LONG, + * as this is the granularity returned by copy_fdset(). + */ +#define NR_OPEN_DEFAULT BITS_PER_LONG + +/* * Open file table structure */ struct files_struct { atomic_t count; int max_fds; + int max_fdset; + int next_fd; struct file ** fd; /* current fd array */ - fd_set close_on_exec; - fd_set open_fds; + fd_set *close_on_exec; + fd_set *open_fds; + fd_set close_on_exec_init; + fd_set open_fds_init; + struct file * fd_array[NR_OPEN_DEFAULT]; }; #define INIT_FILES { \ ATOMIC_INIT(1), \ - NR_OPEN, \ - &init_fd_array[0], \ + NR_OPEN_DEFAULT, \ + __FD_SETSIZE, \ + 0, \ + &init_files.fd_array[0], \ + &init_files.close_on_exec_init, \ + &init_files.open_fds_init, \ { { 0, } }, \ - { { 0, } } \ + { { 0, } }, \ + { NULL, } \ } struct fs_struct { @@ -616,6 +633,45 @@ extern void mmput(struct mm_struct *); /* Remove the current tasks stale references to the old mm_struct */ extern void mm_release(void); + +/* + * Routines for handling the fd arrays + */ +extern struct file ** alloc_fd_array(int); +extern int expand_fd_array(struct files_struct *, int nr); +extern void free_fd_array(struct file **, int); + +extern fd_set *alloc_fdset(int); +extern int expand_fdset(struct files_struct *, int nr); +extern void free_fdset(fd_set *, int); + +/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, + * we may have blocked. */ +static inline int expand_files(struct files_struct *files, int nr) +{ + int err, expand = 0; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_bstrm.h linux.ac/include/linux/sdla_bstrm.h --- linux.vanilla/include/linux/sdla_bstrm.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/sdla_bstrm.h Thu Mar 11 12:59:49 1999 @@ -0,0 +1,217 @@ +/***************************************************************************** +* bsc_api.h Bisync Streaming API header file. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Sep 24, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + +/* Status flag for determining whether to perform a check on socket receive + * queue. + */ +#define NO_SK_RX_CHECK 0x00 +#define TOP_CHECK_SK_RX_Q 0x01 +#define BTM_CHECK_SK_RX_Q 0x02 + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + +/* physical addresses on the adapter + */ +#define SEND_MB_OFF 0x0000 /* base addr of the SEND mb area */ +#define RECEIVE_MB_OFF 0x1000 /* base addr of the RECEIVE mb area */ +#define INTERRUPT_REPORT_IB_OFF 0x1FF0 /* a ptr to the interrupt reporting interface byte */ +#define INTERRUPT_PERMIT_IB_OFF 0x1FF1 /* a pointer to the interrupt permission interface byte */ +#define PTR_MODEM_STATUS_IB 0xFFF4 /* a pointer to the modem status interface byte */ + + +/* BSC streaming commands */ +#define BSC_WRITE 0x01 /* transmit a BSC block */ +#define BSC_READ 0x90 +#define ENABLE_COMMUNICATIONS 0x02 /* enable communications */ +#define DISABLE_COMMUNICATIONS 0x03 /* disable communications */ +#define READ_OPERATIONAL_STATS 0x07 /* retrieve the operational statistics */ +#define FLUSH_OPERATIONAL_STATS 0x08 /* flush the operational statistics */ +#define READ_COMMS_ERR_STATS 0x09 /* read the communication error statistics */ +#define FLUSH_COMMS_ERR_STATS 0x0A /* flush the communication error statistics */ +#define SET_MODEM_STATUS 0x0B /* set the modem status */ +#define READ_MODEM_STATUS 0x0C /* read the current modem status (CTS and DCD status) */ +#define FLUSH_BSC_BUFFERS 0x0D /* flush any queued transmit and receive buffers */ +#define READ_CONFIGURATION 0x10 /* read the current operational configuration */ +#define SET_CONFIGURATION 0x11 /* set the operational configuration */ +#define READ_CODE_VERSION 0x15 /* read the code version */ +#define SET_INTERRUPT_TRIGGERS 0x20 /* set the interrupt triggers */ +#define READ_INTERRUPT_TRIGGERS 0x21 /* read the interrupt trigger configuration */ +#define READ_ADAPTER_CONFIGURATION 0xA0 /* find out what type of adapter is being used */ + + + +/* return code from BSC streaming commands */ +#define COMMAND_SUCCESSFULL 0x00 /* the command was successfull */ +#define COMMUNICATIONS_DISABLED 0x01 /* communications are currently disabled */ +#define COMMUNICATIONS_ENABLED 0x02 /* communications are currently enabled */ +#define SET_CONFIG_BEFORE_ENABLE_COMMS 0x03 /* SET_CONFIGURATION before ENABLE_COMMUNICATIONS */ +#define INVALID_CONFIGURATION_DATA 0x03 /* the passed configuration data is invalid */ +#define INVALID_TX_DATA_LGTH 0x03 /* the length of the data to be transmitted is invalid */ +#define CANT_FLUSH_BUSY_SENDING 0x03 /* the BSC buffers cannot be flushed as a block is being transmitted */ +#define TX_BUFFERS_FULL 0x04 /* the transmit buffers are full */ +#define ILLEGAL_COMMAND 0x05 /* the defined HDLC command is invalid */ +#define MODEM_STATUS_CHANGE 0x10 /* a modem (DCD/CTS) status change ocurred */ +#define NO_DATA_AVAILABLE 0x20 + +/* mailbox definitions */ +/* +The two mailboxes take up a total of 8192 bytes, so each is 4096 bytes in size. However, we reserve the last 16 bytes +in the receive mailbox for miscellaneous interface bytes, so each mailbox is now 4080 bytes. If we subtract 16 bytes +for the mailbox header area, we are left with a mailbox data size of 4064 bytes. +*/ +#define SIZEOF_MB_DATA_BFR 4064 +#define MAILBOX_SIZE 20 + +/* the mailbox structure */ +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char misc_Tx_Rx_bits PACKED; /* miscellaneous transmit and receive bits */ + unsigned char Rx_error_bits PACKED; /* an indication of a block received with an error */ + unsigned short Rx_time_stamp PACKED; /* a millisecond receive time stamp */ + unsigned char reserved[7] PACKED; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */ +} MAILBOX_STRUCT; + +typedef struct { + pid_t pid_num PACKED; + MAILBOX_STRUCT cmdarea PACKED; +} CMDBLOCK_STRUCT; + +/* definitions for setting the configuration */ +#define MAXIMUM_BAUD_RATE 112000 /* the maximum permitted baud rate */ +#define MIN_BLOCK_LENGTH 2 /* the minimum permitted block length */ +#define MAX_BLOCK_LENGTH 2200 /* the maximum permitted block length */ +#define MIN_NO_CONSEC_PADs_EOB 1 /* the minimum number of consecutive PADs defining the end-of-block */ +#define MAX_NO_CONSEC_PADs_EOB 50 /* the maximum number of consecutive PADs defining the end-of-block */ +#define MIN_ADD_LEAD_TX_SYN_CHARS 0 /* the minimum number of additional leading SYN characters */ +#define MAX_ADD_LEAD_TX_SYN_CHARS 50 /* the maximum number of additional leading SYN characters */ +#define MIN_NO_BITS_PER_CHAR 8 /* the minimum number of bits per character */ +#define MAX_NO_BITS_PER_CHAR 8 /* the maximum number of bits per character */ + +/* definitions for the 'Rx_block_type' */ +#define RX_BLOCK_TYPE_1 1 +#define RX_BLOCK_TYPE_2 2 +#define RX_BLOCK_TYPE_3 3 + +/* definitions for 'parity' */ +#define NO_PARITY 0 /* no parity */ +#define ODD_PARITY 1 /* odd parity */ +#define EVEN_PARITY 2 /* even parity */ + +/* definitions for the 'statistics_options' */ +#define RX_STATISTICS 0x0001 /* enable receiver statistics */ +#define RX_TIME_STAMP 0x0002 /* enable the receive time stamp */ +#define TX_STATISTICS 0x0100 /* enable transmitter statistics */ + +/* definitions for the 'misc_config_options' */ +#define STRIP_PARITY_BIT_FROM_DATA 0x0001 /* strip the parity bit from the data for block types 1 & 3 */ + +/* definitions for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_EN_COMMS 0x0001 /* don't raise DTR and RTS when enabling communications */ + +/* the configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned long adapter_frequency PACKED; /* the adapter frequecy */ + unsigned short max_data_length PACKED; /* the maximum length of a BSC data block */ + unsigned short EBCDIC_encoding PACKED; /* EBCDIC/ASCII encoding */ + unsigned short Rx_block_type PACKED; /* the type of BSC block to be received */ + unsigned short no_consec_PADs_EOB PACKED; /* the number of consecutive PADs indicating the end of the block */ + unsigned short no_add_lead_Tx_SYN_chars PACKED; /* the number of additional leading transmit SYN characters */ + unsigned short no_bits_per_char PACKED; /* the number of bits per character */ + unsigned short parity PACKED; /* parity */ + unsigned short misc_config_options PACKED; /* miscellaneous configuration options */ + unsigned short statistics_options PACKED; /* statistic options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ +} CONFIGURATION_STRUCT; + + + +/* definitions for reading the communications errors */ +/* the communications error structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* the number of receiver overrun errors */ + unsigned short BCC_err_count; /* the number of receiver BCC errors */ + unsigned short nxt_Rx_bfr_occupied_count; /* the number of times a block had to be discarded due to buffering */ + /* limitations */ + unsigned short Rx_too_long_int_lvl_count; /* the number of blocks received which exceeded the maximum permitted */ + /* block size (interrupt level) */ + unsigned short Rx_too_long_app_lvl_count; /* the number of blocks received which exceeded the configured maximum */ + /* block size (application level) */ + unsigned short comms_err_res_Rx; /* reserved (later use) for a receive statistic */ + unsigned short Tx_underrun_count; /* the number of transmit underruns */ + unsigned short comms_err_res_Tx; /* reserved (later use) for a transmit statistic */ + unsigned short DCD_state_change_count; /* the number of times DCD changed state */ + unsigned short CTS_state_change_count; /* the number of times CTS changed state */ +} COMMUNICATIONS_ERROR_STRUCT; + + + +/* definitions for reading the operational statistics */ +/* the operational statistics structure */ +typedef struct { + unsigned long no_blocks_Rx PACKED; /* the number of data blocks received and made available for the application */ + unsigned long no_bytes_Rx PACKED; /* the number of bytes received and made available for the application */ + unsigned long no_blocks_Tx PACKED; /* the number of data blocks transmitted */ + unsigned long no_bytes_Tx PACKED; /* the number of bytes transmitted */ +} OPERATIONAL_STATS_STRUCT; + + + +/* definitions for interrupt usage */ +/* 'interrupt_triggers' bit mapping set by a SET_INTERRUPT_TRIGGERS command */ +#define INTERRUPT_ON_RX_BLOCK 0x01 /* interrupt when an data block is + available for the application */ +#define NO_INTERRUPTS 0x00 +#define INTERRUPT_ON_TIMER 0x20 + +/* interrupt types indicated at 'ptr_interrupt_interface_byte' */ +#define RX_INTERRUPT_PENDING 0x01 /* a receive interrupt is pending */ + +typedef struct { + char int_type; + char int_allowed; +} BSC_INT_BYTES; + + +/* definitions for data block transmission */ +/* the setting of the 'misc_Tx_Rx_bits' in the mailbox */ +#define TX_BLK_TRANSPARENT 0x01 /* send a transparent text block */ +#define ETB_DEFINES_EOB 0x02 /* an ETB character defines the end of this text block */ +#define ITB_DEFINES_EOB 0x04 /* an ITB character defines the end of this text block */ +#define USR_DEFINES_TX_DATA 0x10 /* the user application defines the data to be transmitted */ + + + +/* definitions for the 'Rx_error_bits' in the RECEIVE mailbox */ +#define RX_BCC_ERROR 0x01 /* a receive BCC error occurred */ +#define RX_OVERRUN_ERROR 0x02 /* a receive overrun error occurred */ +#define RX_EXCESSIVE_LGTH_ERR_INT_LVL 0x10 /* the received block was too long (interrupt level) */ +#define RX_EXCESSIVE_LGTH_ERR_APP_LVL 0x20 /* the received block was too long (application level) */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_chdlc.h linux.ac/include/linux/sdla_chdlc.h --- linux.vanilla/include/linux/sdla_chdlc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/sdla_chdlc.h Thu Mar 11 13:01:47 1999 @@ -0,0 +1,724 @@ +/************************************************************************* + sdla_chdlc.h Sangoma Cisco HDLC firmware API definitions + + Author: David Fong (Based on code by Gideon Hack and Gene Kozin) + + Copyright: (c) 1995-1998 Sangoma Technologies Inc. + + This program is free software; you can redistribute it and/or + modify it under the term 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. + +=========================================================================== + Oct 28, 1998 Jaspreet Singh Made changes for Dual Port CHDLC. + Jun 11, 1998 David Fong Initial version. +=========================================================================== + + Organization + - Compatibility notes + - Constants defining the shared memory control block (mailbox) + - Interface commands + - Return code from interface commands + - Constants for the commands (structures for casting data) + - UDP Management constants and structures + +*************************************************************************/ + +#ifndef _SDLA_CHDLC_H +# define _SDLC_CHDLC_H + +/*------------------------------------------------------------------------ + Notes: + + All structres defined in this file are byte-aligned. To ensure + portability of this code between different platforms and compilers, one + of the follwoing defines must be defined before including this file: + + Compiler Platform Define Use option + ------------------------------------------------------------ + GNU C Linux _GNUC_ - + Microsoft C DOS/Windows _MSC_ - + +------------------------------------------------------------------------*/ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + + +/* Status flag for determining whether to perform a check on socket receive * queue. + */ +#define NO_SK_RX_CHECK 0x00 +#define TOP_CHECK_SK_RX_Q 0x01 +#define BTM_CHECK_SK_RX_Q 0x02 + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure on the adapter */ +#define SIZEOF_MB_DATA_BFR 4080 /* the size of the actual mailbox data area */ +#define NUMBER_MB_RESERVED_BYTES 0x0A /* the number of reserved bytes in the mailbox header area */ + +/* Just the header, excluding the data area, including pid number */ +#define MAILBOX_SIZE 20 + +#define P0_MAX_NO_DATA_BYTES_IN_FRAME 15354 /* Port 0 - max length of the CHDLC data field */ + +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char port_number PACKED; /* the port number */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */ +} TRUE_CHDLC_MAILBOX_STRUCT; + +/* the control block mailbox structure */ +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char port_number PACKED; /* the port number */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ + unsigned char data[P0_MAX_NO_DATA_BYTES_IN_FRAME] PACKED; /* the maximum data area */ +} CHDLC_MAILBOX_STRUCT; + + +typedef struct { + pid_t pid_num PACKED; + CHDLC_MAILBOX_STRUCT cmdarea PACKED; + +} CMDBLOCK_STRUCT; + + + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* global interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 +#define SET_GLOBAL_CONFIGURATION 0x02 +#define READ_GLOBAL_CONFIGURATION 0x03 +#define READ_GLOBAL_STATISTICS 0x04 +#define FLUSH_GLOBAL_STATISTICS 0x05 +#define SET_MODEM_STATUS 0x06 /* set status of DTR or RTS */ +#define READ_MODEM_STATUS 0x07 /* read status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 +#define FLUSH_COMMS_ERROR_STATS 0x09 +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace config */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace config */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ +#define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the S508/FT1 monitoring */ +#define READ_FT1_OPERATIONAL_STATS 0x1D /* read the S508/FT1 operational statistics */ +#define SET_FT1_MODE 0x1E /* set the operational mode of the S508/FT1 module */ + +/* CHDLC-level interface commands */ +#define READ_CHDLC_CODE_VERSION 0x20 +#define READ_CHDLC_EXCEPTION_CONDITION 0x21 /* read exception condition from the adapter */ +#define SET_CHDLC_CONFIGURATION 0x22 +#define READ_CHDLC_CONFIGURATION 0x23 +#define ENABLE_CHDLC_COMMUNICATIONS 0x24 +#define DISABLE_CHDLC_COMMUNICATIONS 0x25 +#define READ_CHDLC_LINK_STATUS 0x26 +#define READ_CHDLC_OPERATIONAL_STATS 0x27 +#define FLUSH_CHDLC_OPERATIONAL_STATS 0x28 +#define SET_CHDLC_INTERRUPT_TRIGGERS 0x30 /* set application interrupt triggers */ +#define READ_CHDLC_INTERRUPT_TRIGGERS 0x31 /* read application interrupt trigger configuration */ + +/* Special UDP drivers management commands */ +#define CPIPE_ENABLE_TRACING 0x50 +#define CPIPE_DISABLE_TRACING 0x51 +#define CPIPE_GET_TRACE_INFO 0x52 +#define CPIPE_GET_IBA_DATA 0x53 +#define CPIPE_FT1_READ_STATUS 0x54 +#define CPIPE_DRIVER_STAT_IFSEND 0x55 +#define CPIPE_DRIVER_STAT_INTR 0x56 +#define CPIPE_DRIVER_STAT_GEN 0x57 +#define CPIPE_FLUSH_DRIVER_STATS 0x58 +#define CPIPE_ROUTER_UP_TIME 0x59 + +/* Driver specific commands for API */ +#define CHDLC_SEND_NO_WAIT 0xE0 /* send I frames :Poll */ +#define CHDLC_SEND_WAIT 0xE1 /* send I frames :Interrupt*/ +#define CHDLC_READ_NO_WAIT 0xE2 /* receive I frames :Poll */ +#define CHDLC_READ_WAIT 0xE3 /* receive I frames :Interrupt*/ +#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define COMMAND_OK 0x00 + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no CHDLC exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ +#define S508_FT1_ADPTR_NOT_PRESENT 0x0C /* the S508/FT1 adapter is not present */ +#define INVALID_FT1_STATUS_SELECTION 0x0D /* the S508/FT1 status selection is invalid */ +#define FT1_OP_STATS_NOT_ENABLED 0x0D /* the FT1 operational statistics have not been enabled */ +#define FT1_OP_STATS_NOT_AVAILABLE 0x0E /* the FT1 operational statistics are not currently available */ +#define S508_FT1_MODE_SELECTION_BUSY 0x0E /* the S508/FT1 adapter is busy selecting the operational mode */ + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ + +/* return codes from CHDLC-level interface commands */ +#define NO_CHDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no CHDLC exception condition to report */ +#define CHDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define CHDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define DISABLE_CHDLC_COMMS_BEFORE_CFG 0x21 /* CHDLC communications must be disabled before setting the configuration */ +#define ENABLE_CHDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the CHDLC_CONNECT conmmand */ +#define CHDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_CHDLC_CONFIGURATION before enabling comms */ +#define LGTH_CHDLC_CFG_DATA_INVALID 0x22 /* the length of the passed CHDLC configuration data is invalid */ +#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define INVALID_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_CHDLC_INTERRUPT_TRIGGERS */ +#define INVALID_CHDLC_CFG_DATA 0x23 /* the passed CHDLC configuration data is invalid */ +#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define LARGER_PERCENT_TX_BFR_REQUIRED 0x24 /* a larger Tx buffer percentage is required */ +#define LARGER_PERCENT_RX_BFR_REQUIRED 0x25 /* a larger Rx buffer percentage is required */ +#define INVALID_CMND_HDLC_STREAM_MODE 0x4E /* the CHDLC interface command is invalid for HDLC streaming mode */ +#define INVALID_CHDLC_COMMAND 0x4F /* the defined CHDLC interface command is invalid */ + +/* return codes from command READ_CHDLC_EXCEPTION_CONDITION */ +#define EXCEP_LINK_ACTIVE 0x30 /* the CHDLC link has become active */ +#define EXCEP_LINK_INACTIVE_MODEM 0x31 /* the CHDLC link has become inactive (modem status) */ +#define EXCEP_LINK_INACTIVE_KPALV 0x32 /* the CHDLC link has become inactive (keepalive status) */ +#define EXCEP_IP_ADDRESS_DISCOVERED 0x33 /* the IP address has been discovered */ +#define EXCEP_LOOPBACK_CONDITION 0x34 /* a loopback condition has occurred */ + + +/* return code from command CHDLC_SEND_WAIT and CHDLC_SEND_NO_WAIT */ +#define LINK_DISCONNECTED 0x21 +#define NO_TX_BFRS_AVAIL 0x24 + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options PACKED; /* adapter config options */ + unsigned short app_IRQ_timeout PACKED; /* application IRQ timeout */ + unsigned long adapter_operating_frequency PACKED; /* adapter operating frequency */ +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count PACKED; +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned char Rx_overrun_err_count PACKED; + unsigned char CRC_err_count PACKED; /* receiver CRC error count */ + unsigned char Rx_abort_count PACKED; /* abort frames recvd count */ + unsigned char Rx_dis_pri_bfrs_full_count PACKED;/* receiver disabled */ + unsigned char comms_err_stat_reserved_1 PACKED; /* reserved for later */ + unsigned char P1_Tx_abort_msd_Tx_int_count PACKED; /* P1 - abort frames transmitted count (missed Tx interrupt) */ + unsigned char missed_Tx_und_int_count PACKED; /* missed tx underrun interrupt count */ + unsigned char P1_Tx_abort_count PACKED; /*P1-abort frames tx count */ + unsigned char DCD_state_change_count PACKED;/* DCD state change count */ + unsigned char CTS_state_change_count PACKED;/* CTS state change count */ +} COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants used for line tracing + * --------------------------------------------------------------------------*/ + +/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */ +typedef struct { + unsigned char trace_config PACKED; /* trace configuration */ + unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */ + unsigned long ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */ +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_DELAY_MODE 0x04 /* operate the trace in delay mode */ +#define TRACE_DATA_FRAMES 0x08 /* trace Data frames */ +#define TRACE_SLARP_FRAMES 0x10 /* trace SLARP frames */ +#define TRACE_CDP_FRAMES 0x20 /* trace CDP frames */ + +/* the line trace status element configuration structure */ +typedef struct { + unsigned short number_trace_status_elements PACKED; /* number of line trace elements */ + unsigned long base_addr_trace_status_elements PACKED; /* base address of the trace element list */ + unsigned long next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */ + unsigned long base_addr_trace_buffer PACKED; /* base address of the trace data buffer */ + unsigned long end_addr_trace_buffer PACKED; /* end address of the trace data buffer */ +} TRACE_STATUS_EL_CFG_STRUCT; + +/* the line trace status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short trace_length PACKED; /* trace length */ + unsigned char trace_type PACKED; /* trace type */ + unsigned short trace_time_stamp PACKED; /* time stamp */ + unsigned short trace_reserved_1 PACKED; /* reserved for later use */ + unsigned long trace_reserved_2 PACKED; /* reserved for later use */ + unsigned long ptr_data_bfr PACKED; /* ptr to the trace data buffer */ +} TRACE_STATUS_ELEMENT_STRUCT; + +/* "trace_type" bit settings */ +#define TRACE_INCOMING 0x00 +#define TRACE_OUTGOINGING 0x01 +#define TRACE_INCOMING_ABORTED 0x10 +#define TRACE_INCOMING_CRC_ERROR 0x20 +#define TRACE_INCOMING_OVERRUN_ERROR 0x40 + + + +/* the line trace statistics structure */ +typedef struct { + unsigned long frames_traced_count PACKED; /* number of frames traced */ + unsigned long trc_frms_not_recorded_count PACKED; /* number of trace frames discarded */ +} LINE_TRACE_STATS_STRUCT; + + +/* ---------------------------------------------------------------------------- + * Constants for the FT1_MONITOR_STATUS_CTRL command + * --------------------------------------------------------------------------*/ + +#define DISABLE_FT1_STATUS_STATISTICS 0x00 /* disable the FT1 status and statistics monitoring */ +#define ENABLE_READ_FT1_STATUS 0x01 /* read the FT1 operational status */ +#define ENABLE_READ_FT1_OP_STATS 0x02 /* read the FT1 operational statistics */ +#define FLUSH_FT1_OP_STATS 0x04 /* flush the FT1 operational statistics */ + + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_CHDLC_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the CHDLC configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configration options */ + unsigned short modem_status_timer PACKED; /* timer for monitoring modem status changes */ + unsigned short CHDLC_API_options PACKED; /* CHDLC API options */ + unsigned short CHDLC_protocol_options PACKED; /* CHDLC protocol options */ + unsigned short percent_data_buffer_for_Tx PACKED; /* percentage data buffering used for Tx */ + unsigned short CHDLC_statistics_options PACKED; /* CHDLC operational statistics options */ + unsigned short max_CHDLC_data_field_length PACKED; /* the maximum length of the CHDLC Data field */ + unsigned short transmit_keepalive_timer PACKED; /* the transmit keepalive timer */ + unsigned short receive_keepalive_timer PACKED; /* the receive keepalive timer */ + unsigned short keepalive_error_tolerance PACKED; /* the receive keepalive error tolerance */ + unsigned short SLARP_request_timer PACKED; /* the SLARP request timer */ + unsigned long IP_address PACKED; /* the IP address */ + unsigned long IP_netmask PACKED; /* the IP netmask */ + unsigned long ptr_shared_mem_info_struct PACKED; /* a pointer to the shared memory area information structure */ + unsigned long ptr_CHDLC_Tx_stat_el_cfg_struct PACKED; /* a pointer to the transmit status element configuration structure */ + unsigned long ptr_CHDLC_Rx_stat_el_cfg_struct PACKED; /* a pointer to the receive status element configuration structure */ +} CHDLC_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */ +#define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */ + +/* settings for the 'modem_config_options' */ + +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 +/* don't automatically raise DTR and RTS when performing an + ENABLE_CHDLC_COMMUNICATIONS command */ + +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 +/* don't report changes in modem status to the application */ + + +/* bit settings for the 'CHDLC_protocol_options' byte */ + +#define IGNORE_DCD_FOR_LINK_STAT 0x0001 +/* ignore DCD in determining the CHDLC link status */ + +#define IGNORE_CTS_FOR_LINK_STAT 0x0002 +/* ignore CTS in determining the CHDLC link status */ + +#define IGNORE_KPALV_FOR_LINK_STAT 0x0004 +/* ignore keepalive frames in determining the CHDLC link status */ + + +/* settings for the 'CHDLC_statistics_options' */ + +#define CHDLC_TX_DATA_BYTE_COUNT_STAT 0x0001 +/* record the number of Data bytes transmitted */ + +#define CHDLC_RX_DATA_BYTE_COUNT_STAT 0x0002 +/* record the number of Data bytes received */ + +#define CHDLC_TX_THROUGHPUT_STAT 0x0004 +/* compute the Data frame transmit throughput */ + +#define CHDLC_RX_THROUGHPUT_STAT 0x0008 +/* compute the Data frame receive throughput */ + + +/* permitted minimum and maximum values for setting the CHDLC configuration */ +#define P0_MAX_BAUD_RATE 2666000 /* Port 0 - maximum baud rate */ +#define P1_MAX_BAUD_RATE 256000 /* Port 1 - maximum baud rate */ + +#define MIN_MODEM_TIMER 0 /* minimum modem status timer */ +#define MAX_MODEM_TIMER 5000 /* maximum modem status timer */ + +#define P1_MAX_NO_DATA_BYTES_IN_FRAME 2048 /* Port 1 - max length of the CHDLC data field */ + +#define MIN_Tx_KPALV_TIMER 0 /* minimum transmit keepalive timer */ +#define MAX_Tx_KPALV_TIMER 60000 /* maximum transmit keepalive timer */ +#define DEFAULT_Tx_KPALV_TIMER 10000 /* default transmit keepalive timer */ + +#define MIN_Rx_KPALV_TIMER 10 /* minimum receive keepalive timer */ +#define MAX_Rx_KPALV_TIMER 60000 /* maximum receive keepalive timer */ +#define DEFAULT_Rx_KPALV_TIMER 10000 /* default receive keepalive timer */ + +#define MIN_KPALV_ERR_TOL 1 /* min kpalv error tolerance count */ +#define MAX_KPALV_ERR_TOL 20 /* max kpalv error tolerance count */ +#define DEFAULT_KPALV_ERR_TOL 3 /* default value */ + +#define MIN_SLARP_REQ_TIMER 0 /* min transmit SLARP Request timer */ +#define MAX_SLARP_REQ_TIMER 60000 /* max transmit SLARP Request timer */ +#define DEFAULT_SLARP_REQ_TIMER 0 /* default value -- no SLARP */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_CHDLC_LINK_STATUS command + * --------------------------------------------------------------------------*/ + +/* the CHDLC status structure */ +typedef struct { + unsigned char CHDLC_link_status PACKED; /* CHDLC link status */ + unsigned char no_Data_frms_for_app PACKED; /* number of Data frames available for the application */ + unsigned char receiver_status PACKED; /* enabled/disabled */ + unsigned char SLARP_state PACKED; /* internal SLARP state */ +} CHDLC_LINK_STATUS_STRUCT; + +/* settings for the 'CHDLC_link_status' variable */ +#define CHDLC_LINK_INACTIVE 0x00 /* the CHDLC link is inactive */ +#define CHDLC_LINK_ACTIVE 0x01 /* the CHDLC link is active */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_CHDLC_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the CHDLC operational statistics structure */ +typedef struct { + + /* Data frame transmission statistics */ + unsigned long Data_frames_Tx_count PACKED; /* # of frames transmitted */ + unsigned long Data_bytes_Tx_count PACKED; /* # of bytes transmitted */ + unsigned long Data_Tx_throughput PACKED; /* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp PACKED; /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count PACKED; /* number of Data frames discarded (length error) */ + unsigned long reserved_Data_frm_Tx_stat1 PACKED; /* reserved for later */ + unsigned long reserved_Data_frm_Tx_stat2 PACKED; /* reserved for later */ + unsigned long reserved_Data_frm_Tx_stat3 PACKED; /* reserved for later */ + + /* Data frame reception statistics */ + unsigned long Data_frames_Rx_count PACKED; /* number of frames received */ + unsigned long Data_bytes_Rx_count PACKED; /* number of bytes received */ + unsigned long Data_Rx_throughput PACKED; /* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp PACKED; /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_discard_short_count PACKED; /* received Data frames discarded (too short) */ + unsigned long Rx_Data_discard_long_count PACKED; /* received Data frames discarded (too long) */ + unsigned long Rx_Data_discard_inactive_count PACKED; /* received Data frames discarded (link inactive) */ + unsigned long reserved_Data_frm_Rx_stat1 PACKED; /* reserved for later */ + + /* SLARP frame transmission/reception statistics */ + unsigned long CHDLC_SLARP_REQ_Tx_count PACKED; /* number of SLARP Request frames transmitted */ + unsigned long CHDLC_SLARP_REQ_Rx_count PACKED; /* number of SLARP Request frames received */ + unsigned long CHDLC_SLARP_REPLY_Tx_count PACKED; /* number of SLARP Reply frames transmitted */ + unsigned long CHDLC_SLARP_REPLY_Rx_count PACKED; /* number of SLARP Reply frames received */ + unsigned long CHDLC_SLARP_KPALV_Tx_count PACKED; /* number of SLARP keepalive frames transmitted */ + unsigned long CHDLC_SLARP_KPALV_Rx_count PACKED; /* number of SLARP keepalive frames received */ + unsigned long reserved_SLARP_stat1 PACKED; /* reserved for later */ + unsigned long reserved_SLARP_stat2 PACKED; /* reserved for later */ + + /* CDP frame transmission/reception statistics */ + unsigned long CHDLC_CDP_Tx_count PACKED; /* number of CDP frames transmitted */ + unsigned long CHDLC_CDP_Rx_count PACKED; /* number of CDP frames received */ + unsigned long reserved_CDP_stat1 PACKED; /* reserved for later */ + unsigned long reserved_CDP_stat2 PACKED; /* reserved for later */ + unsigned long reserved_CDP_stat3 PACKED; /* reserved for later */ + unsigned long reserved_CDP_stat4 PACKED; /* reserved for later */ + unsigned long reserved_CDP_stat5 PACKED; /* reserved for later */ + unsigned long reserved_CDP_stat6 PACKED; /* reserved for later */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED; /* frames received of with incomplete Cisco HDLC header */ + unsigned short Rx_frms_too_long_count PACKED; /* frames received of excessive length count */ + unsigned short Rx_invalid_CHDLC_addr_count PACKED; /* frames received with an invalid CHDLC address count */ + unsigned short Rx_invalid_CHDLC_ctrl_count PACKED; /* frames received with an invalid CHDLC control field count */ + unsigned short Rx_invalid_CHDLC_type_count PACKED; /* frames received of an invalid CHDLC frame type count */ + unsigned short Rx_SLARP_invalid_code_count PACKED; /* SLARP frame received with an invalid packet code */ + unsigned short Rx_SLARP_Reply_bad_IP_addr PACKED; /* SLARP Reply received - bad IP address */ + unsigned short Rx_SLARP_Reply_bad_netmask PACKED; /* SLARP Reply received - bad netmask */ + unsigned long reserved_frm_format_err1 PACKED; /* reserved for later */ + unsigned long reserved_frm_format_err2 PACKED; /* reserved for later */ + unsigned long reserved_frm_format_err3 PACKED; /* reserved for later */ + unsigned long reserved_frm_format_err4 PACKED; /* reserved for later */ + + /* CHDLC timeout/retry statistics */ + unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incomming SLARP frames */ + unsigned short SLARP_Request_TO_count PACKED; /* timeout count for SLARP Request frames */ + unsigned long To_retry_reserved_stat1 PACKED; /* reserved for later */ + unsigned long To_retry_reserved_stat2 PACKED; /* reserved for later */ + unsigned long To_retry_reserved_stat3 PACKED; /* reserved for later */ + + /* CHDLC link active/inactive and loopback statistics */ + unsigned short link_active_count PACKED; /* number of times that the link went active */ + unsigned short link_inactive_modem_count PACKED; /* number of times that the link went inactive (modem failure) */ + unsigned short link_inactive_keepalive_count PACKED; /* number of times that the link went inactive (keepalive failure) */ + unsigned short link_looped_count PACKED; /* link looped count */ + unsigned long link_status_reserved_stat1 PACKED; /* reserved for later use */ + unsigned long link_status_reserved_stat2 PACKED; /* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1 PACKED; /* reserved for later */ + unsigned long reserved_misc_stat2 PACKED; /* reserved for later */ + unsigned long reserved_misc_stat3 PACKED; /* reserved for later */ + unsigned long reserved_misc_stat4 PACKED; /* reserved for later */ + +} CHDLC_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the SET_CHDLC_INTERRUPT_TRIGGERS/READ_CHDLC_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char CHDLC_interrupt_triggers PACKED; /* CHDLC interrupt trigger configuration */ + unsigned char IRQ PACKED; /* IRQ to be used */ + unsigned short interrupt_timer PACKED; /* interrupt timer */ +} CHDLC_INT_TRIGGERS_STRUCT; + +/* 'CHDLC_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on Data frame reception */ +#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an Data frame may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_CHDLC_EXCEP_COND 0x20 /* interrupt on an CHDLC exception condition */ +#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define CHDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an CHDLC exception condition interrupt is pending */ +#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ + + + +/* ---------------------------------------------------------------------------- + * Constants for Data frame transmission + * --------------------------------------------------------------------------*/ + +/* the Data frame transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ +} CHDLC_TX_STATUS_EL_CFG_STRUCT; + +/* the Data frame transmit status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short frame_length PACKED; /* length of the frame to be transmitted */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long reserved_3 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} CHDLC_DATA_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data frame reception + * --------------------------------------------------------------------------*/ + +/* the Data frame receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */ +} CHDLC_RX_STATUS_EL_CFG_STRUCT; + +/* the Data frame receive status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short frame_length PACKED; /* length of the received frame */ + unsigned char error_flag PACKED; /* frame errors (HDLC_STREAMING_MODE)*/ + unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned long reserved_1 PACKED; /* reserved for internal use */ + unsigned short reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} CHDLC_DATA_RX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status PACKED; /* global status */ + unsigned char modem_status PACKED; /* current modem status */ + unsigned char global_excep_conditions PACKED; /* global exception conditions */ + unsigned char glob_info_reserved[5] PACKED; /* reserved */ + unsigned char codename[4] PACKED; /* Firmware name */ + unsigned char codeversion[4] PACKED; /* Firmware version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the CHDLC information structure */ +typedef struct { + unsigned char CHDLC_status PACKED; /* CHDLC status */ + unsigned char CHDLC_excep_conditions PACKED; /* CHDLC exception conditions */ + unsigned char CHDLC_info_reserved[14] PACKED; /* reserved */ +} CHDLC_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type PACKED; /* type of interrupt triggered */ + unsigned char interrupt_permission PACKED; /* interrupt permission mask */ + unsigned char int_info_reserved[14] PACKED; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the S508/FT1 information structure */ +typedef struct { + unsigned char parallel_port_A_input PACKED; /* input - parallel port A */ + unsigned char parallel_port_B_input PACKED; /* input - parallel port B */ + unsigned char FT1_info_reserved[14] PACKED; /* reserved */ +} FT1_INFORMATION_STRUCT; + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct PACKED; /* the global information structure */ + CHDLC_INFORMATION_STRUCT CHDLC_info_struct PACKED; /* the CHDLC information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct PACKED; /* the interrupt information structure */ + FT1_INFORMATION_STRUCT FT1_info_struct PACKED; /* the S508/FT1 information structure */ +} SHARED_MEMORY_INFO_STRUCT; + +/* ---------------------------------------------------------------------------- + * UDP Management constants and structures + * --------------------------------------------------------------------------*/ + +/* The embedded control block for UDP mgmt + This is essentially a mailbox structure, without the large data field */ + +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char port_number PACKED; /* the port number */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ +} cblock_t; + + +/* UDP management packet layout (data area of ip packet) */ +typedef struct { + unsigned char signature[8] PACKED; + unsigned char request_reply PACKED; + unsigned char id PACKED; + unsigned char reserved[6] PACKED; + cblock_t cblock PACKED; + unsigned char num_frames PACKED; + unsigned char ismoredata PACKED; + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; +} udp_management_packet_t; + +#define UDPMGMT_SIGNATURE "CTPIPEAB" + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 + + + +/* UDP/IP packet (for UDP management) layout */ + +typedef struct { + unsigned char reserved[2] PACKED; + unsigned short ip_length PACKED; + unsigned char reserved2[4] PACKED; + unsigned char ip_ttl PACKED; + unsigned char ip_protocol PACKED; + unsigned short ip_checksum PACKED; + unsigned long ip_src_address PACKED; + unsigned long ip_dst_address PACKED; + unsigned short udp_src_port PACKED; + unsigned short udp_dst_port PACKED; + unsigned short udp_length PACKED; + unsigned short udp_checksum PACKED; + udp_management_packet_t um_packet PACKED; +} ip_packet_t; + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 + + +typedef struct { + unsigned char status PACKED; + unsigned char data_avail PACKED; + unsigned short real_length PACKED; + unsigned short time_stamp PACKED; + unsigned char data[1] PACKED; +} frame_data_t; + + +#ifdef _MSC_ +# pragma pack() +#endif +#endif /* _SDLA_CHDLC_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_fr.h linux.ac/include/linux/sdla_fr.h --- linux.vanilla/include/linux/sdla_fr.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sdla_fr.h Thu Mar 11 12:58:43 1999 @@ -415,6 +415,37 @@ #define FR_ISF_LVE 2 /* issue Link Verification Enquiry */ #define FR_ISF_FSE 3 /* issue Full Status Enquiry */ +/*---------------------------------------------------------------------------- + * Frame Relay ARP Header -- Used for Dynamic route creation with InvARP + */ + +typedef struct arphdr_fr + { + unsigned short ar_hrd PACKED; /* format of hardware addr */ + unsigned short ar_pro PACKED; /* format of protocol addr */ + unsigned char ar_hln PACKED; /* length of hardware addr */ + unsigned char ar_pln PACKED; /* length of protocol addr */ + unsigned short ar_op PACKED; /* ARP opcode */ + unsigned short ar_sha PACKED; /* Sender DLCI addr 2 bytes */ + unsigned long ar_sip PACKED; /* Sender IP addr 4 bytes */ + unsigned short ar_tha PACKED; /* Target DLCI addr 2 bytes */ + unsigned long ar_tip PACKED; /* Target IP addr 4 bytes */ + } arphdr_fr_t; + +/*---------------------------------------------------------------------------- + * Frame Relay RFC 1490 SNAP Header -- Used to check for ARP packets + */ +typedef struct arphdr_1490 + { + unsigned char control PACKED; /* UI, etc... */ + unsigned char pad PACKED; /* Pad */ + unsigned char NLPID PACKED; /* SNAP */ + unsigned char OUI[3] PACKED; /* Ethertype, etc... */ + unsigned short PID PACKED; /* ARP, IP, etc... */ + } arphdr_1490_t; + + + #ifdef _MSC_ # pragma pack() #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_hdlc.h linux.ac/include/linux/sdla_hdlc.h --- linux.vanilla/include/linux/sdla_hdlc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/sdla_hdlc.h Thu Mar 11 12:59:49 1999 @@ -0,0 +1,762 @@ +/***************************************************************************** +* sdla_hdlc.h HDLC API header file. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Oct 14, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + + +/* Status flag for determining whether to perform a check on socket receive * queue. + */ +#define NO_SK_RX_CHECK 0x00 +#define TOP_CHECK_SK_RX_Q 0x01 +#define BTM_CHECK_SK_RX_Q 0x02 + + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + + + + + +/* + * Constants defining the shared memory control block (mailbox) + */ + +/* the base address of the HDLC mailbox structure on the adapter */ +#define HDLC_MB_STRUCT_OFFSET 0x0000 +/* the number of reserved bytes in the mailbox header area */ +#define NUMBER_HDLC_MB_RES_BYTES 0x0A +/* the size of the actual mailbox data area */ +#define SIZEOF_HDLC_MB_DATA_BFR 1008 +#define MAX_NO_DATA_BYTES_IN_I_FRAME 4099 /* maximum length of the HDLC I-field */ + +/* Just the header, excluding the data area */ +#define MAILBOX_SIZE 30 +/* + * the control block mailbox structure for API purposes. + */ +typedef struct { + + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the command code */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char PF_bit PACKED; /* the HDLC P/F bit */ + char MB_reserved[NUMBER_HDLC_MB_RES_BYTES] PACKED; /* for later use */ + char data[MAX_NO_DATA_BYTES_IN_I_FRAME] PACKED; /* the data area */ + +} HDLC_MAILBOX_STRUCT; + + +/* The following structure definition is for driver use ONLY */ + +typedef struct { + + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the command code */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char PF_bit PACKED; /* the HDLC P/F bit */ + char MB_reserved[NUMBER_HDLC_MB_RES_BYTES] PACKED; /* for later use */ + char data[SIZEOF_HDLC_MB_DATA_BFR] PACKED; /* the data area */ + +} TRUE_HDLC_MAILBOX_STRUCT; + + +typedef struct { + pid_t pid_num PACKED; + HDLC_MAILBOX_STRUCT cmdarea PACKED; + +} CMDBLOCK_STRUCT; + +/* + * Interface commands + */ + +/* + * global interface commands + */ + +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace configuration */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace configuration */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ +#define FT1_MONITOR_STATUS_CTRL 0x1E /* set the status of the S508/FT1 monitoring */ +#define SET_FT1_MODE 0x1F /* set the operational mode of the S508/FT1 module */ + +/* + * HDLC-level interface commands + */ + +#define READ_HDLC_CODE_VERSION 0x20 /* read the HDLC code version */ +#define READ_HDLC_EXCEPTION_CONDITION 0x21 /* read an HDLC exception condition from the adapter */ +#define SET_HDLC_CONFIGURATION 0x22 /* set the HDLC operational configuration */ +#define READ_HDLC_CONFIGURATION 0x23 /* read the current HDLC operational configuration */ +#define ENABLE_HDLC_COMMUNICATIONS 0x24 /* enable HDLC communications */ +#define DISABLE_HDLC_COMMUNICATIONS 0x25 /* disable HDLC communications */ +#define HDLC_CONNECT 0x26 /* enter the HDLC ABM state */ +#define HDLC_DISCONNECT 0x27 /* enter the HDLC disconnected state */ +#define READ_HDLC_LINK_STATUS 0x28 /* read the HDLC link status */ +#define READ_HDLC_OPERATIONAL_STATS 0x29 /* retrieve the HDLC operational statistics */ +#define FLUSH_HDLC_OPERATIONAL_STATS 0x2A /* flush the HDLC operational statistics */ +#define SET_HDLC_BUSY_CONDITION 0x2B /* force the HDLC code into a busy condition */ +#define SEND_UI_FRAME 0x2C /* transmit an Unnumbered Information frame */ +#define SET_HDLC_INTERRUPT_TRIGGERS 0x30 /* set the HDLC application interrupt triggers */ +#define READ_HDLC_INTERRUPT_TRIGGERS 0x31 /* read the HDLC application interrupt trigger configuration */ + + +#define HDLC_SEND_NO_WAIT 0xE0 /* send I frames : Poll */ +#define HDLC_SEND_WAIT 0xE1 /* send I frames : Interrupt*/ +#define HDLC_READ_NO_WAIT 0xE2 /* receive I frames : Poll */ +#define HDLC_READ_WAIT 0xE3 /* receive I frames : Interrupt*/ +#define HDLC_READ_TRACE_DATA 0xE4 /* receive Trace data */ + + +/* + * Return codes from interface commands + */ + +#define OK 0x00 /* the interface command was successfull */ + +/* + * return codes from global interface commands + */ + +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no HDLC exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ +#define S508_FT1_ADPTR_NOT_PRESENT 0x0E /* the S508/FT1 adapter is not present */ +#define S508_FT1_MODE_SELECTION_BUSY 0x0F /* the S508/FT1 adapter is busy selecting the operational mode */ + +/* + * return codes from command READ_GLOBAL_EXCEPTION_CONDITION + */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ + +/* + * return codes from HDLC-level interface commands + */ +#define NO_HDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no HDLC exception condition to report */ +#define HDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define HDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define DISABLE_HDLC_COMMS_BEFORE_CFG 0x21 /* HDLC communications must be disabled before setting the configuration */ +#define ENABLE_HDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the HDLC_CONNECT conmmand */ +#define HDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_HDLC_CONFIGURATION before enabling comms */ +#define SET_TRACE_CFG 0x22 /* perform a SET_TRACE_CONFIGURATION */ +#define LGTH_HDLC_CFG_DATA_INVALID 0x22 /* the length of the passed HDLC configuration data is invalid */ +#define LGTH_HDLC_INT_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define HDLC_LINK_NOT_IN_ABM 0x22 /* the HDLC link is not currently in the ABM */ +#define HDLC_LINK_CURRENTLY_IN_ABM 0x22 /* the HDLC link is currently in the ABM */ +#define NO_TX_BFRS_AVAILABLE 0x23 /* no buffers available for transmission */ +#define INVALID_HDLC_APP_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_HDLC_INTERRUPT_TRIGGERS */ +#define INVALID_HDLC_CFG_DATA 0x23 /* the passed HDLC configuration data is invalid */ +#define UI_FRM_TX_BFR_IN_USE 0x23 /* the buffer used for UI frame transmission is currently in use */ +#define T3_LESS_THAN_T1 0x24 /* the configured T3 value is less than T1 */ +#define HDLC_IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define UI_FRM_TX_LGTH_INVALID 0x24 /* the length of the UI frame to be transmitted is invalid */ +#define T4_LESS_THAN_T1 0x25 /* the configured T4 value is less than T1 */ +#define BFR_LGTH_EXCESSIVE_FOR_BFR_CFG 0x26 /* the configured buffer length is excessive for the configuration */ +#define INVALID_HDLC_COMMAND 0x4F /* the defined HDLC interface command is invalid */ + +/* + * return codes from command READ_HDLC_EXCEPTION_CONDITION + */ +#define EXCEP_SABM_RX 0x30 /* a SABM frame was recvd in the ABM */ +#define EXCEP_DISC_RX 0x31 /* a DISC frame was recvd in the ABM */ +#define EXCEP_DM_RX 0x32 /* a DM frame was recvd in the ABM */ +#define EXCEP_UA_RX 0x33 /* a UA frame was recvd in the ABM */ +#define EXCEP_FRMR_RX 0x34 /* a FRMR frame was recvd in the ABM */ +#define EXCEP_UI_RX 0x37 /* a UI frame was received */ +#define EXCEP_SABM_TX_DM_RX 0x38 /* a SABM frame was transmitted due to the reception of a DM */ +#define EXCEP_SABM_TX_UA_RX 0x39 /* a SABM frame was transmitted due to the reception of a UA */ +/* while the link was in the ABM */ +#define EXCEP_SABM_TX_FRMR_RX 0x3A /* a SABM frame was transmitted due to the reception of a FRMR */ +/* while the link was in the ABM */ +#define EXCEP_SABM_TX_UNSOLIC_RESP_RX 0x3B /* a SABM frame was transmitted due to the reception of an */ +/* unsolicited response with the F bit set */ +#define EXCEP_SABM_TX_N2_EXPIRY 0x3C /* a SABM frame was transmitted due to an N2 count expiry */ +#define EXCEP_FRMR_TX 0x3F /* a FRMR frame was transmitted */ +#define EXCEP_SABM_RETRY_LIM_EXCEEDED 0x40 /* the SABM retry limit was exceeded */ +#define EXCEP_DISC_RETRY_LIM_EXCEEDED 0x41 /* the DISC retry limit was exceeded */ +#define EXCEP_FRMR_RETRY_LIM_EXCEEDED 0x42 /* the FRMR retry limit was exceeded */ +#define EXCEP_T3_TIMEOUT_EXCEEDED 0x45 /* the T3 timeout limit has been exceeded */ + +#define NO_TRACE_BUFFERS 0x60 /* No trace buffers are avail */ +#define TRACE_BUFFER_TOO_BIG 0x61 +#define TRACE_BUFFER_NOT_STORED 0x62 + +/* + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION + * commands + */ + +/* + * the global configuration structure + */ +typedef struct { + + unsigned short adapter_config_options; /* configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* operating frequency*/ + +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ + timeout */ + + + +/* + * Constants for the READ_GLOBAL_STATISTICS command + */ + +/* + * the global statistics structure + */ +typedef struct { + + unsigned short app_IRQ_timeout_count; + +} GLOBAL_STATS_STRUCT; + + + +/* + * Constants for the READ_COMMS_ERROR_STATS command + */ + +/* + * the communications error statistics structure + */ + +typedef struct { + + unsigned char Rx_overrun_err_count; /* receiver overrun error count */ + unsigned char CRC_err_count; /* receiver CRC error count */ + unsigned char Rx_abort_count; /* abort frames received count */ + unsigned char Rx_dis_pri_bfrs_full_count; /* receiver disabled count */ + unsigned char comms_err_stat_reserved_1; /* reserved for later use */ + unsigned char comms_err_stat_reserved_2; /* reserved for later use */ + unsigned char missed_Tx_und_int_count;/* missed tx underrun intr count*/ + unsigned char comms_err_stat_reserved_3; /* reserved for later use */ + unsigned char DCD_state_change_count; /* DCD state change count */ + unsigned char CTS_state_change_count; /* CTS state change count */ + +} COMMS_ERROR_STATS_STRUCT; + + + + +/* + * Constants used for line tracing + */ + +/* + * the trace configuration structure (SET_TRACE_CONFIGURATION/ + * READ_TRACE_CONFIGURATION commands) + */ + +typedef struct { + + unsigned char trace_config PACKED; /* trace configuration */ + unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */ + unsigned long ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */ + +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_DELAY_MODE 0x04 /* operate the trace in the + delay mode */ +#define TRACE_I_FRAMES 0x08 /* trace I-frames */ +#define TRACE_SUPERVISORY_FRAMES 0x10 /* trace Supervisory frames */ +#define TRACE_UNNUMBERED_FRAMES 0x20 /* trace Unnumbered frames */ + +/* + * the line trace status element configuration structure + */ + +typedef struct { + + unsigned short number_trace_status_elements PACKED; /* number of line trace elements */ + unsigned long base_addr_trace_status_elements PACKED;/* base address of the trace element list */ + unsigned long next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */ + unsigned long base_addr_trace_buffer PACKED; /* base address of the trace data buffer */ + unsigned long end_addr_trace_buffer PACKED; /* end address of the trace data buffer */ + +} TRACE_STATUS_EL_CFG_STRUCT; + +/* + * the line trace status element structure + */ + +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short trace_length PACKED; /* trace length */ + unsigned char trace_type PACKED; /* trace type */ + unsigned short trace_time_stamp PACKED;/* time stamp */ + unsigned short trace_reserved_1 PACKED;/* reserved for later use */ + unsigned long trace_reserved_2 PACKED; /* reserved for later use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the trace data buffer */ + +} TRACE_STATUS_ELEMENT_STRUCT; + +/* + * the line trace statistics structure + */ + +typedef struct { + + unsigned long frames_traced_count; /* number of frames traced*/ + unsigned long trc_frms_not_recorded_count; /* number of trace frames + discarded */ + unsigned short trc_disabled_internally_count; /* number of times the + trace was disabled + internally */ + +} LINE_TRACE_STATS_STRUCT; + + + +/* + * Constants for the SET_HDLC_CONFIGURATION command + */ + +/* + * the HDLC configuration structure + */ + +typedef struct { + + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ + unsigned short HDLC_API_options PACKED; /* HDLC API options */ + unsigned short HDLC_protocol_options PACKED; /* HDLC protocol options */ + unsigned short HDLC_buffer_config_options PACKED; /* HDLC buffer configuration options */ + unsigned short HDLC_statistics_options PACKED; /* HDLC operational statistics options */ + unsigned short configured_as_DTE PACKED; /* DTE or DCE configuration */ + unsigned short max_HDLC_I_field_length PACKED; /* the maximum length of the HDLC I-field */ + unsigned short HDLC_I_frame_window PACKED; /* k - the I-frame window (maximum number of outstanding I-frames) */ + unsigned short HDLC_T1_timer PACKED; /* the HDLC T1 timer */ + unsigned short HDLC_T2_timer PACKED; /* the HDLC T2 timer */ + unsigned short HDLC_T3_timer PACKED; /* the HDLC T3 timer */ + unsigned short HDLC_T4_timer PACKED; /* the HDLC T4 timer */ + unsigned short HDLC_N2_counter PACKED; /* the HDLC N2 counter */ + unsigned long ptr_shared_mem_info_struct PACKED;/* a pointer to the shared memory area information structure */ + unsigned long ptr_HDLC_Tx_stat_el_cfg_struct PACKED;/* a pointer to the transmit status element configuration structure */ + unsigned long ptr_HDLC_Rx_stat_el_cfg_struct PACKED;/* a pointer to the receive status element configuration structure */ + +} HDLC_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* use V.35 interface level */ +#define INTERFACE_LEVEL_RS232 0x0001 /* use RS-232 interface level */ + +/* settings for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + +/* ENABLE_HDLC_COMMUNICATIONS command */ + +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 /* don't report changes in modem status to the application */ +#define DISABLE_DCD_CTS_INTERRUPTS 0x0004 /* ignore DCD and CTS interrupts on the adapter */ + +/* bit settings for the 'HDLC_API_options' */ +#define PERMIT_HDLC_CONNECT_IN_ABM 0x0001 /* allow the use of the HDLC_CONNECT command while in the ABM */ + +/* bit settings for the 'HDLC_protocol_options' byte */ +#define MOD_8_SELECTED 0x0000 /* use modulo 8 operation */ +#define MOD_128_SELECTED 0x0001 /* use modulo 128 (extended) operation */ +#define AUTO_MODULO_DETECTION 0x0002 /* use automatic modulus detection */ +#define PASSIVE_LINK_SETUP 0x0004 /* no SABMs should be issued when setting up the link */ +#define ENTER_DISC_PHASE_AFTR_DISC_SNT 0x0008 /* enter the disconnnected phase after issuing a DISC command */ + +/* settings for the 'HDLC_buffer_config_options' */ +#define HDLC_I_FRM_RX_HYSTERESIS 0x000F /* the HDLC I-frame receive hysteresis */ +#define HDLC_I_FRM_BFRS_3rd_LVL_PROT 0x0010 /* the HDLC I-frame buffers are to be used by a 3rd level protocol */ + +/* settings for the 'HDLC_statistics_options' */ +#define HDLC_TX_I_FRM_BYTE_COUNT_STAT 0x0001 /* compute the number of I-frame bytes transmitted */ +#define HDLC_RX_I_FRM_BYTE_COUNT_STAT 0x0002 /* compute the number of I-frame bytes received */ +#define HDLC_TX_THROUGHPUT_STAT 0x0004 /* compute the I-frame transmit throughput */ +#define HDLC_RX_THROUGHPUT_STAT 0x0008 /* compute the I-frame receive throughput */ + +/* permitted minimum and maximum values for setting the HDLC configuration */ +#define MAX_BAUD_RATE 2666000 /* maximum baud rate */ +#define MIN_NO_DATA_BYTES_IN_I_FRAME 300 /* minimum length of the configured HDLC I-field */ +#define MIN_PERMITTED_k_VALUE 0 /* minimum I-frame window size */ +#define MAX_PERMITTED_k_VALUE 127 /* maximum I-frame window size */ +#define MIN_PERMITTED_T1_VALUE 1 /* minimum T1 */ +#define MAX_PERMITTED_T1_VALUE 60000 /* maximum T1 */ +#define MIN_PERMITTED_T2_VALUE 0 /* minimum T2 */ +#define MAX_PERMITTED_T2_VALUE 60000 /* maximum T2 */ +#define MIN_PERMITTED_T3_VALUE 0 /* minimum T3 */ +#define MAX_PERMITTED_T3_VALUE 60000 /* maximum T3 */ +#define MIN_PERMITTED_T4_VALUE 0 /* minimum T4 */ +#define MAX_PERMITTED_T4_VALUE 60000 /* maximum T4 */ +#define MIN_PERMITTED_N2_VALUE 1 /* minimum N2 */ +#define MAX_PERMITTED_N2_VALUE 30 /* maximum N2 */ + + +/* + * Constants for the READ_HDLC_LINK_STATUS command + */ + +/* + * the HDLC status structure + */ + +typedef struct { + + unsigned char HDLC_link_status; /* HDLC link status (disconnect/ABM) */ + unsigned char modulus_type; /* configured modulus type */ + unsigned char no_I_frms_for_app;/* number of I-frames available for the application */ + unsigned char receiver_status; /* receiver status (enabled/disabled) */ + unsigned char LAPB_state; /* internal LAPB state */ + unsigned char rotating_SUP_frm_count; /* count of Supervisory frames received */ + +} HDLC_LINK_STATUS_STRUCT; + +/* settings for the 'HDLC_link_status' variable */ +#define HDLC_LINK_DISCONNECTED 0x00 /* the HDLC link is disconnected */ +#define HDLC_LINK_IN_AB 0x01 /* the HDLC link is in the ABM (connected) */ + + + + +/* + * Constants for the READ_HDLC_OPERATIONAL_STATS command + */ + +/* + * the HDLC operational statistics structure + */ + +typedef struct { + + /* Information frame transmission statistics */ + unsigned long I_frames_Tx_ack_count; /* I-frames transmitted (and acknowledged) count */ + unsigned long I_bytes_Tx_ack_count; /* I-bytes transmitted (and acknowledged) count */ + unsigned long I_frm_Tx_throughput; /* I-frame transmit throughput */ + unsigned long no_ms_for_HDLC_Tx_thruput_comp;/* millisecond time used for Tx throughput computation */ + unsigned long I_frames_retransmitted_count; /* I-frames re-transmitted count */ + unsigned long I_bytes_retransmitted_count; /* I-bytes re-transmitted count */ + unsigned short I_frms_not_Tx_lgth_err_count; /* number of I-frames not transmitted (length error) */ + unsigned short Tx_I_frms_disc_st_chg_count; /* the number of I-frames discarded (change in the LAPB state) */ + unsigned long reserved_I_frm_Tx_stat; /* reserved for later use */ + + /* Information frame reception statistics */ + unsigned long I_frames_Rx_buffered_count; /* I-frames received (and buffered) count */ + unsigned long I_bytes_Rx_buffered_count; /* I-bytes received (and buffered) count */ + unsigned long I_frm_Rx_throughput; /* I-frame receive throughput */ + unsigned long no_ms_for_HDLC_Rx_thruput_comp;/* millisecond time used for Rx throughput computation */ + unsigned short I_frms_Rx_too_long_count; /* I-frames received of excessive length count */ + unsigned short I_frms_Rx_seq_err_count; /* out of sequence I-frames received count */ + unsigned long reserved_I_frm_Rx_stat1; /* reserved for later use */ + unsigned long reserved_I_frm_Rx_stat2; /* reserved for later use */ + unsigned long reserved_I_frm_Rx_stat3; /* reserved for later use */ + + /* Supervisory frame transmission/reception statistics */ + unsigned short RR_Tx_count; /* RR frames transmitted count */ + unsigned short RR_Rx_count; /* RR frames received count */ + unsigned short RNR_Tx_count; /* RNR frames transmitted count */ + unsigned short RNR_Rx_count; /* RNR frames received count */ + unsigned short REJ_Tx_count; /* REJ frames transmitted count */ + unsigned short REJ_Rx_count; /* REJ frames received count */ + + /* Unnumbered frame transmission/reception statistics */ + unsigned short SABM_Tx_count; /* SABM frames transmitted count */ + unsigned short SABM_Rx_count; /* SABM frames received count */ + unsigned short SABME_Tx_count; /* SABME frames transmitted count */ + unsigned short SABME_Rx_count; /* SABME frames received count */ + unsigned short DISC_Tx_count; /* DISC frames transmitted count */ + unsigned short DISC_Rx_count; /* DISC frames received count */ + unsigned short DM_Tx_count; /* DM frames transmitted count */ + unsigned short DM_Rx_count; /* DM frames received count */ + unsigned short UA_Tx_count; /* UA frames transmitted count */ + unsigned short UA_Rx_count; /* UA frames received count */ + unsigned short FRMR_Tx_count; /* FRMR frames transmitted count */ + unsigned short FRMR_Rx_count; /* FRMR frames received count */ + unsigned short UI_Tx_count; /* UI frames transmitted count */ + unsigned short UI_Rx_buffered_count;/* UI frames received and buffered count */ + unsigned long reserved_Sup_Unnum_stat1; /* reserved for later use */ + unsigned long reserved_Sup_Unnum_stat2; /* reserved for later use */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_shorter_32_bits_count; /* frames received of less than 32 bits in length count */ + unsigned short Rx_I_fld_Sup_Unnum_frm_count; /* Supervisory/Unnumbered frames received with */ + + /* illegal I-fields count */ + unsigned short Rx_frms_invld_HDLC_addr_count;/* frames received with an invalid HDLC address count */ + unsigned short Rx_invld_HDLC_ctrl_fld_count; /* frames received of an invalid/unsupported */ + /* control field count */ + unsigned long reserved_frm_format_err1; /* reserved for later use */ + unsigned long reserved_frm_format_err2; /* reserved for later use */ + + /* FRMR/UI reception error statistics */ + unsigned short Rx_FRMR_frms_discard_count;/* incomming FRMR frames discarded count */ + unsigned short Rx_UI_frms_discard_count;/* incomming UI frames discarded count */ + unsigned short UI_frms_Rx_invld_lgth_count;/* UI frames of invalid length received count */ + unsigned short reserved_Rx_err_stat1; /* reserved for later use */ + unsigned long reserved_Rx_err_stat2; /* reserved for later use */ + unsigned long reserved_Rx_err_stat3; /* reserved for later use */ + + /* HDLC timeout/retry statistics */ + unsigned short T1_timeout_count; /* T1 timeouts count */ + unsigned short T3_timeout_count; /* T3 timeouts count */ + unsigned short T4_timeout_count; /* T4 timeouts count */ + unsigned short reserved_timeout_stat; /* reserved for later use */ + unsigned short N2_threshold_reached_count;/* N2 threshold reached count */ + unsigned short reserved_threshold_stat; /* reserved for later use */ + unsigned long To_retry_reserved_stat; /* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1; /* reserved for later use */ + unsigned long reserved_misc_stat2; /* reserved for later use */ + unsigned long reserved_misc_stat3; /* reserved for later use */ + unsigned long reserved_misc_stat4; /* reserved for later use */ + +} HDLC_OPERATIONAL_STATS_STRUCT; + + + + +/* + * Constants for the SEND_UI_FRAME command + */ + +#define MAX_LENGTH_UI_DATA 512 /* maximum UI frame data length */ + +/* + * the structure used for UI frame transmission/reception + */ + +typedef struct { + unsigned char HDLC_address; /* HDLC address in the frame */ + unsigned char UI_reserved; /* reserved for internal use */ + char data[MAX_LENGTH_UI_DATA]; /* UI data area */ +} UI_FRAME_STRUCT; + + + + +/* + * Constants for using application interrupts + */ + +/* + * the structure used for the SET_HDLC_INTERRUPT_TRIGGERS/ + * READ_HDLC_INTERRUPT_TRIGGERS command + */ + +typedef struct { + + unsigned char HDLC_interrupt_triggers; /* HDLC interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + +} HDLC_INT_TRIGGERS_STRUCT; + +/* 'HDLC_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on I-frame reception */ +#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an I-frame may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_HDLC_EXCEP_COND 0x20 /* interrupt on an HDLC exception condition */ +#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ + + +/* + * the HDLC interrupt information structure + */ +typedef struct { + + unsigned char interrupt_type PACKED; /* type of interrupt triggered */ + unsigned char interrupt_permission PACKED; /* interrupt permission mask */ + unsigned char int_info_reserved[14] PACKED; /* reserved */ + +} HDLC_INTERRUPT_INFO_STRUCT; + +/* interrupt types indicated at 'interrupt_type' byte of the + HDLC_INTERRUPT_INFO_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /*receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define HDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an HDLC exception condition interrupt is pending */ +#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ + + + +/* + * Constants for Information frame transmission + */ + +/* + * the I-frame transmit status element configuration structure + */ + +typedef struct { + + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ + +} HDLC_TX_STATUS_EL_CFG_STRUCT; + +/* + * the I-frame transmit status element structure + */ +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short I_frame_length PACKED; /* length of the frame*/ + unsigned char P_bit PACKED; /* P-bit setting in the frame */ + unsigned long reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ + +} HDLC_I_FRM_TX_STATUS_EL_STRUCT; + + + +/* + * Constants for Information frame reception + */ + +/* + * the I-frame receive status element configuration structure + */ + +typedef struct { + + unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */ +} HDLC_RX_STATUS_EL_CFG_STRUCT; + +/* + * the I-frame receive status element structure + */ +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short I_frame_length PACKED; /*length of the recvd frame */ + unsigned char P_bit PACKED; /* P-bit setting in the frame */ + unsigned long reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ + +} HDLC_I_FRM_RX_STATUS_EL_STRUCT; + + + +/* + * Constants defining the shared memory information area + */ + + + +/* + * the global information structure + */ + +typedef struct { + + unsigned char global_status PACKED; /* global status */ + unsigned char modem_status PACKED;/* current modem status*/ + unsigned char global_excep_conditions PACKED; /* global exception conditions */ + unsigned char glob_info_reserved[5] PACKED; /* reserved */ + unsigned char code_name[4] PACKED; /* code name */ + unsigned char code_version[4] PACKED; /* code version */ + +} GLOBAL_INFORMATION_STRUCT; + + +/* + * the S508/FT1 information structure + */ + +typedef struct { + + unsigned char parallel_port_A_input PACKED; /* input - parallel port A */ + unsigned char parallel_port_B_input PACKED; /* input - parallel port B */ + unsigned char FT1_info_reserved[14] PACKED; /* reserved */ + +} FT1_INFORMATION_STRUCT; + +/* + * the HDLC information structure + */ + +typedef struct { + + unsigned char HDLC_status PACKED; /* HDLC status */ + unsigned char HDLC_excep_frms_Rx PACKED; /* HDLC exception conditions - received frames */ + unsigned char HDLC_excep_frms_Tx PACKED; /* HDLC exception conditions - transmitted frames */ + unsigned char HDLC_excep_miscellaneous PACKED; /* HDLC exception conditions - miscellaneous */ + unsigned char rotating_SUP_frm_count PACKED; /* rotating Supervisory frame count */ + unsigned char LAPB_status PACKED; /* internal LAPB status */ + unsigned char internal_HDLC_status PACKED; /* internal HDLC status */ + unsigned char HDLC_info_reserved[9] PACKED; /* reserved */ + +} HDLC_INFORMATION_STRUCT; + + + + +/* + * the HDLC shared memory area information structure + */ + +typedef struct { + + GLOBAL_INFORMATION_STRUCT global_info PACKED; /* the global information structure */ + FT1_INFORMATION_STRUCT FT1_info PACKED; /* the S508/FT1 information structure */ + HDLC_INFORMATION_STRUCT HDLC_info PACKED; /* the HDLC information structure */ + HDLC_INTERRUPT_INFO_STRUCT HDLC_interrupt_info PACKED; /* the HDLC interrupt information structure */ + +} HDLC_SHARED_MEMORY_INFO_STRUCT; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_ppp.h linux.ac/include/linux/sdla_ppp.h --- linux.vanilla/include/linux/sdla_ppp.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sdla_ppp.h Thu Mar 11 16:36:15 1999 @@ -48,7 +48,7 @@ #define PPP502_BUF_OFFS 0x0010 /* buffer info block offset */ #define PPP508_MB_VECT 0xE000 /* mailbox window vector */ -#define PPP508_MB_OFFS 0 /* mailbox offset */ +#define PPP508_MB_OFFS 0 /* mailbox offset */ #define PPP508_FLG_OFFS 0x1000 /* status flags offset */ #define PPP508_BUF_OFFS 0x1100 /* buffer info block offset */ @@ -224,8 +224,10 @@ unsigned short auth_retry PACKED; /* 1B: max. retry */ unsigned char auth_options PACKED; /* 1D: authentication opt. */ unsigned char ip_options PACKED; /* 1E: IP options */ - unsigned char ip_local[4] PACKED; /* 1F: local IP address */ - unsigned char ip_remote[4] PACKED; /* 23: remote IP address */ + unsigned long ip_local PACKED; /* 1F: local IP address */ + unsigned long ip_remote PACKED; /* 23: remote IP address */ +//DF unsigned char ip_local[4] PACKED; /* 1F: local IP address */ +//DF unsigned char ip_remote[4] PACKED; /* 23: remote IP address */ unsigned char ipx_options PACKED; /* 27: IPX options */ unsigned char ipx_netno[4] PACKED; /* 28: IPX net number */ unsigned char ipx_local[6] PACKED; /* 2C: local IPX node number*/ @@ -255,8 +257,10 @@ unsigned short auth_retry PACKED; /* 1E: max. retry */ unsigned char auth_options PACKED; /* 20: authentication opt. */ unsigned char ip_options PACKED; /* 21: IP options */ - unsigned char ip_local[4] PACKED; /* 22: local IP address */ - unsigned char ip_remote[4] PACKED; /* 26: remote IP address */ + unsigned long ip_local PACKED; /* 22: local IP address */ + unsigned long ip_remote PACKED; /* 26: remote IP address */ +//DF unsigned char ip_local[4] PACKED; /* 22: local IP address */ +//DF unsigned char ip_remote[4] PACKED; /* 26: remote IP address */ unsigned char ipx_options PACKED; /* 2A: IPX options */ unsigned char ipx_netno[4] PACKED; /* 2B: IPX net number */ unsigned char ipx_local[6] PACKED; /* 2F: local IPX node number*/ @@ -264,6 +268,25 @@ unsigned char ipx_router[48] PACKED; /* 3B: IPX router name*/ unsigned long alt_cpu_clock PACKED; /* 6B: */ } ppp508_conf_t; + +/*---------------------------------------------------------------------------- + * S508 Adapter Read Connection Information Block + * Returned by the PPP_GET_CONNECTION_INFO command + */ +typedef struct ppp508_connect_info +{ + unsigned short mru PACKED; /* 00-01 Remote Max Rec' Unit */ + unsigned char ip_options PACKED; /* 02: Negotiated ip options */ + unsigned long ip_local PACKED; /* 03-06: local IP address */ + unsigned long ip_remote PACKED; /* 07-0A: remote IP address */ + unsigned char ipx_options PACKED; /* 0B: Negotiated ipx options */ + unsigned char ipx_netno[4] PACKED; /* 0C-0F: IPX net number */ + unsigned char ipx_local[6] PACKED; /* 10-1F: local IPX node # */ + unsigned char ipx_remote[6] PACKED; /* 16-1B: remote IPX node # */ + unsigned char ipx_router[48] PACKED; /* 1C-4B: IPX router name */ + unsigned char auth_status PACKED; /* 4C: Authentication Status */ + unsigned char inbd_auth_peerID[1] PACKED; /* 4D: variable length inbound authenticated peer ID */ +} ppp508_connect_info_t; /* 'line_speed' field */ #define PPP_BITRATE_1200 0x01 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_x25.h linux.ac/include/linux/sdla_x25.h --- linux.vanilla/include/linux/sdla_x25.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sdla_x25.h Thu Mar 11 12:58:43 1999 @@ -18,7 +18,7 @@ /*---------------------------------------------------------------------------- * Notes: * ------ - * 1. All structures defined in this file are byte-aligned. To ensure + * 1. All structures defined in this file are byte-alined. To ensure * portability of this code between different platforms and compilers, one * of the following defines must be defined before including this file: * @@ -104,7 +104,7 @@ #define X25_READ 0x22 /* read X.25 packet */ #define X25_WRITE 0x23 /* send X.25 packet */ #define X25_PLACE_CALL 0x30 /* place a call on SVC */ -#define X25_ACCEPT_CALL 0x31 /* accept incoming call */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ #define X25_CLEAR_CALL 0x32 /* clear call */ #define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ #define X25_RESET 0x34 /* send reset request packet */ @@ -116,14 +116,14 @@ #define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ #define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ #define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ -#define X25_INCOMING_CALL_CTL 0x41 /* select incoming call options */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ #define X25_CONFIGURE_PVC 0x42 /* configure PVC */ #define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ #define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ #define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ #define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ #define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ -#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowledged */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ #define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ #define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ #define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ @@ -139,7 +139,7 @@ #define X25RES_LINK_CLOSED 0x03 #define X25RES_INVAL_LENGTH 0x04 #define X25RES_INVAL_CMD 0x05 -#define X25RES_UNNUMBERED_FRAME 0x06 /* unnumbered frame received */ +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ #define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ #define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ #define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ @@ -153,13 +153,13 @@ #define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ #define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ #define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ -#define X25RES_INVAL_CALL_ARG 0x3A /* erroneous call arguments */ -#define X25RES_INVAL_CALL_DATA 0x3B /* erroneous call user data */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ #define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ -#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occurred */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ #define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ #define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ -/*----- Command-dependent results -----*/ +/*----- Command-dependant results -----*/ #define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ #define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ #define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ @@ -167,7 +167,7 @@ #define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ #define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ #define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ -#define X25RES_INVAL_PARAM 0x31 /* INCOMING_CALL_CTL */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ #define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ /* @@ -239,7 +239,7 @@ typedef struct X25Status { unsigned short pvc_map PACKED; /* 00h: PVC map */ - unsigned short icc_map PACKED; /* 02h: Incoming Chan. map */ + unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ @@ -256,7 +256,7 @@ #define X25_RX_INTR 0x01 /* receive interrupt */ #define X25_TX_INTR 0x02 /* transmit interrupt */ #define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ -#define X25_EVENT_INTR 0x10 /* asynchronous event encountered */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ #define X25_CMD_INTR 0x08 /* interface command complete */ /* @@ -390,8 +390,8 @@ unsigned short pktMTU PACKED; /* 0Fh: */ unsigned short loPVC PACKED; /* 11h: */ unsigned short hiPVC PACKED; /* 13h: */ - unsigned short loIncomingSVC PACKED; /* 15h: */ - unsigned short hiIncomingSVC PACKED; /* 17h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ unsigned short loTwoWaySVC PACKED; /* 19h: */ unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ unsigned short loOutgoingSVC PACKED; /* 1Dh: */ @@ -421,8 +421,8 @@ { unsigned short loPVC PACKED; /* 00h: lowest PVC number */ unsigned short hiPVC PACKED; /* 02h: highest PVC number */ - unsigned short loIncomingSVC PACKED; /* 04h: lowest incoming SVC */ - unsigned short hiIncomingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ @@ -499,7 +499,7 @@ /* * Defines for the 'type' field. */ -#define X25LOG_INCOMING 0x00 +#define X25LOG_INCOMMING 0x00 #define X25LOG_APPLICATION 0x01 #define X25LOG_AUTOMATIC 0x02 #define X25LOG_ERROR 0x04 @@ -568,7 +568,7 @@ #define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ #define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ #define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ -#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmission error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ #define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ /***************************************************************************** @@ -582,7 +582,7 @@ unsigned char data[0] PACKED; } THDLCFrame; -typedef struct X25Pkt /*----- X.25 Packet Format ----------*/ +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ { unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdlasfm.h linux.ac/include/linux/sdlasfm.h --- linux.vanilla/include/linux/sdlasfm.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sdlasfm.h Thu Mar 11 12:58:43 1999 @@ -53,12 +53,14 @@ #define SFID_BSC502 2200 #define SFID_SDLC502 3200 #define SFID_HDLC502 4200 +#define SFID_HDLC508 4800 #define SFID_X25_502 5200 #define SFID_X25_508 5800 #define SFID_FR502 6200 #define SFID_FR508 6800 #define SFID_PPP502 7200 #define SFID_PPP508 7800 +#define SFID_CHDLC508 1400 /****** Data Types **********************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/auth.h linux.ac/include/linux/sunrpc/auth.h --- linux.vanilla/include/linux/sunrpc/auth.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sunrpc/auth.h Wed Mar 24 13:00:20 1999 @@ -64,10 +64,10 @@ struct rpc_auth * (*create)(struct rpc_clnt *); void (*destroy)(struct rpc_auth *); - struct rpc_cred * (*crcreate)(struct rpc_task *); + struct rpc_cred * (*crcreate)(int); void (*crdestroy)(struct rpc_cred *); - int (*crmatch)(struct rpc_task *, struct rpc_cred*); + int (*crmatch)(struct rpc_cred *, int); u32 * (*crmarshal)(struct rpc_task *, u32 *, int); int (*crrefresh)(struct rpc_task *); u32 * (*crvalidate)(struct rpc_task *, u32 *); @@ -83,10 +83,12 @@ int rpcauth_unregister(struct rpc_authops *); struct rpc_auth * rpcauth_create(unsigned int, struct rpc_clnt *); void rpcauth_destroy(struct rpc_auth *); -struct rpc_cred * rpcauth_lookupcred(struct rpc_task *); +struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); +struct rpc_cred * rpcauth_bindcred(struct rpc_task *); void rpcauth_holdcred(struct rpc_task *); void rpcauth_releasecred(struct rpc_task *); -int rpcauth_matchcred(struct rpc_task *, struct rpc_cred *); +int rpcauth_matchcred(struct rpc_auth *, + struct rpc_cred *, int); u32 * rpcauth_marshcred(struct rpc_task *, u32 *); u32 * rpcauth_checkverf(struct rpc_task *, u32 *); int rpcauth_refreshcred(struct rpc_task *); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/clnt.h linux.ac/include/linux/sunrpc/clnt.h --- linux.vanilla/include/linux/sunrpc/clnt.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sunrpc/clnt.h Wed Mar 24 18:39:00 1999 @@ -46,7 +46,8 @@ cl_autobind : 1,/* use getport() */ cl_binding : 1,/* doing a getport() */ cl_oneshot : 1,/* dispose after use */ - cl_dead : 1;/* abandoned */ + cl_dead : 1,/* abandoned */ + cl_up : 1;/* server is up */ unsigned int cl_flags; /* misc client flags */ unsigned long cl_hardmax; /* max hard timeout */ @@ -97,7 +98,7 @@ #define rpcproc_name(clnt, proc) ((clnt)->cl_procinfo[proc].p_procname) #define rpcproc_count(clnt, proc) ((clnt)->cl_procinfo[proc].p_count) -#define RPC_CONGESTED(clnt) (RPCXPRT_CONGESTED((clnt)->cl_xprt)) +#define RPC_CONGESTED(clnt) ((clnt)->cl_up && RPCXPRT_CONGESTED((clnt)->cl_xprt)) #define RPC_PEERADDR(clnt) (&(clnt)->cl_xprt->addr) #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/sched.h linux.ac/include/linux/sunrpc/sched.h --- linux.vanilla/include/linux/sunrpc/sched.h Thu Dec 31 18:10:47 1998 +++ linux.ac/include/linux/sunrpc/sched.h Wed Mar 24 12:02:10 1999 @@ -11,6 +11,7 @@ #include #include +#include #include /* @@ -89,6 +90,7 @@ #define RPC_TASK_ROOTCREDS 0x0100 /* force root creds */ #define RPC_TASK_DYNAMIC 0x0200 /* task was kmalloc'ed */ #define RPC_TASK_KILLED 0x0400 /* task was killed */ +#define RPC_TASK_PRIORITY 0x0800 /* resched when waking up */ #define RPC_TASK_NFSWRITE 0x1000 /* an NFS writeback */ #define RPC_IS_RUNNING(t) ((t)->tk_flags & RPC_TASK_RUNNING) @@ -110,6 +112,7 @@ #endif }; +#define RPC_WAITQ_EMPTY(q) ((q)->task == NULL) #ifndef RPC_DEBUG # define RPC_INIT_WAITQ(name) ((struct rpc_wait_queue) { NULL }) #else @@ -128,8 +131,9 @@ void rpc_execute(struct rpc_task *); void rpc_run_child(struct rpc_task *parent, struct rpc_task *child, rpc_action action); -int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *); -void rpc_remove_wait_queue(struct rpc_task *); +int __rpc_add_wait_queue(struct rpc_wait_queue *, + struct rpc_task *); +void __rpc_remove_wait_queue(struct rpc_task *); void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, rpc_action action, rpc_action timer); void rpc_cond_wait(struct rpc_wait_queue *, struct rpc_task *, @@ -152,6 +156,21 @@ void rpc_show_tasks(void); #endif +extern __inline__ int +rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) +{ + if (task->tk_rpcwait != q) + return __rpc_add_wait_queue(q, task); + return 0; +} + +extern __inline__ void +rpc_remove_wait_queue(struct rpc_task *task) +{ + if (task->tk_rpcwait) + __rpc_remove_wait_queue(task); +} + extern __inline__ void * rpc_malloc(struct rpc_task *task, unsigned int size) { @@ -165,11 +184,18 @@ task->tk_action = NULL; } +extern __inline__ void +rpc_kill(struct rpc_task *task, int status) +{ + rpc_exit(task, status); + rpc_wake_up_task(task); +} + #ifdef RPC_DEBUG extern __inline__ char * rpc_qname(struct rpc_wait_queue *q) { - return q->name? q->name : "unknown"; + return q? (q->name? q->name : "unknown") : "none"; } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/types.h linux.ac/include/linux/sunrpc/types.h --- linux.vanilla/include/linux/sunrpc/types.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sunrpc/types.h Wed Mar 24 12:02:10 1999 @@ -58,6 +58,7 @@ } if (*q == item) *q = next; + item->prev = item->next = 0; } #define rpc_insert_list(q, i) \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/xdr.h linux.ac/include/linux/sunrpc/xdr.h --- linux.vanilla/include/linux/sunrpc/xdr.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/sunrpc/xdr.h Mon Feb 1 22:06:55 1999 @@ -1,7 +1,7 @@ /* * include/linux/sunrpc/xdr.h * - * Copyright (C) 1995, 1996 Olaf Kirch + * Copyright (C) 1995-1997 Olaf Kirch */ #ifndef _SUNRPC_XDR_H_ @@ -64,6 +64,25 @@ u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *); u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *); u32 * xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len); + +/* + * Decode 64bit quantities (NFSv3 support) + */ +static inline u32 * +xdr_encode_hyper(u32 *p, __u64 val) +{ + *p++ = htonl(val >> 32); + *p++ = htonl(val & 0xFFFFFFFF); + return p; +} + +static inline u32 * +xdr_decode_hyper(u32 *p, __u64 *valp) +{ + *valp = ((__u64) ntohl(*p++)) << 32; + *valp |= ntohl(*p++); + return p; +} /* * Adjust iovec to reflect end of xdr'ed data (RPC client XDR) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/xprt.h linux.ac/include/linux/sunrpc/xprt.h --- linux.vanilla/include/linux/sunrpc/xprt.h Sat Jan 9 21:50:50 1999 +++ linux.ac/include/linux/sunrpc/xprt.h Wed Mar 24 13:00:20 1999 @@ -17,7 +17,7 @@ /* * Maximum number of iov's we use. */ -#define MAX_IOVEC 8 +#define MAX_IOVEC 9 /* * The transport code maintains an estimate on the maximum number of out- @@ -178,6 +178,8 @@ void (*old_data_ready)(struct sock *, int); void (*old_state_change)(struct sock *); void (*old_write_space)(struct sock *); + + struct wait_queue * cong_wait; }; #define tcp_reclen tcp_recm.header[0] #define tcp_xid tcp_recm.header[1] diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sysv_fs.h linux.ac/include/linux/sysv_fs.h --- linux.vanilla/include/linux/sysv_fs.h Wed Mar 24 10:55:27 1999 +++ linux.ac/include/linux/sysv_fs.h Wed Mar 24 18:24:46 1999 @@ -2,7 +2,7 @@ #define _LINUX_SYSV_FS_H /* - * The SystemV/Coherent filesystem constants/structures/macros + * The SystemV/V7/Coherent filesystem constants/structures/macros */ @@ -61,7 +61,7 @@ typedef u32 sysv_zone_t; /* Among the blocks ... */ -/* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block. +/* Xenix FS, V7 FS, Coherent FS: block 0 is the boot block, block 1 the super-block. SystemV FS: block 0 contains both the boot sector and the super-block. */ /* The first inode zone is sb->sv_firstinodezone (1 or 2). */ @@ -103,6 +103,7 @@ }; + /* Xenix free list block on disk */ struct xenix_freelist_chunk { u16 fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */ @@ -188,6 +189,41 @@ u32 fl_free[SYSV_NICFREE] __packed2__; }; + +/* V7 super-block data on disk */ +#define V7_NICINOD 100 /* number of inode cache entries */ +#define V7_NICFREE 50 /* number of free block list chunk entries */ +struct v7_super_block { + u16 s_isize; /* index of first data zone */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + u16 s_nfree; /* number of free blocks in s_free, <= V7_NICFREE */ + u32 s_free[V7_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + u16 s_ninode; /* number of free inodes in s_inode, <= V7_NICINOD */ + sysv_ino_t s_inode[V7_NICINOD]; /* some free inodes */ + /* locks, not used by Linux or V7: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time __packed2__; /* time of last super block update */ + /* the following fields are not maintained by V7: */ + u32 s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + u16 s_m; /* interleave factor */ + u16 s_n; /* interleave factor */ + char s_fname[6]; /* file system name */ + char s_fpack[6]; /* file system pack name */ +}; + +/* V7 free list block on disk */ +struct v7_freelist_chunk { + u16 fl_nfree; /* number of free blocks in fl_free, <= V7_NICFREE] */ + u32 fl_free[V7_NICFREE] __packed2__; +}; + + /* Coherent super-block data on disk */ #define COH_NICINOD 100 /* number of inode cache entries */ #define COH_NICFREE 64 /* number of free block list chunk entries */ @@ -222,7 +258,7 @@ }; -/* SystemV/Coherent inode data on disk */ +/* SystemV/V7/Coherent inode data on disk */ struct sysv_inode { u16 i_mode; @@ -302,6 +338,7 @@ /* Admissible values for i_nlink: 0.._LINK_MAX */ #define XENIX_LINK_MAX 126 /* ?? */ #define SYSV_LINK_MAX 126 /* 127? 251? */ +#define V7_LINK_MAX 126 /* ?? */ #define COH_LINK_MAX 10000 /* max number of hard links to an inode */ /* The number of inodes per block is @@ -310,7 +347,7 @@ sb->sv_ind_per_block = block_size / sizeof(u32) */ -/* SystemV/Coherent directory entry on disk */ +/* SystemV/V7/Coherent directory entry on disk */ #define SYSV_NAMELEN 14 /* max size of name in struct sysv_dir_entry */ @@ -331,6 +368,7 @@ #define FSTYPE_SYSV4 2 #define FSTYPE_SYSV2 3 #define FSTYPE_COH 4 +#define FSTYPE_V7 5 #define SYSV_MAGIC_BASE 0x012FF7B3 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sysv_fs_i.h linux.ac/include/linux/sysv_fs_i.h --- linux.vanilla/include/linux/sysv_fs_i.h Sun Nov 8 15:06:48 1998 +++ linux.ac/include/linux/sysv_fs_i.h Mon Mar 1 00:18:47 1999 @@ -2,7 +2,7 @@ #define _SYSV_FS_I /* - * SystemV/Coherent FS inode data in memory + * SystemV/V7/Coherent FS inode data in memory */ struct sysv_inode_info { u32 i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sysv_fs_sb.h linux.ac/include/linux/sysv_fs_sb.h --- linux.vanilla/include/linux/sysv_fs_sb.h Sun Nov 8 15:06:48 1998 +++ linux.ac/include/linux/sysv_fs_sb.h Mon Mar 1 00:18:47 1999 @@ -2,8 +2,8 @@ #define _SYSV_FS_SB /* - * SystemV/Coherent super-block data in memory - * The SystemV/Coherent superblock contains dynamic data (it gets modified + * SystemV/V7/Coherent super-block data in memory + * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified * while the system is running). This is in contrast to the Minix and Berkeley * filesystems (where the superblock is never modified). This affects the * sync() operation: we must keep the superblock in a disk buffer and use this diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/wanpipe.h linux.ac/include/linux/wanpipe.h --- linux.vanilla/include/linux/wanpipe.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/wanpipe.h Wed Mar 24 18:32:58 1999 @@ -2,8 +2,7 @@ * wanpipe.h WANPIPE(tm) Multiprotocol WAN Link Driver. * User-level API definitions. * -* Author: Gene Kozin -* Jaspreet Singh +* Author: Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -12,6 +11,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Jun 26, 1998 David Fong Added 'ip_mode' in sdla_t.u.p for dynamic IP +* routing mode configuration +* Jun 12, 1998 David Fong Added Cisco HDLC union member in sdla_t +* Dec 08, 1997 Jaspreet Singh Added 'authenticator' in union of 'sdla_t' * Nov 26, 1997 Jaspreet Singh Added 'load_sharing' structure. Also added * 'devs_struct','dev_to_devtint_next' to 'sdla_t' * Nov 24, 1997 Jaspreet Singh Added 'irq_dis_if_send_count', @@ -97,17 +100,6 @@ } global_stats_t; -/* This structure is used for maitaining a circular linked list of all - * interfaces(devices) per card. It is used in the Interrupt Service routine - * for a transmit interrupt where the start of the loop to dev_tint all - * interfaces changes. - */ -typedef struct load_sharing -{ - struct device* dev_ptr; - struct load_sharing* next; -} load_sharing_t; - /* This is used for interrupt testing */ #define INTR_TEST_MODE 0x02 @@ -156,15 +148,9 @@ char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */ unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/ unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/ + unsigned short force_enable_irq; + char TracingEnabled; /* flag for enabling trace */ global_stats_t statistics; /* global statistics */ - - /* The following is used as a pointer to the structure in our - circular linked list which changes the start of the loop for - dev_tint of all interfaces */ - - load_sharing_t* dev_to_devtint_next; - load_sharing_t* devs_struct; - void* mbox; /* -> mailbox */ void* rxmb; /* -> receive mailbox */ void* flags; /* -> adapter status flags */ @@ -199,7 +185,50 @@ void* rxbuf_last; /* -> last Rx buffer */ unsigned rx_base; /* S508 receive buffer base */ unsigned rx_top; /* S508 receive buffer end */ + char ip_mode; /* STATIC/HOST/PEER IP Mode */ + char authenticator; /* Authenticator for PAP/CHAP */ } p; + struct /* Cisco HDLC-specific data */ + { + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + void* rxmb[2]; /* Receive mail box */ + void* flags[2]; /* flags */ + void* tx_status[2]; /* Tx status element */ + void* rx_status[2]; /* Rx status element */ + void* txbuf[2]; /* -> current Tx buffer */ + void* txbuf_base[2]; /* -> first Tx buffer */ + void* txbuf_last[2]; /* -> last Tx buffer */ + void* rxbuf_base[2]; /* -> first Rx buffer */ + void* rxbuf_last[2]; /* -> last Rx buffer */ + unsigned rx_base[2]; /* S508 receive buffer base */ + unsigned rx_top[2]; /* S508 receive buffer end */ + unsigned short protocol_options[2]; + unsigned short kpalv_tx[2]; /* Tx kpalv timer */ + unsigned short kpalv_rx[2]; /* Rx kpalv timer */ + unsigned short kpalv_err[2]; /* Error tolerance */ + unsigned short slarp_timer[2]; /* SLARP req timer */ + unsigned state[2]; /* state of the link */ + unsigned char api_status[2]; + } c; + struct + { + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + void* trace_status; /* Trace status element */ + void* txbuf; /* -> current Tx buffer */ + void* txbuf_base; /* -> first Tx buffer */ + void* txbuf_last; /* -> last Tx buffer */ + void* rxbuf_base; /* -> first Rx buffer */ + void* rxbuf_last; /* -> last Rx buffer */ + void* tracebuf; /* -> current Trace buffer */ + void* tracebuf_base; /* -> current Trace buffer */ + void* tracebuf_last; /* -> current Trace buffer */ + unsigned rx_base; /* receive buffer base */ + unsigned rx_end; /* receive buffer end */ + unsigned trace_base; /* trace buffer base */ + unsigned trace_end; /* trace buffer end */ + + } h; } u; } sdla_t; @@ -212,6 +241,9 @@ int wpx_init (sdla_t* card, wandev_conf_t* conf); /* wpx.c */ int wpf_init (sdla_t* card, wandev_conf_t* conf); /* wpf.c */ int wpp_init (sdla_t* card, wandev_conf_t* conf); /* wpp.c */ +int wpc_init (sdla_t* card, wandev_conf_t* conf); /* Cisco HDLC */ +int bsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */ +int hdlc_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */ #endif /* __KERNEL__ */ #endif /* _WANPIPE_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/wanrouter.h linux.ac/include/linux/wanrouter.h --- linux.vanilla/include/linux/wanrouter.h Sun Nov 8 15:06:50 1998 +++ linux.ac/include/linux/wanrouter.h Wed Mar 24 18:26:26 1999 @@ -1,10 +1,9 @@ /***************************************************************************** -* router.h Definitions for the WAN Multiprotocol Router Module. +* wanrouter.h Definitions for the WAN Multiprotocol Router Module. * This module provides API and common services for WAN Link * Drivers and is completely hardware-independent. * -* Author: Gene Kozin -* Jaspreet Singh +* Author: Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -13,6 +12,12 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t' +* Jun 12, 1998 David Fong Added Cisco HDLC support. +* Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to +* 'wanif_conf_t' +* Dec 05, 1997 Jaspreet Singh Added 'pap', 'chap' to 'wanif_conf_t' +* Added 'authenticator' to 'wan_ppp_conf_t' * Nov 06, 1997 Jaspreet Singh Changed Router Driver version to 1.1 from 1.0 * Oct 20, 1997 Jaspreet Singh Added 'cir','bc','be' and 'mc' to 'wanif_conf_t' * Added 'enable_IPX' and 'network_number' to @@ -62,12 +67,14 @@ #define WAN_IFNAME_SZ 15 /* max length of the interface name */ #define WAN_DRVNAME_SZ 15 /* max length of the link driver name */ #define WAN_ADDRESS_SZ 31 /* max length of the WAN media address */ +#define USED_BY_FIELD 8 /* max length of the used by field */ /* Defines for UDP PACKET TYPE */ #define UDP_PTPIPE_TYPE 0x01 #define UDP_FPIPE_TYPE 0x02 -#define UDP_DRVSTATS_TYPE 0x03 -#define UDP_INVALID_TYPE 0x04 +#define UDP_CPIPE_TYPE 0x03 +#define UDP_DRVSTATS_TYPE 0x04 +#define UDP_INVALID_TYPE 0x05 /* Command return code */ #define CMD_OK 0 /* normal firmware return code */ @@ -145,9 +152,26 @@ unsigned auth_retry; /* max. retry */ unsigned auth_options; /* authentication opt. */ unsigned ip_options; /* IP options */ + char authenticator; /* AUTHENTICATOR or not */ + char ip_mode; /* Static/Host/Peer */ } wan_ppp_conf_t; /*---------------------------------------------------------------------------- + * CHDLC-specific link-level configuration. + */ +typedef struct wan_chdlc_conf +{ + unsigned char ignore_dcd; /* Protocol options: */ + unsigned char ignore_cts; /* Ignore these to determine */ + unsigned char ignore_keepalive; /* link status (Yes or No) */ + unsigned keepalive_tx_tmr; /* transmit keepalive timer */ + unsigned keepalive_rx_tmr; /* receive keepalive timer */ + unsigned keepalive_err_margin; /* keepalive_error_tolerance */ + unsigned slarp_timer; /* SLARP request timer */ +} wan_chdlc_conf_t; + + +/*---------------------------------------------------------------------------- * WAN device configuration. Passed to ROUTER_SETUP IOCTL. */ typedef struct wandev_conf @@ -169,9 +193,8 @@ char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ char station; /* DTE/DCE, primary/secondary, etc. */ char connection; /* permanent/switched/on-demand */ + char read_mode; /* read mode: Polling or interrupt */ unsigned hw_opt[4]; /* other hardware options */ - unsigned char enable_IPX; /* Enable or Disable IPX */ - unsigned long network_number; /* Network Number for IPX */ unsigned reserved[4]; /****** arbitrary data ***************/ unsigned data_size; /* data buffer size */ @@ -181,6 +204,7 @@ wan_x25_conf_t x25; /* X.25 configuration */ wan_ppp_conf_t ppp; /* PPP configuration */ wan_fr_conf_t fr; /* frame relay configuration */ + wan_chdlc_conf_t chdlc; /* Cisco HDLC configuration */ } u; } wandev_conf_t; @@ -188,6 +212,9 @@ #define WANCONFIG_X25 101 /* X.25 link */ #define WANCONFIG_FR 102 /* frame relay link */ #define WANCONFIG_PPP 103 /* synchronous PPP link */ +#define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ +#define WANCONFIG_BSC 105 /* BiSync Streaming */ +#define WANCONFIG_HDLC 106 /* HDLC Support */ /* * Configuration options defines. @@ -230,9 +257,26 @@ #define WANOPT_ONDEMAND 2 /* activate DTR only before sending */ /* frame relay in-channel signalling */ -#define WANOPT_FR_ANSI 0 /* ANSI T1.617 Annex D */ -#define WANOPT_FR_Q933 1 /* ITU Q.933A */ -#define WANOPT_FR_LMI 2 /* LMI */ +#define WANOPT_FR_ANSI 1 /* ANSI T1.617 Annex D */ +#define WANOPT_FR_Q933 2 /* ITU Q.933A */ +#define WANOPT_FR_LMI 3 /* LMI */ + +/* PPP IP Mode Options */ +#define WANOPT_PPP_STATIC 0 +#define WANOPT_PPP_HOST 1 +#define WANOPT_PPP_PEER 2 + +/* CHDLC Protocol Options */ +/* DF Commmented out for now. + +#define WANOPT_CHDLC_NO_DCD IGNORE_DCD_FOR_LINK_STAT +#define WANOPT_CHDLC_NO_CTS IGNORE_CTS_FOR_LINK_STAT +#define WANOPT_CHDLC_NO_KEEPALIVE IGNORE_KPALV_FOR_LINK_STAT +*/ + +/* read mode */ +#define WANOPT_INTR 0 +#define WANOPT_POLL 1 /*---------------------------------------------------------------------------- * WAN Link Status Info (for ROUTER_STAT IOCTL). @@ -274,7 +318,8 @@ WAN_DISCONNECTED, /* link/channel is disconnected */ WAN_CONNECTING, /* connection is in progress */ WAN_CONNECTED, /* link/channel is operational */ - WAN_LIMIT /* for verification only */ + WAN_LIMIT, /* for verification only */ + WAN_DUALPORT /* for Dual Port cards */ }; /* 'modem_status' masks */ @@ -292,13 +337,34 @@ unsigned config_id; /* configuration identifier */ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + char usedby[USED_BY_FIELD]; /* used by API or WANPIPE */ unsigned idle_timeout; /* sec, before disconnecting */ unsigned hold_timeout; /* sec, before re-connecting */ unsigned cir; /* Committed Information Rate fwd,bwd*/ unsigned bc; /* Committed Burst Size fwd, bwd */ unsigned be; /* Excess Burst Size fwd, bwd */ + unsigned char enable_IPX; /* Enable or Disable IPX */ + unsigned char inarp; /* Send Inverse ARP requests Y/N */ + unsigned inarp_interval; /* sec, between InARP requests */ + unsigned long network_number; /* Network Number for IPX */ char mc; /* Multicast on or off */ - int reserved[8]; /* reserved for future extensions */ + char pap; /* PAP enabled or disabled */ + char chap; /* CHAP enabled or disabled */ + unsigned char userid[511]; /* List of User Id */ + unsigned char passwd[511]; /* List of passwords */ + unsigned char sysname[31]; /* Name of the system */ + unsigned char ignore_dcd; /* Protocol options: */ + unsigned char ignore_cts; /* Ignore these to determine */ + unsigned char ignore_keepalive; /* link status (Yes or No) */ + unsigned keepalive_tx_tmr; /* transmit keepalive timer */ + unsigned keepalive_rx_tmr; /* receive keepalive timer */ + unsigned keepalive_err_margin; /* keepalive_error_tolerance */ + unsigned slarp_timer; /* SLARP request timer */ + unsigned char ttl; /* Time To Live for UDP security */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ } wanif_conf_t; #ifdef __KERNEL__ @@ -308,7 +374,6 @@ #include /* proc filesystem pragmatics */ #include /* in_aton(), in_ntoa() prototypes */ #include /* support for network drivers */ - /*---------------------------------------------------------------------------- * WAN device data space. */ @@ -319,7 +384,7 @@ void* private; /* -> driver private data */ /****** hardware configuration ******/ unsigned ioport; /* adapter I/O port base #1 */ - void * maddr; /* dual-port memory address */ + unsigned long maddr; /* dual-port memory address */ unsigned msize; /* dual-port memory size */ int irq; /* interrupt request level */ int dma; /* DMA request level */ @@ -333,24 +398,23 @@ char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ char station; /* DTE/DCE, primary/secondary, etc. */ char connection; /* permanent/switched/on-demand */ + char read_mode; /* read mode: Polling or interrupt */ unsigned hw_opt[4]; /* other hardware options */ - unsigned char enable_IPX; /* Enable or Disable IPX */ - unsigned long network_number; /* Network Number for IPX */ /****** status and statistics *******/ char state; /* device state */ - unsigned modem_status; /* modem status */ + char api_status; /* device api status */ struct enet_statistics stats; /* interface statistics */ unsigned reserved[16]; /* reserved for future use */ unsigned critical; /* critical section flag */ /****** device management methods ***/ - int (*setup) (struct wan_device* wandev, wandev_conf_t* conf); - int (*shutdown) (struct wan_device* wandev); - int (*update) (struct wan_device* wandev); - int (*ioctl) (struct wan_device* wandev, unsigned cmd, + int (*setup) (struct wan_device *wandev, wandev_conf_t *conf); + int (*shutdown) (struct wan_device *wandev); + int (*update) (struct wan_device *wandev); + int (*ioctl) (struct wan_device *wandev, unsigned cmd, unsigned long arg); - int (*new_if) (struct wan_device* wandev, struct device* dev, - wanif_conf_t* conf); - int (*del_if) (struct wan_device* wandev, struct device* dev); + int (*new_if) (struct wan_device *wandev, struct device *dev, + wanif_conf_t *conf); + int (*del_if) (struct wan_device *wandev, struct device *dev); /****** maintained by the router ****/ struct wan_device* next; /* -> next device */ struct device* dev; /* list of network interfaces */ @@ -359,23 +423,20 @@ } wan_device_t; /* Public functions available for device drivers */ -extern int register_wan_device(wan_device_t* wandev); -extern int unregister_wan_device(char* name); -unsigned short wanrouter_type_trans(struct sk_buff* skb, struct device* dev); -int wanrouter_encapsulate(struct sk_buff* skb, struct device* dev); +extern int register_wan_device(wan_device_t *wandev); +extern int unregister_wan_device(char *name); +unsigned short wanrouter_type_trans(struct sk_buff *skb, struct device *dev); +int wanrouter_encapsulate(struct sk_buff *skb, struct device *dev); /* Proc interface functions. These must not be called by the drivers! */ -extern int wanrouter_proc_init (void); -extern void wanrouter_proc_cleanup (void); -extern int wanrouter_proc_add (wan_device_t* wandev); -extern int wanrouter_proc_delete (wan_device_t* wandev); -extern int wanrouter_ioctl( - struct inode* inode, struct file* file, - unsigned int cmd, unsigned long arg) -; +extern int wanrouter_proc_init(void); +extern void wanrouter_proc_cleanup(void); +extern int wanrouter_proc_add(wan_device_t *wandev); +extern int wanrouter_proc_delete(wan_device_t *wandev); +extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); /* Public Data */ -extern wan_device_t* router_devlist; /* list of registered devices */ +extern wan_device_t *router_devlist; /* list of registered devices */ #endif /* __KERNEL__ */ #endif /* _ROUTER_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/scm.h linux.ac/include/net/scm.h --- linux.vanilla/include/net/scm.h Sun Nov 8 15:10:27 1998 +++ linux.ac/include/net/scm.h Thu Feb 4 14:09:16 1999 @@ -3,8 +3,14 @@ /* Well, we should have at least one descriptor open * to accept passed FDs 8) + * + * False: Consider the case where you issue the read for + * file handles and another thread of your process sharing + * the file handle table closes the socket you are recvmsg()'ing + * on ... */ -#define SCM_MAX_FD (OPEN_MAX-1) + +#define SCM_MAX_FD (OPEN_MAX) struct scm_fp_list { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/scsi/sg.h linux.ac/include/scsi/sg.h --- linux.vanilla/include/scsi/sg.h Sun Nov 8 15:07:03 1998 +++ linux.ac/include/scsi/sg.h Wed Mar 24 18:10:29 1999 @@ -1,34 +1,152 @@ +#ifndef _SCSI_GENERIC_H +#define _SCSI_GENERIC_H + /* History: Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - process control of SCSI devices. + process control of SCSI devices. Development Sponsored by Killy Corp. NY NY -*/ - -#ifndef _SCSI_GENERIC_H -#define _SCSI_GENERIC_H +Original driver (sg.h): +* Copyright (C) 1992 Lawrence Foard +2.x extensions to driver: +* Copyright (C) 1998, 1999 Douglas Gilbert + + + Version: 2.1.30 (990320) + This version for later 2.1.x series and 2.2.x kernels + D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + + Changes since 2.1.21 (990315) + - skipped to 2.1.30 indicating interface change (revert to 2.1.9) + - remove attempt to accomodate cdrecord 1.8, will fix app + - keep SG_?ET_RESERVED_SIZE naming for clarity + Changes since 2.1.20 (990313) + - ommission: left out logic for SG_?ET_ALT_INTERFACE, now added + Changes since 2.1.9 (990309) + - skipped to version 2.1.20 to indicate some interface changes + - incorporate sg changes to make cdrecord 1.8 work (had its + own patches that were different from the original) + - change SG_?ET_BUFF_SIZE to SG_?ET_RESERVED_SIZE for clarity + Changes since 2.1.8 (990303) + - debug ">9" option dumps debug for _all_ active sg devices + - increase allowable dma pool usage + increase minimum threshhold + - pad out sg_scsi_id structure + Changes since 2.1.7 (990227) + - command queuing now "non-default" [back. compat. with cdparanoia] + - Tighten access on some ioctls + + + New features and changes: + - per file descriptor (fd) write-read sequencing and command queues. + - command queuing supported (SG_MAX_QUEUE is maximum per fd). + - scatter-gather supported (allowing potentially megabyte transfers). + - the SCSI target, host and driver status are returned + in unused fields of sg_header (maintaining its original size). + - asynchronous notification support added (SIGPOLL, SIGIO) for + read()s ( write()s should never block). + - pack_id logic added so read() can be made to wait for a specific + pack_id. + - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a + pci scsi adapter). + - this driver no longer uses a single SG_BIG_BUFF sized buffer + obtained at driver/module init time. Rather it obtains a + SG_SCATTER_SZ buffer when a fd is open()ed and frees it at + the corresponding release() (ie pr fd). Hence open() can return + ENOMEM! If write() request > SG_SCATTER_SZ bytes for data then + it can fail with ENOMEM as well (if so, scale back). + - adds several ioctl calls, see ioctl section below. + - SG_SCATTER_SZ's presence indicates this version of "sg" driver. + + Good documentation on the original "sg" device interface and usage can be + found in the Linux HOWTO document: "SCSI Programming HOWTO" by Heiko + Eissfeldt; last updated 7 May 1996. I will add more info on using the + extensions in this driver as required. A quick summary: + An SG device is accessed by writing SCSI commands plus any associated + outgoing data to it; the resulting status codes and any incoming data + are then obtained by a read call. The device can be opened O_NONBLOCK + (non-blocking) and poll() used to monitor its progress. The device may be + opened O_EXCL which excludes other "sg" users from this device (but not + "sd", "st" or "sr" users). The buffer given to the write() call is made + up as follows: + - struct sg_header image (see below) + - scsi command (6, 10 or 12 bytes long) + - data to be written to the device (if any) + + The buffer received from the corresponding read() call contains: + - struct sg_header image (check results + sense_buffer) + - data read back from device (if any) + + The given SCSI command has its LUN field overwritten internally by the + value associated with the device that has been opened. + + Memory (RAM) is used within this driver for direct memory access (DMA) + in transferring data to and from the SCSI device. The dreaded ENOMEM + seems to be more prevalent under early 2.2.x kernels than under the + 2.0.x kernel series. For a given (large) transfer the memory obtained by + this driver must be contiguous or scatter-gather must be used (if + supported by the adapter). [Furthermore, ISA SCSI adapters can only use + memory below the 16MB level on a i386.] + This driver tries hard to find some suitable memory before admitting + defeat and returning ENOMEM. All is not lost if application writers + then back off the amount they are requesting. The value returned by + the SG_GET_RESERVED_SIZE ioctl is guaranteed to be available (one + per fd). This driver does the following: + - attempts to reserve a SG_SCATTER_SZ sized buffer on open(). The + actual amount reserved is given by the SG_GET_RESERVED_SIZE ioctl(). + - each write() needs to reserve a DMA buffer of the size of the + data buffer indicated (excluding sg_header and command overhead). + This buffer, depending on its size, adapter type (ISA or not) and + the amount of memory available will be obtained from the kernel + directly (kmalloc or get_free_pages) or the from the scsi mid-level + dma pool (taking care not to exhaust it). + If the buffer requested is > SG_SCATTER_SZ or memory is tight then + scatter-gather will be used if supported by the adapter. + - write() will also attempt to use the buffer reserved on open() + if it is large enough. + The above strategy ensures that a write() can always depend on a buffer + of the size indicated by the SG_GET_RESERVED_SIZE ioctl() (which could be + 0, but at least the app knows things are tight in advance). + Hence application writers can adopt quite aggressive strategies (e.g. + requesting 512KB) and scale them back in the face of ENOMEM errors. + N.B. Queuing up commands also ties up kernel memory. -/* - An SG device is accessed by writing "packets" to it, the replies - are then read using the read call. The same header is used for - reply, just ignore reply_len field. + More documentation can be found at www.netwinder.org/~dougg */ +#define SG_MAX_SENSE 16 /* too little, unlikely to change in 2.2.x */ + struct sg_header - { - int pack_len; /* length of incoming packet <4096 (including header) */ - int reply_len; /* maximum length <4096 of expected reply */ - int pack_id; /* id number of packet */ - int result; /* 0==ok, otherwise refer to errno codes */ - unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands */ - unsigned int other_flags:31; /* for future use */ - unsigned char sense_buffer[16]; /* used only by reads */ - /* command follows then data for command */ - }; - -/* ioctl's */ -#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout */ -#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout */ +{ + int pack_len; /* [o] reply_len (ie useless), ignored as input */ + int reply_len; /* [i] max length of expected reply (inc. sg_header) */ + int pack_id; /* [io] id number of packet (use ints >= 0) */ + int result; /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */ + unsigned int twelve_byte:1; + /* [i] Force 12 byte command length for group 6 & 7 commands */ + unsigned int target_status:5; /* [o] scsi status from target */ + unsigned int host_status:8; /* [o] host status (see "DID" codes) */ + unsigned int driver_status:8; /* [o] driver status+suggestion */ + unsigned int other_flags:10; /* unused */ + unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is + CHECK_CONDITION or COMMAND_TERMINATED this is output. */ +}; /* This structure is 36 bytes long on i386 */ + + +typedef struct sg_scsi_id { + int host_no; /* as in "scsi" where 'n' is one of 0, 1, 2 etc */ + int channel; + int scsi_id; /* scsi id of target device */ + int lun; + int scsi_type; /* TYPE_... defined in scsi/scsi.h */ + int unused1; /* probably find a good use, set 0 for now */ + int unused2; /* ditto */ + int unused3; +} Sg_scsi_id; + +/* ioctls ( _GET_s yield result via 'int *' 3rd argument unless + otherwise indicated */ +#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies, 10ms on i386 */ +#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */ #define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */ @@ -36,12 +154,66 @@ #define SG_SET_TRANSFORM 0x2204 #define SG_GET_TRANSFORM 0x2205 -#define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */ +#define SG_SET_RESERVED_SIZE 0x2275 /* currently ignored, future addition */ +/* Following yields buffer reserved by open(): 0 <= x <= SG_SCATTER_SZ */ +#define SG_GET_RESERVED_SIZE 0x2272 + +/* The following ioctl takes a 'Sg_scsi_id *' object as its 3rd argument. */ +#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus,chan,dev,lun+type */ +/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */ + +/* Override adapter setting and always DMA using low memory ( <16MB on i386). + Default is 0 (off - use adapter setting) */ +#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */ +#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */ + +/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which + will attempt to read that pack_id or block (or return EAGAIN). If + pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0 + (default) then pack_id ignored by read() and oldest readable fetched. */ +#define SG_SET_FORCE_PACK_ID 0x227b +#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */ + +#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */ + +/* Turn on error sense trace (1..8), dump this device to log/console (9) + or dump all sg device states ( >9 ) to log/console */ +#define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */ + +/* Yields max scatter gather tablesize allowed by current host adapter */ +#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */ + +/* Control whether sequencing per file descriptor (default) or per device */ +#define SG_GET_MERGE_FD 0x2274 /* 0-> per fd (default), 1-> per device */ +#define SG_SET_MERGE_FD 0x2273 /* Attempt to change sequencing state, + if more than 1 fd open on device, will fail with EBUSY */ + +/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q) */ +#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */ +#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */ + + +#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */ #define SG_DEFAULT_RETRIES 1 -#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be - changed if sufficient DMA buffer room available */ +/* Default modes, commented if they differ from original sg driver */ +#define SG_DEF_COMMAND_Q 0 +#define SG_DEF_MERGE_FD 0 /* was 1 -> per device sequencing */ +#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */ +#define SG_DEF_FORCE_PACK_ID 0 + +/* maximum outstanding requests, write() yields EDOM if exceeded */ +#define SG_MAX_QUEUE 16 + +#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */ +/* Largest size (in bytes) a single scatter-gather list element can have. + The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on + i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported + by adapter then this value is the largest data block that can be + read/written by a single scsi command. Max number of scatter-gather + list elements seems to be limited to 255. */ -#define SG_BIG_BUFF 32768 +#define SG_BIG_BUFF SG_SCATTER_SZ /* for backward compatibility */ +/* #define SG_BIG_BUFF (SG_SCATTER_SZ * 8) */ /* =256KB, if you want */ #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/acct.c linux.ac/kernel/acct.c --- linux.vanilla/kernel/acct.c Wed Mar 24 10:55:28 1999 +++ linux.ac/kernel/acct.c Wed Mar 24 11:06:16 1999 @@ -194,13 +194,13 @@ } if (old_acct) { do_acct_process(0,old_acct); - filp_close(old_acct); + filp_close(old_acct, NULL); } out: unlock_kernel(); return error; out_err: - filp_close(file); + filp_close(file, NULL); goto out; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/exit.c linux.ac/kernel/exit.c --- linux.vanilla/kernel/exit.c Wed Mar 24 10:55:28 1999 +++ linux.ac/kernel/exit.c Wed Mar 24 11:06:24 1999 @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef CONFIG_BSD_PROCESS_ACCT #include #endif @@ -159,11 +160,11 @@ j = 0; for (;;) { - unsigned long set = files->open_fds.fds_bits[j]; + unsigned long set; i = j * __NFDBITS; - j++; - if (i >= files->max_fds) + if (i >= files->max_fdset || i >= files->max_fds) break; + set = files->open_fds->fds_bits[j++]; while (set) { if (set & 1) { struct file * file = files->fd[i]; @@ -189,12 +190,14 @@ if (atomic_dec_and_test(&files->count)) { close_files(files); /* - * Free the fd array as appropriate ... + * Free the fd and fdset arrays if we expanded them. */ - if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE) - free_page((unsigned long) files->fd); - else - kfree(files->fd); + if (files->fd != &files->fd_array[0]) + free_fd_array(files->fd, files->max_fds); + if (files->max_fdset > __FD_SETSIZE) { + free_fdset(files->open_fds, files->max_fdset); + free_fdset(files->close_on_exec, files->max_fdset); + } kmem_cache_free(files_cachep, files); } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/fork.c linux.ac/kernel/fork.c --- linux.vanilla/kernel/fork.c Wed Mar 24 10:55:28 1999 +++ linux.ac/kernel/fork.c Mon Mar 22 15:49:15 1999 @@ -323,6 +323,9 @@ if (clone_flags & CLONE_VM) { mmget(current->mm); + tsk->min_flt = tsk->maj_flt = 0; + tsk->cmin_flt = tsk->cmaj_flt = 0; + tsk->nswap = tsk->cnswap = 0; /* * Set up the LDT descriptor for the clone task. */ @@ -375,32 +378,11 @@ return 0; } -/* - * Copy a fd_set and compute the maximum fd it contains. - */ -static inline int __copy_fdset(unsigned long *d, unsigned long *src) -{ - int i; - unsigned long *p = src; - unsigned long *max = src; - - for (i = __FDSET_LONGS; i; --i) { - if ((*d++ = *p++) != 0) - max = p; - } - return (max - src)*sizeof(long)*8; -} - -static inline int copy_fdset(fd_set *dst, fd_set *src) -{ - return __copy_fdset(dst->fds_bits, src->fds_bits); -} - static int copy_files(unsigned long clone_flags, struct task_struct * tsk) { struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; - int size, i, error = 0; + int nfds, size, i, error = 0; /* * A background process may not have any files ... @@ -420,25 +402,74 @@ if (!newf) goto out; - /* - * Allocate the fd array, using get_free_page() if possible. - * Eventually we want to make the array size variable ... - */ - size = NR_OPEN * sizeof(struct file *); - if (size == PAGE_SIZE) - new_fds = (struct file **) __get_free_page(GFP_KERNEL); - else - new_fds = (struct file **) kmalloc(size, GFP_KERNEL); - if (!new_fds) - goto out_release; + size = oldf->max_fdset; + nfds = NR_OPEN_DEFAULT; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " size = %d/%d\n", + oldf->max_fds, oldf->max_fdset); +#endif atomic_set(&newf->count, 1); - newf->max_fds = NR_OPEN; - newf->fd = new_fds; - newf->close_on_exec = oldf->close_on_exec; - i = copy_fdset(&newf->open_fds, &oldf->open_fds); + newf->next_fd = 0; + newf->max_fds = NR_OPEN_DEFAULT; + newf->max_fdset = __FD_SETSIZE; + newf->close_on_exec = &newf->close_on_exec_init; + newf->open_fds = &newf->open_fds_init; + newf->fd = &newf->fd_array[0]; + + /* Even if the old fdset gets grown here, we'll only copy "size" fds */ + if (size > __FD_SETSIZE) { + newf->max_fdset = 0; + error = expand_fdset(newf, size); + if (error) + goto out_release; + } + memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, size/8); + memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, size/8); + if (newf->max_fdset > size) { + int left = (newf->max_fdset-size)/8; + int start = size / (8 * sizeof(unsigned long)); + + memset(&newf->open_fds->fds_bits[start], 0, left); + memset(&newf->close_on_exec->fds_bits[start], 0, left); + } + + /* Find the last open fd */ + for (i = size/(8*sizeof(long)); i > 0; ) { + if (newf->open_fds->fds_bits[--i]) + break; + } + i = (i+1) * 8 * sizeof(long); + +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " first-free = %d/%d\n", i, size); +#endif + + /* Do a sanity check ... */ + if (i > oldf->max_fds) + printk(KERN_ERR + "copy_files: pid %d, open files %d exceeds max %d!\n", + current->pid, i, oldf->max_fds); + + /* + * Check whether we need to allocate a larger fd array. + * Note: we're not a clone task, so the open count won't + * change. + */ + if (i > NR_OPEN_DEFAULT) { + newf->max_fds = 0; + error = expand_fd_array(newf, i); + if (error) + goto out_release; + nfds = newf->max_fds; + } + + /* compute the remainder to be cleared */ + size = (nfds - i) * sizeof(struct file *); old_fds = oldf->fd; + new_fds = newf->fd; + for (; i != 0; i--) { struct file *f = *old_fds++; *new_fds = f; @@ -447,14 +478,20 @@ new_fds++; } /* This is long word aligned thus could use a optimized version */ - memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); + memset(new_fds, 0, size); tsk->files = newf; error = 0; out: +#ifdef FDSET_DEBUG + if (error) + printk (KERN_ERR "copy_files: return %d\n", error); +#endif return error; out_release: + free_fdset (newf->close_on_exec, newf->max_fdset); + free_fdset (newf->open_fds, newf->max_fdset); kmem_cache_free(files_cachep, newf); goto out; } @@ -593,7 +630,7 @@ goto bad_fork_cleanup_sighand; retval = copy_thread(nr, clone_flags, usp, p, regs); if (retval) - goto bad_fork_cleanup_sighand; + goto bad_fork_cleanup_mm; p->semundo = NULL; /* ok, now we should be set up.. */ @@ -640,6 +677,9 @@ down(&sem); return retval; +bad_fork_cleanup_mm: + mmput(p->mm); + p->mm = NULL; bad_fork_cleanup_sighand: exit_sighand(p); bad_fork_cleanup_fs: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/module.c linux.ac/kernel/module.c --- linux.vanilla/kernel/module.c Mon Dec 28 23:09:49 1998 +++ linux.ac/kernel/module.c Mon Dec 28 23:41:26 1998 @@ -942,6 +942,23 @@ return len; } +/* + * String comparison for non-co-versioned kernel and module. + */ +static int +ncv_strcmp(const char *a, const char *b) +{ + size_t alen = strlen(a), blen = strlen(b); + + if (blen == alen + 10 && b[alen] == '_' && b[alen+1] == 'R') + return strncmp(a, b, alen); + else if (alen == blen + 10 && a[blen] == '_' && a[blen+1] == 'R') + return strncmp(a, b, blen); + else + return strcmp(a, b); +} + + /* * Gets the address for a symbol in the given module. If modname is * NULL, it looks for the name in any registered symbol table. If the @@ -962,7 +979,7 @@ for (i = mp->nsyms, sym = mp->syms; i > 0; --i, ++sym) { - if (strcmp(sym->name, symname) == 0) { + if (ncv_strcmp(sym->name, symname) == 0) { return sym->value; } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/signal.c linux.ac/kernel/signal.c --- linux.vanilla/kernel/signal.c Tue Dec 22 23:20:12 1998 +++ linux.ac/kernel/signal.c Wed Mar 24 18:11:13 1999 @@ -363,8 +363,27 @@ } sigaddset(&t->signal, sig); - if (!sigismember(&t->blocked, sig)) + if (!sigismember(&t->blocked, sig)) { t->sigpending = 1; +#ifdef __SMP__ + /* + * If the task is running on a different CPU + * force a reschedule on the other CPU - note that + * the code below is a tad loose and might occasionally + * kick the wrong CPU if we catch the process in the + * process of changing - but no harm is done by that + * other than doing an extra (lightweight) IPI interrupt. + * + * note that we rely on the previous spin_lock to + * lock interrupts for us! No need to set need_resched + * since signal event passing goes through ->blocked. + */ + spin_lock(&runqueue_lock); + if (t->has_cpu && t->processor != smp_processor_id()) + smp_send_reschedule(t->processor); + spin_unlock(&runqueue_lock); +#endif /* __SMP__ */ + } out: spin_unlock_irqrestore(&t->sigmask_lock, flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/sysctl.c linux.ac/kernel/sysctl.c --- linux.vanilla/kernel/sysctl.c Tue Feb 23 14:21:34 1999 +++ linux.ac/kernel/sysctl.c Tue Mar 16 18:57:11 1999 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -165,7 +164,7 @@ {KERN_PANIC, "panic", &panic_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, #ifdef CONFIG_BLK_DEV_INITRD - {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int), + {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(real_root_dev), 0644, NULL, &proc_dointvec}, #endif #ifdef CONFIG_BINFMT_JAVA @@ -563,7 +562,6 @@ continue; } - /* Don't unregoster proc entries that are still being used.. */ if (de->count) continue; @@ -698,10 +696,11 @@ } i = (int *) table->data; - vleft = table->maxlen / sizeof(int); + vleft = table->maxlen; left = *lenp; - for (; left && vleft--; i++, first=0) { + for (; left && vleft > 0; i++, first=0) { + vleft -= sizeof(int); if (write) { while (left) { char c; @@ -736,12 +735,18 @@ val = -val; buffer += len; left -= len; - *i = val; + if(vleft >= 0) + *i = val; + else + *((unsigned short *)i) = val; } else { p = buf; if (!first) *p++ = '\t'; - sprintf(p, "%d", (*i) / conv); + if(vleft >= 0) + sprintf(p, "%d", (*i) / conv); + else + sprintf(p, "%hd", (*((unsigned short *)i)) / (unsigned short)conv); len = strlen(buf); if (len > left) len = left; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/lib/string.c linux.ac/lib/string.c --- linux.vanilla/lib/string.c Sun Nov 8 15:06:44 1998 +++ linux.ac/lib/string.c Thu Nov 12 17:59:56 1998 @@ -294,10 +294,10 @@ int memcmp(const void * cs,const void * ct,size_t count) { const unsigned char *su1, *su2; - signed char res = 0; + int res = 0; for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) - if ((res = *su1 - *su2) != 0) + if ((res = (int)*su1 - (int)*su2) != 0) break; return res; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/filemap.c linux.ac/mm/filemap.c --- linux.vanilla/mm/filemap.c Wed Mar 24 10:55:28 1999 +++ linux.ac/mm/filemap.c Wed Mar 24 11:06:39 1999 @@ -1515,21 +1515,14 @@ /* Get exclusive IO access to the page.. */ wait_on_page(page); - set_bit(PG_locked, &page->flags); /* * Do the real work.. If the writer ends up delaying the write, * the writer needs to increment the page use counts until he * is done with the page. */ - bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes); - status = -EFAULT; - if (bytes) - status = inode->i_op->updatepage(file, page, offset, bytes, sync); + status = inode->i_op->updatepage(file, page, buf, offset, bytes, sync); - /* Mark it unlocked again and drop the page.. */ - clear_bit(PG_locked, &page->flags); - wake_up(&page->wait); __free_page(page); if (status < 0) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/802/tr.c linux.ac/net/802/tr.c --- linux.vanilla/net/802/tr.c Tue Dec 22 23:20:12 1998 +++ linux.ac/net/802/tr.c Mon Mar 1 14:24:09 1999 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/README linux.ac/net/README --- linux.vanilla/net/README Sun Nov 8 15:07:09 1998 +++ linux.ac/net/README Thu Mar 11 13:03:49 1999 @@ -16,7 +16,7 @@ lapb g4klx@g4klx.demon.co.uk netrom g4klx@g4klx.demon.co.uk rose g4klx@g4klx.demon.co.uk -wanrouter genek@compuserve.com and dm@sangoma.com +wanrouter gene@compuserve.com, jaspreet@sangoma and dm@sangoma.com unix alan@lxorguk.ukuu.org.uk x25 g4klx@g4klx.demon.co.uk diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/appletalk/ddp.c linux.ac/net/appletalk/ddp.c --- linux.vanilla/net/appletalk/ddp.c Wed Jan 6 23:02:31 1999 +++ linux.ac/net/appletalk/ddp.c Wed Mar 24 18:08:33 1999 @@ -356,7 +356,7 @@ /* * Scan the networks. */ - + atif->status |= ATIF_PROBE; for(netct = 0; netct <= netrange; netct++) { /* @@ -374,8 +374,10 @@ */ aarp_probe_network(atif); - if(!(atif->status & ATIF_PROBE_FAIL)) + if(!(atif->status & ATIF_PROBE_FAIL)) { + atif->status &= ~ATIF_PROBE; return (0); + } } atif->status &= ~ATIF_PROBE_FAIL; } @@ -383,7 +385,7 @@ if(probe_net > ntohs(atif->nets.nr_lastnet)) probe_net = ntohs(atif->nets.nr_firstnet); } - + atif->status &= ~ATIF_PROBE; return (-EADDRINUSE); /* Network is full... */ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ipconfig.c linux.ac/net/ipv4/ipconfig.c --- linux.vanilla/net/ipv4/ipconfig.c Tue Jan 19 02:57:40 1999 +++ linux.ac/net/ipv4/ipconfig.c Wed Feb 24 01:33:15 1999 @@ -825,7 +825,7 @@ */ if (ic_myaddr == INADDR_NONE || #ifdef CONFIG_ROOT_NFS - root_server_addr == INADDR_NONE || + ic_servaddr == INADDR_NONE || #endif (ic_first_dev && ic_first_dev->next)) { #ifdef CONFIG_IP_PNP_DYNAMIC diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv6/raw.c linux.ac/net/ipv6/raw.c --- linux.vanilla/net/ipv6/raw.c Thu Nov 19 18:38:51 1998 +++ linux.ac/net/ipv6/raw.c Mon Mar 1 14:24:09 1999 @@ -39,8 +39,6 @@ #include -#include - struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; static void raw_v6_hash(struct sock *sk) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/netlink/af_netlink.c linux.ac/net/netlink/af_netlink.c --- linux.vanilla/net/netlink/af_netlink.c Wed Mar 24 10:55:30 1999 +++ linux.ac/net/netlink/af_netlink.c Mon Mar 22 16:00:43 1999 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/netsyms.c linux.ac/net/netsyms.c --- linux.vanilla/net/netsyms.c Wed Mar 24 10:55:30 1999 +++ linux.ac/net/netsyms.c Wed Mar 24 11:07:19 1999 @@ -21,6 +21,9 @@ #include #include #include +#ifdef CONFIG_HIPPI +#include +#endif #include #ifdef CONFIG_BRIDGE @@ -45,6 +48,8 @@ #include extern struct net_proto_family inet_family_ops; +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #include @@ -474,6 +479,15 @@ EXPORT_SYMBOL(kill_fasync); EXPORT_SYMBOL(if_port_text); + +#ifdef CONFIG_HIPPI +EXPORT_SYMBOL(hippi_type_trans); +EXPORT_SYMBOL(init_hippi_dev); +EXPORT_SYMBOL(unregister_hipdev); +#endif + +EXPORT_SYMBOL(sysctl_wmem_max); +EXPORT_SYMBOL(sysctl_rmem_max); #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sched/cls_fw.c linux.ac/net/sched/cls_fw.c --- linux.vanilla/net/sched/cls_fw.c Wed Mar 24 10:55:31 1999 +++ linux.ac/net/sched/cls_fw.c Wed Mar 24 18:06:07 1999 @@ -303,7 +303,11 @@ t->tcm_handle = f->id; - if (!f->res.classid && !f->police) + if (!f->res.classid +#ifdef CONFIG_NET_CLS_POLICE + && !f->police +#endif + ) return skb->len; rta = (struct rtattr*)b; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sched/sch_cbq.c linux.ac/net/sched/sch_cbq.c --- linux.vanilla/net/sched/sch_cbq.c Wed Mar 24 10:55:31 1999 +++ linux.ac/net/sched/sch_cbq.c Mon Mar 22 15:57:48 1999 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sched/sch_sfq.c linux.ac/net/sched/sch_sfq.c --- linux.vanilla/net/sched/sch_sfq.c Wed Mar 24 10:55:31 1999 +++ linux.ac/net/sched/sch_sfq.c Mon Mar 22 15:58:11 1999 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/auth.c linux.ac/net/sunrpc/auth.c --- linux.vanilla/net/sunrpc/auth.c Wed Mar 24 10:55:32 1999 +++ linux.ac/net/sunrpc/auth.c Wed Mar 24 11:07:25 1999 @@ -145,27 +145,26 @@ cred->cr_next = auth->au_credcache[nr]; auth->au_credcache[nr] = cred; cred->cr_expire = jiffies + auth->au_expire; - cred->cr_count++; } /* * Look up a process' credentials in the authentication cache */ static struct rpc_cred * -rpcauth_lookup_credcache(struct rpc_task *task) +rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) { - struct rpc_auth *auth = task->tk_auth; struct rpc_cred **q, *cred = NULL; - int nr; + int nr = 0; - nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR); + if (!(taskflags & RPC_TASK_ROOTCREDS)) + nr = current->uid % RPC_CREDCACHE_NR; if (time_before(auth->au_nextgc, jiffies)) rpcauth_gc_credcache(auth); q = &auth->au_credcache[nr]; while ((cred = *q) != NULL) { - if (auth->au_ops->crmatch(task, cred)) { + if (auth->au_ops->crmatch(cred, taskflags)) { *q = cred->cr_next; break; } @@ -173,10 +172,12 @@ } if (!cred) - cred = auth->au_ops->crcreate(task); + cred = auth->au_ops->crcreate(taskflags); - if (cred) + if (cred != NULL) { rpcauth_insert_credcache(auth, cred); + cred->cr_count++; + } return (struct rpc_cred *) cred; } @@ -202,21 +203,32 @@ } struct rpc_cred * -rpcauth_lookupcred(struct rpc_task *task) +rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) +{ + dprintk("RPC: looking up %s cred\n", + auth->au_ops->au_name); + return rpcauth_lookup_credcache(auth, taskflags); +} + +struct rpc_cred * +rpcauth_bindcred(struct rpc_task *task) { + struct rpc_auth *auth = task->tk_auth; + dprintk("RPC: %4d looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); - return task->tk_cred = rpcauth_lookup_credcache(task); + task->tk_cred = rpcauth_lookup_credcache(auth, task->tk_flags); + if (task->tk_cred == 0) + task->tk_status = -ENOMEM; + return task->tk_cred; } int -rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred) +rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags) { - struct rpc_auth *auth = task->tk_auth; - - dprintk("RPC: %4d matching %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); - return auth->au_ops->crmatch(task, cred); + dprintk("RPC: matching %s cred %d\n", + auth->au_ops->au_name, taskflags); + return auth->au_ops->crmatch(cred, taskflags); } void diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/auth_null.c linux.ac/net/sunrpc/auth_null.c --- linux.vanilla/net/sunrpc/auth_null.c Wed Mar 24 10:55:32 1999 +++ linux.ac/net/sunrpc/auth_null.c Wed Mar 24 11:07:49 1999 @@ -45,15 +45,12 @@ * Create NULL creds for current process */ static struct rpc_cred * -nul_create_cred(struct rpc_task *task) +nul_create_cred(int flags) { struct rpc_cred *cred; - if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred)))) { - task->tk_status = -ENOMEM; + if (!(cred = (struct rpc_cred *) rpc_allocate(flags, sizeof(*cred)))) return NULL; - } - cred->cr_count = 0; cred->cr_flags = RPCAUTH_CRED_UPTODATE; @@ -73,7 +70,7 @@ * Match cred handle against current process */ static int -nul_match(struct rpc_task *task, struct rpc_cred *cred) +nul_match(struct rpc_cred *cred, int taskflags) { return 1; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/auth_unix.c linux.ac/net/sunrpc/auth_unix.c --- linux.vanilla/net/sunrpc/auth_unix.c Wed Mar 24 10:55:32 1999 +++ linux.ac/net/sunrpc/auth_unix.c Mon Feb 1 22:06:55 1999 @@ -60,7 +60,7 @@ } static struct rpc_cred * -unx_create_cred(struct rpc_task *task) +unx_create_cred(int flags) { struct unx_cred *cred; int i; @@ -68,14 +68,12 @@ dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", current->uid, current->gid); - if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred)))) { - task->tk_status = -ENOMEM; + if (!(cred = (struct unx_cred *) rpc_allocate(flags, sizeof(*cred)))) return NULL; - } cred->uc_count = 0; cred->uc_flags = RPCAUTH_CRED_UPTODATE; - if (RPC_DO_ROOTOVERRIDE(task)) { + if (flags & RPC_TASK_ROOTCREDS) { cred->uc_uid = cred->uc_fsuid = 0; cred->uc_gid = cred->uc_fsgid = 0; cred->uc_gids[0] = NOGROUP; @@ -131,12 +129,12 @@ * request root creds (e.g. for NFS swapping). */ static int -unx_match(struct rpc_task * task, struct rpc_cred *rcred) +unx_match(struct rpc_cred * rcred, int taskflags) { struct unx_cred *cred = (struct unx_cred *) rcred; int i; - if (!RPC_DO_ROOTOVERRIDE(task)) { + if (!(taskflags & RPC_TASK_ROOTCREDS)) { int groups; if (cred->uc_uid != current->uid diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/clnt.c linux.ac/net/sunrpc/clnt.c --- linux.vanilla/net/sunrpc/clnt.c Sun Nov 8 15:07:19 1998 +++ linux.ac/net/sunrpc/clnt.c Tue Feb 23 21:08:50 1999 @@ -98,8 +98,11 @@ clnt->cl_stats = program->stats; clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait"); - if (!clnt->cl_port) + if (!clnt->cl_port) { clnt->cl_autobind = 1; + clnt->cl_up = 0; + } else + clnt->cl_up = 1; if (!rpcauth_create(flavor, clnt)) goto out_no_auth; @@ -136,7 +139,7 @@ clnt->cl_protname, clnt->cl_server); while (clnt->cl_users) { #ifdef RPC_DEBUG - printk("rpc_shutdown_client: client %s, tasks=%d\n", + dprintk("RPC: rpc_shutdown_client: client %s, tasks=%d\n", clnt->cl_protname, clnt->cl_users); #endif /* Don't let rpc_release_client destroy us */ @@ -195,7 +198,6 @@ static void rpc_default_callback(struct rpc_task *task) { - rpc_release_task(task); } /* @@ -264,7 +266,7 @@ /* Bind the user cred, set up the call info struct and * execute the task */ - if (rpcauth_lookupcred(task) != NULL) { + if (rpcauth_bindcred(task) != NULL) { rpc_call_setup(task, proc, argp, resp, 0); rpc_execute(task); } else @@ -294,7 +296,8 @@ task->tk_flags |= flags; /* Increment call count */ - rpcproc_count(task->tk_client, proc)++; + if (task->tk_proc < task->tk_client->cl_maxproc) + rpcproc_count(task->tk_client, proc)++; } /* @@ -305,7 +308,6 @@ rpc_restart_call(struct rpc_task *task) { if (task->tk_flags & RPC_TASK_KILLED) { - rpc_release_task(task); return; } task->tk_action = call_bind; @@ -320,6 +322,12 @@ { struct rpc_clnt *clnt = task->tk_client; + if (task->tk_proc >= clnt->cl_maxproc) { + printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n", + clnt->cl_protname, clnt->cl_vers, task->tk_proc); + rpc_exit(task, -EIO); + return; + } task->tk_action = call_reserve; task->tk_status = 0; if (!clnt->cl_port) @@ -460,13 +468,6 @@ req->rq_rlen = bufsiz; req->rq_rnr = 1; - if (task->tk_proc > clnt->cl_maxproc) { - printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n", - clnt->cl_protname, clnt->cl_vers, task->tk_proc); - rpc_exit(task, -EIO); - return; - } - /* Encode header and provided arguments */ encode = rpcproc_encode(clnt, task->tk_proc); if (!(p = call_header(task))) { @@ -546,10 +547,22 @@ else task->tk_action = call_transmit; } else if (status == -ENOTCONN) { + clnt->cl_up = 0; task->tk_action = call_reconnect; - } else if (status == -ECONNREFUSED && clnt->cl_autobind) { - task->tk_action = call_bind; - clnt->cl_port = 0; + } else if (status == -ECONNREFUSED) { + clnt->cl_up = 0; + if (clnt->cl_chatty) { + task->tk_flags |= RPC_CALL_MAJORSEEN; + printk("%s: server %s not responding, timed out\n", + clnt->cl_protname, clnt->cl_server); + } + if (clnt->cl_autobind) { + task->tk_action = call_bind; + clnt->cl_port = 0; + } else + task->tk_action = call_transmit; + if (! clnt->cl_softrtry) + rpc_delay(task, 5*HZ); } else { if (clnt->cl_chatty) printk("%s: RPC call returned error %d\n", @@ -593,14 +606,16 @@ } if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) { task->tk_flags |= RPC_CALL_MAJORSEEN; - if (req) + if (req) { + clnt->cl_up = 0; printk("%s: server %s not responding, still trying\n", clnt->cl_protname, clnt->cl_server); - else + } + else /* This is not a server timeout problem! */ printk("%s: task %d can't get a request slot\n", clnt->cl_protname, task->tk_pid); } - if (clnt->cl_autobind) + if (clnt->cl_autobind && req) clnt->cl_port = 0; minor_timeout: @@ -653,6 +668,11 @@ printk("%s: server %s OK\n", clnt->cl_protname, clnt->cl_server); task->tk_flags &= ~RPC_CALL_MAJORSEEN; + } + if (!clnt->cl_up) { + clnt->cl_up = 1; + if (clnt->cl_xprt && !RPCXPRT_CONGESTED(clnt->cl_xprt)) + wake_up(&clnt->cl_xprt->cong_wait); } if (task->tk_status < 12) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/pmap_clnt.c linux.ac/net/sunrpc/pmap_clnt.c --- linux.vanilla/net/sunrpc/pmap_clnt.c Sun Nov 8 15:07:19 1998 +++ linux.ac/net/sunrpc/pmap_clnt.c Tue Feb 23 21:08:50 1999 @@ -121,12 +121,13 @@ task->tk_action = NULL; } else if (clnt->cl_port == 0) { /* Program not registered */ - task->tk_status = -EACCES; + task->tk_status = -EPROTONOSUPPORT; task->tk_action = NULL; } else { /* byte-swap port number first */ clnt->cl_port = htons(clnt->cl_port); clnt->cl_xprt->addr.sin_port = clnt->cl_port; + clnt->cl_up = 1; } clnt->cl_binding = 0; rpc_wake_up(&clnt->cl_bindwait); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/sched.c linux.ac/net/sunrpc/sched.c --- linux.vanilla/net/sunrpc/sched.c Wed Mar 10 21:13:14 1999 +++ linux.ac/net/sunrpc/sched.c Sun Mar 7 19:56:34 1999 @@ -82,14 +82,12 @@ * Everyone else gets appended to the queue to ensure proper FIFO behavior. */ int -rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) +__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) { if (task->tk_rpcwait) { - if (task->tk_rpcwait != queue) - { - printk(KERN_WARNING "RPC: doubly enqueued task!\n"); - return -EWOULDBLOCK; - } + printk(KERN_WARNING "RPC: task already queued!\n"); + dprintk("task already on %s, to be added to %s\n", + rpc_qname(task->tk_rpcwait), rpc_qname(queue)); return 0; } if (RPC_IS_SWAPPER(task)) @@ -109,12 +107,10 @@ * Note: must be called with interrupts disabled. */ void -rpc_remove_wait_queue(struct rpc_task *task) +__rpc_remove_wait_queue(struct rpc_task *task) { - struct rpc_wait_queue *queue; + struct rpc_wait_queue *queue = task->tk_rpcwait; - if (!(queue = task->tk_rpcwait)) - return; rpc_remove_list(&queue->task, task); task->tk_rpcwait = NULL; @@ -149,16 +145,13 @@ /* * Delete any timer for the current task. - * Must be called with interrupts off. */ inline void rpc_del_timer(struct rpc_task *task) { - if (task->tk_timeout) { - dprintk("RPC: %4d deleting timer\n", task->tk_pid); - del_timer(&task->tk_timer); - task->tk_timeout = 0; - } + dprintk("RPC: %4d deleting timer\n", task->tk_pid); + del_timer(&task->tk_timer); + task->tk_timeout = 0; } /* @@ -183,6 +176,8 @@ task->tk_status = status; } wake_up(&rpciod_idle); + if (task->tk_flags & RPC_TASK_PRIORITY) + current->need_resched = 1; } else { wake_up(&task->tk_wait); } @@ -389,6 +384,7 @@ return 0; } +restarted: while (1) { /* * Execute any pending callback. @@ -428,7 +424,7 @@ /* * Check whether task is sleeping. - * Note that if the task may go to sleep in tk_action, + * Note that if the task goes to sleep in tk_action, * and the RPC reply arrives before we get here, it will * have state RUNNING, but will still be on schedq. */ @@ -453,7 +449,7 @@ * When the task received a signal, remove from * any queues etc, and make runnable again. */ - if (signalled()) + if (signalled() && task->tk_client->cl_intr) __rpc_wake_up(task); dprintk("RPC: %4d sync task resuming\n", @@ -467,7 +463,8 @@ * clean up after sleeping on some queue, we don't * break the loop here, but go around once more. */ - if (!RPC_IS_ASYNC(task) && signalled()) { + if (!RPC_IS_ASYNC(task) && signalled() + && task->tk_client->cl_intr) { dprintk("RPC: %4d got signal\n", task->tk_pid); rpc_exit(task, -ERESTARTSYS); } @@ -477,15 +474,33 @@ if (task->tk_exit) { status = task->tk_status; task->tk_exit(task); + /* If tk_action is non-null, the user wants us to restart */ + if (task->tk_action) { + if (!(signalled() && task->tk_client->cl_intr) + && !RPC_ASSASSINATED(task)) { + /* Release RPC slot and buffer memory */ + if (task->tk_rqstp) + xprt_release(task); + if (task->tk_buffer) { + rpc_free(task->tk_buffer); + task->tk_buffer = NULL; + } + goto restarted; + } + printk("RPC: dead task tries to walk away.\n"); + } } + /* Release all resources associated with the task */ + rpc_release_task(task); return status; } /* * User-visible entry point to the scheduler. - * The recursion protection is for debugging. It should go away once - * the code has stabilized. + * + * This may be called recursively if e.g. an async NFS task updates + * the attributes and finds that dirty pages must be flushed. */ void rpc_execute(struct rpc_task *task) @@ -493,13 +508,14 @@ static int executing = 0; int incr = RPC_IS_ASYNC(task)? 1 : 0; - if (incr) { - if (rpc_inhibit) { - printk(KERN_INFO "RPC: execution inhibited!\n"); + if (executing || rpc_inhibit) { + if (!incr) { + dprintk("RPC: rpc_execute called recursively!!\n"); + task->tk_status = -EIO; return; } - if (executing) - printk(KERN_WARNING "RPC: %d tasks executed\n", executing); + rpc_make_runnable(task); + return; } executing += incr; @@ -574,12 +590,13 @@ else gfp = GFP_KERNEL; - do { + while(1) { if ((buffer = (u32 *) kmalloc(size, gfp)) != NULL) { dprintk("RPC: allocated buffer %p\n", buffer); return buffer; } - if ((flags & RPC_TASK_SWAPPER) && !swap_buffer_used++) { + if ((flags & RPC_TASK_SWAPPER) + && size < PAGE_SIZE && !swap_buffer_used++) { dprintk("RPC: used last-ditch swap buffer\n"); return swap_buffer; } @@ -587,7 +604,7 @@ return NULL; current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ>>4); - } while (!signalled()); + } return NULL; } @@ -635,8 +652,9 @@ task->tk_magic = 0xf00baa; task->tk_pid = rpc_task_id++; #endif - dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, - current->pid); + dprintk("RPC: %d new task procpid %d%s\n", + task->tk_pid, current->pid, + (flags & RPC_TASK_DYNAMIC) ? " (alloc)" : ""); } /* @@ -653,10 +671,7 @@ if (!task) goto cleanup; - rpc_init_task(task, clnt, callback, flags); - - dprintk("RPC: %4d allocated task\n", task->tk_pid); - task->tk_flags |= RPC_TASK_DYNAMIC; + rpc_init_task(task, clnt, callback, flags | RPC_TASK_DYNAMIC); out: return task; @@ -678,6 +693,9 @@ dprintk("RPC: %4d release task\n", task->tk_pid); + /* Remove from any wait queue we're still on */ + rpc_remove_wait_queue(task); + /* Remove from global task list */ prev = task->tk_prev_task; next = task->tk_next_task; @@ -688,6 +706,9 @@ else all_tasks = next; + /* Delete any running timer */ + rpc_del_timer(task); + /* Release resources */ if (task->tk_rqstp) xprt_release(task); @@ -740,7 +761,6 @@ parent->tk_status = child->tk_status; rpc_wake_up_task(parent); } - rpc_release_task(child); } /* @@ -972,36 +992,3 @@ MOD_DEC_USE_COUNT; } -#ifdef RPC_DEBUG -#include -void rpc_show_tasks(void) -{ - struct rpc_task *t = all_tasks, *next; - struct nfs_wreq *wreq; - - if (!t) - return; - printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " - "-rpcwait -action- --exit--\n"); - for (; t; t = next) { - next = t->tk_next_task; - printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", - t->tk_pid, t->tk_proc, t->tk_flags, t->tk_status, - t->tk_client, t->tk_client->cl_prog, - t->tk_rqstp, t->tk_timeout, - t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " ", - t->tk_action, t->tk_exit); - - if (!(t->tk_flags & RPC_TASK_NFSWRITE)) - continue; - /* NFS write requests */ - wreq = (struct nfs_wreq *) t->tk_calldata; - printk(" NFS: flgs=%08x, pid=%d, pg=%p, off=(%d, %d)\n", - wreq->wb_flags, wreq->wb_pid, wreq->wb_page, - wreq->wb_offset, wreq->wb_bytes); - printk(" name=%s/%s\n", - wreq->wb_file->f_dentry->d_parent->d_name.name, - wreq->wb_file->f_dentry->d_name.name); - } -} -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/sunrpc_syms.c linux.ac/net/sunrpc/sunrpc_syms.c --- linux.vanilla/net/sunrpc/sunrpc_syms.c Sun Nov 8 15:07:19 1998 +++ linux.ac/net/sunrpc/sunrpc_syms.c Mon Feb 1 22:06:55 1999 @@ -26,13 +26,16 @@ EXPORT_SYMBOL(rpc_allocate); EXPORT_SYMBOL(rpc_free); EXPORT_SYMBOL(rpc_execute); +EXPORT_SYMBOL(rpc_new_task); EXPORT_SYMBOL(rpc_init_task); EXPORT_SYMBOL(rpc_release_task); EXPORT_SYMBOL(rpc_sleep_on); +EXPORT_SYMBOL(rpc_wake_up); EXPORT_SYMBOL(rpc_wake_up_next); EXPORT_SYMBOL(rpc_wake_up_task); EXPORT_SYMBOL(rpc_new_child); EXPORT_SYMBOL(rpc_run_child); +EXPORT_SYMBOL(rpciod_wake_up); EXPORT_SYMBOL(rpciod_down); EXPORT_SYMBOL(rpciod_up); @@ -60,7 +63,9 @@ EXPORT_SYMBOL(rpcauth_free_credcache); EXPORT_SYMBOL(rpcauth_insert_credcache); EXPORT_SYMBOL(rpcauth_lookupcred); +EXPORT_SYMBOL(rpcauth_bindcred); EXPORT_SYMBOL(rpcauth_matchcred); +EXPORT_SYMBOL(rpcauth_holdcred); EXPORT_SYMBOL(rpcauth_releasecred); /* RPC server stuff */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/svcsock.c linux.ac/net/sunrpc/svcsock.c --- linux.vanilla/net/sunrpc/svcsock.c Wed Mar 24 10:55:33 1999 +++ linux.ac/net/sunrpc/svcsock.c Sat Mar 20 23:13:19 1999 @@ -265,9 +265,9 @@ set_fs(oldfs); #endif - dprintk("svc: socket %p sendto([%p %d... ], %d, %d) = %d\n", + dprintk("svc: socket %p sendto([%p %ld... ], %d, %d) = %d\n", rqstp->rq_sock, - iov[0].iov_base, iov[0].iov_len, nr, + iov[0].iov_base, (long)iov[0].iov_len, nr, buflen, len); return len; @@ -324,8 +324,8 @@ set_fs(oldfs); #endif - dprintk("svc: socket %p recvfrom(%p, %d) = %d\n", rqstp->rq_sock, - iov[0].iov_base, iov[0].iov_len, len); + dprintk("svc: socket %p recvfrom(%p, %ld) = %d\n", rqstp->rq_sock, + iov[0].iov_base, (long)iov[0].iov_len, len); return len; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/sysctl.c linux.ac/net/sunrpc/sysctl.c --- linux.vanilla/net/sunrpc/sysctl.c Sat Jan 9 21:50:52 1999 +++ linux.ac/net/sunrpc/sysctl.c Mon Feb 1 22:06:55 1999 @@ -98,10 +98,6 @@ while (left && isspace(*p)) left--, p++; *(unsigned int *) table->data = value; - /* Display the RPC tasks on writing to rpc_debug */ - if (table->ctl_name == CTL_RPCDEBUG) { - rpc_show_tasks(); - } } else { if (!access_ok(VERIFY_WRITE, buffer, left)) return -EFAULT; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/xprt.c linux.ac/net/sunrpc/xprt.c --- linux.vanilla/net/sunrpc/xprt.c Wed Mar 24 10:55:33 1999 +++ linux.ac/net/sunrpc/xprt.c Wed Mar 24 18:01:54 1999 @@ -31,7 +31,7 @@ * primitives that `transparently' work for processes as well as async * tasks that rely on callbacks. * - * Copyright (C) 1995, 1996, Olaf Kirch + * Copyright (C) 1995-1997, Olaf Kirch * * TCP callback races fixes (C) 1998 Red Hat Software * TCP send fixes (C) 1998 Red Hat Software @@ -948,7 +948,7 @@ struct rpc_timeout *timeo; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - int status; + int status = 0; dprintk("RPC: %4d xprt_transmit(%x)\n", task->tk_pid, *(u32 *)(req->rq_svec[0].iov_base)); @@ -1164,13 +1164,13 @@ task->tk_rqstp = req; req->rq_next = NULL; xprt_request_init(task, xprt); + + if (xprt->free && !RPCXPRT_CONGESTED(xprt)) + rpc_wake_up_next(&xprt->backlog); } else { task->tk_status = -EAGAIN; } - if (xprt->free && !RPCXPRT_CONGESTED(xprt)) - rpc_wake_up_next(&xprt->backlog); - return; bad_list: @@ -1226,6 +1226,7 @@ dprintk("RPC: %4d release request %p\n", task->tk_pid, req); +#if 0 /* remove slot from queue of pending */ start_bh_atomic(); if (task->tk_rpcwait) { @@ -1237,6 +1238,7 @@ rpc_remove_wait_queue(task); } end_bh_atomic(); +#endif /* Decrease congestion value. */ xprt->cong -= RPC_CWNDSCALE; @@ -1245,15 +1247,13 @@ /* If congestion threshold is not yet reached, pass on the request slot. * This looks kind of kludgy, but it guarantees backlogged requests * are served in order. - * N.B. This doesn't look completely safe, as the task is still - * on the backlog list after wake-up. */ if (!RPCXPRT_CONGESTED(xprt)) { struct rpc_task *next = rpc_wake_up_next(&xprt->backlog); if (next && next->tk_rqstp == 0) { - xprt->cong += RPC_CWNDSCALE; next->tk_rqstp = req; + xprt->cong += RPC_CWNDSCALE; xprt_request_init(next, xprt); return; } @@ -1263,9 +1263,8 @@ req->rq_next = xprt->free; xprt->free = req; - /* If not congested, wake up the next backlogged process */ - if (!RPCXPRT_CONGESTED(xprt)) - rpc_wake_up_next(&xprt->backlog); + if (!RPCXPRT_CONGESTED(xprt) && rpc_wake_up_next(&xprt->backlog) == 0) + wake_up(&xprt->cong_wait); } /* @@ -1327,6 +1326,7 @@ xprt->prot = proto; xprt->stream = (proto == IPPROTO_TCP)? 1 : 0; xprt->cwnd = RPC_INITCWND; + xprt->congtime = jiffies; #ifdef SOCK_HAS_USER_DATA inet->user_data = xprt; #else @@ -1503,6 +1503,7 @@ rpc_wake_up(&xprt->pending); rpc_wake_up(&xprt->backlog); rpc_wake_up(&xprt->reconn); + wake_up(&xprt->cong_wait); } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/wanrouter/patchlevel linux.ac/net/wanrouter/patchlevel --- linux.vanilla/net/wanrouter/patchlevel Sat Jan 9 21:50:52 1999 +++ linux.ac/net/wanrouter/patchlevel Thu Mar 11 12:51:59 1999 @@ -1 +1 @@ -2.0.3 +2.0.4 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/wanrouter/wanmain.c linux.ac/net/wanrouter/wanmain.c --- linux.vanilla/net/wanrouter/wanmain.c Thu Dec 31 18:10:50 1998 +++ linux.ac/net/wanrouter/wanmain.c Thu Mar 11 13:11:53 1999 @@ -47,7 +47,9 @@ #include /* WAN router API definitions */ #include /* __initfunc et al. */ -/****** Defines and Macros **************************************************/ +/* + * Defines and Macros + */ #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) @@ -56,48 +58,49 @@ #define max(a,b) (((a)>(b))?(a):(b)) #endif -/****** Function Prototypes *************************************************/ - /* - * Kernel loadable module interface. + * Function Prototypes */ +/* + * Kernel loadable module interface. + */ #ifdef MODULE int init_module (void); void cleanup_module (void); #endif -/* +/* * WAN device IOCTL handlers */ -static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf); -static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat); -static int device_shutdown (wan_device_t* wandev); -static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf); -static int device_del_if (wan_device_t* wandev, char* u_name); - -/* +static int device_setup(wan_device_t *wandev, wandev_conf_t *u_conf); +static int device_stat(wan_device_t *wandev, wandev_stat_t *u_stat); +static int device_shutdown(wan_device_t *wandev); +static int device_new_if(wan_device_t *wandev, wanif_conf_t *u_conf); +static int device_del_if(wan_device_t *wandev, char *u_name); + +/* * Miscellaneous */ -static wan_device_t* find_device (char* name); -static int delete_interface (wan_device_t* wandev, char* name, int forse); +static wan_device_t *find_device (char *name); +static int delete_interface (wan_device_t *wandev, char *name, int force); /* * Global Data */ static char fullname[] = "WAN Router"; -static char copyright[] = "(c) 1995-1997 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static char modname[] = ROUTER_NAME; /* short module name */ -wan_device_t * router_devlist = NULL; /* list of registered devices */ -static int devcnt = 0; +wan_device_t* router_devlist = NULL; /* list of registered devices */ +static int devcnt = 0; -/* - * Organizationally Unique Identifiers for encapsulation/decapsulation +/* + * Organize Unique Identifiers for encapsulation/decapsulation */ - + static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 }; #if 0 static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 }; @@ -114,12 +117,12 @@ fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); err = wanrouter_proc_init(); if (err) - printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname); + printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname); + + /* + * Initialise compiled in boards + */ - /* - * Initialise compiled in boards - */ - #ifdef CONFIG_VENDOR_SANGOMA wanpipe_init(); #endif @@ -133,14 +136,14 @@ */ /* - * Module 'insert' entry point. - * o print announcement - * o initialize static data - * o create /proc/net/router directory and static entries + * Module 'insert' entry point. + * o print announcement + * o initialize static data + * o create /proc/net/router directory and static entries * - * Return: 0 Ok + * Return: 0 Ok * < 0 error. - * Context: process + * Context: process */ int init_module (void) @@ -156,10 +159,10 @@ } /* - * Module 'remove' entry point. - * o delete /proc/net/router directory and static entries. + * Module 'remove' entry point. + * o delete /proc/net/router directory and static entries. */ - + void cleanup_module (void) { wanrouter_proc_cleanup(); @@ -168,27 +171,27 @@ #endif /* - * Kernel APIs + * Kernel APIs */ /* - * Register WAN device. - * o verify device credentials - * o create an entry for the device in the /proc/net/router directory - * o initialize internally maintained fields of the wan_device structure - * o link device data space to a singly-linked list - * o if it's the first device, then start kernel 'thread' - * o increment module use count + * Register WAN device. + * o verify device credentials + * o create an entry for the device in the /proc/net/router directory + * o initialize internally maintained fields of the wan_device structure + * o link device data space to a singly-linked list + * o if it's the first device, then start kernel 'thread' + * o increment module use count * - * Return: - * 0 Ok - * < 0 error. + * Return: + * 0 Ok + * < 0 error. * - * Context: process + * Context: process */ -int register_wan_device(wan_device_t* wandev) +int register_wan_device(wan_device_t *wandev) { int err, namelen; @@ -247,8 +250,8 @@ * Context: process */ - -int unregister_wan_device(char* name) + +int unregister_wan_device(char *name) { wan_device_t *wandev, *prev; @@ -294,7 +297,7 @@ */ -int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev) +int wanrouter_encapsulate (struct sk_buff *skb, struct device *dev) { int hdr_len = 0; @@ -336,7 +339,7 @@ */ -unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev) +unsigned short wanrouter_type_trans (struct sk_buff *skb, struct device *dev) { int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ unsigned short ethertype; @@ -379,18 +382,19 @@ return ethertype; } + /* * WAN device IOCTL. * o find WAN device associated with this node * o execute requested action or pass command to the device driver */ -int wanrouter_ioctl(struct inode* inode, struct file* file, +int wanrouter_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; - struct proc_dir_entry* dent; - wan_device_t* wandev; + struct proc_dir_entry *dent; + wan_device_t *wandev; if (!capable(CAP_NET_ADMIN)){ return -EPERM; @@ -455,9 +459,9 @@ * o call driver's setup() entry point */ -static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf) +static int device_setup (wan_device_t *wandev, wandev_conf_t *u_conf) { - void* data; + void *data; wandev_conf_t *conf; int err= -EINVAL; @@ -493,9 +497,9 @@ else err = -EFAULT; } - else + else err = -ENOBUFS; - + if (data) vfree(data); } @@ -510,9 +514,9 @@ * o call driver's shutdown() entry point */ -static int device_shutdown (wan_device_t* wandev) +static int device_shutdown (wan_device_t *wandev) { - struct device* dev; + struct device *dev; if (wandev->state == WAN_UNCONFIGURED) return 0; @@ -534,7 +538,7 @@ * Get WAN device status & statistics. */ -static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat) +static int device_stat (wan_device_t *wandev, wandev_stat_t *u_stat) { wandev_stat_t stat; @@ -563,10 +567,10 @@ * o register network interface */ -static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf) +static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf) { wanif_conf_t conf; - struct device* dev; + struct device *dev; int err; if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) @@ -619,13 +623,14 @@ return err; } + /* * Delete WAN logical channel. * o verify user address space * o copy configuration data to kernel address space */ -static int device_del_if (wan_device_t* wandev, char* u_name) +static int device_del_if (wan_device_t *wandev, char *u_name) { char name[WAN_IFNAME_SZ + 1]; @@ -638,6 +643,7 @@ return delete_interface(wandev, name, 0); } + /* * Miscellaneous Functions */ @@ -647,9 +653,9 @@ * Return pointer to the WAN device data space or NULL if device not found. */ -static wan_device_t* find_device (char* name) +static wan_device_t *find_device(char *name) { - wan_device_t* wandev; + wan_device_t *wandev; for (wandev = router_devlist;wandev && strcmp(wandev->name, name); wandev = wandev->next); @@ -673,7 +679,7 @@ * sure that opened interfaces are not removed! */ -static int delete_interface (wan_device_t* wandev, char* name, int force) +static int delete_interface (wan_device_t *wandev, char *name, int force) { struct device *dev, *prev; @@ -719,4 +725,3 @@ /* * End */ - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/wanrouter/wanproc.c linux.ac/net/wanrouter/wanproc.c --- linux.vanilla/net/wanrouter/wanproc.c Thu Nov 19 18:38:52 1998 +++ linux.ac/net/wanrouter/wanproc.c Sun Mar 21 00:40:52 1999 @@ -49,7 +49,7 @@ typedef struct wan_stat_entry { - struct wan_stat_entry * next; + struct wan_stat_entry *next; char *description; /* description string */ void *data; /* -> data */ unsigned data_type; /* data type */ @@ -61,7 +61,7 @@ /* Proc filesystem interface */ static int router_proc_perms(struct inode *, int); -static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); +static ssize_t router_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); /* Methods for preparing data for reading proc entries */ @@ -179,7 +179,7 @@ /* * /proc/net/router */ - + static struct proc_dir_entry proc_router = { 0, /* .low_ino */ @@ -399,7 +399,7 @@ wandev->ioport, wandev->irq, wandev->dma, - virt_to_phys(wandev->maddr), + wandev->maddr, wandev->msize, wandev->hw_opt[0], wandev->hw_opt[1], @@ -527,16 +527,12 @@ return cnt; } -/* - * End - */ - #else /* * No /proc - output stubs */ - + __initfunc(int wanrouter_proc_init(void)) { return 0; @@ -558,3 +554,9 @@ } #endif + + +/* + * End + */ +