diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Tue Feb 23 14:21:32 1999 +++ linux.ac/CREDITS Fri Feb 26 01:47:18 1999 @@ -1061,6 +1061,14 @@ S: L3R 8B2 S: Canada +N: Russell Kroll +E: rkroll@exploits.org +W: http://www.exploits.org/ +D: V4L Aztech radio card driver, mods to Aimslab driver +S: Post Office Box 49458 +S: Colorado Springs, Colorado 80949-9458 +S: USA + N: Gero Kuhlmann E: gero@gkminix.han.de D: mounting root via NFS diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes --- linux.vanilla/Documentation/Changes Sun Jan 24 19:55:29 1999 +++ linux.ac/Documentation/Changes Tue Feb 16 17:11:41 1999 @@ -250,6 +250,11 @@ The ISDN code in the stock 2.0 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 Tue Feb 23 14:21:32 1999 +++ linux.ac/Documentation/Configure.help Mon Mar 1 00:29:24 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. @@ -1089,25 +1089,6 @@ recommended to read the NET-3-HOWTO, available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. -Network aliasing -CONFIG_NET_ALIAS - If you say Y here, you will be able to set multiple network - addresses on the same low-level network device driver. This is - typically used for services that act differently based on the - address they listen on (e.g. "multihosting" or "virtual domains" or - "virtual hosting services" on the web server apache and the ftp - server wuftpd -- read the Virtual-Services-HOWTO, available via FTP - (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO) - or for connecting to different logical networks through the same - physical interface (most commonly an Ethernet networking card). See - Documentation/networking/alias.txt for more info. - - This is the generic part, later when configuring network protocol - options you will be asked for protocol-specific aliasing support, - and you will have to say Y to at least one of them, most likely to - "IP: aliasing support". If you need this feature (for any protocol, - like IP) say Y; if unsure, say N. - Socket filtering CONFIG_FILTER The Linux Socket Filter is derived from the Berkeley Packet Filter. @@ -1762,6 +1743,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 @@ -2099,7 +2092,7 @@ CONFIG_PNP_PARPORT Some IEEE-1284 conforming parallel-port devices can identify themselves when requested. Say Y to enable this feature, or M to - compile it as a module (parport_ieee1284.o). If in doubt, say N. + compile it as a module (parport_probe.o). If in doubt, say N. Enable loadable module support CONFIG_MODULES @@ -2735,20 +2728,6 @@ enabled. Those programs that would benefit from disabling this facility can do it on a per connection basis themselves. -IP: Drop source routed frames -CONFIG_IP_NOSR - Usually, the originator of an IP frame (packet) specifies only the - destination, and the hosts along the way do the routing, i.e. they - decide how to forward the frame. However, there is a feature of the - IP protocol that allows to specify the full route for a given frame - already at its origin. A frame with such a fully specified route is - called "source routed". The question now is whether we should honour - these route requests when such frames arrive, or if we should drop - all those frames instead. Honouring them can introduce security - problems (and is rarely a useful feature), and hence it is - recommended that you say Y here unless you really know what you're - doing. - IP: Allow large windows (not recommended if <16 MB of memory) CONFIG_SKB_LARGE On high speed, long distance networks the performance limit on @@ -3712,34 +3691,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. +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. -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). - - 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 @@ -4203,6 +4197,17 @@ say M here and read Documentation/modules.txt. The module will be called initio.o +Initio 91XXU(W) SCSI support +CONFIG_SCSI_INITIO + This is support for the Initio 91XXU(W) SCSI host adapter. + Please read the SCSI-HOWTO, available via FTP (user: anonymous) at + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called initio.o + PAS16 SCSI support CONFIG_SCSI_PAS16 This is support for a SCSI host adapter. It is explained in section @@ -4216,6 +4221,17 @@ The module will be called pas16.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Initio INI-A100U2W SCSI support +CONFIG_SCSI_INIA100 + This is support for the Initio INI-A100U2W SCSI host adapter. + Please read the SCSI-HOWTO, available via FTP (user: anonymous) at + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called a100u2w.o + PCI2000 support CONFIG_SCSI_PCI2000 This is support for the PCI2000I EIDE interface card which acts as a @@ -4408,6 +4424,23 @@ say M here and read Documentation/modules.txt. The module will be called NCR53c406.o. +Symbios Logic sym53c416 support +CONFIG_SCSI_SYM53C416 + This is support for the sym53c416 SCSI host adapter. This is the + SCSI adapter that comes with some hp scanners. This driver requires that + the sym53c416 is configured first using some sort of pnp configuration + program (e.g. isapnp) or by a PnP aware BIOS. If you are using isapnp then + you need to compile it as a module and then load it using insmod after + isapnp has run. The parameters of the configured card(s) should be passed + to the driver. The format is: + + insmod sym53c416 sym53c416=, [sym53c416_1=,] + + There is support for up to four adapters. If you want to compile this + driver as a module ( = code which can be inserted in and removed from + the running kernel whenever you want), say M here and read + Documentation/modules.txt. + Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support CONFIG_SCSI_DC390T This driver supports PCI SCSI host adapters based on the Am53C974A @@ -7034,11 +7067,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 @@ -8924,6 +8958,20 @@ here (the module will be called sound.o) if you haven't found a driver for your sound card above, then pick your driver from the list below. + +Persistent DMA buffers +CONFIG_SOUND_DMAP + Linux can often have problems allocating DMA buffers for ISA cards on + machines with more than 16MB of RAM. This is because ISA DMA buffers + must exist below the 16MB boundry and it is quite possible that we + can't find a large enough free block in this region after the machine + has been running for any amount of time. If you say Y here the DMA + buffers (64Kb) will be allocated at boot time and kept until the + shutdown. This option is only usefull if you say Y to OSS sound + modules. If you say M to OSS sound modules then you can just pass to + the sound.o module a "dmabuf=1" command-line argument. + + Say Y unless you have 16MB or less RAM or a PCI sound card. Support for Aztech Sound Galaxy (non-PnP) cards CONFIG_SOUND_SGALAXY @@ -9463,6 +9511,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 @@ -10503,6 +10556,44 @@ CONFIG_RADIO_SF16FMI_PORT Enter the I/O port of your SF16FMI radio card. +Typhoon Radio +CONFIG_RADIO_TYPHOON + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-typhoon.o + +Support for /proc/radio-typhoon +CONFIG_RADIO_TYPHOON_PROC_FS + Say Y here if you want the typhoon radio card driver to write + status information (frequency, volume, muted, mute frequency, + base address) to /proc/radio-typhoon. The file can be viewed with + your favorite pager (i.e. use "more /proc/radio-typhoon" or "less + /proc/radio-typhoon" or simply "cat /proc/radio-typhoon"). + +Typhoon I/O port (0x316 or 0x336) +CONFIG_RADIO_TYPHOON_PORT + Enter the I/O port of your Typhoon or EcoRadio radio card. + +Typhoon frequency set when muting the device (kHz) +CONFIG_RADIO_TYPHOON_MUTEFREQ + Enter the frequency used for muting the radio. The device is never + completely silent. If the volume is just turned down, you can still + hear silent voices and music. For that reason, the frequency of the + radio device is set to the frequency you can enter here whenever + the device is muted. There should be no local radio station at that + frequency. + Zoltrix Radio CONFIG_RADIO_ZOLTRIX Choose Y here if you have one of these FM radio cards, and then fill @@ -10748,24 +10839,10 @@ Documentation/modules.txt. IrLAN emulates an Ethernet and makes it possible to put up a wireless LAN using infrared beams. -IrLAN Client Protocol -CONFIG_IRLAN_CLIENT - Say Y here if you want to build support for the IrLAN client - protocol. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLAN client protocol can be used to - talk with infrared access points like the HP NetbeamIR, or the ESI - JetEye NET. You can also connect to another Linux machine running - the IrLAN server protocol for ad-hoc networking! - -IrLAN Server Protocol -CONFIG_IRLAN_SERVER - Say Y here if you want to build support for infrared LAN access. If - you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLAN server protocol makes it - possible to set up a wireless LAN with a machine running the IrLAN - client protocol. Notice that the IrLAN server protocol currently - only emulates an access point and does not implement the ad-hoc - specification of IrLAN, but this will not be noticeable by the user. + The IrLAN protocol can be used to talk with infrared access points + like the HP NetbeamIR, or the ESI JetEye NET. You can also connect + to another Linux machine running the IrLAN protocol for ac-hoc + networking! IrOBEX Protocol CONFIG_IROBEX @@ -10877,6 +10954,15 @@ the normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for Tekram dongles you will have to insert "irattach -d tekram" in the /etc/irda/drivers script. + +Greenwich GIrBIL dongle +CONFIG_GIRBIL_DONGLE + Say Y here if you want to build support for the Greenwich GIrBIL + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Greenwich dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Greenwich dongles you will have to + insert "irattach -d girbil" in the /etc/irda/drivers script. VME (Motorola and BVM) support CONFIG_VME 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/sound/CMI8330 linux.ac/Documentation/sound/CMI8330 --- linux.vanilla/Documentation/sound/CMI8330 Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/sound/CMI8330 Sat Feb 27 21:02:23 1999 @@ -0,0 +1,85 @@ +How to enable CMI 8330 soundchip on Linux +------------------------------------------ +Stefan Laudat + +Hello folks, + + The CMI8330 soundchip is a very small chip found on many recent + motherboards. In order to use it you just have to use a proper + isapnp.conf and a little bit of patience. + + Of course you will have to compile kernel sound support as module, + as shown below: + +CONFIG_SOUND=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_ADLIB=m +CONFIG_SOUND_MPU401=m +# Just for fun :) +CONFIG_SOUND_MSS=m + + The /etc/isapnp.conf file will be: + + + +(READPORT 0x0203) +(ISOLATE PRESERVE) +(IDENTIFY *) +(VERBOSITY 2) +(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING +(VERIFYLD N) +# WSS + +(CONFIGURE CMI0001/16777472 (LD 0 +(IO 0 (SIZE 8) (BASE 0x0530)) +(IO 1 (SIZE 8) (BASE 0x0388)) +(INT 0 (IRQ 5 (MODE +E))) +(DMA 0 (CHANNEL 0)) +(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# Control device ? + +(CONFIGURE CMI0001/16777472 (LD 1 +(IO 0 (SIZE 2) (BASE 0x0330)) +(INT 0 (IRQ 11 (MODE +E))) +(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# Joystick + +(CONFIGURE CMI0001/16777472 (LD 2 +(IO 0 (SIZE 8) (BASE 0x0200)) +(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# SB... +(CONFIGURE CMI0001/16777472 (LD 3 +(IO 0 (SIZE 16) (BASE 0x0220)) +(INT 0 (IRQ 7 (MODE +E))) +(DMA 0 (CHANNEL 1)) +(DMA 1 (CHANNEL 5)) +(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + + +(WAITFORKEY) + + + + The module sequence is trivial: + +/sbin/modprobe sound +/sbin/insmod uart401 +/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1 +/sbin/insmod mpu401 io=0x330 +/sbin/insmod opl3 io=0x388 +# In case you want the MSS instead of SB use +/sbin/insmod ad1848 io=0x530 dma=0 irq=5 + + The soundchip is now fully initialized. Enjoy it. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Feb 23 14:21:32 1999 +++ linux.ac/MAINTAINERS Mon Mar 1 18:24:33 1999 @@ -324,7 +324,7 @@ M: arobinso@nyx.net L: linux-kernel@vger.rutgers.edu W: http://www.nyx.net/~arobinso -S: Maintainted +S: Maintained HFS FILESYSTEM P: Adrian Sun @@ -637,6 +637,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 @@ -678,9 +683,18 @@ S: Supported SPARC: +P: David S. Miller +M: davem@dm.cobaltmicro.com P: Eddie C. Dost M: ecd@skynet.be +P: Jakub Jelinek +M: jj@sunsite.ms.mff.cuni.cz +P: Anton Blanchard +M: anton@jubilex.progsoc.uts.edu.au L: sparclinux@vger.rutgers.edu +L: ultralinux@vger.rutgers.edu +W: http://ultra.linux.cz +W: http://www.geog.ubc.ca/s_linux.html S: Maintained SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER @@ -704,10 +718,8 @@ S: Supported STARMODE RADIO IP (STRIP) PROTOCOL DRIVER -P: Stuart Cheshire -M: cheshire@cs.stanford.edu W: http://mosquitonet.Stanford.EDU/strip.html -S: Maintained +S: Unsupported ? SVGA HANDLING P: Martin Mares @@ -804,4 +816,4 @@ THE REST P: Linus Torvalds -S: Buried alive in diapers +S: Buried alive in reporters diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Tue Feb 23 14:21:32 1999 +++ linux.ac/Makefile Tue Mar 2 01:59:31 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 2 -EXTRAVERSION = +EXTRAVERSION = -ac7 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -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/arch/alpha/defconfig linux.ac/arch/alpha/defconfig --- linux.vanilla/arch/alpha/defconfig Mon Dec 28 23:09:39 1998 +++ linux.ac/arch/alpha/defconfig Fri Feb 26 01:59:54 1999 @@ -91,7 +91,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -108,7 +107,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # 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 Sun Jan 24 19:55:29 1999 +++ linux.ac/arch/alpha/kernel/time.c Wed Feb 24 16:35:19 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_state = TIME_ERROR; /* p. 24, (a) */ 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 Sun Nov 8 15:08:43 1998 +++ linux.ac/arch/arm/defconfig Thu Feb 25 22:38:32 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,47 +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 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 # @@ -100,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 # @@ -112,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 Mon Feb 22 21:50:54 1999 @@ -1,51 +1,56 @@ +#include + /*============================================================================ * 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 +62,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 +124,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 +188,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 Sun Jan 24 19:55:30 1999 +++ linux.ac/arch/arm/kernel/time.c Fri Jan 22 10:49:32 1999 @@ -130,27 +130,12 @@ time_state = TIME_ERROR; /* p. 24, (a) */ 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/defconfig linux.ac/arch/i386/defconfig --- linux.vanilla/arch/i386/defconfig Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/i386/defconfig Fri Feb 26 01:59:54 1999 @@ -104,7 +104,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -121,7 +120,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # 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/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 Tue Mar 2 01:15:36 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 @@ -197,7 +202,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 +230,7 @@ #ifdef CONFIG_PROC_FS static void compute_ascii (void); #endif +static int k6_has_ranges(void); struct set_mtrr_context @@ -236,6 +242,15 @@ }; /* + * No point continually digging through complex CPU conditionals.. + */ + +static int mtrr_flags; + +#define MTRR_PRESENT 1 +#define MTRR_WRCOMB 2 + +/* * 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 @@ -267,13 +282,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 +311,9 @@ { unsigned long tmp; + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return; + /* flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); @@ -319,6 +339,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 +363,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 +444,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 +621,16 @@ 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; + } + state->def_type = 0; + state->enabled = 1; } /* End Function get_mtrr_state */ @@ -545,6 +653,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 +848,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 (base + size < 0x100000) - { - printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n", - base, size); - 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; } - /* 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) + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { - 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 +963,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 +1282,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 +1315,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 +1357,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/process.c linux.ac/arch/i386/kernel/process.c --- linux.vanilla/arch/i386/kernel/process.c Sun Jan 24 19:55:30 1999 +++ linux.ac/arch/i386/kernel/process.c Mon Mar 1 00:21:35 1999 @@ -316,7 +316,7 @@ /* Make sure the first page is mapped to the start of physical memory. It is normally not mapped, to trap kernel NULL pointer dereferences. */ - pg0[0] = 7; + pg0[0] = _PAGE_USER | _PAGE_RW | _PAGE_PRESENT; /* * Use `swapper_pg_dir' as our page directory. We bother with diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/ptrace.c linux.ac/arch/i386/kernel/ptrace.c --- linux.vanilla/arch/i386/kernel/ptrace.c Thu Jan 14 01:25:21 1999 +++ linux.ac/arch/i386/kernel/ptrace.c Wed Feb 24 16:38:51 1999 @@ -354,6 +354,7 @@ { struct task_struct *child; struct user * dummy = NULL; + unsigned long flags; int i, ret; lock_kernel(); @@ -391,15 +392,15 @@ if (child->flags & PF_PTRACED) goto out; child->flags |= PF_PTRACED; - if (child->p_pptr != current) { - unsigned long flags; - write_lock_irqsave(&tasklist_lock, flags); + write_lock_irqsave(&tasklist_lock, flags); + if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); } + write_unlock_irqrestore(&tasklist_lock, flags); + send_sig(SIGSTOP, child, 1); ret = 0; goto out; @@ -559,7 +560,6 @@ } case PTRACE_DETACH: { /* detach a process that was attached. */ - unsigned long flags; long tmp; ret = -EIO; 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 Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/i386/kernel/setup.c Sat Feb 27 17:18:12 1999 @@ -381,7 +381,17 @@ } -__initfunc(static int amd_model(struct cpuinfo_x86 *c)) +#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)) { unsigned int n, dummy, *v; @@ -401,6 +411,76 @@ return 1; } +__initfunc(static int amd_model(struct cpuinfo_x86 *c)) +{ + u32 l, h; + unsigned long flags; + int mbytes = max_mapnr >> (20-PAGE_SHIFT); + + int r=get_model_name(c); + + /* + * Now do the cache operations. + */ + + switch(c->x86) + { + case 5: + if( c->x86_model < 6 ) + { + /* Anyone with a K5 want to fill this in */ + break; + } + + /* K6 with old style WHCR */ + if( c->x86_model < 8 || + (c->x86_model== 8 && c->x86_mask < 8)) + { + /* We can only write allocate on the low 508Mb */ + if(mbytes>508) + mbytes=508; + + rdmsr(0xC0000082, l, h); + if((l&0x0000FFFF)==0) + { + l=(1<<0)|(mbytes/4); + save_flags(flags); + __cli(); + __asm__ __volatile__ ("wbinvd": : :"memory"); + wrmsr(0xC0000082, l, h); + restore_flags(flags); + printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", + mbytes); + + } + break; + } + if (c->x86_model == 8 || c->x86_model == 9) + { + /* The more serious chips .. */ + + if(mbytes>4092) + mbytes=4092; + rdmsr(0xC0000082, l, h); + if((l&0xFFFF0000)==0) + { + l=(mbytes<<22)|(1<<16); + save_flags(flags); + __cli(); + __asm__ __volatile__ ("wbinvd": : :"memory"); + wrmsr(0xC0000082, l, h); + restore_flags(flags); + printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", + mbytes); + } + break; + } + break; + } + return r; +} + + /* * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ @@ -517,7 +597,7 @@ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { - amd_model(c); /* get CPU marketing name */ + get_model_name(c); /* get CPU marketing name */ c->x86_capability&=~X86_FEATURE_TSC; return; } @@ -726,15 +806,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)) static char *cpu_vendor_names[] __initdata = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" }; @@ -785,8 +856,8 @@ static char *x86_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce", "cx8", "9", "10", "sep", "12", "pge", "14", "cmov", - "16", "17", "18", "19", "20", "21", "22", "mmx", - "24", "25", "26", "27", "28", "29", "30", "31" + "16", "17", "snum", "19", "20", "21", "22", "mmx", + "24", "kni", "26", "27", "28", "29", "30", "31" }; struct cpuinfo_x86 *c = cpu_data; int i, n; 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 Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/i386/kernel/smp.c Mon Mar 1 00:21:35 1999 @@ -474,7 +474,7 @@ */ cfg=pg0[0]; - pg0[0] = (mp_lapic_addr | 7); + pg0[0] = (mp_lapic_addr | _PAGE_USER | _PAGE_RW | _PAGE_PRESENT); local_flush_tlb(); boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID)); @@ -1329,7 +1329,7 @@ * Install writable page 0 entry. */ cfg = pg0[0]; - pg0[0] = 3; /* writeable, present, addr 0 */ + pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* writeable, present, addr 0 */ local_flush_tlb(); /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/defconfig linux.ac/arch/m68k/defconfig --- linux.vanilla/arch/m68k/defconfig Sun Jan 24 19:55:30 1999 +++ linux.ac/arch/m68k/defconfig Fri Feb 26 01:59:54 1999 @@ -78,7 +78,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -95,7 +94,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set 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/defconfig linux.ac/arch/mips/defconfig --- linux.vanilla/arch/mips/defconfig Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/defconfig Fri Feb 26 01:59:54 1999 @@ -90,7 +90,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -107,7 +106,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # 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 Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/mips/kernel/sysirix.c Fri Dec 4 17:14:23 1998 @@ -788,7 +788,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; } @@ -1111,7 +1112,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; } @@ -1583,7 +1585,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; } @@ -1727,7 +1730,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; } @@ -1879,7 +1883,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; } @@ -2040,7 +2045,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; @@ -2151,7 +2157,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; @@ -2212,7 +2219,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/apus_defconfig linux.ac/arch/ppc/apus_defconfig --- linux.vanilla/arch/ppc/apus_defconfig Mon Dec 28 23:09:41 1998 +++ linux.ac/arch/ppc/apus_defconfig Fri Feb 26 01:59:54 1999 @@ -100,7 +100,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -118,7 +117,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/chrp_defconfig linux.ac/arch/ppc/chrp_defconfig --- linux.vanilla/arch/ppc/chrp_defconfig Mon Dec 28 23:09:41 1998 +++ linux.ac/arch/ppc/chrp_defconfig Fri Feb 26 01:59:54 1999 @@ -85,7 +85,6 @@ # CONFIG_PACKET is not set # 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 @@ -99,7 +98,6 @@ CONFIG_IP_ALIAS=y # CONFIG_SYN_COOKIES is not set CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_IPX is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/common_defconfig linux.ac/arch/ppc/common_defconfig --- linux.vanilla/arch/ppc/common_defconfig Sat Jan 9 21:50:36 1999 +++ linux.ac/arch/ppc/common_defconfig Fri Feb 26 01:59:54 1999 @@ -87,7 +87,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -100,7 +99,6 @@ # CONFIG_IP_ALIAS is not set CONFIG_SYN_COOKIES=y # CONFIG_INET_RARP is not set -# CONFIG_IP_NOSR is not set CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_IPX is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/defconfig linux.ac/arch/ppc/defconfig --- linux.vanilla/arch/ppc/defconfig Wed Jan 6 23:02:18 1999 +++ linux.ac/arch/ppc/defconfig Fri Feb 26 01:59:55 1999 @@ -102,7 +102,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -120,7 +119,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/process.c linux.ac/arch/ppc/kernel/process.c --- linux.vanilla/arch/ppc/kernel/process.c Sat Jan 9 21:50:36 1999 +++ linux.ac/arch/ppc/kernel/process.c Sat Jan 9 21:57:09 1999 @@ -67,7 +67,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; 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/ppc/mbx_defconfig linux.ac/arch/ppc/mbx_defconfig --- linux.vanilla/arch/ppc/mbx_defconfig Mon Dec 28 23:09:41 1998 +++ linux.ac/arch/ppc/mbx_defconfig Fri Feb 26 01:59:55 1999 @@ -14,7 +14,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_APUS is not set CONFIG_MBX=y -CONFIG_SMP=n CONFIG_MACH_SPECIFIC=y CONFIG_SERIAL_CONSOLE=y @@ -75,7 +74,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -90,7 +88,6 @@ # CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set # CONFIG_IPX is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/pmac_defconfig linux.ac/arch/ppc/pmac_defconfig --- linux.vanilla/arch/ppc/pmac_defconfig Wed Jan 6 23:02:18 1999 +++ linux.ac/arch/ppc/pmac_defconfig Fri Feb 26 01:59:55 1999 @@ -102,7 +102,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -120,7 +119,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/prep_defconfig linux.ac/arch/ppc/prep_defconfig --- linux.vanilla/arch/ppc/prep_defconfig Mon Dec 28 23:09:41 1998 +++ linux.ac/arch/ppc/prep_defconfig Fri Feb 26 01:59:55 1999 @@ -84,7 +84,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -97,7 +96,6 @@ # CONFIG_IP_ALIAS is not set CONFIG_SYN_COOKIES=y # CONFIG_INET_RARP is not set -# CONFIG_IP_NOSR is not set CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_IPX is not set diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/defconfig linux.ac/arch/sparc/defconfig --- linux.vanilla/arch/sparc/defconfig Tue Dec 22 23:19:33 1998 +++ linux.ac/arch/sparc/defconfig Fri Feb 26 01:59:55 1999 @@ -101,7 +101,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -118,7 +117,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=m -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set 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/defconfig linux.ac/arch/sparc64/defconfig --- linux.vanilla/arch/sparc64/defconfig Tue Dec 22 23:19:34 1998 +++ linux.ac/arch/sparc64/defconfig Fri Feb 26 01:59:55 1999 @@ -128,7 +128,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -145,7 +144,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=m -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set 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/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 Sun Jan 24 23:54:36 1999 @@ -11,6 +11,7 @@ fi 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 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 24 23:54:36 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 Sun Jan 24 23:54:36 1999 @@ -136,6 +136,7 @@ #include #include #include +#include #include #include #include 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 Sun Jan 24 23:54:36 1999 @@ -81,6 +81,8 @@ icside_irqenable_arcin_v5, icside_irqdisable_arcin_v5, NULL, + NULL, + NULL, NULL }; @@ -106,9 +108,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 }; @@ -220,8 +235,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 Sun Jan 24 23:54:36 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/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 Sun Jan 24 23:54:36 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/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 Sun Jan 24 23:54:37 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 Sun Jan 24 23:54:37 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/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 Sun Jan 24 23:54:37 1999 @@ -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 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 Jan 24 23:54:37 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 @@ -471,6 +473,25 @@ return error; } +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 +506,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 @@ -942,17 +959,13 @@ 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_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]); + ether3_get_dev(my_ethers[i], ec[i]); if(register_netdev(my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_ECARDS; i++) { if(my_ethers[i]) { kfree(my_ethers[i]); my_ethers[i] = NULL; 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 Sun Jan 24 23:54:37 1999 @@ -461,6 +461,8 @@ etherh_irq_enable, etherh_irq_disable, NULL, + NULL, + NULL, NULL }; 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 Sun Jan 24 23:54:37 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 * @@ -186,26 +188,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 +197,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 +230,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; +} + +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); + 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 +410,7 @@ } /* wait 25 cs. SCSI standard says 250ms. */ - acornscsi_csdelay (25); + acornscsi_csdelay(25); } /*============================================================================================= @@ -461,80 +480,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 +582,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 +590,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 +603,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 +611,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 +645,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 +666,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 +686,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 +694,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 +704,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 +722,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 +730,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 +743,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 +757,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 +777,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 +798,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 +828,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 +897,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 +908,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 +926,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 +945,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 +954,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 +971,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 +990,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 +999,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 +1010,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 +1036,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 +1059,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 +1069,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 +1097,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 +1108,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 +1127,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 +1145,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 +1155,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 +1182,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 +1197,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 +1220,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 +1276,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 +1296,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 +1393,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); - message = sbic_arm_read (host->scsi.io_port, DATA); + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); + + 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 +1487,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 +1511,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 +1521,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 +1535,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 +1551,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 +1566,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 +1585,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 +1599,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 +1627,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 +1644,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 +1676,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 +1699,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 +1720,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 +1770,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 +1785,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 +1815,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 +1823,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 +1853,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 +1862,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 +1891,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 +1937,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 +1986,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 +2007,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 +2033,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 +2071,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 +2084,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 +2143,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 +2190,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 +2215,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 +2273,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 +2322,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 +2392,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 +2486,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 +2508,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 +2524,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 +2555,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 +2578,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 +2600,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 +2608,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: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * 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) * 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 +2815,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 +2832,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 +2856,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 +2883,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 +2891,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 +2929,7 @@ host->scsi.irq = NO_IRQ; } - acornscsi_init (host); + acornscsi_init(host); ++count; } @@ -2688,12 +2937,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 +2950,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 +2985,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 +3021,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 +3036,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 +3058,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 Jan 24 23:54:37 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 */ @@ -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/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 24 23:54:37 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 Jan 24 23:54:37 1999 @@ -123,6 +123,8 @@ eesoxscsi_irqenable, eesoxscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -379,6 +381,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 Jan 24 23:54:37 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; - } + info->scsi.phase = PHASE_COMMAND; } -/* 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; - } -} - -/* 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: @@ -1819,7 +2021,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 +2035,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 +2296,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 +2350,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 Sun Jan 24 23:54:37 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 Jan 24 23:54:37 1999 @@ -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 Jan 24 23:54:37 1999 @@ -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 24 23:54:37 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 Sun Jan 24 23:54:37 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/ap1000/apfddi.c linux.ac/drivers/ap1000/apfddi.c --- linux.vanilla/drivers/ap1000/apfddi.c Sun Nov 8 15:08:12 1998 +++ linux.ac/drivers/ap1000/apfddi.c Mon Mar 1 14:24:08 1999 @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/ap1000/ringbuf.c linux.ac/drivers/ap1000/ringbuf.c --- linux.vanilla/drivers/ap1000/ringbuf.c Sun Nov 8 15:08:12 1998 +++ linux.ac/drivers/ap1000/ringbuf.c Mon Mar 1 14:24:08 1999 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/genhd.c linux.ac/drivers/block/genhd.c --- linux.vanilla/drivers/block/genhd.c Tue Feb 23 14:21:32 1999 +++ linux.ac/drivers/block/genhd.c Sat Feb 20 01:06:46 1999 @@ -879,7 +879,7 @@ res = 0; for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { - if(!(bh = bread(dev,blk,get_ptable_blocksize(dev)))) { + if(!(bh = bread(dev,blk,512))) { printk("Dev %s: unable to read RDB block %d\n", kdevname(dev),blk); goto rdb_done; @@ -896,7 +896,7 @@ blk = htonl(rdb->rdb_PartitionList); brelse(bh); for (part = 1; blk > 0 && part <= 16; part++) { - if (!(bh = bread(dev,blk, get_ptable_blocksize(dev)))) { + if (!(bh = bread(dev,blk, 512))) { printk("Dev %s: unable to read partition block %d\n", kdevname(dev),blk); goto rdb_done; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/hd.c linux.ac/drivers/block/hd.c --- linux.vanilla/drivers/block/hd.c Tue Jan 19 02:57:23 1999 +++ linux.ac/drivers/block/hd.c Thu Feb 18 20:27:35 1999 @@ -744,11 +744,12 @@ */ - if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) { if (cmos_disks & 0x0f) NR_HD = 2; else NR_HD = 1; + } } #endif /* __i386__ */ for (drive=0 ; drive < NR_HD ; drive++) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-cd.c linux.ac/drivers/block/ide-cd.c --- linux.vanilla/drivers/block/ide-cd.c Sun Jan 24 19:55:33 1999 +++ linux.ac/drivers/block/ide-cd.c Wed Feb 24 17:04:26 1999 @@ -33,6 +33,7 @@ * boot * -Integrate DVD-ROM support in driver. Thanks to Merete Gotsæd-Petersen * of Pioneer Denmark for providing me with a drive for testing. + * -Implement Features and Profiles. * * * ---------------------------------- @@ -230,9 +231,23 @@ * 4.52 Jan 19, 1999 -- Jens Axboe * - Detect DVD-ROM/RAM drives * + * 4.53 Feb 22, 1999 - Include other model Samsung and one Goldstar + * drive in transfer size limit. + * - Fix the I/O error when doing eject without a medium + * loaded on some drives. + * - CDROMREADMODE2 is now implemented through + * CDROMREADRAW, since many drives don't support + * MODE2 (even though ATAPI 2.6 says they must). + * - Added ignore parameter to ide-cd (as a module), eg + * insmod ide-cd ignore='hda hdb' + * Useful when using ide-cd in conjunction with + * ide-scsi. TODO: non-modular way of doing the + * same. + * + * *************************************************************************/ -#define IDECD_VERSION "4.52" +#define IDECD_VERSION "4.53" #include #include @@ -252,7 +267,6 @@ #include "ide.h" #include "ide-cd.h" - /**************************************************************************** * Generic packet command support and error handling routines. */ @@ -1527,6 +1541,10 @@ CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; stat = 0; } + + /* no medium, that's alright. */ + if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a) + stat = 0; if (stat == 0) CDROM_STATE_FLAGS (drive)->door_locked = lockflag; @@ -1806,7 +1824,6 @@ return cdrom_queue_packet_command (drive, &pc); } - /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ static int @@ -2092,22 +2109,17 @@ if (cmd == CDROMREADMODE1) { blocksize = CD_FRAMESIZE; format = 2; - } else if (cmd == CDROMREADMODE2) { - blocksize = CD_FRAMESIZE_RAW0; - format = 3; - } else { + } else { /* for RAW and MODE2. */ blocksize = CD_FRAMESIZE_RAW; format = 0; } - stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize); - if (stat) return stat; + + copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); - copy_from_user (&msf, (void *)arg, sizeof (msf)); + lba = msf_to_lba(msf.cdmsf_min0, + msf.cdmsf_sec0, + msf.cdmsf_frame0); - lba = msf_to_lba (msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0); - /* Make sure the TOC is up to date. */ stat = cdrom_read_toc (drive, NULL); if (stat) return stat; @@ -2117,14 +2129,21 @@ if (lba < 0 || lba >= toc->capacity) return -EINVAL; - buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL); + buf = (char *) kmalloc (blocksize, GFP_KERNEL); if (buf == NULL) return -ENOMEM; stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize, NULL); - if (stat == 0) - copy_to_user ((char *)arg, buf, blocksize); + + if (stat == 0) { + if (cmd == CDROMREADMODE2) { + /* For Mode2, skip the Sync, Header, and Subheader */ + copy_to_user_ret((char *)arg, buf+16, CD_FRAMESIZE_RAW0, -EFAULT); + } else { + copy_to_user_ret((char *)arg, buf, blocksize, -EFAULT); + } + } kfree (buf); return stat; @@ -2486,14 +2505,12 @@ static int ide_cdrom_reset (struct cdrom_device_info *cdi) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct request req; ide_init_drive_cmd (&req); req.cmd = RESET_DRIVE_COMMAND; return ide_do_drive_cmd (drive, &req, ide_wait); - } @@ -2501,9 +2518,10 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct atapi_request_sense rq; if (position) { - int stat = cdrom_lockdoor (drive, 0, NULL); + int stat = cdrom_lockdoor (drive, 0, &rq); if (stat) return stat; } @@ -2980,12 +2998,17 @@ CDROM_CONFIG_FLAGS (drive)->no_eject = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0; - /* limit transfer size per interrupt. currently only one Samsung - drive needs this. */ + /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; - if (drive->id != NULL) - if (strcmp (drive->id->model, "SAMSUNG CD-ROM SCR-2432") == 0) + if (drive->id != NULL) { + if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430")) + CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + else if (!strcmp (drive->id->model, "GCD-R580B")) + CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + /* 124/SECTORS_PER_FRAME; ? */ + } #if ! STANDARD_ATAPI /* by default Sanyo 3 CD changer support is turned off and @@ -3155,7 +3178,13 @@ NULL }; +/* options */ +char *ignore = NULL; + #ifdef MODULE +MODULE_PARM(ignore, "s"); +MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); + int init_module (void) { return ide_cdrom_init(); @@ -3183,6 +3212,12 @@ MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { + /* skip drives that we were told to ignore */ + if (ignore != NULL) + if (strstr(ignore, drive->name)) { + printk("ide-cd: ignoring drive %s\n", drive->name); + continue; + } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-cd.h linux.ac/drivers/block/ide-cd.h --- linux.vanilla/drivers/block/ide-cd.h Sun Jan 24 19:55:33 1999 +++ linux.ac/drivers/block/ide-cd.h Sun Feb 28 02:23:57 1999 @@ -85,6 +85,9 @@ #define MECHANISM_STATUS 0xbd #define READ_CD 0xbe +/* DVD Opcodes */ +#define DVD_GET_PERFORMANCE 0xac + /* Page codes for mode sense/set */ @@ -562,7 +565,7 @@ /* Sector buffer. If a read request wants only the first part of a cdrom block, we cache the rest of the block here, - in the expectation that that data is going to be wanted soon. + in the expectation that the data is going to be wanted soon. SECTOR_BUFFERED is the number of the first buffered sector, and NSECTORS_BUFFERED is the number of sectors in the buffer. Before the buffer is allocated, we should have @@ -656,6 +659,7 @@ { PLAY_CD, "Play CD" }, { MECHANISM_STATUS, "Mechanism Status" }, { READ_CD, "Read CD" }, + { DVD_GET_PERFORMANCE, "Get Performance" }, }; @@ -776,7 +780,8 @@ { 0x6400, "Illegal mode for this track or incompatible medium" }, - { 0xb900, "Play operation oborted (sic)" }, + /* Following error is misspelled in ATAPI 2.6 */ + { 0xb900, "Play operation oborted [sic]" }, { 0xbf00, "Loss of streaming" }, }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.c linux.ac/drivers/block/ide.c --- linux.vanilla/drivers/block/ide.c Tue Jan 19 02:57:24 1999 +++ linux.ac/drivers/block/ide.c Mon Feb 1 00:37:11 1999 @@ -2068,6 +2068,12 @@ (unsigned long *) &loc->start)) return -EFAULT; return 0; } + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[HWIF(drive)->major] + [minor&PARTN_MASK], + (int *)arg); + case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); 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 Sun Nov 8 15:07:36 1998 +++ linux.ac/drivers/block/rd.c Mon Feb 1 00:39:15 1999 @@ -170,14 +170,12 @@ break; case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE, (long *) arg, - sizeof(long)); - if (err) - return err; - put_user(rd_length[MINOR(inode->i_rdev)] / 512, + return put_user(rd_length[MINOR(inode->i_rdev)] / 512, (long *) arg); - return 0; - + case BLKSSZGET: + /* Block size of media */ + return put_user(rd_blocksizes[MINOR(inode->i_rdev)], + (int *)arg); default: break; }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/cdrom.c linux.ac/drivers/cdrom/cdrom.c --- linux.vanilla/drivers/cdrom/cdrom.c Tue Jan 19 02:57:24 1999 +++ linux.ac/drivers/cdrom/cdrom.c Tue Mar 2 01:53:25 1999 @@ -24,8 +24,9 @@ -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. - - + + -- Sync options and capability flags. + Revision History @@ -97,17 +98,29 @@ cdi->options in various ioctl. -- Added version to proc entry. - 2.52 Jan 16, 1998 - Jens Axboe + 2.52 Jan 16, 1999 - Jens Axboe -- Fixed an error in open_for_data where we would sometimes not return the correct error value. Thanks Huba Gaspar . -- Fixed module usage count - usage was based on /proc/sys/dev instead of /proc/sys/dev/cdrom. This could lead to an oops when other - modules had entries in dev. + modules had entries in dev. Feb 02 - real bug was in sysctl.c where + dev would be removed even though it was used. cdrom.c just illuminated + that bug. + + 2.53 Feb 22, 1999 - Jens Axboe + -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has + been "rewritten" because capabilities and options aren't in sync. They + should be... + -- Added CDROM_LOCKDOOR ioctl. Locks the door and keeps it that way. + -- Added CDROM_RESET ioctl. + -- Added CDROM_DEBUG ioctl. Enable debug messages on-the-fly. + -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs + from parsing /proc/sys/dev/cdrom/info. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 2.52" -#define VERSION "Id: cdrom.c 2.52 1999/01/16" +#define REVISION "Revision: 2.53" +#define VERSION "Id: cdrom.c 2.53 1999/02/22" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -144,6 +157,8 @@ /* used to tell the module to turn on full debugging messages */ static int debug = 0; +/* used to keep tray locked at all times */ +static int keeplocked = 0; /* default compatibility mode */ static int autoclose=1; static int autoeject=0; @@ -164,13 +179,11 @@ #endif /* These are used to simplify getting data in from and back to user land */ -#define IOCTL_IN(arg, type, in) { \ - if ( copy_from_user(&in, (type *) arg, sizeof in) ) \ - return -EFAULT; } - -#define IOCTL_OUT(arg, type, out) { \ - if ( copy_to_user((type *) arg, &out, sizeof out) ) \ - return -EFAULT; } +#define IOCTL_IN(arg, type, in) \ + copy_from_user_ret(&in, (type *) arg, sizeof in, -EFAULT) + +#define IOCTL_OUT(arg, type, out) \ + copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT) #define FM_WRITE 0x2 /* file mode write bit */ @@ -328,7 +341,7 @@ if (fp->f_mode & FM_WRITE) return -EROFS; purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (cdi->use_count || purpose) + if (purpose) ret = cdi->ops->open(cdi, purpose); else ret = open_for_data(cdi); @@ -517,10 +530,10 @@ if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); if (cdi->use_count == 0 && /* last process that closes dev*/ - cdo->capability & CDC_LOCK) { + cdo->capability & CDC_LOCK && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); - } + } opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || !(fp && fp->f_flags & O_NONBLOCK); cdo->release(cdi); @@ -716,18 +729,18 @@ cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) return -ENOSYS; - if (cdi->use_count != 1) + if (cdi->use_count != 1) return -EBUSY; - if (cdo->capability & ~cdi->mask & CDC_LOCK) { + if (cdo->capability & ~cdi->mask & CDC_LOCK) if ((ret=cdo->lock_door(cdi, 0))) return ret; - } + return cdo->tray_move(cdi, 1); } case CDROMCLOSETRAY: cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); - if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) + if (!(cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)) return -ENOSYS; return cdo->tray_move(cdi, 0); @@ -755,8 +768,21 @@ case CDROM_SET_OPTIONS: cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); - if (cdo->capability & arg & ~cdi->mask) - return -ENOSYS; + /* options need to be in sync with capability. too late for + that, so we have to check each one separately... */ + switch (arg) { + case CDO_USE_FFLAGS: + case CDO_CHECK_TYPE: + break; + case CDO_LOCK: + if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) + return -ENOSYS; + break; + /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */ + default: + if (!(cdo->capability & ~cdi->mask & arg)) + return -ENOSYS; + } cdi->options |= (int) arg; return cdi->options; @@ -783,6 +809,37 @@ return cdo->select_disc(cdi, arg); } + case CDROMRESET: { + cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); + if (!(cdo->capability & ~cdi->mask & CDC_RESET)) + return -ENOSYS; + return cdo->reset(cdi); + } + + case CDROM_LOCKDOOR: { + cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl"); + if (cdo->capability & ~cdi->mask & CDC_LOCK) { + keeplocked = arg ? 1 : 0; + return cdo->lock_door(cdi, arg); + } else + return -EDRIVE_CANT_DO_THIS; + } + + case CDROM_DEBUG: { + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis"); + debug = arg ? 1 : 0; + return 0; + } + + case CDROM_GET_CAPABILITY: { + cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); + return cdo->capability; + } + + + /* The following function is implemented, although very few audio * discs give Universal Product Code information, which should just be * the Medium Catalog Number on the box. Note, that the way the code @@ -1123,7 +1180,7 @@ return; cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); - cdrom_root_table->de->fill_inode = &cdrom_procfs_modcount; + cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; initialized = 1; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/cm206.c linux.ac/drivers/cdrom/cm206.c --- linux.vanilla/drivers/cdrom/cm206.c Sun Nov 8 15:08:06 1998 +++ linux.ac/drivers/cdrom/cm206.c Mon Mar 1 14:24:08 1999 @@ -186,7 +186,6 @@ #include #include #include -#include /* #include */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux.ac/drivers/char/Config.in --- linux.vanilla/drivers/char/Config.in Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/char/Config.in Tue Feb 16 17:27:11 1999 @@ -139,6 +139,16 @@ if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 fi + dep_tristate 'Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV + if [ "$CONFIG_PROC_FS" = "y" ]; then + if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then + bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS + fi + fi + if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then + hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 + int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 + fi dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/char/Makefile Tue Feb 16 17:27:11 1999 @@ -44,12 +44,17 @@ ifdef CONFIG_VT L_OBJS += keyboard.o endif -ifneq ($(ARCH),m68k) -L_OBJS += pc_keyb.o defkeymap.o + ifneq ($(ARCH),m68k) + L_OBJS += pc_keyb.o defkeymap.o + endif +else +ifdef CONFIG_PCI +L_OBJS += defkeymap.o keyboard.o endif -ifdef CONFIG_MAGIC_SYSRQ -L_OBJS += sysrq.o endif + +ifdef CONFIG_MAGIC_SYSRQ +LX_OBJS += sysrq.o endif ifeq ($(CONFIG_ATARI_DSP56K),y) @@ -361,6 +366,14 @@ else ifeq ($(CONFIG_RADIO_RTRACK2),m) M_OBJS += radio-rtrack2.o + endif +endif + +ifeq ($(CONFIG_RADIO_TYPHOON),y) +L_OBJS += radio-typhoon.o +else + ifeq ($(CONFIG_RADIO_TYPHOON),m) + M_OBJS += radio-typhoon.o endif 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 Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/char/bttv.c Sat Feb 27 02:13:55 1999 @@ -1558,12 +1558,33 @@ static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; - + btv->user--; audio(btv, AUDIO_INTERN); btv->cap&=~3; bt848_set_risc_jmps(btv); + /* + * A word of warning. At this point the chip + * is still capturing because its FIFO hasn't emptied + * and the DMA control operations are posted PCI + * operations. + */ + + btread(BT848_I2C); /* This fixes the PCI posting delay */ + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + /* + * We have allowed it to drain. + */ if(btv->fbuffer) rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF); btv->fbuffer=0; @@ -3037,7 +3058,7 @@ btv->risc_jmp[12]=BT848_RISC_JUMP; btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp); - /* enable cpaturing and DMA */ + /* enable capturing */ btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -3242,7 +3263,7 @@ if (astat&BT848_INT_SCERR) { IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); bt848_dma(btv, 0); - bt848_dma(btv, 1); + bt848_dma(btv, 3); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); 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 Sun Nov 8 15:10:11 1998 +++ linux.ac/drivers/char/bw-qcam.c Sun Jan 24 21:15:01 1999 @@ -5,6 +5,28 @@ * * Video4Linux conversion work by Alan Cox. * Parport compatibility by Phil Blundell. + * Busy loop avoidance by Mark Cooke. + * + * Module parameters: + * + * maxpoll=<1 - 5000> + * + * When polling the QuickCam for a response, busy-wait for a + * maximum of this many loops. The default of 250 gives little + * impact on interactive response. + * + * NOTE: If this parameter is set too high, the processor + * will busy wait until this loop times out, and then + * slowly poll for a further 5 seconds before failing + * the transaction. You have been warned. + * + * yieldlines=<1 - 250> + * + * When acquiring a frame from the camera, the data gathering + * loop will yield back to the scheduler after completing + * this many lines. The default of 4 provides a trade-off + * between increased frame acquisition time and impact on + * interactive response. */ /* qcam-lib.c -- Library for programming with the Connectix QuickCam. @@ -58,6 +80,14 @@ #include "bw-qcam.h" +#if LINUX_VERSION_CODE >= 0x020117 +MODULE_PARM(maxpoll,"i"); +MODULE_PARM(yieldlines,"i"); +#endif + +static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ +static unsigned int yieldlines=4; /* Yield after this many during capture */ + extern __inline__ int read_lpstatus(struct qcam_device *q) { return parport_read_status(q->pport); @@ -154,6 +184,7 @@ q->top = 1; q->left = 14; q->mode = -1; + q->status = QC_PARAM_CHANGE; return q; } @@ -209,14 +240,17 @@ { /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs>1050) + if(runs>(maxpoll+1000)) /* 5 seconds */ return -1; } } @@ -226,14 +260,17 @@ { /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs++>1050) /* 5 seconds */ + if(runs++>(maxpoll+1000)) /* 5 seconds */ return -1; } } @@ -256,14 +293,17 @@ status = read_lpdata(q); /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs++>1050) /* 5 seconds */ + if(runs++>(maxpoll+1000)) /* 5 seconds */ return 0; } while ((status & 1) != val); @@ -287,7 +327,7 @@ lastreg = reg = read_lpstatus(q) & 0xf0; - for (i = 0; i < 300; i++) + for (i = 0; i < 500; i++) { reg = read_lpstatus(q) & 0xf0; if (reg != lastreg) @@ -296,9 +336,20 @@ mdelay(2); } - /* Be liberal in what you accept... */ - if (count > 30 && count < 200) +#if 0 + /* Force camera detection during testing. Sometimes the camera + won't be flashing these bits. Possibly unloading the module + in the middle of a grab? Or some timeout condition? + I've seen this parameter as low as 19 on my 450Mhz box - mpc */ + printk("Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); + return 1; +#endif + + /* Be (even more) liberal in what you accept... */ + +/* if (count > 30 && count < 200) */ + if (count > 20 && count < 300) return 1; /* found */ else return 0; /* not found */ @@ -352,6 +403,8 @@ static int qc_setscanmode(struct qcam_device *q) { + int old_mode = q->mode; + switch (q->transfer_scale) { case 1: @@ -383,6 +436,10 @@ case QC_UNIDIR: break; } + + if (q->mode != old_mode) + q->status |= QC_PARAM_CHANGE; + return 0; } @@ -434,8 +491,11 @@ qc_command(q, q->contrast); qc_command(q, 0x1f); qc_command(q, q->whitebal); -} + /* Clear flag that we must update the grabbing parameters on the camera + before we grab the next frame */ + q->status &= (~QC_PARAM_CHANGE); +} /* Qc_readbytes reads some bytes from the QC and puts them in the supplied buffer. It returns the number of bytes read, @@ -539,7 +599,7 @@ long qc_capture(struct qcam_device * q, char *buf, unsigned long len) { - int i, j, k; + int i, j, k, yield; int bytes; int linestotrans, transperline; int divisor; @@ -575,7 +635,7 @@ q->transfer_scale; transperline = (transperline + divisor - 1) / divisor; - for (i = 0; i < linestotrans; i++) + for (i = 0, yield = yieldlines; i < linestotrans; i++) { for (pixels_read = j = 0; j < transperline; j++) { @@ -599,6 +659,18 @@ pixels_read += bytes; } (void) qc_readbytes(q, 0); /* reset state machine */ + + /* Grabbing an entire frame from the quickcam is a lengthy + process. We don't (usually) want to busy-block the + processor for the entire frame. yieldlines is a module + parameter. If we yield every line, the minimum frame + time will be 240 / 200 = 1.2 seconds. The compile-time + default is to yield every 4 lines. */ + if (i >= yield) { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + yield = i + yieldlines; + } } if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) @@ -745,9 +817,12 @@ qcam->bpp = p.depth; qc_setscanmode(qcam); - parport_claim_or_block(qcam->pdev); + qcam->status |= QC_PARAM_CHANGE; + +/* parport_claim_or_block(qcam->pdev); qc_set(qcam); parport_release(qcam->pdev); +*/ return 0; } case VIDIOCSWIN: @@ -779,6 +854,11 @@ qcam->transfer_scale = 1; } qc_setscanmode(qcam); + + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + /* Ok we figured out what to use from our wide choice */ return 0; } @@ -824,11 +904,15 @@ parport_claim_or_block(qcam->pdev); /* Probably should have a semaphore against multiple users */ qc_reset(qcam); + + /* Update the camera parameters if we need to */ + if (qcam->status & QC_PARAM_CHANGE) + qc_set(qcam); + len=qc_capture(qcam, buf,count); parport_release(qcam->pdev); return len; } - static struct video_device qcam_template= { @@ -909,6 +993,17 @@ for (port = parport_enumerate(); port; port=port->next) init_bwqcam(port); + + /* Do some sanity checks on the module parameters. */ + if (maxpoll > 5000) { + printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n"); + maxpoll = 5000; + } + + if (yieldlines < 1) { + printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n"); + yieldlines = 1; + } return (num_cams)?0:-ENODEV; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bw-qcam.h linux.ac/drivers/char/bw-qcam.h --- linux.vanilla/drivers/char/bw-qcam.h Sun Nov 8 15:07:44 1998 +++ linux.ac/drivers/char/bw-qcam.h Sun Jan 24 21:15:01 1999 @@ -48,6 +48,9 @@ #define MAX_HEIGHT 243 #define MAX_WIDTH 336 +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + struct qcam_device { struct video_device vdev; struct pardevice *pdev; @@ -59,6 +62,6 @@ int port_mode; int transfer_scale; int top, left; + int status; unsigned int saved_bits; }; - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/console.c linux.ac/drivers/char/console.c --- linux.vanilla/drivers/char/console.c Sun Jan 24 19:55:33 1999 +++ linux.ac/drivers/char/console.c Mon Mar 1 14:24:08 1999 @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include @@ -2778,7 +2777,7 @@ set_cursor(currcons); } -u16 vcs_scr_readw(int currcons, u16 *org) +u16 vcs_scr_readw(int currcons, const u16 *org) { if ((unsigned long)org == pos && softcursor_original != -1) return softcursor_original; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/epca.c linux.ac/drivers/char/epca.c --- linux.vanilla/drivers/char/epca.c Thu Jan 14 01:25:21 1999 +++ linux.ac/drivers/char/epca.c Mon Mar 1 14:24:08 1999 @@ -83,7 +83,6 @@ #include #include #include -#include #include #ifdef MODULE 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/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/char/pcxx.c linux.ac/drivers/char/pcxx.c --- linux.vanilla/drivers/char/pcxx.c Tue Jan 19 02:57:26 1999 +++ linux.ac/drivers/char/pcxx.c Mon Mar 1 14:24:08 1999 @@ -68,7 +68,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-aimslab.c linux.ac/drivers/char/radio-aimslab.c --- linux.vanilla/drivers/char/radio-aimslab.c Thu Jan 14 01:25:21 1999 +++ linux.ac/drivers/char/radio-aimslab.c Fri Feb 26 01:47:18 1999 @@ -3,6 +3,11 @@ * Coverted to new API by Alan Cox * Various bugfixes and enhancements by Russell Kroll * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Frequency range expanded to start at 87 MHz + * * TODO: Allow for more than one of these foolish entities :-) * * Notes on the hardware (reverse engineered from other peoples' @@ -156,14 +161,11 @@ /* adapted from radio-aztech.c */ - /* We want to compute x * 100 / 16 without overflow - * So we compute x*6 + (x/100)*25 to give x*6.25 - */ - - freq = freq * 6 + freq/4; /* massage the data a little */ - freq += 1070; /* IF = 10.7 MHz */ - freq /= 5; /* ref = 25 kHz */ + /* now uses VIDEO_TUNER_LOW for fine tuning */ + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 800; /* Convert to 50 kHz units */ + send_0_byte (io, dev); /* 0: LSB of frequency */ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ @@ -229,9 +231,9 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(88*16); - v.rangehigh=(108*16); - v.flags=0; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*rt_getsigstr(rt); if(copy_to_user(arg,&v, sizeof(v))) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-aztech.c linux.ac/drivers/char/radio-aztech.c --- linux.vanilla/drivers/char/radio-aztech.c Sun Nov 8 15:07:47 1998 +++ linux.ac/drivers/char/radio-aztech.c Fri Feb 26 01:47:18 1999 @@ -1,9 +1,7 @@ -/* aztech.c - Aztech radio card driver for Linux 2.1 by Russell Kroll +/* radio-aztech.c - Aztech radio card driver for Linux 2.2 * - * Heavily modified to support the new 2.1 radio card interfaces by - * Russell Kroll (rkroll@exploits.org) - * - * Based on code by + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: * * Quay Ly * Donald Song @@ -14,6 +12,11 @@ * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ * along with more information on the card itself. * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Range expanded to 87-108 MHz (from 87.9-107.8) + * * Notable changes from the original source: * - includes stripped down to the essentials * - for loops used as delays replaced with udelay() @@ -113,11 +116,8 @@ { int i; - /* 6.25 * */ - frequency = frequency*6 + frequency/4; /* massage data a bit */ - - frequency += 1070; /* tuning needs 24 data bits */ - frequency /= 5; + frequency += 171200; /* Add 10.7 MHz IF */ + frequency /= 800; /* Convert to 50 kHz units */ send_0_byte (dev); /* 0: LSB of frequency */ @@ -179,9 +179,9 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(879*16)/10; - v.rangehigh=(1078*16)/10; - v.flags=0; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*az_getsigstr(az); if(az_getstereo(az)) @@ -292,7 +292,7 @@ return -EINVAL; request_region(io, 2, "aztech"); - printk(KERN_INFO "Aztech radio card driver v0.40/19980422 rkroll@exploits.org\n"); + printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); /* mute card - prevents noisy bootups */ outb (0, io); return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-typhoon.c linux.ac/drivers/char/radio-typhoon.c --- linux.vanilla/drivers/char/radio-typhoon.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/radio-typhoon.c Tue Feb 16 17:27:11 1999 @@ -0,0 +1,428 @@ +/* Typhoon Radio Card driver for radio support + * (c) 1999 Dr. Henrik Seidel + * + * Card manufacturer: + * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e + * + * Notes on the hardware + * + * This card has two output sockets, one for speakers and one for line. + * The speaker output has volume control, but only in four discrete + * steps. The line output has neither volume control nor mute. + * + * The card has auto-stereo according to its manual, although it all + * sounds mono to me (even with the Win/DOS drivers). Maybe it's my + * antenna - I really don't know for sure. + * + * Frequency control is done digitally. + * + * Volume control is done digitally, but there are only four different + * possible values. So you should better always turn the volume up and + * use line control. I got the best results by connecting line output + * to the sound card microphone input. For such a configuration the + * volume control has no effect, since volume control only influences + * the speaker output. + * + * There is no explicit mute/unmute. So I set the radio frequency to a + * value where I do expect just noise and turn the speaker volume down. + * The frequency change is necessary since the card never seems to be + * completely silent. + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* radio card status report */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TYPHOON_* */ + +#define BANNER "Typhoon Radio Card driver v0.1\n" + +#ifndef CONFIG_RADIO_TYPHOON_PORT +#define CONFIG_RADIO_TYPHOON_PORT -1 +#endif + +#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 +#endif + +struct typhoon_device { + int users; + int iobase; + int curvol; + int muted; + unsigned long curfreq; + unsigned long mutefreq; +}; + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency); +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); +static void typhoon_mute(struct typhoon_device *dev); +static void typhoon_unmute(struct typhoon_device *dev); +static int typhoon_setvol(struct typhoon_device *dev, int vol); +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); +static int typhoon_open(struct video_device *dev, int flags); +static void typhoon_close(struct video_device *dev); +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS +static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, + int unused); +#endif +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +int typhoon_init(struct video_init *v); +#else +int typhoon_init(struct video_init *v) __init; +#endif + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) +{ + vol >>= 14; /* Map 16 bit to 2 bit */ + vol &= 3; + outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ +} + +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency) +{ + unsigned long outval; + unsigned long x; + + /* + * The frequency transfer curve is not linear. The best fit I could + * get is + * + * outval = -155 + exp((f + 15.55) * 0.057)) + * + * where frequency f is in MHz. Since we don't have exp in the kernel, + * I approximate this function by a third order polynomial. + * + */ + + x = frequency / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + + outb_p((outval >> 8) & 0x01, dev->iobase + 4); + outb_p(outval >> 9, dev->iobase + 6); + outb_p(outval & 0xff, dev->iobase + 8); + + return 0; +} + +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) +{ + typhoon_setfreq_generic(dev, frequency); + dev->curfreq = frequency; + return 0; +} + +static void typhoon_mute(struct typhoon_device *dev) +{ + if (dev->muted == 1) + return; + typhoon_setvol_generic(dev, 0); + typhoon_setfreq_generic(dev, dev->mutefreq); + dev->muted = 1; +} + +static void typhoon_unmute(struct typhoon_device *dev) +{ + if (dev->muted == 0) + return; + typhoon_setfreq_generic(dev, dev->curfreq); + typhoon_setvol_generic(dev, dev->curvol); + dev->muted = 0; +} + +static int typhoon_setvol(struct typhoon_device *dev, int vol) +{ + if (dev->muted && vol != 0) { /* user is unmuting the card */ + dev->curvol = vol; + typhoon_unmute(dev); + return 0; + } + if (vol == dev->curvol) /* requested volume == current */ + return 0; + + if (vol == 0) { /* volume == 0 means mute the card */ + typhoon_mute(dev); + dev->curvol = vol; + return 0; + } + typhoon_setvol_generic(dev, vol); + dev->curvol = vol; + return 0; +} + + +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0; /* We can't get the signal strength */ + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if (copy_to_user(arg, &typhoon->curfreq, + sizeof(typhoon->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if (copy_from_user(&typhoon->curfreq, arg, + sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v, 0, sizeof(v)); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + v.mode |= VIDEO_SOUND_MONO; + v.volume = typhoon->curvol; + v.step = 1 << 14; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.audio) + return -EINVAL; + + if (v.flags & VIDEO_AUDIO_MUTE) + typhoon_mute(typhoon); + else + typhoon_unmute(typhoon); + + if (v.flags & VIDEO_AUDIO_VOLUME) + typhoon_setvol(typhoon, v.volume); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int typhoon_open(struct video_device *dev, int flags) +{ + struct typhoon_device *typhoon = dev->priv; + if (typhoon->users) + return -EBUSY; + typhoon->users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void typhoon_close(struct video_device *dev) +{ + struct typhoon_device *typhoon = dev->priv; + typhoon->users--; + MOD_DEC_USE_COUNT; +} + +static struct typhoon_device typhoon_unit = +{ + 0, /* users */ + CONFIG_RADIO_TYPHOON_PORT, /* iobase */ + 0, /* curvol */ + 0, /* muted */ + CONFIG_RADIO_TYPHOON_MUTEFREQ, /* curfreq */ + CONFIG_RADIO_TYPHOON_MUTEFREQ /* mutefreq */ +}; + +static struct video_device typhoon_radio = +{ + "Typhoon Radio", + VID_TYPE_TUNER, + VID_HARDWARE_TYPHOON, + typhoon_open, + typhoon_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + typhoon_ioctl, + NULL, + NULL +}; + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + +static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, + int unused) +{ + #ifdef MODULE + #define MODULEPROCSTRING "Driver loaded as a module" + #else + #define MODULEPROCSTRING "Driver compiled into kernel" + #endif + + #define LIMIT (PAGE_SIZE - 80) + + len = 0; + len += sprintf(buf + len, BANNER); + if (len > LIMIT) return len; + len += sprintf(buf + len, "Load type: " MODULEPROCSTRING "\n\n"); + if (len > LIMIT) return len; + len += sprintf(buf + len, "frequency = %lu kHz\n", + typhoon_unit.curfreq >> 4); + if (len > LIMIT) return len; + len += sprintf(buf + len, "volume = %d\n", typhoon_unit.curvol); + if (len > LIMIT) return len; + len += sprintf(buf + len, "mute = %s\n", typhoon_unit.muted ? + "on" : "off"); + if (len > LIMIT) return len; + len += sprintf(buf + len, "iobase = 0x%x\n", typhoon_unit.iobase); + if (len > LIMIT) return len; + len += sprintf(buf + len, "mute frequency = %lu kHz\n", + typhoon_unit.mutefreq >> 4); + return len; +} + +static struct proc_dir_entry typhoon_proc_entry = { + 0, /* low_ino: inode is dynamic */ + 13, "radio-typhoon", /* length of name and name */ + S_IFREG | S_IRUGO, /* mode */ + 1, 0, 0, /* nlinks, owner, group */ + 0, /* size -- not used */ + NULL, /* operations -- use default */ + &typhoon_read_proc, /* function used to read data */ + /* nothing more */ +}; + +#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ + +int typhoon_init(struct video_init *v) +{ + printk(KERN_INFO BANNER); + if (check_region(typhoon_unit.iobase, 8)) { + printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", + typhoon_unit.iobase); + return -EBUSY; + } + + typhoon_radio.priv = &typhoon_unit; + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) + return -EINVAL; + + request_region(typhoon_unit.iobase, 8, "typhoon"); + printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); + printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", + typhoon_unit.mutefreq); + typhoon_unit.mutefreq <<= 4; + + /* mute card - prevents noisy bootups */ + typhoon_mute(&typhoon_unit); + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + + if (proc_register(&proc_root, &typhoon_proc_entry)) + printk(KERN_ERR "radio-typhoon: registering /proc/radio-typhoon failed\n"); + +#endif + + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); +MODULE_PARM(mutefreq, "i"); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +EXPORT_NO_SYMBOLS; + +static int io = -1; +static unsigned long mutefreq = 0; + +int init_module(void) +{ + if (io == -1) { + printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); + return -EINVAL; + } + typhoon_unit.iobase = io; + + if (mutefreq < 87000 || mutefreq > 108500) { + printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); + printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + return -EINVAL; + } + typhoon_unit.mutefreq = mutefreq; + + return typhoon_init(NULL); +} + +void cleanup_module(void) +{ + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + + if (proc_unregister(&proc_root, typhoon_proc_entry.low_ino)) + printk(KERN_ERR "radio-typhoon: unregistering /proc/radio-typhoon failed\n"); + +#endif + + video_unregister_device(&typhoon_radio); + release_region(io, 8); +} + +#endif + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-zoltrix.c linux.ac/drivers/char/radio-zoltrix.c --- linux.vanilla/drivers/char/radio-zoltrix.c Sat Jan 9 21:50:38 1999 +++ linux.ac/drivers/char/radio-zoltrix.c Fri Feb 19 10:50:13 1999 @@ -11,7 +11,8 @@ * at a low frequency, and it is not possible (at least I have not found) * to get fine volume control over the low volume range. * - * Some code derived from code by Frans Brinkman + * Some code derived from code by Romolo Manfredini + * romolo@bicnet.it * * 1999-01-05 - (C. van Schaik) * - Changed tuning to 1/160Mhz accuracy @@ -285,10 +286,10 @@ if (v.flags & VIDEO_AUDIO_MUTE) zol_mute(zol); else + { zol_unmute(zol); - - if (v.flags & VIDEO_AUDIO_VOLUME) zol_setvol(zol, v.volume / 4096); + } if (v.mode & VIDEO_SOUND_STEREO) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/rocket.c linux.ac/drivers/char/rocket.c --- linux.vanilla/drivers/char/rocket.c Sun Nov 8 15:10:13 1998 +++ linux.ac/drivers/char/rocket.c Mon Mar 1 14:24:08 1999 @@ -80,7 +80,6 @@ #include #include #include -#include #include #ifdef ENABLE_PCI #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/tpqic02.c linux.ac/drivers/char/tpqic02.c --- linux.vanilla/drivers/char/tpqic02.c Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/char/tpqic02.c Mon Mar 1 14:24:08 1999 @@ -75,7 +75,6 @@ #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/videodev.c linux.ac/drivers/char/videodev.c --- linux.vanilla/drivers/char/videodev.c Sun Jan 24 19:55:34 1999 +++ linux.ac/drivers/char/videodev.c Tue Feb 16 17:27:11 1999 @@ -72,6 +72,9 @@ #ifdef CONFIG_RADIO_GEMTEK extern int gemtek_init(struct video_init *); #endif +#ifdef CONFIG_RADIO_TYPHOON +extern int typhoon_init(struct video_init *); +#endif #ifdef CONFIG_VIDEO_PMS extern int init_pms_cards(struct video_init *); #endif @@ -101,7 +104,7 @@ #endif #ifdef CONFIG_RADIO_RTRACK {"RTrack", rtrack_init}, -#endif +#endif #ifdef CONFIG_RADIO_SF16FMI {"SF16FMI", fmi_init}, #endif @@ -110,6 +113,9 @@ #endif #ifdef CONFIG_RADIO_GEMTEK {"GemTek", gemtek_init}, +#endif +#ifdef CONFIG_RADIO_TYPHOON + {"radio-typhoon", typhoon_init}, #endif {"end", NULL} }; 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 Tue Dec 22 23:19:39 1998 +++ linux.ac/drivers/fc4/soc.c Mon Mar 1 14:24:08 1999 @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/3c509.c linux.ac/drivers/net/3c509.c --- linux.vanilla/drivers/net/3c509.c Tue Dec 22 23:19:40 1998 +++ linux.ac/drivers/net/3c509.c Sun Feb 28 22:23:45 1999 @@ -1,8 +1,8 @@ /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ /* - Written 1993-1997 by Donald Becker. + Written 1993-1998 by Donald Becker. - Copyright 1994-1997 by Donald Becker. + Copyright 1994-1998 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and distributed according to the terms of the GNU Public License, @@ -35,19 +35,24 @@ other cleanups. -djb Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. Rick Payne: Fixed SMP race condition + v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb + v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb + v1.15 1/31/98 Faster recovery for Tx errors. -djb + v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb */ -static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c509.c:1.16 (2.2) 2/3/98 becker@cesdis.gsfc.nasa.gov.\n"; /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (400*HZ/1000) /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -#define INTR_WORK 10 +static int max_interrupt_work = 10; +#include #include -#include /* for CONFIG_MCA */ +#include #include #include #include @@ -129,12 +134,13 @@ /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; + char mca_slot; }; -static int id_port = 0x100; +static int id_port = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static struct device *el3_root_dev = NULL; static ushort id_read_eeprom(int index); -static ushort read_eeprom(short ioaddr, int index); +static ushort read_eeprom(int ioaddr, int index); static int el3_open(struct device *dev); static int el3_start_xmit(struct sk_buff *skb, struct device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -144,14 +150,29 @@ static int el3_close(struct device *dev); static void set_multicast_list(struct device *dev); - +#ifdef CONFIG_MCA +struct el3_mca_adapters_struct { + char* name; + int id; +}; + +struct el3_mca_adapters_struct el3_mca_adapters[] = { + { "3Com 3c529 EtherLink III (10base2)", 0x627c }, + { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, + { "3Com 3c529 EtherLink III (test mode)", 0x62db }, + { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 }, + { "3Com 3c529 EtherLink III (TP)", 0x62f7 }, + { NULL, 0 }, +}; +#endif int el3_probe(struct device *dev) { short lrs_state = 0xff, i; - ushort ioaddr, irq, if_port; - short phys_addr[3]; + int ioaddr, irq, if_port; + u16 phys_addr[3]; static int current_tag = 0; + int mca_slot = -1; /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ @@ -182,69 +203,72 @@ } #ifdef CONFIG_MCA -#define MCA_NUMBER_OF_SLOTS 8 -#define MCA_PORT_POS_SEL 0x096 -#define MCA_PORT_ID_REG_0 0x100 -#define MCA_PORT_ID_REG_1 0x101 -#define MCA_SELECT_BIT 0x08 - if (MCA_bus) - { - u_int mca_id; - u_char posreg[4]; - int mca_slot; - - if (el3_debug > 2) - printk("3c529: probing...\n"); - /* This should probably be done once early on and read into - * a structure somewhere... */ - for (mca_slot = 0; mca_slot < MCA_NUMBER_OF_SLOTS; mca_slot++) - { - /* Select MCA slot i */ - outb_p(mca_slot | MCA_SELECT_BIT, MCA_PORT_POS_SEL); - mca_id = ((inb_p(MCA_PORT_ID_REG_1)<<8) - + inb_p(MCA_PORT_ID_REG_0)); - if (mca_id == 0x627C /* 10base2 */ - || mca_id == 0x627D /* 10baseT */ - || mca_id == 0x62DB /* Test mode */ - || mca_id == 0x62F6 /* TP or coax */ - || mca_id == 0x62F7) /* TP only */ - { - if (el3_debug > 1) - printk("3c529: Found with id 0x%x at slot %d\n", - mca_id, mca_slot); - posreg[0] = inb_p(0x102); posreg[1] = inb_p(0x103); - posreg[2] = inb_p(0x104); posreg[3] = inb_p(0x105); - break; + /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, heavily + * modified by Chris Beauregard (cpbeaure@csclub.uwaterloo.ca) + * to support standard MCA probing. + * + * redone for multi-card detection by ZP Gu (zpg@castle.net) + * now works as a module + */ + + if( MCA_bus ) { + int slot, j; + u_char pos4, pos5; + + for( j = 0; el3_mca_adapters[j].name != NULL; j ++ ) { + slot = 0; + while( slot != MCA_NOTFOUND ) { + slot = mca_find_unused_adapter( + el3_mca_adapters[j].id, slot ); + if( slot == MCA_NOTFOUND ) break; + + /* if we get this far, an adapter has been + * detected and is enabled + */ + + printk("3c509: found %s at slot %d\n", + el3_mca_adapters[j].name, slot + 1 ); + + pos4 = mca_read_stored_pos( slot, 4 ); + pos5 = mca_read_stored_pos( slot, 5 ); + + ioaddr = ((short)((pos4&0xfc)|0x02)) << 8; + irq = pos5 & 0x0f; + + /* probing for a card at a particular IO/IRQ */ + if(dev && ((dev->irq >= 1 && dev->irq != irq) || + (dev->base_addr >= 1 && dev->base_addr != ioaddr))) { + slot++; /* probing next slot */ + continue; + } + + /* claim the slot */ + mca_set_adapter_name(slot, el3_mca_adapters[j].name); + mca_set_adapter_procfn(slot, NULL, NULL); + mca_mark_as_used(slot); + + if_port = pos4 & 0x03; + if (el3_debug > 2) { + printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); + } + for (i = 0; i < 3; i++) { + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + } + + mca_slot = slot; + + goto found; } - mca_id = 0xFFFF; - } - /* Read values from POS registers so now disable */ - outb(0,MCA_PORT_POS_SEL); - if (mca_id != 0xFFFF && !(posreg[0]&0x01)) - printk("3c529: Adapter found but disabled in slot %d\n", mca_slot); - else if (mca_id != 0xFFFF && posreg[0]&0x01) - { - /* Found and adapter is enabled */ - if (el3_debug > 2) - printk("3c529: pos registers 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", - posreg[0], posreg[1], posreg[2], posreg[3]); - ioaddr = ((short)((posreg[2]&0xfc)|0x02)) << 8; - irq = posreg[3] & 0x0f; - if_port = posreg[2] & 0x03; - if (el3_debug > 2) - printk("3c529: irq %d ioaddr 0x%x ifport %d\n", - irq, ioaddr, if_port); - for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - goto found; } + /* if we get here, we didn't find an MCA adapter */ + return -ENODEV; } #endif /* Reset the ISA PnP mechanism on 3c509b. */ outb(0x02, 0x279); /* Select PnP config control register. */ outb(0x02, 0xA79); /* Return to WaitForKey state. */ /* Select an open I/O location at 0x1*0 to do contention select. */ - for (id_port = 0x100; id_port < 0x200; id_port += 0x10) { + for ( ; id_port < 0x200; id_port += 0x10) { if (check_region(id_port, 1)) continue; outb(0x00, id_port); @@ -288,18 +312,23 @@ } { - unsigned short iobase = id_read_eeprom(8); + unsigned int iobase = id_read_eeprom(8); if_port = iobase >> 14; ioaddr = 0x200 + ((iobase & 0x1f) << 4); } - if (dev && dev->irq > 1 && dev->irq < 16) - irq = dev->irq; - else - irq = id_read_eeprom(9) >> 12; + irq = id_read_eeprom(9) >> 12; - if (dev && dev->base_addr != 0 - && dev->base_addr != (unsigned short)ioaddr) { - return -ENODEV; + if (dev) { /* Set passed-in IRQ or I/O Addr. */ + if (dev->irq > 1 && dev->irq < 16) + irq = dev->irq; + + if (dev->base_addr) { + if (dev->mem_end == 0x3c509 /* Magic key */ + && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) + ioaddr = dev->base_addr & 0x3f0; + else if (dev->base_addr != ioaddr) + return -ENODEV; + } } /* Set the adaptor tag so that the next card can be found. */ @@ -342,7 +371,8 @@ if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct el3_private)); - + + ((struct el3_private *)dev->priv)->mca_slot = mca_slot; ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; el3_root_dev = dev; @@ -364,7 +394,7 @@ /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(short ioaddr, int index) +static ushort read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ @@ -394,7 +424,6 @@ } - static int el3_open(struct device *dev) { @@ -464,7 +493,7 @@ /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull, + outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, ioaddr + EL3_CMD); if (el3_debug > 3) @@ -589,7 +618,7 @@ struct device *dev = (struct device *)dev_id; struct el3_private *lp; int ioaddr, status; - int i = INTR_WORK; + int i = max_interrupt_work; if (dev == NULL) { printk ("el3_interrupt(): irq %d for unknown device.\n", irq); @@ -624,7 +653,7 @@ dev->tbusy = 0; mark_bh(NET_BH); } - if (status & (AdapterFailure | RxEarly | StatsFull)) { + if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); @@ -632,6 +661,18 @@ el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } + if (status & TxComplete) { /* Really Tx error. */ + struct el3_private *lp = (struct el3_private *)dev->priv; + short tx_status; + int i = 4; + + while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { + if (tx_status & 0x38) lp->stats.tx_aborted_errors++; + if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); + if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); + outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ + } + } if (status & AdapterFailure) { /* Adapter failure requires Rx reset and reinit. */ outw(RxReset, ioaddr + EL3_CMD); @@ -730,6 +771,8 @@ while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; + + outw(RxDiscard, ioaddr + EL3_CMD); lp->stats.rx_errors++; switch (error) { case 0x0000: lp->stats.rx_over_errors++; break; @@ -761,19 +804,21 @@ (pkt_len + 3) >> 2); #endif + outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ lp->stats.rx_packets++; continue; - } else if (el3_debug) + } + outw(RxDiscard, ioaddr + EL3_CMD); + lp->stats.rx_dropped++; + if (el3_debug) printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } - lp->stats.rx_dropped++; - outw(RxDiscard, ioaddr + EL3_CMD); + inw(ioaddr + EL3_STATUS); /* Delay. */ while (inw(ioaddr + EL3_STATUS) & 0x1000) - printk(" Waiting for 3c509 to discard packet, status %x.\n", + printk(KERN_DEBUG " Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); } @@ -786,7 +831,7 @@ static void set_multicast_list(struct device *dev) { - short ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; if (el3_debug > 1) { static int old = 0; if (old != dev->mc_count) { @@ -844,7 +889,7 @@ } #ifdef MODULE -/* Parameter that may be passed into the module. */ +/* Parameters that may be passed into the module. */ static int debug = -1; static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1}; @@ -880,7 +925,12 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (el3_root_dev) { - next_dev = ((struct el3_private *)el3_root_dev->priv)->next_dev; + struct el3_private *lp = (struct el3_private *)el3_root_dev->priv; +#ifdef CONFIG_MCA + if(lp->mca_slot!=-1) + mca_mark_as_unused(lp->mca_slot); +#endif + next_dev = lp->next_dev; unregister_netdev(el3_root_dev); release_region(el3_root_dev->base_addr, EL3_IO_EXTENT); kfree(el3_root_dev); @@ -888,7 +938,7 @@ } } #endif /* MODULE */ - + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/8390.c linux.ac/drivers/net/8390.c --- linux.vanilla/drivers/net/8390.c Sat Jan 9 21:50:40 1999 +++ linux.ac/drivers/net/8390.c Thu Feb 18 20:30:14 1999 @@ -165,8 +165,10 @@ spin_lock_irqsave(&ei_local->page_lock, flags); NS8390_init(dev, 1); - spin_unlock_irqrestore(&ei_local->page_lock, flags); + /* Set the flag before we drop the lock, That way the IRQ arrives + after its set and we get no silly warnings */ dev->start = 1; + spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; return 0; } 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 Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/Config.in Fri Feb 26 14:20: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 @@ -53,6 +62,7 @@ tristate '3c507 support' CONFIG_EL16 if [ "$CONFIG_MCA" = "y" ]; then tristate '3c523 support' CONFIG_ELMC + #tristate '3c527 support' CONFIG_ELMC_II fi fi tristate '3c509/3c579 support' CONFIG_EL3 @@ -81,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 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 @@ -113,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 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -143,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 @@ -151,7 +161,6 @@ 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 if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS @@ -159,17 +168,13 @@ 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 @@ -181,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 @@ -201,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 @@ -212,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 @@ -225,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 @@ -239,11 +271,14 @@ 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 Tue Jan 19 02:57:28 1999 +++ linux.ac/drivers/net/Makefile Thu Feb 18 17:35:52 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 @@ -430,6 +414,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 @@ -478,6 +470,14 @@ endif endif +ifeq ($(CONFIG_ELMC_II),y) +L_OBJS += 3c527.o +else + ifeq ($(CONFIG_ELMC_II),m) + M_OBJS += 3c527.o + endif +endif + ifeq ($(CONFIG_EL3),y) L_OBJS += 3c509.o else @@ -756,6 +756,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 @@ -1046,6 +1059,7 @@ ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda +MOD_IN_SUB_DIRS += irda else ifeq ($(CONFIG_IRDA),m) MOD_SUB_DIRS += irda diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/bsd_comp.c linux.ac/drivers/net/bsd_comp.c --- linux.vanilla/drivers/net/bsd_comp.c Sun Nov 8 15:07:26 1998 +++ linux.ac/drivers/net/bsd_comp.c Mon Mar 1 14:24:08 1999 @@ -70,7 +70,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/cosa.c linux.ac/drivers/net/cosa.c --- linux.vanilla/drivers/net/cosa.c Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/net/cosa.c Tue Feb 16 17:29:53 1999 @@ -1,4 +1,4 @@ -/* $Id: cosa.c,v 1.11 1998/12/24 23:44:23 kas Exp $ */ +/* $Id: cosa.c,v 1.21 1999/02/06 19:49:18 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -27,7 +27,7 @@ * Masaryk University (http://www.ics.muni.cz/). The hardware is * developed by Jiri Novotny . More information * and the photo of both cards is available at - * http://www.kozakmartin.cz/cosa.html. The card documentation, firmwares + * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/. * For Linux-specific utilities, see below in the "Software info" section. * If you want to order the card, contact Jiri Novotny. @@ -141,11 +141,13 @@ unsigned int datareg, statusreg; /* I/O ports */ unsigned short irq, dma; /* IRQ and DMA number */ unsigned short startaddr; /* Firmware start address */ + unsigned short busmaster; /* Use busmastering? */ int nchannels; /* # of channels on this card */ int driver_status; /* For communicating with firware */ int firmware_status; /* Downloaded, reseted, etc. */ int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */ int rxtx; /* RX or TX in progress? */ + int enabled; int usage; /* usage count */ int txchan, txsize, rxsize; struct channel_data *rxchan; @@ -331,9 +333,8 @@ static int get_wait_data(struct cosa_data *cosa); static int put_wait_data(struct cosa_data *cosa, int data); static int puthexnumber(struct cosa_data *cosa, int number); -static void put_driver_status_common(struct cosa_data *cosa, int nolock); -#define put_driver_status(x) put_driver_status_common((x), 0) -#define put_driver_status_nolock(x) put_driver_status_common((x), 1) +static void put_driver_status(struct cosa_data *cosa); +static void put_driver_status_nolock(struct cosa_data *cosa); /* Interrupt handling */ static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs); @@ -357,7 +358,7 @@ #endif { int i; - printk(KERN_INFO "cosa v1.03 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.04 (c) 1997-8 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -630,9 +631,14 @@ if (dev->tbusy) { if (time_before(jiffies, dev->trans_start+2*HZ)) return 1; /* Two seconds timeout */ + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } cosa_kick(chan->cosa); - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; if (chan->tx_skb) { dev_kfree_skb(chan->tx_skb); chan->tx_skb = 0; @@ -659,6 +665,14 @@ d->tbusy = 1; cosa_disable_rx(chan); spin_lock_irqsave(&chan->cosa->lock, flags); + if (chan->rx_skb) { + kfree_skb(chan->rx_skb); + chan->rx_skb = 0; + } + if (chan->tx_skb) { + kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } chan->usage=0; chan->cosa->usage--; MOD_DEC_USE_COUNT; @@ -1128,6 +1142,17 @@ return nr_cards; case COSAIONRCHANS: return cosa->nchannels; + case COSAIOBMSET: + if (!suser()) + return -EACCES; + if (is_8bit(cosa)) + return -EINVAL; + if (arg != COSA_BM_OFF && arg != COSA_BM_ON) + return -EINVAL; + cosa->busmaster = arg; + return 0; + case COSAIOBMGET: + return cosa->busmaster; } return -ENOIOCTLCMD; } @@ -1208,37 +1233,67 @@ return 0; } -static void put_driver_status_common(struct cosa_data *cosa, int nolock) +static void put_driver_status(struct cosa_data *cosa) { unsigned flags=0; int status; - if (!nolock) - spin_lock_irqsave(&cosa->lock, flags); + spin_lock_irqsave(&cosa->lock, flags); status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) | (cosa->txbitmap ? DRIVER_TX_READY : 0) | (cosa->txbitmap? ~(cosa->txbitmap<rxtx || nolock) { -#ifdef DEBUG_IO - debug_data_cmd(cosa, status); -#endif - cosa_putdata8(cosa, status); + if (!cosa->rxtx) { if (cosa->rxbitmap|cosa->txbitmap) { - cosa_putstatus(cosa, SR_RX_INT_ENA); + if (!cosa->enabled) { + cosa_putstatus(cosa, SR_RX_INT_ENA); #ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_INT_ENA); + debug_status_out(cosa, SR_RX_INT_ENA); #endif - } else { + cosa->enabled = 1; + } + } else if (cosa->enabled) { + cosa->enabled = 0; cosa_putstatus(cosa, 0); #ifdef DEBUG_IO debug_status_out(cosa, 0); #endif } + cosa_putdata8(cosa, status); +#ifdef DEBUG_IO + debug_data_cmd(cosa, status); +#endif } - if (!nolock) - spin_unlock_irqrestore(&cosa->lock, flags); + spin_unlock_irqrestore(&cosa->lock, flags); +} + +static void put_driver_status_nolock(struct cosa_data *cosa) +{ + int status; + + status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) + | (cosa->txbitmap ? DRIVER_TX_READY : 0) + | (cosa->txbitmap? ~(cosa->txbitmap<rxbitmap|cosa->txbitmap) { + cosa_putstatus(cosa, SR_RX_INT_ENA); +#ifdef DEBUG_IO + debug_status_out(cosa, SR_RX_INT_ENA); +#endif + cosa->enabled = 1; + } else { + cosa_putstatus(cosa, 0); +#ifdef DEBUG_IO + debug_status_out(cosa, 0); +#endif + cosa->enabled = 0; + } + cosa_putdata8(cosa, status); +#ifdef DEBUG_IO + debug_data_cmd(cosa, status); +#endif } /* @@ -1249,9 +1304,14 @@ static void cosa_kick(struct cosa_data *cosa) { unsigned flags, flags1; + char *s = "Unknown"; - printk(KERN_INFO "%s: DMA timeout - restarting.\n", cosa->name); + if (test_bit(RXBIT, &cosa->rxtx)) + s = "RX"; + if (test_bit(TXBIT, &cosa->rxtx)) + s = "TX"; + printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); spin_lock_irqsave(&cosa->lock, flags); cosa->rxtx = 0; @@ -1261,6 +1321,13 @@ release_dma_lock(flags1); /* FIXME: Anything else? */ + udelay(100); + cosa_putstatus(cosa, 0); + udelay(100); + (void) cosa_getdata8(cosa); + udelay(100); + cosa_putdata8(cosa, 0); + udelay(100); put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); } @@ -1556,6 +1623,10 @@ * COSA status byte. I have moved the rx/tx/eot interrupt handling into * separate functions to make it more readable. These functions are inline, * so there should be no overhead of function call. + * + * In the COSA bus-master mode, we need to tell the card the address of a + * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait. + * It's time to use the bottom half :-( */ /* @@ -1606,13 +1677,13 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { + cosa_putstatus(cosa, SR_TX_INT_ENA); cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)| ((cosa->txsize >> 8) & 0x1f)); - cosa_putstatus(cosa, SR_TX_INT_ENA); #ifdef DEBUG_IO + debug_status_out(cosa, SR_TX_INT_ENA); debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)| ((cosa->txsize >> 8) & 0x1f)); - debug_status_out(cosa, SR_TX_INT_ENA); debug_data_in(cosa, cosa_getdata8(cosa)); #else cosa_getdata8(cosa); @@ -1630,27 +1701,57 @@ #endif } } else { + cosa_putstatus(cosa, SR_TX_INT_ENA); cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000) | (cosa->txsize & 0x1fff)); - cosa_getdata16(cosa); #ifdef DEBUG_IO - debug_status_out(cosa, ((cosa->txchan<<13) & 0xe000) + debug_status_out(cosa, SR_TX_INT_ENA); + debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000) | (cosa->txsize & 0x1fff)); - debug_data_in(cosa, cosa_getdata16(cosa)); + debug_data_in(cosa, cosa_getdata8(cosa)); + debug_status_out(cosa, 0); #else - cosa_getdata16(cosa); + cosa_getdata8(cosa); #endif + cosa_putstatus(cosa, 0); } - /* start the DMA */ - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - set_dma_mode(cosa->dma, DMA_MODE_WRITE); - set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); - set_dma_count(cosa->dma, cosa->txsize); - enable_dma(cosa->dma); - release_dma_lock(flags1); + if (cosa->busmaster) { + unsigned long addr = virt_to_bus(cosa->txbuf); + int count=0; + printk(KERN_INFO "busmaster IRQ\n"); + while (!(cosa_getstatus(cosa)&SR_TX_RDY)) { + count++; + udelay(10); + if (count > 1000) break; + } + printk(KERN_INFO "status %x\n", cosa_getstatus(cosa)); + printk(KERN_INFO "ready after %d loops\n", count); + cosa_putdata16(cosa, (addr >> 16)&0xffff); + + count = 0; + while (!(cosa_getstatus(cosa)&SR_TX_RDY)) { + count++; + if (count > 1000) break; + udelay(10); + } + printk(KERN_INFO "ready after %d loops\n", count); + cosa_putdata16(cosa, addr &0xffff); + flags1 = claim_dma_lock(); + set_dma_mode(cosa->dma, DMA_MODE_CASCADE); + enable_dma(cosa->dma); + release_dma_lock(flags1); + } else { + /* start the DMA */ + flags1 = claim_dma_lock(); + disable_dma(cosa->dma); + clear_dma_ff(cosa->dma); + set_dma_mode(cosa->dma, DMA_MODE_WRITE); + set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); + set_dma_count(cosa->dma, cosa->txsize); + enable_dma(cosa->dma); + release_dma_lock(flags1); + } cosa_putstatus(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA); #ifdef DEBUG_IO debug_status_out(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA); @@ -1671,21 +1772,16 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { set_bit(IRQBIT, &cosa->rxtx); - cosa_putstatus(cosa, 0); cosa->rxsize = cosa_getdata8(cosa) <<8; #ifdef DEBUG_IO - debug_status_out(cosa, 0); debug_data_in(cosa, cosa->rxsize >> 8); #endif - put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); return; } else { clear_bit(IRQBIT, &cosa->rxtx); - cosa_putstatus(cosa, 0); cosa->rxsize |= cosa_getdata8(cosa) & 0xff; #ifdef DEBUG_IO - debug_status_out(cosa, 0); debug_data_in(cosa, cosa->rxsize & 0xff); #endif #if 0 @@ -1695,12 +1791,8 @@ } } else { cosa->rxsize = cosa_getdata16(cosa); - cosa_putstatus(cosa, 0); - cosa_putdata8(cosa, DRIVER_RX_READY); #ifdef DEBUG_IO debug_data_in(cosa, cosa->rxsize); - debug_status_out(cosa, 0); - debug_cmd_out(cosa, DRIVER_RX_READY); #endif #if 0 printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n", @@ -1725,10 +1817,7 @@ reject: /* Reject the packet */ printk(KERN_INFO "cosa%d: rejecting packet on channel %d\n", cosa->num, cosa->rxchan->num); - /* FIXME: This works for COSA only (not SRP) */ - cosa->rxtx = 0; - put_driver_status(cosa); - return; + cosa->rxbuf = cosa->bouncebuf; } /* start the DMA */ @@ -1746,8 +1835,12 @@ release_dma_lock(flags); spin_lock_irqsave(&cosa->lock, flags); cosa_putstatus(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA); + if (!is_8bit(cosa) && (status & SR_TX_RDY)) + cosa_putdata8(cosa, DRIVER_RX_READY); #ifdef DEBUG_IO debug_status_out(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA); + if (!is_8bit(cosa) && (status & SR_TX_RDY)) + debug_data_cmd(cosa, DRIVER_RX_READY); #endif spin_unlock_irqrestore(&cosa->lock, flags); } @@ -1756,11 +1849,12 @@ { unsigned long flags, flags1; spin_lock_irqsave(&cosa->lock, flags); + flags1 = claim_dma_lock(); + disable_dma(cosa->dma); + clear_dma_ff(cosa->dma); + release_dma_lock(flags1); if (test_bit(TXBIT, &cosa->rxtx)) { struct channel_data *chan = cosa->chan+cosa->txchan; -#ifdef DEBUG_IRQS - printk(KERN_INFO "cosa%d: end of transfer.\n", cosa->num); -#endif if (chan->tx_done) if (chan->tx_done(chan, cosa->txsize)) clear_bit(chan->num, &cosa->txbitmap); @@ -1775,6 +1869,9 @@ printk("\n"); } #endif + /* Packet for unknown channel? */ + if (cosa->rxbuf == cosa->bouncebuf) + goto out; if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); if (cosa->rxchan->rx_done) @@ -1786,12 +1883,11 @@ } /* * Clear the RXBIT, TXBIT and IRQBIT (the latest should be - * cleared anyway). + * cleared anyway). We should do it as soon as possible + * so that we can tell the COSA we are done and to give it a time + * for recovery. */ - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - release_dma_lock(flags1); +out: cosa->rxtx = 0; put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); @@ -1799,7 +1895,7 @@ static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs) { - int status; + unsigned status; int count = 0; struct cosa_data *cosa = cosa_; again: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/cosa.h linux.ac/drivers/net/cosa.h --- linux.vanilla/drivers/net/cosa.h Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/net/cosa.h Tue Feb 16 17:30:03 1999 @@ -1,4 +1,4 @@ -/* $Id: cosa.h,v 1.5 1998/12/24 12:40:18 kas Exp $ */ +/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -98,5 +98,14 @@ /* Get the number of channels on this card */ #define COSAIONRCHANS _IO('C',0xf8) + +/* Set the driver for the bus-master operations */ +#define COSAIOBMSET _IOW('C', 0xf9, sizeof(unsigned short)) + +#define COSA_BM_OFF 0 /* Bus-mastering off - use ISA DMA (default) */ +#define COSA_BM_ON 1 /* Bus-mastering on - faster but untested */ + +/* Gets the busmaster status */ +#define COSAIOBMGET _IO('C', 0xfa) #endif /* !COSA_H__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/cs89x0.c linux.ac/drivers/net/cs89x0.c --- linux.vanilla/drivers/net/cs89x0.c Sun Nov 8 15:10:16 1998 +++ linux.ac/drivers/net/cs89x0.c Thu Feb 4 20:22:31 1999 @@ -991,22 +991,26 @@ 0, 0, 0, 0, 0, NULL, NULL }; -int io=0; -int irq=0; -#endif -#ifdef MODULE -int debug=1; -char *media="auto"; -char *duplex="f"; +static int io=0; +static int irq=0; +static int debug=0; +static char media[8]; +static int duplex=-1; + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(media, "s"); +MODULE_PARM(duplex, "i"); + +EXPORT_NO_SYMBOLS; /* * media=t - specify media type or media=2 or media=aui or medai=auto -* duplex=f - specify forced half/full/autonegotiate duplex - or duplex=h - or duplex=auto +* duplex=0 - specify forced half/full/autonegotiate duplex * debug=# - debug level @@ -1044,12 +1048,14 @@ /* boy, they'd better get these right */ if (!strcmp(media, "rj45")) lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; - if (!strcmp(media, "aui")) + else if (!strcmp(media, "aui")) lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; - if (!strcmp(media, "bnc")) + else if (!strcmp(media, "bnc")) lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; + else + lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; - if (!strcmp(duplex, "auto")) + if (duplex==-1) lp->auto_neg_cnf = AUTO_NEG_ENABLE; if (io == 0) { 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/ibmtr.c linux.ac/drivers/net/ibmtr.c --- linux.vanilla/drivers/net/ibmtr.c Tue Jan 26 09:44:20 1999 +++ linux.ac/drivers/net/ibmtr.c Mon Mar 1 14:24:08 1999 @@ -128,11 +128,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -1353,12 +1351,23 @@ static void tr_tx(struct device *dev) { struct tok_info *ti=(struct tok_info *) dev->priv; - struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data; + struct trh_hdr *trhdr; unsigned int hdr_len; __u32 dhb; unsigned char xmit_command; int i; struct trllc *llc; + + if(ti->current_skb==NULL) + { + printk(KERN_ERR "%s: tx request but no packet!\n", + dev->name); + dev->tbusy=0; + mark_bh(NET_BH); + return; + } + + trhdr=(struct trh_hdr *)ti->current_skb->data; if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF) DPRINTK("ASB not free !!!\n"); @@ -1603,6 +1612,7 @@ writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); writew(ti->exsap_station_id, ti->srb +offsetof(struct srb_xmit, station_id)); + wmb(); /* This must be written before the IRQ hits */ writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); dev->trans_start=jiffies; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/Config.in linux.ac/drivers/net/irda/Config.in --- linux.vanilla/drivers/net/irda/Config.in Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/Config.in Tue Feb 16 17:45:19 1999 @@ -9,6 +9,7 @@ dep_tristate ' ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRTTY_SIR dep_tristate ' ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRTTY_SIR dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRTTY_SIR + dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRTTY_SIR fi fi dep_tristate ' NSC PC87108' CONFIG_NSC_FIR $CONFIG_IRDA diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/Makefile linux.ac/drivers/net/irda/Makefile --- linux.vanilla/drivers/net/irda/Makefile Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/Makefile Tue Feb 16 17:45:19 1999 @@ -68,6 +68,14 @@ endif endif +ifeq ($(CONFIG_GIRBIL_DONGLE),y) +L_OBJS += girbil.o +else + ifeq ($(CONFIG_GIRBIL_DONGLE),m) + M_OBJS += girbil.o + endif +endif + include $(TOPDIR)/Rules.make clean: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/actisys.c linux.ac/drivers/net/irda/actisys.c --- linux.vanilla/drivers/net/irda/actisys.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/actisys.c Tue Feb 16 17:45:19 1999 @@ -1,13 +1,13 @@ /********************************************************************* * * Filename: actisys.c - * Version: 0.4 + * Version: 0.5 * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ * dongles * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Jan 18 11:30:25 1999 + * Modified at: Tue Feb 9 15:38:16 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -70,9 +70,10 @@ static void actisys_open( struct irda_device *idev, int type) { - strcat( idev->name, " <-> actisys"); + strcat(idev->description, " <-> actisys"); idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -85,24 +86,20 @@ /* * Function actisys_change_speed (tty, baud) * - * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. - * To cycle through the available baud rates, pulse RTS low for a few ms. - * To be compatible with the new IR-220L+, we have to reset the dongle - * first since its not possible cycle around anymore and still be - * compatible with both dongles :-( + * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. + * To cycle through the available baud rates, pulse RTS low for a few + * ms. */ static void actisys_change_speed( struct irda_device *idev, int baudrate) { struct irtty_cb *self; struct tty_struct *tty; - int arg; struct termios old_termios; int cflag; int current_baudrate; int index = 0; - mm_segment_t fs; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG( 4, __FUNCTION__ "()\n"); ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -115,10 +112,10 @@ current_baudrate = idev->qos.baud_rate.value; /* Find the correct baudrate index for the currently used baudrate */ - while ( current_baudrate != baud_rates[index]) + while (current_baudrate != baud_rates[index]) index++; - DEBUG( 0, __FUNCTION__ "(), index=%d\n", index); + DEBUG( 4, __FUNCTION__ "(), index=%d\n", index); if ( !self->tty) return; @@ -127,38 +124,18 @@ /* Cycle through avaiable baudrates until we reach the correct one */ while ( current_baudrate != baudrate) { - DEBUG( 0, __FUNCTION__ "(), current baudrate = %d\n", + DEBUG( 4, __FUNCTION__ "(), current baudrate = %d\n", baud_rates[index]); - DEBUG( 0, __FUNCTION__ "(), Clearing RTS\n"); /* Set DTR, clear RTS */ - arg = TIOCM_DTR|TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ - "Error clearing RTS!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, FALSE); /* Wait at a few ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); /* Set DTR, Set RTS */ - arg = TIOCM_DTR | TIOCM_RTS |TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ "Error setting RTS!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, TRUE); /* Wait at a few ms again */ current->state = TASK_INTERRUPTIBLE; @@ -172,8 +149,8 @@ current_baudrate = baud_rates[index]; } - DEBUG( 0, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); + DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", + baud_rates[index]); /* Now change the speed of the serial port */ old_termios = *(tty->termios); @@ -200,9 +177,8 @@ break; } + /* Change speed of serial port */ tty->termios->c_cflag = cflag; - - DEBUG( 0, __FUNCTION__ "(), Setting the speed of the serial port\n"); tty->driver.set_termios( tty, &old_termios); } @@ -219,10 +195,6 @@ { struct irtty_cb *self; struct tty_struct *tty; - int arg = 0; - mm_segment_t fs; - - DEBUG( 4, __FUNCTION__ "()\n"); ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -236,36 +208,16 @@ if ( !tty) return; - DEBUG( 0, __FUNCTION__ "(), Clearing DTR\n"); - arg = TIOCM_RTS | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG( 0, __FUNCTION__"(), ioctl error!\n"); - } - set_fs(fs); + /* Clear DTR */ + irtty_set_dtr_rts(tty, FALSE, TRUE); /* Sleep 10-20 ms*/ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); - DEBUG( 0, __FUNCTION__ "(), Setting DTR\n"); - arg = TIOCM_RTS | TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG( 0, __FUNCTION__"(), ioctl error!\n"); - } - set_fs(fs); - idev->qos.baud_rate.value = 9600; } @@ -287,6 +239,9 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); /* * Function init_module (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/esi.c linux.ac/drivers/net/irda/esi.c --- linux.vanilla/drivers/net/irda/esi.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/esi.c Tue Feb 16 17:45:19 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: esi.c - * Version: 1.1 - * Description: Driver for the Extended Systems JetEye PC + * Version: 1.2 + * Description: Driver for the Extended Systems JetEye PC dongle * Status: Experimental. * Author: Thomas Davis, * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Mon Jan 18 11:30:32 1999 + * Modified at: Tue Feb 9 15:36:47 1999 * Modified by: Dag Brattli * Sources: esi.c * @@ -71,6 +71,7 @@ strcat( idev->description, " <-> esi"); idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -90,10 +91,9 @@ { struct irtty_cb *self; struct tty_struct *tty; - int arg = TIOCM_OUT2; + int dtr, rts; struct termios old_termios; int cflag; - mm_segment_t fs; ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -116,37 +116,25 @@ switch (baud) { case 19200: cflag |= B19200; - arg |= TIOCM_DTR; + dtr = TRUE; + rts = FALSE; break; case 115200: cflag |= B115200; - arg |= TIOCM_RTS | TIOCM_DTR; + dtr = rts = TRUE; break; case 9600: default: cflag |= B9600; - arg |= TIOCM_RTS; + dtr = FALSE; + rts = TRUE; break; } - + /* Change speed of serial driver */ tty->termios->c_cflag = cflag; tty->driver.set_termios( tty, &old_termios); - /* - * The ioctl function, or actually set_modem_info in serial.c - * expects a pointer to the argument in user space. To hack us - * around this we use the set_fs function to fool the routines - * that check if they are called from user space. We also need - * to send a pointer to the argument so get_user() gets happy. - * DB. - */ - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ "(), error setting ESI speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, dtr, rts); } static void esi_reset( struct irda_device *idev, int unused) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/girbil.c linux.ac/drivers/net/irda/girbil.c --- linux.vanilla/drivers/net/irda/girbil.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/irda/girbil.c Tue Feb 16 17:45:19 1999 @@ -0,0 +1,276 @@ +/********************************************************************* + * + * Filename: girbil.c + * Version: 1.0 + * Description: Implementation for the Greenwich GIrBIL dongle + * Status: Experimental. + * Author: Dag Brattli + * Created at: Sat Feb 6 21:02:33 1999 + * Modified at: Tue Feb 9 15:36:36 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +static void girbil_reset(struct irda_device *dev, int unused); +static void girbil_open(struct irda_device *dev, int type); +static void girbil_close(struct irda_device *dev); +static void girbil_change_speed(struct irda_device *dev, int baud); +static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos); + +/* Control register 1 */ +#define GIRBIL_TXEN 0x01 /* Enable transmitter */ +#define GIRBIL_RXEN 0x02 /* Enable receiver */ +#define GIRBIL_ECAN 0x04 /* Cancel self emmited data */ +#define GIRBIL_ECHO 0x08 /* Echo control characters */ + +/* LED Current Register (0x2) */ +#define GIRBIL_HIGH 0x20 +#define GIRBIL_MEDIUM 0x21 +#define GIRBIL_LOW 0x22 + +/* Baud register (0x3) */ +#define GIRBIL_2400 0x30 +#define GIRBIL_4800 0x31 +#define GIRBIL_9600 0x32 +#define GIRBIL_19200 0x33 +#define GIRBIL_38400 0x34 +#define GIRBIL_57600 0x35 +#define GIRBIL_115200 0x36 + +/* Mode register (0x4) */ +#define GIRBIL_IRDA 0x40 +#define GIRBIL_ASK 0x41 + +/* Control register 2 (0x5) */ +#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ + +static struct dongle dongle = { + GIRBIL_DONGLE, + girbil_open, + girbil_close, + girbil_reset, + girbil_change_speed, + girbil_init_qos, +}; + +__initfunc(void girbil_init(void)) +{ + irtty_register_dongle(&dongle); +} + +void girbil_cleanup(void) +{ + irtty_unregister_dongle(&dongle); +} + +static void girbil_open(struct irda_device *idev, int type) +{ + strcat( idev->description, " <-> girbil"); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; + + MOD_INC_USE_COUNT; +} + +static void girbil_close(struct irda_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +/* + * Function girbil_change_speed (dev, speed) + * + * Set the speed for the Girbil type dongle. Warning, this + * function must be called with a process context! + * + */ +static void girbil_change_speed(struct irda_device *idev, int speed) +{ + struct irtty_cb *self; + struct tty_struct *tty; + struct termios old_termios; + int cflag; + __u8 control[2]; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = (struct irtty_cb *) idev->priv; + + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); + + if (!self->tty) + return; + + tty = self->tty; + + old_termios = *(tty->termios); + cflag = tty->termios->c_cflag; + + cflag &= ~CBAUD; + + switch (speed) { + case 9600: + default: + cflag |= B9600; + control[0] = GIRBIL_9600; + break; + case 19200: + cflag |= B19200; + control[0] = GIRBIL_19200; + break; + case 34800: + cflag |= B38400; + control[0] = GIRBIL_38400; + break; + case 57600: + cflag |= B57600; + control[0] = GIRBIL_57600; + break; + case 115200: + cflag |= B115200; + control[0] = GIRBIL_115200; + break; + } + control[1] = GIRBIL_LOAD; + + /* Set DTR and Clear RTS to enter command mode */ + irtty_set_dtr_rts(tty, FALSE, TRUE); + + /* Write control bytes */ + if (tty->driver.write) + tty->driver.write(self->tty, 0, control, 2); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); + + /* Now change the speed of the serial port */ + tty->termios->c_cflag = cflag; + tty->driver.set_termios(tty, &old_termios); +} + +/* + * Function girbil_reset (driver) + * + * This function resets the girbil dongle. Warning, this function + * must be called with a process context!! + * + * Algorithm: + * 0. set RTS, and wait at least 5 ms + * 1. clear RTS + */ +void girbil_reset(struct irda_device *idev, int unused) +{ + struct irtty_cb *self; + struct tty_struct *tty; + __u8 control = GIRBIL_TXEN | GIRBIL_RXEN /* | GIRBIL_ECAN */; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = (struct irtty_cb *) idev->priv; + + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); + + tty = self->tty; + if (!tty) + return; + + /* Reset dongle */ + irtty_set_dtr_rts(tty, TRUE, FALSE); + + /* Sleep at least 5 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Set DTR and clear RTS to enter command mode */ + irtty_set_dtr_rts(tty, FALSE, TRUE); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Write control byte */ + if (tty->driver.write) + tty->driver.write(self->tty, 0, &control, 1); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); +} + +/* + * Function girbil_init_qos (qos) + * + * Initialize QoS capabilities + * + */ +static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos) +{ + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ +} + +#ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); + +/* + * Function init_module (void) + * + * Initialize Girbil module + * + */ +int init_module(void) +{ + girbil_init(); + return(0); +} + +/* + * Function cleanup_module (void) + * + * Cleanup Girbil module + * + */ +void cleanup_module(void) +{ + girbil_cleanup(); +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/irport.c linux.ac/drivers/net/irda/irport.c --- linux.vanilla/drivers/net/irda/irport.c Tue Jan 26 09:44:20 1999 +++ linux.ac/drivers/net/irda/irport.c Wed Jan 27 19:06:11 1999 @@ -96,7 +96,7 @@ #ifdef MODULE static void irport_cleanup(void) { - int i; +/* int i; */ DEBUG( 4, __FUNCTION__ "()\n"); @@ -303,7 +303,6 @@ int irport_hard_xmit( struct sk_buff *skb, struct device *dev) { struct irda_device *idev; - int xbofs; int actual; DEBUG( 4, __FUNCTION__ "()\n"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/irtty.c linux.ac/drivers/net/irda/irtty.c --- linux.vanilla/drivers/net/irda/irtty.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/irtty.c Tue Feb 16 17:45:19 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: irtty.c - * Version: 1.0 + * Version: 1.1 * Description: IrDA line discipline implementation * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Mon Jan 18 15:32:03 1999 + * Modified at: Tue Feb 9 13:08:25 1999 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -206,6 +206,7 @@ self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200; self->idev.qos.min_turn_time.bits = 0x03; + self->idev.flags = IFF_SIR | IFF_PIO; irda_qos_bits_to_value( &self->idev.qos); /* Specify which buffer allocation policy we need */ @@ -272,8 +273,6 @@ kfree( self); MOD_DEC_USE_COUNT; - - DEBUG( 4, "IrTTY: close() -->\n"); } /* @@ -289,6 +288,8 @@ struct irtty_cb *self; int cflag; + DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); + ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -360,10 +361,15 @@ DEBUG( 0, __FUNCTION__ "(), Tekram dongle!\n"); request_module( "tekram"); break; - case ACTISYS_DONGLE: + case ACTISYS_DONGLE: /* FALLTHROUGH */ + case ACTISYS_PLUS_DONGLE: DEBUG( 0, __FUNCTION__ "(), ACTiSYS dongle!\n"); request_module( "actisys"); break; + case GIRBIL_DONGLE: + DEBUG( 0, __FUNCTION__ "(), GIrBIL dongle!\n"); + request_module( "girbil"); + break; default: DEBUG( 0, __FUNCTION__ "(), Unknown dongle type!\n"); return; @@ -373,8 +379,7 @@ node = hashbin_find( dongles, type, NULL); if ( !node) { - DEBUG( 0, __FUNCTION__ - "(), Unable to find requested dongle\n"); + DEBUG(0, __FUNCTION__ "(), Unable to find requested dongle\n"); return; } self->dongle_q = node; @@ -401,8 +406,7 @@ * The Swiss army knife of system calls :-) * */ -static int irtty_ioctl( struct tty_struct *tty, void *file, int cmd, - void *arg) +static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { struct irtty_cb *self; int err = 0; @@ -444,8 +448,8 @@ * been received, which can now be decapsulated and delivered for * further processing */ -static void irtty_receive_buf( struct tty_struct *tty, const unsigned - char *cp, char *fp, int count) +static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; @@ -464,11 +468,8 @@ cp++; continue; } - /* - * Unwrap and destuff one byte - */ + /* Unwrap and destuff one byte */ async_unwrap_char( &self->idev, *cp++); - /* self->rx_over_errors++; */ } } @@ -478,7 +479,7 @@ * Transmit skb * */ -static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev) +static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irtty_cb *self; struct irda_device *idev; @@ -487,43 +488,40 @@ ASSERT( dev != NULL, return 0;); ASSERT( skb != NULL, return 0;); - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } - idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return 0;); - ASSERT( self->magic == IRTTY_MAGIC, return 0;); + ASSERT(self != NULL, return 0;); + ASSERT(self->magic == IRTTY_MAGIC, return 0;); /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) - return 0; + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; /* * Transfer skb to tx_buff while wrapping, stuffing and making CRC */ - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); dev->trans_start = jiffies; if ( self->tty->driver.write) - actual = self->tty->driver.write( self->tty, 0, - idev->tx_buff.data, - idev->tx_buff.len); + actual = self->tty->driver.write(self->tty, 0, + idev->tx_buff.data, + idev->tx_buff.len); idev->tx_buff.offset = actual; idev->tx_buff.head = idev->tx_buff.data + actual; + + idev->stats.tx_packets++; + idev->stats.tx_bytes += idev->tx_buff.len; #if 0 /* * Did we transmit the whole frame? Commented out for now since @@ -535,8 +533,7 @@ irda_unlock( &self->tbusy); } #endif - - dev_kfree_skb( skb); + dev_kfree_skb(skb); return 0; } @@ -587,8 +584,6 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); idev->netdev.tbusy = 0; /* Unlock */ - idev->stats.tx_packets++; - idev->stats.tx_bytes += idev->tx_buff.len; /* Tell network layer that we want more frames */ mark_bh( NET_BH); @@ -602,8 +597,6 @@ actual = tty->driver.write( tty, 0, idev->tx_buff.head, count); idev->tx_buff.offset += actual; idev->tx_buff.head += actual; - - DEBUG( 4, "actual=%d, sent %d\n", actual, count); } /* @@ -648,8 +641,7 @@ } /* Make new IrDA dongle */ - new = (struct dongle_q *) kmalloc (sizeof (struct dongle_q), - GFP_KERNEL); + new = (struct dongle_q *)kmalloc(sizeof(struct dongle_q), GFP_KERNEL); if (new == NULL) { return 1; @@ -675,6 +667,35 @@ kfree( node); } + +void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts) +{ + mm_segment_t fs; + int arg = TIOCM_OUT2; + + if (rts) + arg |= TIOCM_RTS; + if (dtr) + arg |= TIOCM_DTR; + + /* + * The ioctl() function, or actually set_modem_info() in serial.c + * expects a pointer to the argument in user space. To hack us + * around this, we use the set_fs() function to fool the routines + * that check if they are called from user space. We also need + * to send a pointer to the argument so get_user() gets happy. DB. + */ + + fs = get_fs(); + set_fs(get_ds()); + + if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { + DEBUG(0, __FUNCTION__ "(), error!\n"); + } + set_fs(fs); +} + + static int irtty_net_init( struct device *dev) { /* Set up to be a normal IrDA network device driver */ @@ -714,6 +735,9 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("IrDA TTY device driver"); /* * Function init_module (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/pc87108.c linux.ac/drivers/net/irda/pc87108.c --- linux.vanilla/drivers/net/irda/pc87108.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/pc87108.c Mon Mar 1 14:24:08 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Mon Dec 28 08:46:16 1998 + * Modified at: Tue Feb 9 13:29:40 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli @@ -50,7 +50,6 @@ #include #include #include -#include #include #include @@ -100,7 +99,9 @@ /* Some prototypes */ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, unsigned int irq, unsigned int dma); +#ifdef MODULE static int pc87108_close( struct irda_device *idev); +#endif /* MODULE */ static int pc87108_probe( int iobase, int board_addr, int irq, int dma); static void pc87108_pio_receive( struct irda_device *idev); static int pc87108_dma_receive( struct irda_device *idev); @@ -221,6 +222,8 @@ idev->qos.min_turn_time.bits = 0x07; irda_qos_bits_to_value( &idev->qos); + idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; + /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; idev->tx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -250,6 +253,7 @@ return 0; } +#ifdef MODULE /* * Function pc87108_close (idev) * @@ -276,6 +280,7 @@ return 0; } +#endif /* MODULE */ /* * Function pc87108_probe (iobase, board_addr, irq, dma) @@ -720,12 +725,6 @@ iobase = idev->io.iobase; DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); - - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } /* Lock transmit buffer */ if ( irda_lock( (void *) &dev->tbusy) == FALSE) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/tekram.c linux.ac/drivers/net/irda/tekram.c --- linux.vanilla/drivers/net/irda/tekram.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/irda/tekram.c Tue Feb 16 17:45:19 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: tekram.c - * Version: 0.4 + * Version: 0.5 * Description: Implementation of the Tekram IrMate IR-210B dongle * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Jan 18 11:30:38 1999 + * Modified at: Tue Feb 9 15:36:55 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -63,9 +63,12 @@ irtty_unregister_dongle( &dongle); } -static void tekram_open( struct irda_device *dev, int type) +static void tekram_open( struct irda_device *idev, int type) { - strcat( dev->name, " <-> tekram"); + strcat(idev->description, " <-> tekram"); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -96,11 +99,8 @@ struct irtty_cb *self; struct tty_struct *tty; struct termios old_termios; - int arg = 0; int cflag; __u8 byte; - int actual; - mm_segment_t fs; DEBUG( 4, __FUNCTION__ "()\n"); @@ -147,44 +147,22 @@ } /* Set DTR, Clear RTS */ - DEBUG( 0, __FUNCTION__ "(), Setting DTR, Clearing RTS\n"); - arg = TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, FALSE); /* Wait at least 7us */ udelay( 7); - DEBUG( 0, __FUNCTION__ "(), Writing control byte\n"); /* Write control byte */ if ( tty->driver.write) - actual = tty->driver.write( self->tty, 0, &byte, 1); + tty->driver.write( self->tty, 0, &byte, 1); /* Wait at least 100 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout( 10); /* Set DTR, Set RTS */ - DEBUG( 0, __FUNCTION__ "(), Setting DTR, Setting RTS\n"); - arg = TIOCM_DTR | TIOCM_RTS | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, TRUE); - DEBUG( 0, __FUNCTION__ "(), Setting new speed on serial port\n"); /* Now change the speed of the serial port */ tty->termios->c_cflag = cflag; tty->driver.set_termios( tty, &old_termios); @@ -208,8 +186,6 @@ { struct irtty_cb *self; struct tty_struct *tty; - int arg = 0; - mm_segment_t fs; DEBUG( 4, __FUNCTION__ "()\n"); @@ -225,51 +201,22 @@ if ( !tty) return; - DEBUG( 0, __FUNCTION__ "(), Power off dongle\n"); - arg = TIOCM_RTS | TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG(0, "error setting ESI speed!\n"); - } - set_fs(fs); + /* Power off dongle */ + irtty_set_dtr_rts(tty, FALSE, FALSE); /* Sleep 50 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(5); - - DEBUG( 0, __FUNCTION__ "(), Set DTR, clear RTS\n"); - /* Set DTR, clear RTS */ - arg = TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "Error setting Tekram speed!\n"); - } - set_fs(fs); + + /* Clear DTR, Set RTS */ + irtty_set_dtr_rts(tty, FALSE, TRUE); /* Should sleep 1 ms, but 10-20 should not do any harm */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); - DEBUG( 0, __FUNCTION__ "(), STATE3\n"); - /* Clear DTR, clear RTS */ - arg = TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + /* Set DTR, Set RTS */ + irtty_set_dtr_rts(tty, TRUE, TRUE); /* Finished! */ } @@ -287,6 +234,9 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); /* * Function init_module (void) @@ -311,4 +261,4 @@ tekram_cleanup(); } -#endif +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/uircc.c linux.ac/drivers/net/irda/uircc.c --- linux.vanilla/drivers/net/irda/uircc.c Tue Jan 26 09:44:21 1999 +++ linux.ac/drivers/net/irda/uircc.c Tue Feb 16 17:45:19 1999 @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Dec 26 10:59:03 1998 - * Modified at: Tue Jan 19 23:54:04 1999 + * Modified at: Tue Feb 9 13:30:41 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -196,6 +196,8 @@ idev->qos.min_turn_time.bits = 0x07; irda_qos_bits_to_value( &idev->qos); + + idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -271,9 +273,11 @@ static int uircc_probe( int iobase, int iobase2, int irq, int dma) { int version; +#if 0 int probe_irq=0; unsigned long mask; int i; +#endif DEBUG( 0, __FUNCTION__ "()\n"); @@ -442,20 +446,12 @@ DEBUG(0, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); /* Use irport for SIR speeds */ - if ( idev->io.baudrate <= 115200) { - return irport_hard_xmit( skb, dev); - } - - if ( dev->tbusy) { - __u8 sr3; - - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; + if (idev->io.baudrate <= 115200) { + return irport_hard_xmit(skb, dev); } /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) + if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; memcpy( idev->tx_buff.data, skb->data, skb->len); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/w83977af_ir.c linux.ac/drivers/net/irda/w83977af_ir.c --- linux.vanilla/drivers/net/irda/w83977af_ir.c Tue Dec 22 23:19:44 1998 +++ linux.ac/drivers/net/irda/w83977af_ir.c Tue Feb 16 17:45:19 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Mon Dec 14 21:51:53 1998 + * Modified at: Tue Feb 9 13:30:35 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Corel Computer Corp. @@ -204,6 +204,8 @@ /* The HP HDLS-1100 needs 1 ms according to the specs */ idev->qos.min_turn_time.bits = 0x03; /* 1ms and more */ irda_qos_bits_to_value( &idev->qos); + + idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -468,12 +470,6 @@ iobase = idev->io.iobase; DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); - - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } /* Lock transmit buffer */ if ( irda_lock( (void *) &dev->tbusy) == FALSE) 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 Sun Nov 8 15:07:29 1998 +++ linux.ac/drivers/net/myri_sbus.c Mon Mar 1 14:24:08 1999 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -278,7 +277,7 @@ mp->rx_skbs[i] = skb; skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - rxd[i].myri_scatters[0].addr = (u32) ((unsigned long)skb->data); + rxd[i].myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE; rxd[i].ctx = i; rxd[i].num_sg = 1; @@ -340,12 +339,6 @@ dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; - -#ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), - skb->len, mp->myri_sbus_dev->my_bus); -#endif - entry = NEXT_TX(entry); } mp->tx_old = entry; @@ -437,8 +430,7 @@ drops++; DRX(("DROP ")); mp->enet_stats.rx_dropped++; - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -447,7 +439,7 @@ } #ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), + mmu_sync_dma(sbus_dvma_addr(skb->data), skb->len, mp->myri_sbus_dev->my_bus); #endif @@ -464,8 +456,7 @@ mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)new_skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(new_skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -489,8 +480,7 @@ /* Reuse original ring buffer. */ DRX(("reuse ")); - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -600,6 +590,12 @@ return 1; } + +#ifdef NEED_DMA_SYNCHRONIZATION + mmu_sync_dma(sbus_dvma_addr(skb->data), + skb->len, mp->myri_sbus_dev->my_bus); +#endif + /* This is just to prevent multiple PIO reads for TX_BUFFS_AVAIL. */ head = sq->head; tail = sq->tail; @@ -628,8 +624,7 @@ txd = &sq->myri_txd[entry]; mp->tx_skbs[entry] = skb; - txd->myri_gathers[0].addr = - (unsigned int) ((unsigned long)skb->data); + txd->myri_gathers[0].addr = sbus_dvma_addr(skb->data); txd->myri_gathers[0].len = len; txd->num_sg = 1; txd->chan = KERNEL_CHANNEL; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ne.c linux.ac/drivers/net/ne.c --- linux.vanilla/drivers/net/ne.c Tue Dec 22 23:19:46 1998 +++ linux.ac/drivers/net/ne.c Fri Feb 26 01:51:53 1999 @@ -105,6 +105,7 @@ {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */ {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */ {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ + {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {0,} }; #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ne2.c linux.ac/drivers/net/ne2.c --- linux.vanilla/drivers/net/ne2.c Sat Jan 9 21:50:41 1999 +++ linux.ac/drivers/net/ne2.c Mon Mar 1 14:24:08 1999 @@ -75,7 +75,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/plip.c linux.ac/drivers/net/plip.c --- linux.vanilla/drivers/net/plip.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/plip.c Fri Feb 26 01:53:20 1999 @@ -1217,7 +1217,7 @@ plip_searchfor(int list[], int a) { int i; - for (i = 0; i < 3 && list[i] != -1; i++) { + for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { if (list[i] == a) return 1; } return 0; @@ -1240,7 +1240,7 @@ /* If the user feeds parameters, use them */ while (pb) { if ((parport[0] == -1 && (!timid || !pb->devices)) || - plip_searchfor(parport, i)) { + plip_searchfor(parport, pb->number)) { if (i == PLIP_MAX) { printk(KERN_ERR "plip: too many devices\n"); break; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ppp.c linux.ac/drivers/net/ppp.c --- linux.vanilla/drivers/net/ppp.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/net/ppp.c Mon Mar 1 14:24:09 1999 @@ -61,7 +61,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ppp_deflate.c linux.ac/drivers/net/ppp_deflate.c --- linux.vanilla/drivers/net/ppp_deflate.c Sun Nov 8 15:07:30 1998 +++ linux.ac/drivers/net/ppp_deflate.c Mon Mar 1 14:24:09 1999 @@ -43,7 +43,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ 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/net/shaper.c linux.ac/drivers/net/shaper.c --- linux.vanilla/drivers/net/shaper.c Thu Nov 19 18:38:38 1998 +++ linux.ac/drivers/net/shaper.c Mon Mar 1 14:24:09 1999 @@ -53,13 +53,19 @@ * This will be fixed in BETA4 */ +/* + * bh_atomic() SMP races fixes and rewritten the locking code to be SMP safe + * and irq-mask friendly. NOTE: we can't use start_bh_atomic() in kick_shaper() + * because it's going to be recalled from an irq handler, and synchronize_bh() + * is a nono if called from irq context. + * 1999 Andrea Arcangeli + */ #include #include #include #include #include -#include #include #include #include @@ -83,21 +89,17 @@ static int shaper_lock(struct shaper *sh) { - unsigned long flags; - save_flags(flags); - cli(); /* - * Lock in an interrupt may fail + * Lock in an interrupt must fail */ - if(sh->locked && in_interrupt()) + while (test_and_set_bit(0, &sh->locked)) { - restore_flags(flags); - return 0; + if (!in_interrupt()) + sleep_on(&sh->wait_queue); + else + return 0; + } - while(sh->locked) - sleep_on(&sh->wait_queue); - sh->locked=1; - restore_flags(flags); return 1; } @@ -105,7 +107,7 @@ static void shaper_unlock(struct shaper *sh) { - sh->locked=0; + clear_bit(0, &sh->locked); wake_up(&sh->wait_queue); shaper_kick(sh); } @@ -240,7 +242,6 @@ dev_kfree_skb(ptr); } shaper_unlock(shaper); - shaper_kick(shaper); return 0; } @@ -285,24 +286,16 @@ static void shaper_kick(struct shaper *shaper) { struct sk_buff *skb; - unsigned long flags; - save_flags(flags); - cli(); - - del_timer(&shaper->timer); - /* * Shaper unlock will kick */ - if(shaper->locked) - { + if (test_and_set_bit(0, &shaper->locked)) + { if(sh_debug) printk("Shaper locked.\n"); - shaper->timer.expires=jiffies+1; - add_timer(&shaper->timer); - restore_flags(flags); + mod_timer(&shaper->timer, jiffies); return; } @@ -320,7 +313,7 @@ if(sh_debug) printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies); - if(skb->shapeclock - jiffies <= SHAPER_BURST) + if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST)) { /* * Pull the frame and get interrupts back on. @@ -329,8 +322,6 @@ skb_unlink(skb); if (shaper->recovery < skb->shapeclock + skb->shapelen) shaper->recovery = skb->shapeclock + skb->shapelen; - restore_flags(flags); - /* * Pass on to the physical target device via * our low level packet thrower. @@ -338,7 +329,6 @@ skb->shapepend=0; shaper_queue_xmit(shaper, skb); /* Fire */ - cli(); } else break; @@ -349,17 +339,9 @@ */ if(skb!=NULL) - { - del_timer(&shaper->timer); - shaper->timer.expires=skb->shapeclock; - add_timer(&shaper->timer); - } - - /* - * Interrupts on, mission complete - */ - - restore_flags(flags); + mod_timer(&shaper->timer, skb->shapeclock); + + clear_bit(0, &shaper->locked); } @@ -370,8 +352,14 @@ static void shaper_flush(struct shaper *shaper) { struct sk_buff *skb; + if(!shaper_lock(shaper)) + { + printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n"); + return; + } while((skb=skb_dequeue(&shaper->sendq))!=NULL) dev_kfree_skb(skb); + shaper_unlock(shaper); } /* @@ -405,7 +393,9 @@ { struct shaper *shaper=dev->priv; shaper_flush(shaper); + start_bh_atomic(); del_timer(&shaper->timer); + end_bh_atomic(); MOD_DEC_USE_COUNT; return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk_g16.c linux.ac/drivers/net/sk_g16.c --- linux.vanilla/drivers/net/sk_g16.c Sun Nov 8 15:07:22 1998 +++ linux.ac/drivers/net/sk_g16.c Mon Mar 1 14:55:42 1999 @@ -733,7 +733,7 @@ SK_print_pos(dev, "POS registers after ROM, RAM config"); #endif - board = (SK_RAM *) rom_addr; + board = (SK_RAM *) bus_to_virt(rom_addr); /* Read in station address */ for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/smc-ultra.c linux.ac/drivers/net/smc-ultra.c --- linux.vanilla/drivers/net/smc-ultra.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/net/smc-ultra.c Mon Mar 1 15:12:23 1999 @@ -2,7 +2,7 @@ /* This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. - Written 1993-1996 by Donald Becker. + Written 1993-1998 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. @@ -14,7 +14,7 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - This driver uses the cards in the 8390-compatible, shared memory mode. + This driver uses the cards in the 8390-compatible mode. Most of the run-time complexity is handled by the generic code in 8390.c. The code in this file is responsible for @@ -27,6 +27,8 @@ ultra_block_input() Routines for reading and writing blocks of ultra_block_output() packet buffer memory. + ultra_pio_input() + ultra_pio_output() This driver enables the shared memory only when doing the actual data transfers to avoid a bug in early version of the card that corrupted @@ -34,7 +36,7 @@ This driver now supports the programmed-I/O (PIO) data transfer mode of the EtherEZ. It does not use the non-8390-compatible "Altego" mode. - That support (if available) is smc-ez.c. + That support (if available) is in smc-ez.c. Changelog: @@ -44,8 +46,7 @@ */ static const char *version = - "smc-ultra.c:v2.00 6/6/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - + "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; #include @@ -75,13 +76,13 @@ static void ultra_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_block_output(struct device *dev, int count, - const unsigned char *buf, int start_page); + const unsigned char *buf, const int start_page); static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void ultra_pio_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, int start_page); + const unsigned char *buf, const int start_page); static int ultra_close_card(struct device *dev); @@ -155,11 +156,8 @@ if (load_8390_module("smc-ultra.c")) return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ - if (dev == NULL) { - printk("smc-ultra.c: Passed a NULL device.\n"); + if (dev == NULL) dev = init_etherdev(0, 0); - } if (ei_debug && version_printed++ == 0) printk(version); @@ -255,12 +253,19 @@ ultra_open(struct device *dev) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ + unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40, + 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, }; if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) return -EAGAIN; outb(0x00, ioaddr); /* Disable shared memory for safety. */ outb(0x80, ioaddr + 5); + /* Set the IRQ line. */ + outb(inb(ioaddr + 4) | 0x80, ioaddr + 4); + outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13); + outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4); + if (ei_status.block_input == &ultra_pio_input) { outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ outb(0x01, ioaddr + 0x19); /* Enable ring read auto-wrap. */ @@ -358,7 +363,7 @@ byte-sequentially to IOPA, with no intervening I/O operations, and the data is read or written to the IOPD data port. The only potential complication is that the address register is shared - must be always be rewritten between each read/write direction change. + and must be always be rewritten between each read/write direction change. This is no problem for us, as the 8390 code ensures that we are single threaded. */ static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, @@ -379,20 +384,17 @@ /* For now set the address again, although it should already be correct. */ outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */ outb(ring_offset >> 8, ioaddr + IOPA); + /* We know skbuffs are padded to at least word alignment. */ insw(ioaddr + IOPD, buf, (count+1)>>1); -#ifdef notdef - /* We don't need this -- skbuffs are padded to at least word alignment. */ - if (count & 0x01) { - buf[count-1] = inb(ioaddr + IOPD); -#endif } static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, int start_page) + const unsigned char *buf, const int start_page) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ outb(start_page, ioaddr + IOPA); + /* An extra odd byte is OK here as well. */ outsw(ioaddr + IOPD, buf, (count+1)>>1); } @@ -461,15 +463,12 @@ } if (register_netdev(dev) != 0) { printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - lock_8390_module(); - return 0; - } + if (found != 0) return 0; /* Got at least one. */ return -ENXIO; } found++; } - lock_8390_module(); + return 0; } @@ -481,15 +480,14 @@ for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { struct device *dev = &dev_ultra[this_dev]; if (dev->priv != NULL) { + /* NB: ultra_close_card() does free_irq + irq2dev */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; - void *priv = dev->priv; - /* NB: ultra_close_card() does free_irq */ + kfree(dev->priv); + dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); unregister_netdev(dev); - kfree(priv); } } - unlock_8390_module(); } #endif /* MODULE */ @@ -500,6 +498,7 @@ * version-control: t * kept-new-versions: 5 * c-indent-level: 4 + * c-basic-offset: 4 * tab-width: 4 * End: */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/smc9194.c linux.ac/drivers/net/smc9194.c --- linux.vanilla/drivers/net/smc9194.c Sun Nov 8 15:07:26 1998 +++ linux.ac/drivers/net/smc9194.c Mon Mar 1 14:24:09 1999 @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunhme.c linux.ac/drivers/net/sunhme.c --- linux.vanilla/drivers/net/sunhme.c Thu Nov 19 18:38:39 1998 +++ linux.ac/drivers/net/sunhme.c Mon Mar 1 14:24:09 1999 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #ifndef __sparc_v9__ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunqe.c linux.ac/drivers/net/sunqe.c --- linux.vanilla/drivers/net/sunqe.c Sun Nov 8 15:07:29 1998 +++ linux.ac/drivers/net/sunqe.c Mon Mar 1 14:24:09 1999 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.c linux.ac/drivers/net/wavelan.c --- linux.vanilla/drivers/net/wavelan.c Sun Nov 8 15:07:22 1998 +++ linux.ac/drivers/net/wavelan.c Thu Feb 18 20:32:39 1999 @@ -290,24 +290,26 @@ wv_16_on(ioaddr, hacr); } /* psa_write */ -#ifdef PSA_CRC +#ifdef SET_PSA_CRC /*------------------------------------------------------------------*/ /* - * Calculate the PSA CRC (not tested yet) - * As the WaveLAN drivers don't use the CRC, I won't use it either. - * Thanks to Nico Valster for the code + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code * NOTE: By specifying a length including the CRC position the - * returned value should be zero. (i.e. a correct checksum in the PSA). + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. */ -static u_short -psa_crc(u_short * psa, /* The PSA */ +static inline u_short +psa_crc(u_char * psa, /* The PSA */ int size) /* Number of short for CRC */ { int byte_cnt; /* Loop on the PSA */ u_short crc_bytes = 0; /* Data in the PSA */ int bit_cnt; /* Loop on the bits of the short */ - for(byte_cnt = 0; byte_cnt <= size; byte_cnt++ ) + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) { crc_bytes ^= psa[byte_cnt]; /* Its an xor */ @@ -322,7 +324,47 @@ return crc_bytes; } /* psa_crc */ -#endif /* PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(device * dev, + u_long ioaddr, + u_short hacr) +{ + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc ((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +} /* update_psa_checksum */ +#endif /* SET_PSA_CRC */ /*------------------------------------------------------------------*/ /* @@ -706,21 +748,21 @@ unsigned short ias_addr; /* Check mc_config command */ - if(status & AC_SFLD_OK != 0) + if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n", dev->name, str, status); /* check ia-config command */ ias_addr = mcs_addr - sizeof(ac_ias_t); obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if(status & AC_SFLD_OK != 0) + if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n", dev->name, str, status); /* Check config command. */ cfg_addr = ias_addr - sizeof(ac_cfg_t); obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if(status & AC_SFLD_OK != 0) + if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n", dev->name, str, status); #endif /* DEBUG_CONFIG_ERROR */ @@ -1890,6 +1932,10 @@ /* Disable NWID in the mmc (no filtering). */ mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); } +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif break; case SIOCGIWNWID: @@ -1946,6 +1992,10 @@ psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); break; @@ -1993,6 +2043,10 @@ mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); } +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif break; case SIOCGIWENCODE: @@ -2206,6 +2260,10 @@ psa.psa_quality_thr = *(wrq->u.name) & 0x0F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, (unsigned char *)&psa.psa_quality_thr, 1); +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); break; @@ -2316,7 +2374,7 @@ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); /* Copy data to wireless stuff. */ - wstats->status = m.mmr_dce_status; + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; @@ -2892,6 +2950,10 @@ (unsigned char *)&psa.psa_quality_thr, 1); psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa, (unsigned char *)&psa.psa_conf_status, 1); +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif #endif } @@ -2918,21 +2980,18 @@ m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; - /* Encryption stuff is missing. */ - /* * Set default modem control parameters. * See NCR document 407-0024326 Rev. A. */ m.mmw_jabber_enable = 0x01; + m.mmw_freeze = 0; m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; m.mmw_ifs = 0x20; m.mmw_mod_delay = 0x04; m.mmw_jam_time = 0x38; - m.mmw_encr_enable = 0; m.mmw_des_io_invert = 0; - m.mmw_freeze = 0; m.mmw_decay_prm = 0; m.mmw_decay_updat_prm = 0; @@ -3398,39 +3457,29 @@ /* Create a configure action. */ memset(&cfg, 0x00, sizeof(cfg)); -#if 0 - /* - * The default board configuration - */ - cfg.fifolim_bytecnt = 0x080c; - cfg.addrlen_mode = 0x2600; - cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */ - cfg.slot_time = 0xf00c; /* slottime=12 */ - cfg.hardware = 0x0008; /* tx even without CD */ - cfg.min_frame_len = 0x0040; -#endif /* 0 */ - /* * For Linux we invert AC_CFG_ALOC() so as to conform * to the way that net packets reach us from above. * (See also ac_tx_t.) + * + * Updated from Wavelan Manual WCIN085B */ cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); - cfg.cfg_fifolim = AC_CFG_FIFOLIM(8); - cfg.cfg_byte8 = AC_CFG_SAV_BF(0) | + cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); + cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | AC_CFG_ILPBCK(0) | AC_CFG_PRELEN(AC_CFG_PLEN_2) | AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); - cfg.cfg_byte10 = AC_CFG_BOFMET(0) | - AC_CFG_ACR(0) | + cfg.cfg_byte10 = AC_CFG_BOFMET(1) | + AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); - cfg.cfg_ifs = 32; - cfg.cfg_slotl = 0; + cfg.cfg_ifs = 0x20; + cfg.cfg_slotl = 0x0C; cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | - AC_CFG_SLTTMHI(2); + AC_CFG_SLTTMHI(0); cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | AC_CFG_BTSTF(0) | AC_CFG_CRC16(0) | @@ -4016,6 +4065,10 @@ #endif psa_write(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1); +#ifdef SET_PSA_CRC + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, HACR_DEFAULT); +#endif wv_hacr_reset(ioaddr); } } @@ -4196,7 +4249,7 @@ init_module(void) { mac_addr mac; /* MAC address (check WaveLAN existence) */ - int ret = 0; + int ret = -EIO; /* Return error if no cards found */ int i; #ifdef DEBUG_MODULE_TRACE @@ -4241,7 +4294,11 @@ /* Deallocate everything. */ /* Note: if dev->priv is mallocated, there is no way to fail. */ kfree_s(dev, sizeof(struct device)); - ret = -EIO; + } + else + { + /* If at least one device OK, we do not fail */ + ret = 0; } } /* if there is something at the address */ } /* Loop on all addresses. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.h linux.ac/drivers/net/wavelan.h --- linux.vanilla/drivers/net/wavelan.h Sun Nov 8 15:07:24 1998 +++ linux.ac/drivers/net/wavelan.h Thu Feb 18 20:32:39 1999 @@ -28,6 +28,8 @@ { { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ /* Add your card here and send me the patch! */ }; @@ -293,6 +295,7 @@ #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ unsigned char mmr_unused2[2]; /* unused */ unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.p.h linux.ac/drivers/net/wavelan.p.h --- linux.vanilla/drivers/net/wavelan.p.h Sun Nov 8 15:07:28 1998 +++ linux.ac/drivers/net/wavelan.p.h Tue Mar 2 02:13:54 1999 @@ -18,13 +18,7 @@ * This driver provides a Linux interface to the WaveLAN ISA hardware. * The WaveLAN is a product of Lucent (http://www.wavelan.com/). * This division was formerly part of NCR and then AT&T. - * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and - * Aironet (Arlan). If you have one of those products, you will need to - * make some changes below. - * - * This driver is still beta software. A lot of bugs have been corrected, - * a lot of functionality is implemented, and the whole appears stable, - * but there is still room for improvement (encryption, performance). + * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. * * To learn how to use this driver, read the NET3 HOWTO. * If you want to exploit the many other functionalities, read the comments @@ -35,12 +29,22 @@ /* ------------------------ SPECIFIC NOTES ------------------------ */ /* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + * * wavelan.o is too darned big * --------------------------- * That's true! There is a very simple way to reduce the driver * object by 33%! Comment out the following line: * #include * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * * MAC address and hardware detection: * ----------------------------------- * The detection code for the WaveLAN checks that the first three @@ -60,23 +64,6 @@ * 3) Compile and verify * 4) Send me the MAC code. I will include it in the next version. * - * "CU Inactive" message at boot up: - * ----------------------------------- - * It seems that there is some weird timing problem with the - * Intel microcontroller. In fact, this message is triggered by a - * bad reading of the onboard RAM the first time we read the - * control block. If you ignore this message, all is OK (but in - * fact, currently, it resets the WaveLAN hardware). - * - * There are two ways to get rid of that problem. The first - * is to add a dummy read of the scb at the end of - * wv_82586_config. The second is to add the timers - * wv_synchronous_cmd and wv_ack (the udelay just after the - * waiting loops--it seems that the controller is not totally ready - * when it says it is). - * - * In the current code, I use the second solution (to be - * consistent with the original solution of Bruce Janson). */ /* --------------------- WIRELESS EXTENSIONS --------------------- */ @@ -273,6 +260,22 @@ * - encryption setting from Brent Elphick (thanks a lot!) * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) * + * Other changes (not by me) : + * ------------------------- + * - Spelling and gramar "rectification". + * + * Changes made for release in 2.0.37 & 2.2.2 : + * ------------------------------------------ + * - Correct status in /proc/net/wireless + * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) + * - Module init code don't fail if we found at least one card in + * the address list (Karlis Peisenieks) + * - Missing parenthesis (Christopher Peterson) + * - Correct i82586 configuration parameters + * - Encryption initialisation bug (Robert McCormack) + * - New mac addresses detected in the probe + * - Increase watchdog for busy envirnoments + * * Wishes & dreams: * ---------------- * - roaming @@ -342,9 +345,9 @@ /* Options */ #define USE_PSA_CONFIG /* Use info from the PSA. */ +#define SET_PSA_CRC /* Calculate and set the CRC on PSA */ #define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions. */ #undef STRUCT_CHECK /* Verify padding of structures. */ -#undef PSA_CRC /* Check CRC in PSA. */ #undef OLDIES /* old code (to redo) */ #undef RECORD_SNR /* to redo */ #undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ @@ -359,11 +362,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v16 (wireless extensions) 17/4/97\n"; +static const char *version = "wavelan.c : v18 (wireless extensions) 18/2/99\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */ +#define WATCHDOG_JIFFIES 256 /* TODO: express in HZ. */ /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) 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 Tue Jan 19 02:57:29 1999 +++ linux.ac/drivers/pci/oldproc.c Mon Mar 1 00:28:28 1999 @@ -542,6 +542,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 Sun Nov 8 15:10:18 1998 +++ linux.ac/drivers/sbus/sbus.c Mon Mar 1 14:24:09 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 Sun Jan 3 03:52:01 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 @@ -66,6 +64,7 @@ fi if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI + dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI fi if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT @@ -76,6 +75,7 @@ fi fi dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI +dep_tristate 'symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then @@ -117,7 +117,7 @@ dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI -# dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI + dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/Makefile linux.ac/drivers/scsi/Makefile --- linux.vanilla/drivers/scsi/Makefile Sun Jan 3 03:52:01 1999 +++ linux.ac/drivers/scsi/Makefile Sat Jan 30 18:29:12 1999 @@ -298,6 +298,14 @@ endif endif +ifeq ($(CONFIG_SCSI_INIA100),y) +L_OBJS += a100u2w.o +else + ifeq ($(CONFIG_SCSI_INIA100),m) + M_OBJS += a100u2w.o + endif +endif + ifeq ($(CONFIG_SCSI_QLOGIC_FC),y) L_OBJS += qlogicfc.o else @@ -576,6 +584,14 @@ endif endif +ifeq ($(CONFIG_SCSI_SYM53C416),y) +L_OBJS += sym53c416.o +else + ifeq ($(CONFIG_SCSI_SYM53C416),m) + M_OBJS += sym53c416.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_IDESCSI),y) L_OBJS += ide-scsi.o else @@ -616,6 +632,9 @@ $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o $(LD) -r -o initio.o ini9100u.o i91uscsi.o rm -f ini9100u.o i91uscsi.o + +a100u2w.o: inia100.o i60uscsi.o + $(LD) -r -o a100u2w.o inia100.o i60uscsi.o megaraid.o: megaraid.c $(CC) $(CFLAGS) -c megaraid.c 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 Mon Mar 1 00:28:48 1999 @@ -160,21 +160,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 +246,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/atp870u.c linux.ac/drivers/scsi/atp870u.c --- linux.vanilla/drivers/scsi/atp870u.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/atp870u.c Tue Feb 16 17:41:52 1999 @@ -1684,7 +1684,7 @@ struct Scsi_Host * shpnt = NULL; int count = 0; static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0}; - static struct pci_dev *pdev = NULL; + static struct pci_dev *pdev = NULL, *acard_pdev[3]; printk("aec671x_detect: \n"); if (!pci_present()) @@ -1729,6 +1729,7 @@ chip_ver[2]=0; /* To avoid messing with the things below... */ + acard_pdev[2] = pdev; pci_device_fn[2] = pdev->devfn; pci_bus[2] = pdev->bus->number; @@ -1746,15 +1747,18 @@ } if ( pci_device_fn[2] < pci_device_fn[0] ) { + acard_pdev[1]=acard_pdev[0]; pci_bus[1]=pci_bus[0]; pci_device_fn[1]=pci_device_fn[0]; chip_ver[1]=chip_ver[0]; + acard_pdev[0]=acard_pdev[2]; pci_bus[0]=pci_bus[2]; pci_device_fn[0]=pci_device_fn[2]; chip_ver[0]=chip_ver[2]; } else if ( pci_device_fn[2] < pci_device_fn[1] ) { + acard_pdev[1]=acard_pdev[2]; pci_bus[1]=pci_bus[2]; pci_device_fn[1]=pci_device_fn[2]; chip_ver[1]=chip_ver[2]; @@ -1774,6 +1778,7 @@ return count; } + pdev = acard_pdev[h]; pdev->devfn = pci_device_fn[h]; pdev->bus->number = pci_bus[h]; 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/hosts.c linux.ac/drivers/scsi/hosts.c --- linux.vanilla/drivers/scsi/hosts.c Tue Jan 19 02:57:31 1999 +++ linux.ac/drivers/scsi/hosts.c Tue Feb 16 17:43:48 1999 @@ -223,6 +223,10 @@ #include "NCR53c406a.h" #endif +#ifdef CONFIG_SCSI_SYM53C416 +#include "sym53c416.h" +#endif + #ifdef CONFIG_SCSI_DC390T #include "dc390.h" #endif @@ -283,6 +287,10 @@ #include "ini9100u.h" #endif +#ifdef CONFIG_SCSI_INIA100 +#include "inia100.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif @@ -452,7 +460,7 @@ #ifdef CONFIG_SCSI_AIC7XXX AIC7XXX, #endif -#ifdef CONFIG_FD_MCS +#ifdef CONFIG_SCSI_FD_MCS FD_MCS, #endif #ifdef CONFIG_SCSI_FUTURE_DOMAIN @@ -467,6 +475,9 @@ #ifdef CONFIG_SCSI_NCR53C406A /* 53C406A should come before QLOGIC */ NCR53c406a, #endif +#ifdef CONFIG_SCSI_SYM53C416 + SYM53C416, +#endif #ifdef CONFIG_SCSI_QLOGIC_FAS QLOGICFAS, #endif @@ -532,6 +543,9 @@ #endif #ifdef CONFIG_SCSI_INITIO INI9100U, +#endif +#ifdef CONFIG_SCSI_INIA100 + INIA100, #endif #ifdef CONFIG_SCSI_QLOGICPTI QLOGICPTI, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/i60uscsi.c linux.ac/drivers/scsi/i60uscsi.c --- linux.vanilla/drivers/scsi/i60uscsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/i60uscsi.c Sat Jan 30 18:29:12 1999 @@ -0,0 +1,956 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ************************************************************************* + * + * module: i60uscsi.c + * DESCRIPTION: + * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host + * adapters + * + * 07/02/98 hl - v.91n Initial drivers. + * 09/14/98 hl - v1.01 Support new Kernel. + * 09/22/98 hl - v1.01a Support reset. + * 09/24/98 hl - v1.01b Fixed reset. + * 10/05/98 hl - v1.02 split the source code and release. + * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up + **************************************************************************/ + +#ifndef CVT_LINUX_VERSION +#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) +#endif + +#include +#include +#include "i60uscsi.h" + + +/* ---- INTERNAL FUNCTIONS ---- */ +static UCHAR waitChipReady(ORC_HCS * hcsp); +static UCHAR waitFWReady(ORC_HCS * hcsp); +static UCHAR waitFWReady(ORC_HCS * hcsp); +static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp); +static UCHAR waitHDOoff(ORC_HCS * hcsp); +static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData); +static unsigned short get_FW_version(ORC_HCS * hcsp); +static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value); +static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn); +static int se2_rd_all(ORC_HCS * hcsp); +static void se2_update_all(ORC_HCS * hcsp); /* setup default pattern */ +static void read_eeprom(ORC_HCS * hcsp); +static UCHAR load_FW(ORC_HCS * hcsp); +static void setup_SCBs(ORC_HCS * hcsp); +static void initAFlag(ORC_HCS * hcsp); +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp); + +/* ---- EXTERNAL FUNCTIONS ---- */ +extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb); + +/* ---- INTERNAL VARIABLES ---- */ +ORC_HCS orc_hcs[MAX_SUPPORTED_ADAPTERS]; +static INIA100_ADPT_STRUCT inia100_adpt[MAX_SUPPORTED_ADAPTERS]; +/* set by inia100_setup according to the command line */ +int orc_num_scb; + +NVRAM nvram, *nvramp = &nvram; +static UCHAR dftNvRam[64] = +{ +/*----------header -------------*/ + 0x01, /* 0x00: Sub System Vendor ID 0 */ + 0x11, /* 0x01: Sub System Vendor ID 1 */ + 0x60, /* 0x02: Sub System ID 0 */ + 0x10, /* 0x03: Sub System ID 1 */ + 0x00, /* 0x04: SubClass */ + 0x01, /* 0x05: Vendor ID 0 */ + 0x11, /* 0x06: Vendor ID 1 */ + 0x60, /* 0x07: Device ID 0 */ + 0x10, /* 0x08: Device ID 1 */ + 0x00, /* 0x09: Reserved */ + 0x00, /* 0x0A: Reserved */ + 0x01, /* 0x0B: Revision of Data Structure */ + /* -- Host Adapter Structure --- */ + 0x01, /* 0x0C: Number Of SCSI Channel */ + 0x01, /* 0x0D: BIOS Configuration 1 */ + 0x00, /* 0x0E: BIOS Configuration 2 */ + 0x00, /* 0x0F: BIOS Configuration 3 */ + /* --- SCSI Channel 0 Configuration --- */ + 0x07, /* 0x10: H/A ID */ + 0x83, /* 0x11: Channel Configuration */ + 0x20, /* 0x12: MAX TAG per target */ + 0x0A, /* 0x13: SCSI Reset Recovering time */ + 0x00, /* 0x14: Channel Configuration4 */ + 0x00, /* 0x15: Channel Configuration5 */ + /* SCSI Channel 0 Target Configuration */ + /* 0x16-0x25 */ + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + /* --- SCSI Channel 1 Configuration --- */ + 0x07, /* 0x26: H/A ID */ + 0x83, /* 0x27: Channel Configuration */ + 0x20, /* 0x28: MAX TAG per target */ + 0x0A, /* 0x29: SCSI Reset Recovering time */ + 0x00, /* 0x2A: Channel Configuration4 */ + 0x00, /* 0x2B: Channel Configuration5 */ + /* SCSI Channel 1 Target Configuration */ + /* 0x2C-0x3B */ + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0x00, /* 0x3C: Reserved */ + 0x00, /* 0x3D: Reserved */ + 0x00, /* 0x3E: Reserved */ + 0x00 /* 0x3F: Checksum */ +}; + + +/***************************************************************************/ +static void waitForPause(unsigned amount) +{ + ULONG the_time = jiffies + amount; /* 0.01 seconds per jiffy */ + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + while (time_before_eq(jiffies, the_time)); +#else + while (jiffies < the_time); +#endif +} + +/***************************************************************************/ +UCHAR waitChipReady(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitFWReady(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitSCSIRSTdone(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitHDOoff(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI) + return (TRUE); /* Wait HDI set */ + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +unsigned short get_FW_version(ORC_HCS * hcsp) +{ + UCHAR bData; + union { + unsigned short sVersion; + unsigned char cVersion[2]; + } Version; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION); + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + return (Version.sVersion); +} + +/***************************************************************************/ +UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value) +{ + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, value); /* Write value */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + return (TRUE); +} + +/***************************************************************************/ +UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn) +{ + unsigned char bData; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + return (TRUE); +} + +/***************************************************************************/ +void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +{ + scbp->SCB_Status = SCB_POST; + ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx); + return; +} + + +/*********************************************************************** + Read SCSI H/A configuration parameters from serial EEPROM +************************************************************************/ +int se2_rd_all(ORC_HCS * hcsp) +{ + int i; + UCHAR *np, chksum = 0; + + np = (UCHAR *) nvramp; + for (i = 0; i < 64; i++, np++) { /* <01> */ + if (get_NVRAM(hcsp, (unsigned char) i, np) == FALSE) + return -1; +// *np++ = get_NVRAM(hcsp, (unsigned char ) i); + } + +/*------ Is ckecksum ok ? ------*/ + np = (UCHAR *) nvramp; + for (i = 0; i < 63; i++) + chksum += *np++; + + if (nvramp->CheckSum != (UCHAR) chksum) + return -1; + return 1; +} + +/************************************************************************ + Update SCSI H/A configuration parameters from serial EEPROM +*************************************************************************/ +void se2_update_all(ORC_HCS * hcsp) +{ /* setup default pattern */ + int i; + UCHAR *np, *np1, chksum = 0; + + /* Calculate checksum first */ + np = (UCHAR *) dftNvRam; + for (i = 0; i < 63; i++) + chksum += *np++; + *np = chksum; + + np = (UCHAR *) dftNvRam; + np1 = (UCHAR *) nvramp; + for (i = 0; i < 64; i++, np++, np1++) { + if (*np != *np1) { + set_NVRAM(hcsp, (unsigned char) i, *np); + } + } + return; +} + +/************************************************************************* + Function name : read_eeprom +**************************************************************************/ +void read_eeprom(ORC_HCS * hcsp) +{ + if (se2_rd_all(hcsp) != 1) { + se2_update_all(hcsp); /* setup default pattern */ + se2_rd_all(hcsp); /* load again */ + } +} + + +/***************************************************************************/ +UCHAR load_FW(ORC_HCS * hcsp) +{ + U32 dData; + USHORT wBIOSAddress; + USHORT i; + UCHAR *pData, bData; + + + bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG); + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */ + ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00); + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00); + if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) { + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01); + if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) { + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Enable SRAM programming */ + pData = (UCHAR *) & dData; + dData = 0; /* Initial FW address to 0 */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10); + *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11); + *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12); + *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2)); + ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData); /* Write FW address */ + + wBIOSAddress = (USHORT) dData; /* FW code locate at BIOS address + ? */ + for (i = 0, pData = (UCHAR *) & dData; /* Download the code */ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); + *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + if ((i % 4) == 3) { + ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData); /* Write every 4 bytes */ + pData = (UCHAR *) & dData; + } + } + + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Reset program count 0 */ + wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */ + for (i = 0, pData = (UCHAR *) & dData; /* Check the code */ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); + *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + if ((i % 4) == 3) { + if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) { + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /*Disable EEPROM programming */ + return (FALSE); + } + pData = (UCHAR *) & dData; + } + } + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (TRUE); +} + +/***************************************************************************/ +void setup_SCBs(ORC_HCS * hcsp) +{ + ORC_SCB *pVirScb; + int i; + UCHAR j; + ESCB *pVirEscb; + PVOID pPhysEscb; + PVOID tPhysEscb; + + j = 0; + pVirScb = NULL; + tPhysEscb = (PVOID) NULL; + pPhysEscb = (PVOID) NULL; + /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb); /* Total number of SCBs */ + /* SCB HCS_Base address 0 */ + ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray); + /* SCB HCS_Base address 1 */ + ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray); + + /* setup scatter list address with one buffer */ + pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; + pVirEscb = (ESCB *) hcsp->HCS_virEscbArray; + + for (i = 0; i < orc_num_scb; i++) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i)); + pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb); + pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb); +#else + pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i)); + pVirScb->SCB_SGPAddr = (U32) pPhysEscb; + pVirScb->SCB_SensePAddr = (U32) pPhysEscb; +#endif + pVirScb->SCB_EScb = pVirEscb; + pVirScb->SCB_ScbIdx = i; + pVirScb++; + pVirEscb++; + } + + return; +} + +/***************************************************************************/ +static void initAFlag(ORC_HCS * hcsp) +{ + UCHAR i, j; + + for (i = 0; i < MAX_CHANNELS; i++) { + for (j = 0; j < 8; j++) { + hcsp->BitAllocFlag[i][j] = 0xffffffff; + } + } +} + +/***************************************************************************/ +int init_orchid(ORC_HCS * hcsp) +{ + UBYTE *readBytep; + USHORT revision; + UCHAR i; + + initAFlag(hcsp); + ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */ + if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */ + revision = get_FW_version(hcsp); + if (revision == 0xFFFF) { + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ + if (waitChipReady(hcsp) == FALSE) + return (-1); + load_FW(hcsp); /* Download FW */ + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */ + if (waitFWReady(hcsp) == FALSE) + return (-1); + /* Wait for firmware ready */ + } else { + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + } + } else { /* Orchid is not Ready */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ + if (waitChipReady(hcsp) == FALSE) + return (-1); + load_FW(hcsp); /* Download FW */ + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */ + + /* clear HOSTSTOP */ + if (waitFWReady(hcsp) == FALSE) /* Wait for firmware ready */ + return (-1); + } + +/*------------- get serial EEProm settting -------*/ + + read_eeprom(hcsp); + + if (nvramp->Revision != 1) + return (-1); + + hcsp->HCS_SCSI_ID = nvramp->SCSI0Id; + hcsp->HCS_BIOS = nvramp->BIOSConfig1; + hcsp->HCS_MaxTar = MAX_TARGETS; + readBytep = (UCHAR *) & (nvramp->Target00Config); + for (i = 0; i < 16; readBytep++, i++) { + hcsp->TargetFlag[i] = *readBytep; + hcsp->MaximumTags[i] = orc_num_scb; + } /* for */ + + if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */ + hcsp->HCS_Flags |= HCF_SCSI_RESET; + } + ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */ + return (0); +} + +/***************************************************************************** + Function name : orc_reset_scsi_bus + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_reset_scsi_bus(ORC_HCS * pHCB) +{ /* I need Host Control Block Information */ + ULONG flags; + +#if 0 + printk("inia100: enter inia100_reset\n"); +#endif + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); +#endif + + initAFlag(pHCB); + /* reset scsi bus */ + ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); + if (waitSCSIRSTdone(pHCB) == FALSE) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_ERROR); + } else { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_SUCCESS); + } +} + +/***************************************************************************** + Function name : orc_device_reset + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags) +{ /* I need Host Control Block Information */ + ORC_SCB *pScb; + ESCB *pVirEscb; + ORC_SCB *pVirScb; + UCHAR i; + ULONG flags; + +#if 0 + printk("inia100: enter inia100_reset\n"); +#endif + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); +#endif + pScb = (ORC_SCB *) NULL; + pVirEscb = (ESCB *) NULL; + + /* setup scatter list address with one buffer */ + pVirScb = (ORC_SCB *) pHCB->HCS_virScbArray; + + initAFlag(pHCB); + /* device reset */ + for (i = 0; i < orc_num_scb; i++) { + pVirEscb = pVirScb->SCB_EScb; + if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) + break; + pVirScb++; + } + + if (i == orc_num_scb) { + printk("Unable to Reset - No SCB Found\n"); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_NOT_RUNNING); + } + if ((pScb = orc_alloc_scb(pHCB)) == NULL) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_NOT_RUNNING); + } + pScb->SCB_Opcode = ORC_BUSDEVRST; + pScb->SCB_Target = target; + pScb->SCB_HaStat = 0; + pScb->SCB_TaStat = 0; + pScb->SCB_Status = 0x0; + pScb->SCB_Link = 0xFF; + pScb->SCB_Reserved0 = 0; + pScb->SCB_Reserved1 = 0; + pScb->SCB_XferLen = 0; + pScb->SCB_SGLen = 0; + + pVirEscb->SCB_Srb = 0; + if (ResetFlags & SCSI_RESET_SYNCHRONOUS) { + pVirEscb->SCB_Srb = (unsigned char *) SCpnt; + } + orc_exec_scb(pHCB, pScb); /* Start execute SCB */ +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return SCSI_RESET_PENDING; +} + + +/***************************************************************************/ +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +{ + ORC_SCB *pTmpScb; + UCHAR Ch; + ULONG idx; + UCHAR index; + UCHAR i; + ULONG flags; + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + Ch = hcsp->HCS_Index; + for (i = 0; i < 8; i++) { + for (index = 0; index < 32; index++) { + if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) { + hcsp->BitAllocFlag[Ch][i] &= ~(1 << index); + break; + } + } + idx = index + 32 * i; + pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (pTmpScb); + } +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (NULL); +} + + +/***************************************************************************/ +void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +{ + ULONG flags; + UCHAR Index; + UCHAR i; + UCHAR Ch; + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + Ch = hcsp->HCS_Index; + Index = scbp->SCB_ScbIdx; + i = Index / 32; + Index %= 32; + hcsp->BitAllocFlag[Ch][i] |= (1 << Index); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif +} + + +/***************************************************************************** + Function name : Addinia100_into_Adapter_table + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, + BYTE bBus, BYTE bDevice) +{ + unsigned int i, j; + + for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { + if (inia100_adpt[i].ADPT_BIOS < wBIOS) + continue; + if (inia100_adpt[i].ADPT_BIOS == wBIOS) { + if (inia100_adpt[i].ADPT_BASE == wBASE) + if (inia100_adpt[i].ADPT_Bus != 0xFF) + return (FAILURE); + else if (inia100_adpt[i].ADPT_BASE < wBASE) + continue; + } + for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) { + inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE; + inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR; + inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS; + inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus; + inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device; + } + inia100_adpt[i].ADPT_BASE = wBASE; + inia100_adpt[i].ADPT_INTR = bInterrupt; + inia100_adpt[i].ADPT_BIOS = wBIOS; + inia100_adpt[i].ADPT_Bus = bBus; + inia100_adpt[i].ADPT_Device = bDevice; + return (SUCCESSFUL); + } + return (FAILURE); +} + + +/***************************************************************************** + Function name : init_inia100Adapter_table + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +void init_inia100Adapter_table(void) +{ + int i; + + for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { /* Initialize adapter structure */ + inia100_adpt[i].ADPT_BIOS = 0xffff; + inia100_adpt[i].ADPT_BASE = 0xffff; + inia100_adpt[i].ADPT_INTR = 0xff; + inia100_adpt[i].ADPT_Bus = 0xff; + inia100_adpt[i].ADPT_Device = 0xff; + } +} + +/***************************************************************************** + Function name : get_orcPCIConfig + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx) +{ + pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE; /* Supply base address */ + pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */ + pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR; /* Supply interrupt line */ + return; +} + + +/***************************************************************************** + Function name : abort_SCB + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb) +{ + unsigned char bData, bStatus; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + if (bStatus == 1) /* 0 - Successfully */ + return (FALSE); /* 1 - Fail */ + return (TRUE); +} + +/***************************************************************************** + Function name : inia100_abort + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt) +{ + ESCB *pVirEscb; + ORC_SCB *pVirScb; + UCHAR i; + ULONG flags; + +#if 0 + printk("inia100: abort SRB \n"); +#endif +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + + pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; + + for (i = 0; i < orc_num_scb; i++, pVirScb++) { + pVirEscb = pVirScb->SCB_EScb; + if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) { + if (pVirScb->SCB_TagMsg == 0) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_BUSY); + } else { + if (abort_SCB(hcsp, pVirScb)) { + pVirEscb->SCB_Srb = NULL; +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_SUCCESS); + } else { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_NOT_RUNNING); + } + } + } + } +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_NOT_RUNNING); +} + +/*********************************************************************** + Routine Description: + This is the interrupt service routine for the Orchid SCSI adapter. + It reads the interrupt register to determine if the adapter is indeed + the source of the interrupt and clears the interrupt at the device. + Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + Return Value: +***********************************************************************/ +void orc_interrupt( + ORC_HCS * hcsp +) +{ + BYTE bScbIdx; + ORC_SCB *pScb; + + if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) { + return; // (FALSE); + + } + do { + bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE); + + pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx)); + pScb->SCB_Status = 0x0; + + inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb); + } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT)); + return; //(TRUE); + +} /* End of I1060Interrupt() */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/i60uscsi.h linux.ac/drivers/scsi/i60uscsi.h --- linux.vanilla/drivers/scsi/i60uscsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/i60uscsi.h Wed Feb 3 21:57:36 1999 @@ -0,0 +1,574 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ************************************************************************** + * + * Module: inia100.h + * Description: INI-A100U2W LINUX device driver header + * Revision History: + * 06/18/98 HL, Initial Version 1.02 + * 12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up. + **************************************************************************/ + +#include + +#define ULONG unsigned long +#define PVOID void * +#define USHORT unsigned short +#define UCHAR unsigned char +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define UBYTE unsigned char +#define UWORD unsigned short +#define UDWORD unsigned long +#ifdef ALPHA +#define U32 unsigned int +#else +#define U32 unsigned long +#endif + +#ifndef NULL +#define NULL 0 /* zero */ +#endif +#ifndef TRUE +#define TRUE (1) /* boolean true */ +#endif +#ifndef FALSE +#define FALSE (0) /* boolean false */ +#endif +#ifndef FAILURE +#define FAILURE (-1) +#endif +#if 1 +#define ORC_MAXQUEUE 245 +#else +#define ORC_MAXQUEUE 25 +#endif + +#define TOTAL_SG_ENTRY 32 +#define MAX_TARGETS 16 +#define IMAX_CDB 15 +#define SENSE_SIZE 14 +#define MAX_SUPPORTED_ADAPTERS 4 +#define SUCCESSFUL 0x00 + +#define I920_DEVICE_ID 0x0002 /* Initio's inic-950 product ID */ + +/************************************************************************/ +/* Scatter-Gather Element Structure */ +/************************************************************************/ +typedef struct ORC_SG_Struc { + U32 SG_Ptr; /* Data Pointer */ + U32 SG_Len; /* Data Length */ +} ORC_SG; + +typedef struct inia100_Adpt_Struc { + UWORD ADPT_BIOS; /* 0 */ + UWORD ADPT_BASE; /* 1 */ + UBYTE ADPT_Bus; /* 2 */ + UBYTE ADPT_Device; /* 3 */ + UBYTE ADPT_INTR; /* 4 */ +} INIA100_ADPT_STRUCT; + + +/* SCSI related definition */ +#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ +#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ + + +#define ORC_OFFSET_SCB 16 +#define ORC_MAX_SCBS 250 +#define MAX_CHANNELS 2 +#define MAX_ESCB_ELE 64 +#define TCF_DRV_255_63 0x0400 + +/********************************************************/ +/* Orchid Configuration Register Set */ +/********************************************************/ +#define ORC_PVID 0x00 /* Vendor ID */ +#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */ +#define ORC_PDID 0x02 /* Device ID */ +#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */ +#define ORC_COMMAND 0x04 /* Command */ +#define BUSMS 0x04 /* BUS MASTER Enable */ +#define IOSPA 0x01 /* IO Space Enable */ +#define ORC_STATUS 0x06 /* Status register */ +#define ORC_REVISION 0x08 /* Revision number */ +#define ORC_BASE 0x10 /* Base address */ +#define ORC_BIOS 0x50 /* Expansion ROM base address */ +#define ORC_INT_NUM 0x3C /* Interrupt line */ +#define ORC_INT_PIN 0x3D /* Interrupt pin */ + + +/********************************************************/ +/* Orchid Host Command Set */ +/********************************************************/ +#define ORC_CMD_NOP 0x00 /* Host command - NOP */ +#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ +#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ +#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ +#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ +#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ +#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ +#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ + +/********************************************************/ +/* Orchid Register Set */ +/********************************************************/ +#define ORC_GINTS 0xA0 /* Global Interrupt Status */ +#define QINT 0x04 /* Reply Queue Interrupt */ +#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ +#define MQINT 0x04 /* Mask Reply Queue Interrupt */ +#define ORC_GCFG 0xA2 /* Global Configure */ +#define EEPRG 0x01 /* Enable EEPROM programming */ +#define ORC_GSTAT 0xA3 /* Global status */ +#define WIDEBUS 0x10 /* Wide SCSI Devices connected */ +#define ORC_HDATA 0xA4 /* Host Data */ +#define ORC_HCTRL 0xA5 /* Host Control */ +#define SCSIRST 0x80 /* SCSI bus reset */ +#define HDO 0x40 /* Host data out */ +#define HOSTSTOP 0x02 /* Host stop RISC engine */ +#define DEVRST 0x01 /* Device reset */ +#define ORC_HSTUS 0xA6 /* Host Status */ +#define HDI 0x02 /* Host data in */ +#define RREADY 0x01 /* RISC engine is ready to receive */ +#define ORC_NVRAM 0xA7 /* Nvram port address */ +#define SE2CS 0x008 +#define SE2CLK 0x004 +#define SE2DO 0x002 +#define SE2DI 0x001 +#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ +#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */ +#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ +#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */ +#define ORC_FWBASEADR 0xAC /* Firmware base address */ + +#define ORC_EBIOSADR0 0xB0 /* External Bios address */ +#define ORC_EBIOSADR1 0xB1 /* External Bios address */ +#define ORC_EBIOSADR2 0xB2 /* External Bios address */ +#define ORC_EBIOSDATA 0xB3 /* External Bios address */ + +#define ORC_SCBSIZE 0xB7 /* SCB size register */ +#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ +#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ + +#define ORC_RISCCTL 0xE0 /* RISC Control */ +#define PRGMRST 0x002 +#define DOWNLOAD 0x001 +#define ORC_PRGMCTR0 0xE2 /* RISC program counter */ +#define ORC_PRGMCTR1 0xE3 /* RISC program counter */ +#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */ + +typedef struct orc_extended_scb { /* Extended SCB */ + ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */ + unsigned char *SCB_Srb; /*50 SRB Pointer */ +// Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */ +} ESCB; + +/*********************************************************************** + SCSI Control Block +************************************************************************/ +typedef struct orc_scb { /* Scsi_Ctrl_Blk */ + UBYTE SCB_Opcode; /*00 SCB command code&residual */ + UBYTE SCB_Flags; /*01 SCB Flags */ + UBYTE SCB_Target; /*02 Target Id */ + UBYTE SCB_Lun; /*03 Lun */ + U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */ + U32 SCB_XferLen; /*08 Data Transfer Length */ + U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */ + U32 SCB_SGLen; /*10 SG list # * 8 */ + U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */ + U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */ + UBYTE SCB_HaStat; /*1C Host Status */ + UBYTE SCB_TaStat; /*1D Target Status */ + UBYTE SCB_Status; /*1E SCB status */ + UBYTE SCB_Link; /*1F Link pointer, default 0xFF */ + UBYTE SCB_SenseLen; /*20 Sense Allocation Length */ + UBYTE SCB_CDBLen; /*21 CDB Length */ + UBYTE SCB_Ident; /*22 Identify */ + UBYTE SCB_TagMsg; /*23 Tag Message */ + UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */ + UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */ + U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */ + + ESCB *SCB_EScb; /*38 Extended SCB Pointer */ +#ifndef ALPHA + UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */ +#endif +} ORC_SCB; + +/* Opcodes of ORCSCB_Opcode */ +#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */ +#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ + +/* Status of ORCSCB_Status */ +#define SCB_COMPLETE 0x00 /* SCB request completed */ +#define SCB_POST 0x01 /* SCB is posted by the HOST */ + +/* Bit Definition for ORCSCB_Flags */ +#define SCF_DISINT 0x01 /* Disable HOST interrupt */ +#define SCF_DIR 0x18 /* Direction bits */ +#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ +#define SCF_DIN 0x08 /* From Target to Initiator */ +#define SCF_DOUT 0x10 /* From Initiator to Target */ +#define SCF_NO_XF 0x18 /* No data transfer */ +#define SCF_POLL 0x40 + +/* Error Codes for ORCSCB_HaStat */ +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + + +/* Error Codes for ORCSCB_TaStat */ +#define TARGET_CHK_COND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_TAG_FULL 0x28 + + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ +#define MSG_STAG 0x20 +#define MSG_HTAG 0x21 +#define MSG_OTAG 0x22 + +#define MSG_IGNOREWIDE 0x23 + +#define MSG_IDENT 0x80 +#define MSG_DISC 0x40 /* Disconnect allowed */ + + +/* SCSI MESSAGE */ +#define MSG_EXTEND 0x01 +#define MSG_SDP 0x02 +#define MSG_ABORT 0x06 +#define MSG_REJ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY 0x09 +#define MSG_DEVRST 0x0C +#define MSG_STAG 0x20 + +/*********************************************************************** + Target Device Control Structure +**********************************************************************/ + +typedef struct ORC_Tar_Ctrl_Struc { + UBYTE TCS_DrvDASD; /* 6 */ + UBYTE TCS_DrvSCSI; /* 7 */ + UBYTE TCS_DrvHead; /* 8 */ + UWORD TCS_DrvFlags; /* 4 */ + UBYTE TCS_DrvSector; /* 7 */ +} ORC_TCS, *PORC_TCS; + +/* Bit Definition for TCF_DrvFlags */ +#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */ +#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */ + + +/*********************************************************************** + Host Adapter Control Structure +************************************************************************/ +typedef struct ORC_Ha_Ctrl_Struc { + USHORT HCS_Base; /* 00 */ + UBYTE HCS_Index; /* 02 */ + UBYTE HCS_Intr; /* 04 */ + UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */ + UBYTE HCS_BIOS; /* 07 BIOS configuration */ + + UBYTE HCS_Flags; /* 0B */ + UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */ + UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */ + + USHORT HCS_Units; /* Number of units this adapter */ + USHORT HCS_AFlags; /* Adapter info. defined flags */ + ULONG HCS_Timeout; /* Adapter timeout value */ + PVOID HCS_virScbArray; /* 28 Virtual Pointer to SCB array */ + U32 HCS_physScbArray; /* Scb Physical address */ + PVOID HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */ + U32 HCS_physEscbArray; /* scatter list Physical address */ + UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */ + UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */ + UBYTE ActiveTags[16][16]; /* 50 */ + ORC_TCS HCS_Tcs[16]; /* 28 */ + U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t BitAllocFlagLock; +#endif + ULONG pSRB_head; + ULONG pSRB_tail; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t pSRB_lock; +#endif +} ORC_HCS; + +/* Bit Definition for HCS_Flags */ + +#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */ +#define HCF_PARITY 0x02 /* parity card */ +#define HCF_LVDS 0x10 /* parity card */ + +/* Bit Definition for TargetFlag */ + +#define TCF_EN_255 0x08 +#define TCF_EN_TAG 0x10 +#define TCF_BUSY 0x20 +#define TCF_DISCONNECT 0x40 +#define TCF_SPIN_UP 0x80 + +/* Bit Definition for HCS_AFlags */ +#define HCS_AF_IGNORE 0x01 /* Adapter ignore */ +#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */ +#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */ + + +/*---------------------------------------*/ +/* TimeOut for RESET to complete (30s) */ +/* */ +/* After a RESET the drive is checked */ +/* every 200ms. */ +/*---------------------------------------*/ +#define DELAYED_RESET_MAX (30*1000L) +#define DELAYED_RESET_INTERVAL 200L + +/*----------------------------------------------*/ +/* TimeOut for IRQ from last interrupt (5s) */ +/*----------------------------------------------*/ +#define IRQ_TIMEOUT_INTERVAL (5*1000L) + +/*----------------------------------------------*/ +/* Retry Delay interval (200ms) */ +/*----------------------------------------------*/ +#define DELAYED_RETRY_INTERVAL 200L + +#define INQUIRY_SIZE 36 +#define CAPACITY_SIZE 8 +#define DEFAULT_SENSE_LEN 14 + +#define DEVICE_NOT_FOUND 0x86 + +/*----------------------------------------------*/ +/* Definition for PCI device */ +/*----------------------------------------------*/ +#define MAX_PCI_DEVICES 21 +#define MAX_PCI_BUSES 8 + +typedef struct Adpt_Struc { + USHORT ADPT_BIOS; /* 0 */ + UBYTE ADPT_BASE; /* 1 */ + UBYTE ADPT_Bus; /* 2 */ + UBYTE ADPT_Device; /* 3 */ + UBYTE ADPT_Reserved[3]; +} JACS, *PJACS; + +typedef struct _NVRAM { +/*----------header ---------------*/ + UCHAR SubVendorID0; /* 00 - Sub Vendor ID */ + UCHAR SubVendorID1; /* 00 - Sub Vendor ID */ + UCHAR SubSysID0; /* 02 - Sub System ID */ + UCHAR SubSysID1; /* 02 - Sub System ID */ + UCHAR SubClass; /* 04 - Sub Class */ + UCHAR VendorID0; /* 05 - Vendor ID */ + UCHAR VendorID1; /* 05 - Vendor ID */ + UCHAR DeviceID0; /* 07 - Device ID */ + UCHAR DeviceID1; /* 07 - Device ID */ + UCHAR Reserved0[2]; /* 09 - Reserved */ + UCHAR Revision; /* 0B - Revision of data structure */ + /* ----Host Adapter Structure ---- */ + UCHAR NumOfCh; /* 0C - Number of SCSI channel */ + UCHAR BIOSConfig1; /* 0D - BIOS configuration 1 */ + UCHAR BIOSConfig2; /* 0E - BIOS boot channel&target ID */ + UCHAR BIOSConfig3; /* 0F - BIOS configuration 3 */ + /* ----SCSI channel Structure ---- */ + /* from "CTRL-I SCSI Host Adapter SetUp menu " */ + UCHAR SCSI0Id; /* 10 - Channel 0 SCSI ID */ + UCHAR SCSI0Config; /* 11 - Channel 0 SCSI configuration */ + UCHAR SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */ + UCHAR SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */ + UCHAR ReservedforChannel0[2]; /* 14 - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target00Config; /* 16 - Channel 0 Target 0 config */ + UCHAR Target01Config; /* 17 - Channel 0 Target 1 config */ + UCHAR Target02Config; /* 18 - Channel 0 Target 2 config */ + UCHAR Target03Config; /* 19 - Channel 0 Target 3 config */ + UCHAR Target04Config; /* 1A - Channel 0 Target 4 config */ + UCHAR Target05Config; /* 1B - Channel 0 Target 5 config */ + UCHAR Target06Config; /* 1C - Channel 0 Target 6 config */ + UCHAR Target07Config; /* 1D - Channel 0 Target 7 config */ + UCHAR Target08Config; /* 1E - Channel 0 Target 8 config */ + UCHAR Target09Config; /* 1F - Channel 0 Target 9 config */ + UCHAR Target0AConfig; /* 20 - Channel 0 Target A config */ + UCHAR Target0BConfig; /* 21 - Channel 0 Target B config */ + UCHAR Target0CConfig; /* 22 - Channel 0 Target C config */ + UCHAR Target0DConfig; /* 23 - Channel 0 Target D config */ + UCHAR Target0EConfig; /* 24 - Channel 0 Target E config */ + UCHAR Target0FConfig; /* 25 - Channel 0 Target F config */ + + UCHAR SCSI1Id; /* 26 - Channel 1 SCSI ID */ + UCHAR SCSI1Config; /* 27 - Channel 1 SCSI configuration */ + UCHAR SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */ + UCHAR SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */ + UCHAR ReservedforChannel1[2]; /* 2A - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target10Config; /* 2C - Channel 1 Target 0 config */ + UCHAR Target11Config; /* 2D - Channel 1 Target 1 config */ + UCHAR Target12Config; /* 2E - Channel 1 Target 2 config */ + UCHAR Target13Config; /* 2F - Channel 1 Target 3 config */ + UCHAR Target14Config; /* 30 - Channel 1 Target 4 config */ + UCHAR Target15Config; /* 31 - Channel 1 Target 5 config */ + UCHAR Target16Config; /* 32 - Channel 1 Target 6 config */ + UCHAR Target17Config; /* 33 - Channel 1 Target 7 config */ + UCHAR Target18Config; /* 34 - Channel 1 Target 8 config */ + UCHAR Target19Config; /* 35 - Channel 1 Target 9 config */ + UCHAR Target1AConfig; /* 36 - Channel 1 Target A config */ + UCHAR Target1BConfig; /* 37 - Channel 1 Target B config */ + UCHAR Target1CConfig; /* 38 - Channel 1 Target C config */ + UCHAR Target1DConfig; /* 39 - Channel 1 Target D config */ + UCHAR Target1EConfig; /* 3A - Channel 1 Target E config */ + UCHAR Target1FConfig; /* 3B - Channel 1 Target F config */ + UCHAR reserved[3]; /* 3C - Reserved */ + /* ---------- CheckSum ---------- */ + UCHAR CheckSum; /* 3F - Checksum of NVRam */ +} NVRAM, *PNVRAM; + +/* Bios Configuration for nvram->BIOSConfig1 */ +#define NBC_BIOSENABLE 0x01 /* BIOS enable */ +#define NBC_CDROM 0x02 /* Support bootable CDROM */ +#define NBC_REMOVABLE 0x04 /* Support removable drive */ + +/* Bios Configuration for nvram->BIOSConfig2 */ +#define NBB_TARGET_MASK 0x0F /* Boot SCSI target ID number */ +#define NBB_CHANL_MASK 0xF0 /* Boot SCSI channel number */ + +/* Bit definition for nvram->SCSIConfig */ +#define NCC_BUSRESET 0x01 /* Reset SCSI bus at power up */ +#define NCC_PARITYCHK 0x02 /* SCSI parity enable */ +#define NCC_LVDS 0x10 /* Enable LVDS */ +#define NCC_ACTTERM1 0x20 /* Enable active terminator 1 */ +#define NCC_ACTTERM2 0x40 /* Enable active terminator 2 */ +#define NCC_AUTOTERM 0x80 /* Enable auto termination */ + +/* Bit definition for nvram->TargetxConfig */ +#define NTC_PERIOD 0x07 /* Maximum Sync. Speed */ +#define NTC_1GIGA 0x08 /* 255 head / 63 sectors (64/32) */ +#define NTC_NO_SYNC 0x10 /* NO SYNC. NEGO */ +#define NTC_NO_WIDESYNC 0x20 /* NO WIDE SYNC. NEGO */ +#define NTC_DISC_ENABLE 0x40 /* Enable SCSI disconnect */ +#define NTC_SPINUP 0x80 /* Start disk drive */ + +/* Default NVRam values */ +#define NBC_DEFAULT (NBC_ENABLE) +#define NCC_DEFAULT (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK) +#define NCC_MAX_TAGS 0x20 /* Maximum tags per target */ +#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */ +#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE) + +typedef union { /* Union define for mechanism 1 */ + struct { + unsigned char RegNum; + unsigned char FcnNum:3; + unsigned char DeviceNum:5; + unsigned char BusNum; + unsigned char Reserved:7; + unsigned char Enable:1; + } sConfigAdr; + unsigned long lConfigAdr; +} CONFIG_ADR; + +typedef union { /* Union define for mechanism 2 */ + struct { + unsigned char RegNum; + unsigned char DeviceNum; + unsigned short Reserved; + } sHostAdr; + unsigned long lHostAdr; +} HOST_ADR; + +#define ORC_RD(x,y) (UCHAR)(inb( (int)((ULONG)((ULONG)x+(UCHAR)y)) )) +#define ORC_RDLONG(x,y) (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) )) + +#define ORC_WR( adr,data) outb( (UCHAR)(data), (int)(adr)) +#define ORC_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr)) +#define ORC_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr)) + + +#define SCSI_ABORT_SNOOZE 0 +#define SCSI_ABORT_SUCCESS 1 +#define SCSI_ABORT_PENDING 2 +#define SCSI_ABORT_BUSY 3 +#define SCSI_ABORT_NOT_RUNNING 4 +#define SCSI_ABORT_ERROR 5 + +#define SCSI_RESET_SNOOZE 0 +#define SCSI_RESET_PUNT 1 +#define SCSI_RESET_SUCCESS 2 +#define SCSI_RESET_PENDING 3 +#define SCSI_RESET_WAKEUP 4 +#define SCSI_RESET_NOT_RUNNING 5 +#define SCSI_RESET_ERROR 6 + +#define SCSI_RESET_SYNCHRONOUS 0x01 +#define SCSI_RESET_ASYNCHRONOUS 0x02 +#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 +#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 + +#define SCSI_RESET_BUS_RESET 0x100 +#define SCSI_RESET_HOST_RESET 0x200 +#define SCSI_RESET_ACTION 0xff 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/inia100.c linux.ac/drivers/scsi/inia100.c --- linux.vanilla/drivers/scsi/inia100.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/inia100.c Wed Feb 3 21:57:36 1999 @@ -0,0 +1,952 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ************************************************************************** + * + * module: inia100.c + * DESCRIPTION: + * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host + * adapters + * 09/24/98 hl - v1.02 initial production release. + * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up. + **************************************************************************/ + +#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#ifdef MODULE +#include +#endif + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) +#include +#endif +#include +#include +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) +#include +#endif +#include +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) +#include +#endif +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "inia100.h" +#include +#include + + +#else + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "sd.h" +#include "hosts.h" +#include +#include "inia100.h" +#endif + +#ifdef MODULE +Scsi_Host_Template driver_template = INIA100; +#include "scsi_module.c" +#endif + +#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) )) + +char *inia100_Copyright = "Copyright (C) 1998-99"; +char *inia100_InitioName = "by Initio Corporation"; +char *inia100_ProductName = "INI-A100U2W"; +char *inia100_Version = "v1.02a"; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +struct proc_dir_entry proc_scsi_inia100 = +{ + PROC_SCSI_INIA100, 7, "INIA100", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif + +/* set by inia100_setup according to the command line */ +static int setup_called = 0; +static int orc_num_ch = MAX_SUPPORTED_ADAPTERS; /* Maximum 4 adapters */ + +/* ---- INTERNAL VARIABLES ---- */ +#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) +static char *setup_str = (char *) NULL; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr0(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr1(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr2(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr3(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr4(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr5(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr6(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr7(int irq, void *dev_id, struct pt_regs *); +#else +static void inia100_intr0(int irq, struct pt_regs *); +static void inia100_intr1(int irq, struct pt_regs *); +static void inia100_intr2(int irq, struct pt_regs *); +static void inia100_intr3(int irq, struct pt_regs *); +static void inia100_intr4(int irq, struct pt_regs *); +static void inia100_intr5(int irq, struct pt_regs *); +static void inia100_intr6(int irq, struct pt_regs *); +static void inia100_intr7(int irq, struct pt_regs *); +#endif + +static void inia100_panic(char *msg); +void inia100SCBPost(BYTE * pHcb, BYTE * pScb); + +/* ---- EXTERNAL VARIABLES ---- */ +extern int Addinia100_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE); +extern void init_inia100Adapter_table(void); +extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp); +extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp); +extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp); +extern void orc_interrupt(ORC_HCS * hcsp); +extern int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags); +extern int orc_reset_scsi_bus(ORC_HCS * pHCB); +extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb); +extern int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt); +extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx); +extern int init_orchid(ORC_HCS * hcsp); + +extern int orc_num_scb; +extern ORC_HCS orc_hcs[]; + +/***************************************************************************** + Function name : inia100AppendSRBToQueue + Description : This function will push current request into save list + Input : pSRB - Pointer to SCSI request block. + pHCB - Pointer to host adapter structure + Output : None. + Return : None. +*****************************************************************************/ +static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB) +{ + ULONG flags; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_lock_irqsave(&(pHCB->pSRB_lock), flags); +#else + save_flags(flags); + cli(); +#endif + + pSRB->next = NULL; /* Pointer to next */ + if (pHCB->pSRB_head == NULL) + pHCB->pSRB_head = pSRB; + else + pHCB->pSRB_tail->next = pSRB; /* Pointer to next */ + pHCB->pSRB_tail = pSRB; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); +#else + restore_flags(flags); +#endif + return; +} + +/***************************************************************************** + Function name : inia100PopSRBFromQueue + Description : This function will pop current request from save list + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB) +{ + Scsi_Cmnd *pSRB; + ULONG flags; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_lock_irqsave(&(pHCB->pSRB_lock), flags); +#else + save_flags(flags); + cli(); +#endif + + if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) { + pHCB->pSRB_head = pHCB->pSRB_head->next; + pSRB->next = NULL; + } +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); +#else + restore_flags(flags); +#endif + return (pSRB); +} + +/***************************************************************************** + Function name : inia100_setup + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +void inia100_setup(char *str, int *ints) +{ + if (setup_called) + inia100_panic("inia100: inia100_setup called twice.\n"); + + setup_called = ints[0]; + setup_str = str; +} + +/***************************************************************************** + Function name : orc_ReturnNumberOfAdapters + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +int orc_ReturnNumberOfAdapters(void) +{ + unsigned int i, iAdapters; + + iAdapters = 0; + /* + * PCI-bus probe. + */ + if (pcibios_present()) { + struct { + unsigned short vendor_id; + unsigned short device_id; + } const inia100_pci_devices[] = + { + {ORC_VENDOR_ID, I920_DEVICE_ID}, + {ORC_VENDOR_ID, ORC_DEVICE_ID} + }; + + unsigned int dRegValue; + unsigned short command; + WORD wBIOS, wBASE; + BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum; + +#ifdef MMAPIO + unsigned long page_offset, base; +#endif + +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + struct pci_dev *pdev = NULL; +#else + int index; + unsigned char pci_bus, pci_devfn; +#endif + + bPCIBusNum = 0; + bPCIDeviceNum = 0; + init_inia100Adapter_table(); + for (i = 0; i < NUMBER(inia100_pci_devices); i++) { +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + pdev = NULL; + while ((pdev = pci_find_device(inia100_pci_devices[i].vendor_id, + inia100_pci_devices[i].device_id, + pdev))) +#else + index = 0; + while (!(pcibios_find_device(inia100_pci_devices[i].vendor_id, + inia100_pci_devices[i].device_id, + index++, &pci_bus, &pci_devfn))) +#endif + { + if (iAdapters >= MAX_SUPPORTED_ADAPTERS) + break; /* Never greater than maximum */ + + if (i == 0) { + /* + printk("inia100: The RAID controller is not supported by\n"); + printk("inia100: this driver, we are ignoring it.\n"); + */ + } else { + /* + * Read sundry information from PCI BIOS. + */ +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + bPCIBusNum = pdev->bus->number; + bPCIDeviceNum = pdev->devfn; + dRegValue = pdev->base_address[0]; + if (dRegValue == -1) { /* Check return code */ + printk("\n\rinia100: orchid read configuration error.\n"); + return (0); /* Read configuration space error */ + } + /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ + wBASE = (WORD) dRegValue; + + /* Now read the interrupt line */ + dRegValue = pdev->irq; + bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ + pci_read_config_word(pdev, PCI_COMMAND, &command); + pci_write_config_word(pdev, PCI_COMMAND, + command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); + +#else + bPCIBusNum = pci_bus; + bPCIDeviceNum = pci_devfn; + pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0, + &dRegValue); + if (dRegValue == -1) { /* Check return code */ + printk("\n\rinia100: Orchid read configuration error.\n"); + return (0); /* Read configuration space error */ + } + /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ + wBASE = (WORD) dRegValue; + + /* Now read the interrupt line */ + pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE, + &dRegValue); + bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ + pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command); + pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, + command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); +#endif + wBASE &= PCI_BASE_ADDRESS_IO_MASK; + wBIOS = ORC_RDWORD(wBASE, 0x50); + +#ifdef MMAPIO + base = wBASE & PAGE_MASK; + page_offset = wBASE - base; + + /* + * replace the next line with this one if you are using 2.1.x: + * temp_p->maddr = ioremap(base, page_offset + 256); + */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0) + wBASE = ioremap(base, page_offset + 256); +#else + wBASE = (WORD) vremap(base, page_offset + 256); +#endif + if (wBASE) { + wBASE += page_offset; + } +#endif + + if (Addinia100_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum, + bPCIDeviceNum) == SUCCESSFUL) + iAdapters++; + } + } /* while(pdev=....) */ + } /* for PCI_DEVICES */ + } /* PCI BIOS present */ + return (iAdapters); +} + +/***************************************************************************** + Function name : inia100_detect + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_detect(Scsi_Host_Template * tpnt) +{ + ORC_HCS *pHCB; + struct Scsi_Host *hreg; + U32 sz; + U32 i; /* 01/14/98 */ + int ok = 0, iAdapters; + ULONG dBiosAdr; + BYTE *pbBiosAdr; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + tpnt->proc_dir = &proc_scsi_inia100; +#endif + if (setup_called) { + /* Setup by inia100_setup */ + printk("inia100: processing commandline: "); + } + /* Get total number of adapters in the motherboard */ + iAdapters = orc_ReturnNumberOfAdapters(); + + /* printk("inia100: Total Initio Adapters = %d\n", iAdapters); */ + if (iAdapters == 0) /* If no orc founded, return */ + return (0); + + orc_num_ch = (iAdapters > orc_num_ch) ? orc_num_ch : iAdapters; + orc_num_scb = ORC_MAXQUEUE; + + /* clear the memory needed for HCS */ + i = orc_num_ch * sizeof(ORC_HCS); + memset((unsigned char *) &orc_hcs[0], 0, i); /* Initialize orc_hcs 0 */ + +#if 0 + printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n", + orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB)); +#endif + + for (i = 0, pHCB = &orc_hcs[0]; /* Get pointer for control block */ + i < orc_num_ch; + i++, pHCB++) { + + pHCB->pSRB_head = NULL; /* Initial SRB save queue */ + pHCB->pSRB_tail = NULL; /* Initial SRB save queue */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */ +#endif + /* Get total memory needed for SCB */ + sz = orc_num_scb * sizeof(ORC_SCB); + if ((pHCB->HCS_virScbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) { + printk("inia100: SCB memory allocation error\n"); + return (0); + } + memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz); + pHCB->HCS_physScbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virScbArray); + + /* Get total memory needed for ESCB */ + sz = orc_num_scb * sizeof(ESCB); + if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) { + printk("inia100: ESCB memory allocation error\n"); + return (0); + } + memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz); + pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray); + + request_region(pHCB->HCS_Base, 0x100, "inia100"); /* Register */ + get_orcPCIConfig(pHCB, i); + + dBiosAdr = pHCB->HCS_BIOS; + dBiosAdr = (dBiosAdr << 4); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pbBiosAdr = phys_to_virt(dBiosAdr); +#endif + + if (init_orchid(pHCB)) { /* Initial orchid chip */ + printk("inia100: initial orchid fail!!\n"); + return (0); + } + hreg = scsi_register(tpnt, sizeof(ORC_HCS)); + if (hreg == NULL) { + printk("Invalid scsi_register pointer.\n"); + } + hreg->io_port = pHCB->HCS_Base; + hreg->n_io_port = 0xff; + hreg->can_queue = orc_num_scb; /* 03/05/98 */ + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + hreg->unique_id = pHCB->HCS_Base; + hreg->max_id = pHCB->HCS_MaxTar; +#endif + + hreg->max_lun = 32; /* 10/21/97 */ +/* + hreg->max_lun = 8; + hreg->max_channel = 1; + */ + hreg->irq = pHCB->HCS_Intr; + hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */ + hreg->base = (UCHAR *) pHCB; + +#if 1 + hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */ +#else + hreg->sg_tablesize = SG_NONE; /* No SG */ +#endif + + /* Initial orc chip */ + switch (i) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + case 0: + ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 1: + ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 2: + ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 3: + ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 4: + ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 5: + ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 6: + ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 7: + ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + default: + inia100_panic("inia100: Too many host adapters\n"); + break; + } + + if (ok < 0) { + if (ok == -EINVAL) { + printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr); + printk(" Contact author.\n"); + } else { + if (ok == -EBUSY) + printk("inia100: IRQ %d already in use. Configure another.\n", pHCB->HCS_Intr); + else { + printk("\ninia100: Unexpected error code on requesting IRQ %d.\n", + pHCB->HCS_Intr); + printk(" Contact author.\n"); + } + } + inia100_panic("inia100: driver needs an IRQ.\n"); + } +#endif + } + + tpnt->this_id = -1; + tpnt->can_queue = 1; + return 1; +} + +/***************************************************************************** + Function name : inia100BuildSCB + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt) +{ /* Create corresponding SCB */ + struct scatterlist *pSrbSG; + ORC_SG *pSG; /* Pointer to SG list */ + int i; + U32 TotalLen; + ESCB *pEScb; + + pEScb = pSCB->SCB_EScb; + pEScb->SCB_Srb = SCpnt; + pSG = NULL; + + pSCB->SCB_Opcode = ORC_EXECSCSI; + pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */ + pSCB->SCB_Target = SCpnt->target; + pSCB->SCB_Lun = SCpnt->lun; + pSCB->SCB_Reserved0 = 0; + pSCB->SCB_Reserved1 = 0; + pSCB->SCB_SGLen = 0; + + if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) { + pSG = (ORC_SG *) & pEScb->ESCB_SGList[0]; + if (SCpnt->use_sg) { + TotalLen = 0; + pSCB->SCB_SGLen = (U32) (SCpnt->use_sg * 8); + pSrbSG = (struct scatterlist *) SCpnt->request_buffer; + for (i = 0; i < SCpnt->use_sg; i++, pSG++, pSrbSG++) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pSG->SG_Ptr = (U32) (VIRT_TO_BUS(pSrbSG->address)); +#else + pSG->SG_Ptr = (U32) pSrbSG->address; +#endif + pSG->SG_Len = (U32) pSrbSG->length; + TotalLen += (U32) pSrbSG->length; + } + } else { /* Non SG */ + pSCB->SCB_SGLen = 0x8; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pSG->SG_Ptr = (U32) (VIRT_TO_BUS(SCpnt->request_buffer)); +#else + pSG->SG_PTR = (U32) SCpnt->request_buffer; +#endif + pSG->SG_Len = (U32) SCpnt->request_bufflen; + } + } + pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr; + pSCB->SCB_HaStat = 0; + pSCB->SCB_TaStat = 0; + pSCB->SCB_Link = 0xFF; + pSCB->SCB_SenseLen = SENSE_SIZE; + pSCB->SCB_CDBLen = SCpnt->cmd_len; + if (pSCB->SCB_CDBLen >= IMAX_CDB) { + printk("max cdb length= %x\b", SCpnt->cmd_len); + pSCB->SCB_CDBLen = IMAX_CDB; + } + pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW; + if (SCpnt->device->tagged_supported) { /* Tag Support */ + pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ + } else { + pSCB->SCB_TagMsg = 0; /* No tag support */ + } + memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen); + return; +} + +/***************************************************************************** + Function name : inia100_queue + Description : Queue a command and setup interrupts for a free bus. + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +{ + register ORC_SCB *pSCB; + ORC_HCS *pHCB; /* Point to Host adapter control block */ + + if (SCpnt->lun > 16) { + SCpnt->result = (DID_TIME_OUT << 16); + done(SCpnt); /* Notify system DONE */ + return (0); + } + pHCB = (ORC_HCS *) SCpnt->host->base; + SCpnt->scsi_done = done; + /* Get free SCSI control block */ + if ((pSCB = orc_alloc_scb(pHCB)) == NULL) { + inia100AppendSRBToQueue(pHCB, SCpnt); /* Buffer this request */ + /* printk("inia100_entry: can't allocate SCB\n"); */ + return (0); + } + inia100BuildSCB(pHCB, pSCB, SCpnt); + orc_exec_scb(pHCB, pSCB); /* Start execute SCB */ + + return (0); +} + +/***************************************************************************** + Function name : inia100_command + Description : We only support command in interrupt-driven fashion + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_command(Scsi_Cmnd * SCpnt) +{ + printk("inia100: interrupt driven driver; use inia100_queue()\n"); + return -1; +} + +/***************************************************************************** + Function name : inia100_abort + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_abort(Scsi_Cmnd * SCpnt) +{ + ORC_HCS *hcsp; + + hcsp = (ORC_HCS *) SCpnt->host->base; + return orc_abort_srb(hcsp, (ULONG) SCpnt); +} + +/***************************************************************************** + Function name : inia100_reset + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +{ /* I need Host Control Block Information */ + ORC_HCS *pHCB; + pHCB = (ORC_HCS *) SCpnt->host->base; + + if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) + return orc_reset_scsi_bus(pHCB); + else + return orc_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags); + +} + +/***************************************************************************** + Function name : inia100SCBPost + Description : This is callback routine be called when orc finish one + SCSI command. + Input : pHCB - Pointer to host adapter control block. + pSCB - Pointer to SCSI control block. + Output : None. + Return : None. +*****************************************************************************/ +void inia100SCBPost(BYTE * pHcb, BYTE * pScb) +{ + Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */ + ORC_HCS *pHCB; + ORC_SCB *pSCB; + ESCB *pEScb; + + pHCB = (ORC_HCS *) pHcb; + pSCB = (ORC_SCB *) pScb; + pEScb = pSCB->SCB_EScb; + if ((pSRB = (Scsi_Cmnd *) pEScb->SCB_Srb) == 0) { + printk("inia100SCBPost: SRB pointer is empty\n"); + orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + return; + } + pEScb->SCB_Srb = NULL; + + switch (pSCB->SCB_HaStat) { + case 0x0: + case 0xa: /* Linked command complete without error and linked normally */ + case 0xb: /* Linked command complete without error interrupt generated */ + pSCB->SCB_HaStat = 0; + break; + + case 0x11: /* Selection time out-The initiator selection or target + reselection was not complete within the SCSI Time out period */ + pSCB->SCB_HaStat = DID_TIME_OUT; + break; + + case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus + phase sequence was requested by the target. The host adapter + will generate a SCSI Reset Condition, notifying the host with + a SCRD interrupt */ + pSCB->SCB_HaStat = DID_RESET; + break; + + case 0x1a: /* SCB Aborted. 07/21/98 */ + pSCB->SCB_HaStat = DID_ABORT; + break; + + case 0x12: /* Data overrun/underrun-The target attempted to transfer more data + than was allocated by the Data Length field or the sum of the + Scatter / Gather Data Length fields. */ + case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ + case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */ + + default: + printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat); + pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */ + break; + } + + if (pSCB->SCB_TaStat == 2) { /* Check condition */ + memcpy((unsigned char *) &pSRB->sense_buffer[0], + (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE); + } + pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16); + pSRB->scsi_done(pSRB); /* Notify system DONE */ + + /* Find the next pending SRB */ + if ((pSRB = inia100PopSRBFromQueue(pHCB)) != NULL) { /* Assume resend will success */ + /* Reuse old SCB */ + inia100BuildSCB(pHCB, pSCB, pSRB); /* Create corresponding SCB */ + orc_exec_scb(pHCB, pSCB); /* Start execute SCB */ + } else { /* No Pending SRB */ + orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + } + return; +} + +/***************************************************************************** + Function name : inia100_biosparam + Description : Return the "logical geometry" + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) +#else +int inia100_biosparam(Scsi_Disk * disk, int dev, int *info_array) +#endif +{ + ORC_HCS *pHcb; /* Point to Host adapter control block */ + ORC_TCS *pTcb; + + pHcb = (ORC_HCS *) disk->device->host->base; + pTcb = &pHcb->HCS_Tcs[disk->device->id]; + + if (pTcb->TCS_DrvHead) { + info_array[0] = pTcb->TCS_DrvHead; + info_array[1] = pTcb->TCS_DrvSector; + info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector; + } else { + if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) { + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = disk->capacity / 255 / 63; + } else { + info_array[0] = 64; + info_array[1] = 32; + info_array[2] = disk->capacity >> 11; + } + } + return 0; +} + + +static void subIntr(ORC_HCS * pHCB, int irqno) +{ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); +#endif + + if (pHCB->HCS_Intr != irqno) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, flags); +#endif + return; + } + orc_interrupt(pHCB); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, flags); +#endif +} + +/* + * Interrupts handler (main routine of the driver) + */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr0(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[0], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr1(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[1], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr2(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[2], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr3(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[3], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr4(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[4], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr5(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[5], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr6(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[6], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr7(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[7], irqno); +} + +/* + * Dump the current driver status and panic... + */ +static void inia100_panic(char *msg) +{ + printk("\ninia100_panic: %s\n", msg); + panic("inia100 panic"); +} + +/*#include "inia100scsi.c" */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/inia100.h linux.ac/drivers/scsi/inia100.h --- linux.vanilla/drivers/scsi/inia100.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/inia100.h Tue Mar 2 02:03:44 1999 @@ -0,0 +1,503 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ************************************************************************** + * + * Module: inia100.h + * Description: INI-A100U2W LINUX device driver header + * Revision History: + * 06/18/98 HL, Initial production Version 1.02 + * 12/19/98 bv, Use spinlocks for 2.1.95 and up + ****************************************************************************/ + +#ifndef CVT_LINUX_VERSION +#define CVT_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S)) +#endif + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#include "sd.h" + +extern int inia100_detect(Scsi_Host_Template *); +extern int inia100_command(Scsi_Cmnd *); +extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +extern int inia100_abort(Scsi_Cmnd *); +extern int inia100_reset(Scsi_Cmnd *, unsigned int); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1, 3, 0) +extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */ +extern struct proc_dir_entry proc_scsi_inia100; +#else +extern int inia100_biosparam(Disk *, int, int *); /*for linux v1.13 */ +#endif + +#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a" + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0) +#define INIA100 { \ + NULL, \ + NULL, \ + inia100_REVID, \ + inia100_detect, \ + NULL, \ + NULL, \ + inia100_command, \ + inia100_queue, \ + inia100_abort, \ + inia100_reset, \ + NULL, \ + inia100_biosparam, \ + 1, \ +7, \ +SG_ALL, \ +1, \ +0, \ +0, \ +ENABLE_CLUSTERING \ +} + +#else + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2, 1, 75) +#define INIA100 { \ + NULL, \ + NULL, \ + &proc_scsi_inia100, \ + NULL, \ + inia100_REVID, \ + inia100_detect, \ + NULL, \ + NULL, \ + inia100_command, \ + inia100_queue, \ + inia100_abort, \ + inia100_reset, \ + NULL, \ + inia100_biosparam, \ + 1, \ + 7, \ + 0, \ + 1, \ + 0, \ + 0, \ + ENABLE_CLUSTERING \ +} +#else /* Version >= 2.1.75 */ +#define INIA100 { \ + next: NULL, \ + module: NULL, \ + proc_dir: &proc_scsi_inia100, \ + proc_info: NULL, \ + name: inia100_REVID, \ + detect: inia100_detect, \ + release: NULL, \ + info: NULL, \ + command: inia100_command, \ + queuecommand: inia100_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: inia100_abort, \ + reset: inia100_reset, \ + slave_attach: NULL, \ + bios_param: inia100_biosparam, \ + can_queue: 1, \ + this_id: 1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} +#endif +#endif + +#define VIRT_TO_BUS(i) (unsigned int) virt_to_bus((void *)(i)) +#define ULONG unsigned long +#define PVOID void * +#define USHORT unsigned short +#define UCHAR unsigned char +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define UBYTE unsigned char +#define UWORD unsigned short +#define UDWORD unsigned long +#ifdef ALPHA +#define U32 unsigned int +#else +#define U32 unsigned long +#endif + +#ifndef NULL +#define NULL 0 /* zero */ +#endif +#ifndef TRUE +#define TRUE (1) /* boolean true */ +#endif +#ifndef FALSE +#define FALSE (0) /* boolean false */ +#endif +#ifndef FAILURE +#define FAILURE (-1) +#endif +#if 1 +#define ORC_MAXQUEUE 245 +#else +#define ORC_MAXQUEUE 25 +#endif + +#define TOTAL_SG_ENTRY 32 +#define MAX_TARGETS 16 +#define IMAX_CDB 15 +#define SENSE_SIZE 14 +#define MAX_SUPPORTED_ADAPTERS 4 +#define SUCCESSFUL 0x00 + +#define I920_DEVICE_ID 0x0002 /* Initio's inic-950 product ID */ + +/************************************************************************/ +/* Scatter-Gather Element Structure */ +/************************************************************************/ +typedef struct ORC_SG_Struc { + U32 SG_Ptr; /* Data Pointer */ + U32 SG_Len; /* Data Length */ +} ORC_SG; + + +/* SCSI related definition */ +#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ +#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ + + +#define ORC_OFFSET_SCB 16 +#define ORC_MAX_SCBS 250 +#define MAX_CHANNELS 2 +#define MAX_ESCB_ELE 64 +#define TCF_DRV_255_63 0x0400 + +/********************************************************/ +/* Orchid Configuration Register Set */ +/********************************************************/ +#define ORC_PVID 0x00 /* Vendor ID */ +#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */ +#define ORC_PDID 0x02 /* Device ID */ +#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */ +#define ORC_COMMAND 0x04 /* Command */ +#define BUSMS 0x04 /* BUS MASTER Enable */ +#define IOSPA 0x01 /* IO Space Enable */ +#define ORC_STATUS 0x06 /* Status register */ +#define ORC_REVISION 0x08 /* Revision number */ +#define ORC_BASE 0x10 /* Base address */ +#define ORC_BIOS 0x50 /* Expansion ROM base address */ +#define ORC_INT_NUM 0x3C /* Interrupt line */ +#define ORC_INT_PIN 0x3D /* Interrupt pin */ + +/********************************************************/ +/* Orchid Host Command Set */ +/********************************************************/ +#define ORC_CMD_NOP 0x00 /* Host command - NOP */ +#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ +#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ +#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ +#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ +#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ +#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ +#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ + +/********************************************************/ +/* Orchid Register Set */ +/********************************************************/ +#define ORC_GINTS 0xA0 /* Global Interrupt Status */ +#define QINT 0x04 /* Reply Queue Interrupt */ +#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ +#define MQINT 0x04 /* Mask Reply Queue Interrupt */ +#define ORC_GCFG 0xA2 /* Global Configure */ +#define EEPRG 0x01 /* Enable EEPROM programming */ +#define ORC_GSTAT 0xA3 /* Global status */ +#define WIDEBUS 0x10 /* Wide SCSI Devices connected */ +#define ORC_HDATA 0xA4 /* Host Data */ +#define ORC_HCTRL 0xA5 /* Host Control */ +#define SCSIRST 0x80 /* SCSI bus reset */ +#define HDO 0x40 /* Host data out */ +#define HOSTSTOP 0x02 /* Host stop RISC engine */ +#define DEVRST 0x01 /* Device reset */ +#define ORC_HSTUS 0xA6 /* Host Status */ +#define HDI 0x02 /* Host data in */ +#define RREADY 0x01 /* RISC engine is ready to receive */ +#define ORC_NVRAM 0xA7 /* Nvram port address */ +#define SE2CS 0x008 +#define SE2CLK 0x004 +#define SE2DO 0x002 +#define SE2DI 0x001 +#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ +#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */ +#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ +#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */ +#define ORC_FWBASEADR 0xAC /* Firmware base address */ + +#define ORC_EBIOSADR0 0xB0 /* External Bios address */ +#define ORC_EBIOSADR1 0xB1 /* External Bios address */ +#define ORC_EBIOSADR2 0xB2 /* External Bios address */ +#define ORC_EBIOSDATA 0xB3 /* External Bios address */ + +#define ORC_SCBSIZE 0xB7 /* SCB size register */ +#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ +#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ + +#define ORC_RISCCTL 0xE0 /* RISC Control */ +#define PRGMRST 0x002 +#define DOWNLOAD 0x001 +#define ORC_PRGMCTR0 0xE2 /* RISC program counter */ +#define ORC_PRGMCTR1 0xE3 /* RISC program counter */ +#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */ + +typedef struct orc_extended_scb { /* Extended SCB */ + ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */ + Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */ +} ESCB; + +/*********************************************************************** + SCSI Control Block +************************************************************************/ +typedef struct orc_scb { /* Scsi_Ctrl_Blk */ + UBYTE SCB_Opcode; /*00 SCB command code&residual */ + UBYTE SCB_Flags; /*01 SCB Flags */ + UBYTE SCB_Target; /*02 Target Id */ + UBYTE SCB_Lun; /*03 Lun */ + U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */ + U32 SCB_XferLen; /*08 Data Transfer Length */ + U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */ + U32 SCB_SGLen; /*10 SG list # * 8 */ + U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */ + U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */ + UBYTE SCB_HaStat; /*1C Host Status */ + UBYTE SCB_TaStat; /*1D Target Status */ + UBYTE SCB_Status; /*1E SCB status */ + UBYTE SCB_Link; /*1F Link pointer, default 0xFF */ + UBYTE SCB_SenseLen; /*20 Sense Allocation Length */ + UBYTE SCB_CDBLen; /*21 CDB Length */ + UBYTE SCB_Ident; /*22 Identify */ + UBYTE SCB_TagMsg; /*23 Tag Message */ + UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */ + UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */ + U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */ + + ESCB *SCB_EScb; /*38 Extended SCB Pointer */ +#ifndef ALPHA + UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */ +#endif +} ORC_SCB; + +/* Opcodes of ORCSCB_Opcode */ +#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */ +#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ + +/* Status of ORCSCB_Status */ +#define SCB_COMPLETE 0x00 /* SCB request completed */ +#define SCB_POST 0x01 /* SCB is posted by the HOST */ + +/* Bit Definition for ORCSCB_Flags */ +#define SCF_DISINT 0x01 /* Disable HOST interrupt */ +#define SCF_DIR 0x18 /* Direction bits */ +#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ +#define SCF_DIN 0x08 /* From Target to Initiator */ +#define SCF_DOUT 0x10 /* From Initiator to Target */ +#define SCF_NO_XF 0x18 /* No data transfer */ +#define SCF_POLL 0x40 + +/* Error Codes for ORCSCB_HaStat */ +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + + +/* Error Codes for ORCSCB_TaStat */ +#define TARGET_CHK_COND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_TAG_FULL 0x28 + + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ +#define MSG_STAG 0x20 +#define MSG_HTAG 0x21 +#define MSG_OTAG 0x22 + +#define MSG_IGNOREWIDE 0x23 + +#define MSG_IDENT 0x80 +#define MSG_DISC 0x40 /* Disconnect allowed */ + + +/* SCSI MESSAGE */ +#define MSG_EXTEND 0x01 +#define MSG_SDP 0x02 +#define MSG_ABORT 0x06 +#define MSG_REJ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY 0x09 +#define MSG_DEVRST 0x0C +#define MSG_STAG 0x20 + +/*********************************************************************** + Target Device Control Structure +**********************************************************************/ + +typedef struct ORC_Tar_Ctrl_Struc { + UBYTE TCS_DrvDASD; /* 6 */ + UBYTE TCS_DrvSCSI; /* 7 */ + UBYTE TCS_DrvHead; /* 8 */ + UWORD TCS_DrvFlags; /* 4 */ + UBYTE TCS_DrvSector; /* 7 */ +} ORC_TCS, *PORC_TCS; + +/* Bit Definition for TCF_DrvFlags */ +#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */ +#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */ + + +/*********************************************************************** + Host Adapter Control Structure +************************************************************************/ +typedef struct ORC_Ha_Ctrl_Struc { + USHORT HCS_Base; /* 00 */ + UBYTE HCS_Index; /* 02 */ + UBYTE HCS_Intr; /* 04 */ + UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */ + UBYTE HCS_BIOS; /* 07 BIOS configuration */ + + UBYTE HCS_Flags; /* 0B */ + UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */ + UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */ + + USHORT HCS_Units; /* Number of units this adapter */ + USHORT HCS_AFlags; /* Adapter info. defined flags */ + ULONG HCS_Timeout; /* Adapter timeout value */ + PVOID HCS_virScbArray; /* 28 Virtual Pointer to SCB array */ + U32 HCS_physScbArray; /* Scb Physical address */ + PVOID HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */ + U32 HCS_physEscbArray; /* scatter list Physical address */ + UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */ + UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */ + UBYTE ActiveTags[16][16]; /* 50 */ + ORC_TCS HCS_Tcs[16]; /* 28 */ + U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t BitAllocFlagLock; +#endif + Scsi_Cmnd *pSRB_head; + Scsi_Cmnd *pSRB_tail; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t pSRB_lock; +#endif +} ORC_HCS; + +/* Bit Definition for HCS_Flags */ + +#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */ +#define HCF_PARITY 0x02 /* parity card */ +#define HCF_LVDS 0x10 /* parity card */ + +/* Bit Definition for TargetFlag */ + +#define TCF_EN_255 0x08 +#define TCF_EN_TAG 0x10 +#define TCF_BUSY 0x20 +#define TCF_DISCONNECT 0x40 +#define TCF_SPIN_UP 0x80 + +/* Bit Definition for HCS_AFlags */ +#define HCS_AF_IGNORE 0x01 /* Adapter ignore */ +#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */ +#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */ + + +/*---------------------------------------*/ +/* TimeOut for RESET to complete (30s) */ +/* */ +/* After a RESET the drive is checked */ +/* every 200ms. */ +/*---------------------------------------*/ +#define DELAYED_RESET_MAX (30*1000L) +#define DELAYED_RESET_INTERVAL 200L + +/*----------------------------------------------*/ +/* TimeOut for IRQ from last interrupt (5s) */ +/*----------------------------------------------*/ +#define IRQ_TIMEOUT_INTERVAL (5*1000L) + +/*----------------------------------------------*/ +/* Retry Delay interval (200ms) */ +/*----------------------------------------------*/ +#define DELAYED_RETRY_INTERVAL 200L + +#define INQUIRY_SIZE 36 +#define CAPACITY_SIZE 8 +#define DEFAULT_SENSE_LEN 14 + +#define DEVICE_NOT_FOUND 0x86 + +/*----------------------------------------------*/ +/* Definition for PCI device */ +/*----------------------------------------------*/ +#define MAX_PCI_DEVICES 21 +#define MAX_PCI_BUSES 8 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 Thu Jan 14 01:25:25 1999 +++ linux.ac/drivers/scsi/megaraid.c Mon Mar 1 14:24:09 1999 @@ -1,24 +1,27 @@ /*=================================================================== * * Linux MegaRAID device driver - * + * * Copyright 1998 American Megatrends 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. + * 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. * - * Version : 0.92 + * Version : 0.96 * * Description: Linux device driver for AMI MegaRAID controller * + * Supported controllers: MegaRAID 418, 428, 438, 466, 762 + * + * Maintainer: Jeff L Jones + * * History: * * Version 0.90: - * Works and has been tested with the MegaRAID 428 controller, and - * the MegaRAID 438 controller. Probably works with the 466 also, - * but not tested. + * Original source contributed by Dell; integrated it into the kernel and + * cleaned up some things. Added support for 438/466 controllers. * * Version 0.91: * Aligned mailbox area on 16-byte boundry. @@ -35,31 +38,50 @@ * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: - * Small changes to the comments/formatting. Plus a couple of - * added notes. Returned to the authors. No actual code changes - * save printk levels. - * 8 Oct 98 Alan Cox + * Small changes to the comments/formatting. Plus a couple of + * added notes. Returned to the authors. No actual code changes + * save printk levels. + * 8 Oct 98 Alan Cox * * Merged with 2.1.131 source tree. - * 12 Dec 98 K. Baranowski + * 12 Dec 98 K. Baranowski + * + * Version 0.93: + * Added support for vendor specific ioctl commands (0x80+xxh) + * Changed some fields in MEGARAID struct to better values. + * Added signature check for Rp controllers under 2.0 kernels + * Changed busy-wait loop to be time-based + * Fixed SMP race condition in isr + * Added kfree (sgList) on release + * Added #include linux/version.h to megaraid.h for hosts.h + * Changed max_id to represent max logical drives instead of targets. + * + * Version 0.94: + * Got rid of some excess locking/unlocking + * Fixed slight memory corruption problem while memcpy'ing into mailbox + * Changed logical drives to be reported as luns rather than targets + * Changed max_id to 16 since it is now max targets/chan again. + * Improved ioctl interface for upcoming megamgr + * + * Version 0.95: + * Fixed problem of queueing multiple commands to adapter; + * still has some strange problems on some setups, so still + * defaults to single. To enable parallel commands change + * #define MULTI_IO in megaraid.h + * Changed kmalloc allocation to be done in beginning. + * Got rid of C++ style comments + * + * Version 0.96: + * 762 fully supported. * * BUGS: - * Tested with 2.1.90, but unfortunately there is a bug in pci.c which - * fails to detect our controller. Does work with 2.1.118--don't know - * which kernel in between it was fixed in. - * With SMP enabled under 2.1.118 with more than one processor, gets an - * error message "scsi_end_request: buffer-list destroyed" under heavy - * IO, but doesn't seem to affect operation, or data integrity. The - * message doesn't occur without SMP enabled, or with one proccessor with - * SMP enabled, or under any combination under 2.0 kernels. + * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that + * fails to detect the controller as a pci device on the system. * *===================================================================*/ -#define QISR 1 #define CRLFSTR "\n" -#define MULTIQ 1 - #include #ifdef MODULE @@ -68,10 +90,8 @@ #if LINUX_VERSION_CODE >= 0x20100 char kernel_version[] = UTS_RELEASE; -/* originally ported by Dell Corporation; updated, released, and maintained by - American Megatrends */ -MODULE_AUTHOR("American Megatrends Inc."); -MODULE_DESCRIPTION("AMI MegaRAID driver"); +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI MegaRAID driver"); #endif #endif @@ -90,9 +110,7 @@ #include #include -#include #include -#include /* for kmalloc() */ #if LINUX_VERSION_CODE < 0x20100 #include #else @@ -112,14 +130,18 @@ * * #Defines * - *================================================================*/ + *================================================================ + */ #if LINUX_VERSION_CODE < 0x020100 #define ioremap vremap #define iounmap vfree /* simulate spin locks */ -typedef struct {volatile char lock;} spinlock_t; +typedef struct { + volatile char lock; +} spinlock_t; + #define spin_lock_init(x) { (x)->lock = 0;} #define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ (x)->lock=1; save_flags(flags);\ @@ -143,7 +165,15 @@ (*node) = obj; \ (*node)->##next = NULL; \ spin_unlock_irqrestore(&mega_lock,cpuflag);\ -}; +} + +/* a non-locking version (if we already have the lock) */ +#define ENQUEUE_NL(obj,type,list,next) \ +{ type **node; \ + for(node=&(list); *node; node=(type **)&(*node)->##next); \ + (*node) = obj; \ + (*node)->##next = NULL; \ +} #define DEQUEUE(obj,type,list,next) \ { long cpuflag; \ @@ -154,125 +184,124 @@ spin_unlock_irqrestore(&mega_lock,cpuflag);\ }; -u_long RDINDOOR(mega_host_config *megaCfg) +u_long RDINDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base + 0x20); + return readl (megaCfg->base + 0x20); } -void WRINDOOR(mega_host_config *megaCfg, u_long value) +void WRINDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x20); + writel (value, megaCfg->base + 0x20); } -u_long RDOUTDOOR(mega_host_config *megaCfg) +u_long RDOUTDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base+0x2C); + return readl (megaCfg->base + 0x2C); } -void WROUTDOOR(mega_host_config *megaCfg, u_long value) +void WROUTDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x2C); + writel (value, megaCfg->base + 0x2C); } /*================================================================ * * Function prototypes * - *================================================================*/ -static int MegaIssueCmd(mega_host_config *megaCfg, - u_char *mboxData, - mega_scb *scb, + *================================================================ + */ +static int MegaIssueCmd (mega_host_config * megaCfg, + u_char * mboxData, + mega_scb * scb, int intr); -static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, - u_long *buffer, u_long *length); +static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u_long * buffer, u_long * length); -static void mega_runque(void *); -static void mega_rundoneq(void); -static void mega_cmd_done(mega_host_config *,mega_scb *, int); +static void mega_runque (void *); +static void mega_rundoneq (void); +static void mega_cmd_done (mega_host_config *, mega_scb *, int); +static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); +static inline void freeSgList(mega_host_config *megaCfg); /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 #if SERDEBUG -static void ser_init(void); -static void ser_puts(char *str); -static void ser_putc(char c); -static int ser_printk(const char *fmt, ...); +static void ser_init (void); +static void ser_puts (char *str); +static void ser_putc (char c); +static int ser_printk (const char *fmt,...); #endif /*================================================================ * * Global variables * - *================================================================*/ -static int numCtlrs = 0; -static mega_host_config *megaCtlrs[4] = { 0 }; - -/* Change this to 0 if you want to see the raw drives */ -static int use_raid = 1; + *================================================================ + */ +static int numCtlrs = 0; +static mega_host_config *megaCtlrs[12] = {0}; /* Queue of pending/completed SCBs */ -static mega_scb *qPending = NULL; +static mega_scb *qPending = NULL; static Scsi_Cmnd *qCompleted = NULL; volatile static spinlock_t mega_lock; -static struct tq_struct runq = {0,0,mega_runque,NULL}; +static struct tq_struct runq = {0, 0, mega_runque, NULL}; -struct proc_dir_entry proc_scsi_megaraid = { +struct proc_dir_entry proc_scsi_megaraid = +{ PROC_SCSI_MEGARAID, 8, "megaraid", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #if SERDEBUG -static char strbuf[MAX_SERBUF+1]; +static char strbuf[MAX_SERBUF + 1]; -static void ser_init() +static void ser_init () { - unsigned port=COM_BASE; + unsigned port = COM_BASE; - outb(0x80,port+3); - outb(0,port+1); - /* 9600 Baud, if 19200: outb(6,port) */ - outb(12, port); - outb(3,port+3); - outb(0,port+1); + outb (0x80, port + 3); + outb (0, port + 1); + /* 9600 Baud, if 19200: outb(6,port) */ + outb (12, port); + outb (3, port + 3); + outb (0, port + 1); } -static void ser_puts(char *str) +static void ser_puts (char *str) { - char *ptr; + char *ptr; - ser_init(); - for (ptr=str;*ptr;++ptr) - ser_putc(*ptr); + ser_init (); + for (ptr = str; *ptr; ++ptr) + ser_putc (*ptr); } -static void ser_putc(char c) +static void ser_putc (char c) { - unsigned port=COM_BASE; + unsigned port = COM_BASE; - while ((inb(port+5) & 0x20)==0); - outb(c,port); - if (c==0x0a) - { - while ((inb(port+5) & 0x20)==0); - outb(0x0d,port); - } + while ((inb (port + 5) & 0x20) == 0); + outb (c, port); + if (c == 0x0a) { + while ((inb (port + 5) & 0x20) == 0); + outb (0x0d, port); + } } -static int ser_printk(const char *fmt, ...) +static int ser_printk (const char *fmt,...) { - va_list args; - int i; - long flags; + va_list args; + int i; + long flags; - spin_lock_irqsave(mega_lock,flags); - va_start(args,fmt); - i = vsprintf(strbuf,fmt,args); - ser_puts(strbuf); - va_end(args); - spin_unlock_irqrestore(&mega_lock,flags); + va_start (args, fmt); + i = vsprintf (strbuf, fmt, args); + ser_puts (strbuf); + va_end (args); - return i; + return i; } #define TRACE(a) { ser_printk a;} @@ -281,14 +310,14 @@ #define TRACE(A) #endif -void callDone(Scsi_Cmnd *SCpnt) +void callDone (Scsi_Cmnd * SCpnt) { if (SCpnt->result) { - TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, - SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, - SCpnt->result)); + TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, + SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, + SCpnt->result)); } - SCpnt->scsi_done(SCpnt); + SCpnt->scsi_done (SCpnt); } /*------------------------------------------------------------------------- @@ -299,96 +328,95 @@ /*================================================ * Initialize SCB structures - *================================================*/ -static void initSCB(mega_host_config *megaCfg) + *================================================ + */ +static int initSCB (mega_host_config * megaCfg) { int idx; - for(idx=0; idxmax_cmds; idx++) { - megaCfg->scbList[idx].idx = -1; - megaCfg->scbList[idx].flag = 0; - megaCfg->scbList[idx].sgList = NULL; - megaCfg->scbList[idx].SCpnt = NULL; + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + megaCfg->scbList[idx].idx = -1; + megaCfg->scbList[idx].flag = 0; + megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST, + GFP_ATOMIC | GFP_DMA); + if (megaCfg->scbList[idx].sgList == NULL) { + printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx); + freeSgList(megaCfg); + return -1; + } + megaCfg->scbList[idx].SCpnt = NULL; } + return 0; } /*=========================== * Allocate a SCB structure - *===========================*/ -static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt) + *=========================== + */ +static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) { - int idx; - long flags; + int idx; + long flags; - spin_lock_irqsave(&mega_lock,flags); - for(idx=0; idxmax_cmds; idx++) { + spin_lock_irqsave (&mega_lock, flags); + for (idx = 0; idx < megaCfg->max_cmds; idx++) { if (megaCfg->scbList[idx].idx < 0) { - /* Set Index and SCB pointer */ - megaCfg->scbList[idx].flag = 0; - megaCfg->scbList[idx].idx = idx; + /* Set Index and SCB pointer */ + megaCfg->scbList[idx].idx = idx; + spin_unlock_irqrestore (&mega_lock, flags); + megaCfg->scbList[idx].flag = 0; megaCfg->scbList[idx].SCpnt = SCpnt; - megaCfg->scbList[idx].next = NULL; - spin_unlock_irqrestore(&mega_lock,flags); - - if (megaCfg->scbList[idx].sgList == NULL) { - megaCfg->scbList[idx].sgList = - kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA); - } + megaCfg->scbList[idx].next = NULL; return &megaCfg->scbList[idx]; } } - spin_unlock_irqrestore(&mega_lock,flags); + spin_unlock_irqrestore (&mega_lock, flags); + + printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); - printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); - return NULL; } /*======================= * Free a SCB structure - *=======================*/ -static void freeSCB(mega_scb *scb) + *======================= + */ +static void freeSCB (mega_scb * scb) { - long flags; - - spin_lock_irqsave(&mega_lock,flags); - scb->flag = 0; - scb->idx = -1; - scb->next = NULL; + scb->flag = 0; + scb->next = NULL; scb->SCpnt = NULL; - spin_unlock_irqrestore(&mega_lock,flags); + scb->idx = -1; } /* Run through the list of completed requests */ -static void mega_rundoneq() +static void mega_rundoneq () { mega_host_config *megaCfg; - Scsi_Cmnd *SCpnt; - long islogical; + Scsi_Cmnd *SCpnt; + char islogical; + + while (1) { + DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + if (SCpnt == NULL) + return; - while(1) { - DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); - if (SCpnt == NULL) return; - - megaCfg = (mega_host_config *)SCpnt->host->hostdata; - - /* Check if we're allowing access to RAID drives or physical - * if use_raid == 1 and this wasn't a disk on the max channel or - * if use_raid == 0 and this was a disk on the max channel - * then fail. - */ - islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; + + islogical = (SCpnt->channel == megaCfg->host->max_channel && + SCpnt->target == 0); if (SCpnt->cmnd[0] == INQUIRY && - ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && - (islogical != use_raid)) { - SCpnt->result = 0xF0; + ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && + !islogical) { + SCpnt->result = 0xF0; } /* Convert result to error */ - switch(SCpnt->result) { - case 0x00: case 0x02: + switch (SCpnt->result) { + case 0x00: + case 0x02: SCpnt->result |= (DID_OK << 16); break; case 0x8: @@ -400,16 +428,16 @@ } /* Callback */ - callDone(SCpnt); + callDone (SCpnt); } } /* Add command to the list of completed requests */ -static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status) +static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status) { pScb->SCpnt->result = status; - ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); - freeSCB(pScb); + ENQUEUE (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + freeSCB (pScb); } /*---------------------------------------------------- @@ -417,42 +445,45 @@ * * Run as a scheduled task *----------------------------------------------------*/ -static void mega_runque(void *dummy) +static void mega_runque (void *dummy) { mega_host_config *megaCfg; - mega_scb *pScb; - long flags; + mega_scb *pScb; + long flags; /* Take care of any completed requests */ - mega_rundoneq(); + mega_rundoneq (); - DEQUEUE(pScb,mega_scb,qPending,next); + DEQUEUE (pScb, mega_scb, qPending, next); if (pScb) { - megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata; + if (pScb->SCpnt) { + TRACE(("NULL SCpnt for idx %d!\n",pScb->idx)); + } + megaCfg = (mega_host_config *) pScb->SCpnt->host->hostdata; - if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) { - TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n", - pScb->SCpnt->serial_number, - pScb->SCpnt->cmnd[0], - pScb->SCpnt->channel, - pScb->SCpnt->target, - pScb->SCpnt->lun, - intr_count, - megaCfg->mbox->busy, - (megaCfg->flag & IN_ISR) ? 1 : 0, - (megaCfg->flag & PENDING) ? 1 : 0)); + if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR | PENDING)) { + TRACE (("%.08lx %.02x <%d.%d.%d> busy%d isr%d pending%d\n", + pScb->SCpnt->serial_number, + pScb->SCpnt->cmnd[0], + pScb->SCpnt->channel, + pScb->SCpnt->target, + pScb->SCpnt->lun, + megaCfg->mbox->busy, + (megaCfg->flag & IN_ISR) ? 1 : 0, + (megaCfg->flag & PENDING) ? 1 : 0)); } - if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) { + if (MegaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) { /* We're BUSY... come back later */ - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); pScb->next = qPending; - qPending = pScb; - spin_unlock_irqrestore(&mega_lock,flags); + qPending = pScb; + spin_unlock_irqrestore (&mega_lock, flags); - if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */ - queue_task(&runq, &tq_scheduler); + if (!(megaCfg->flag & PENDING)) { + /* If PENDING, irq will schedule task */ + queue_task (&runq, &tq_scheduler); } } } @@ -466,17 +497,22 @@ * If NULL is returned, the scsi_done function MUST have been called * *-------------------------------------------------------------------*/ -static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) +static mega_scb * mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) { - mega_scb *pScb; - mega_mailbox *mbox; + mega_scb *pScb; + mega_mailbox *mbox; mega_passthru *pthru; - long seg; + long seg; + char islogical; - /* We don't support multi-luns */ - if (SCpnt->lun != 0) { + if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */ + return mega_ioctl (megaCfg, SCpnt); + + islogical = (SCpnt->channel == megaCfg->host->max_channel && SCpnt->target == 0); + + if (!islogical && SCpnt->lun != 0) { SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } @@ -485,45 +521,46 @@ * Logical drive commands * *-----------------------------------------------------*/ - if (SCpnt->channel == megaCfg->host->max_channel) { - switch(SCpnt->cmnd[0]) { + if (islogical) { + switch (SCpnt->cmnd[0]) { case TEST_UNIT_READY: - memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen); + memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case MODE_SENSE: - memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]); + memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case READ_CAPACITY: case INQUIRY: /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } pthru = &pScb->pthru; - mbox = (mega_mailbox *)&pScb->mboxData; + mbox = (mega_mailbox *) & pScb->mboxData; - memset(mbox, 0, sizeof(pScb->mboxData)); - memset(pthru, 0, sizeof(mega_passthru)); - pthru->timeout = 0; - pthru->ars = 0; - pthru->islogical = 1; - pthru->logdrv = SCpnt->target; - pthru->cdblen = SCpnt->cmd_len; - pthru->dataxferaddr = virt_to_bus(SCpnt->request_buffer); - pthru->dataxferlen = SCpnt->request_bufflen; - memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = SCpnt->lun; + pthru->cdblen = SCpnt->cmd_len; + pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer); + pthru->dataxferlen = SCpnt->request_bufflen; + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); /* Initialize mailbox area */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; @@ -532,51 +569,51 @@ case READ_10: case WRITE_10: /* Allocate a SCB and initialize mailbox */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } - mbox = (mega_mailbox *)&pScb->mboxData; + mbox = (mega_mailbox *) & pScb->mboxData; - memset(mbox, 0, sizeof(pScb->mboxData)); - mbox->logdrv = SCpnt->target; - mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? + memset (mbox, 0, sizeof (pScb->mboxData)); + mbox->logdrv = SCpnt->lun; + mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; - + /* 6-byte */ if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { - mbox->numsectors = - (u_long)SCpnt->cmnd[4]; - mbox->lba = - ((u_long)SCpnt->cmnd[1] << 16) | - ((u_long)SCpnt->cmnd[2] << 8) | - (u_long)SCpnt->cmnd[3]; + mbox->numsectors = + (u_long) SCpnt->cmnd[4]; + mbox->lba = + ((u_long) SCpnt->cmnd[1] << 16) | + ((u_long) SCpnt->cmnd[2] << 8) | + (u_long) SCpnt->cmnd[3]; mbox->lba &= 0x1FFFFF; } - + /* 10-byte */ if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { - mbox->numsectors = - (u_long)SCpnt->cmnd[8] | - ((u_long)SCpnt->cmnd[7] << 8); + mbox->numsectors = + (u_long) SCpnt->cmnd[8] | + ((u_long) SCpnt->cmnd[7] << 8); mbox->lba = - ((u_long)SCpnt->cmnd[2] << 24) | - ((u_long)SCpnt->cmnd[3] << 16) | - ((u_long)SCpnt->cmnd[4] << 8) | - (u_long)SCpnt->cmnd[5]; + ((u_long) SCpnt->cmnd[2] << 24) | + ((u_long) SCpnt->cmnd[3] << 16) | + ((u_long) SCpnt->cmnd[4] << 8) | + (u_long) SCpnt->cmnd[5]; } - + /* Calculate Scatter-Gather info */ - mbox->numsgelements = build_sglist(megaCfg, pScb, - (u_long*)&mbox->xferaddr, - (u_long*)&seg); + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); return pScb; - + default: SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } } @@ -587,31 +624,32 @@ *-----------------------------------------------------*/ else { /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } pthru = &pScb->pthru; - mbox = (mega_mailbox *)pScb->mboxData; - - memset(mbox, 0, sizeof(pScb->mboxData)); - memset(pthru, 0, sizeof(mega_passthru)); - pthru->timeout = 0; - pthru->ars = 0; + mbox = (mega_mailbox *) pScb->mboxData; + + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; pthru->islogical = 0; - pthru->channel = SCpnt->channel; - pthru->target = SCpnt->target; - pthru->cdblen = SCpnt->cmd_len; - memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - pthru->numsgelements = build_sglist(megaCfg, pScb, - (u_long *)&pthru->dataxferaddr, - (u_long *)&pthru->dataxferlen); - + pthru->channel = SCpnt->channel; + pthru->target = SCpnt->target; + pthru->cdblen = SCpnt->cmd_len; + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + pthru->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & pthru->dataxferaddr, + (u_long *) & pthru->dataxferlen); + /* Initialize mailbox */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; } @@ -619,88 +657,183 @@ } /*-------------------------------------------------------------------- + * build RAID commands for controller, passed down through ioctl() + *--------------------------------------------------------------------*/ +static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + mega_scb *pScb; + mega_ioctl_mbox *mbox; + mega_mailbox *mailbox; + mega_passthru *pthru; + long seg; + unsigned char *data = (unsigned char *)SCpnt->request_buffer; + int i; + + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + +#if 0 + printk("\nBUF: "); + for (i=0;i<18;i++) { + printk(" %x",data[i]); + } + printk("......\n"); +#endif + + mbox = (mega_ioctl_mbox *) & pScb->mboxData; + mailbox = (mega_mailbox *) & pScb->mboxData; + memset (mailbox, 0, sizeof (pScb->mboxData)); + + if (data[0] == 0x03) { /* passthrough command */ + unsigned char cdblen = data[2]; + + pthru = &pScb->pthru; + memset (pthru, 0, sizeof (mega_passthru)); + pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0; + pthru->timeout = data[cdblen+3] & 0x07; + pthru->reqsenselen = 14; + pthru->ars = (data[cdblen+3] & 0x08) ? 1:0; + pthru->logdrv = data[cdblen+4]; + pthru->channel = data[cdblen+5]; + pthru->target = data[cdblen+6]; + pthru->cdblen = cdblen; + memcpy (pthru->cdb, &data[3], cdblen); + + mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mailbox->xferaddr = virt_to_bus (pthru); + + + pthru->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & pthru->dataxferaddr, + (u_long *) & pthru->dataxferlen); + + for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { + data[i] = data[i+cdblen+7]; + } + + return pScb; + } + /* else normal (nonpassthru) command */ + + mbox->cmd = data[0]; + mbox->channel = data[1]; + mbox->param = data[2]; + mbox->pad[0] = data[3]; + mbox->logdrv = data[4]; + + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); + + for (i=0;i<(SCpnt->request_bufflen-6);i++) { + data[i] = data[i+6]; + } + + return (pScb); +} + + +/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/ -static void megaraid_isr(int irq, void *devp, struct pt_regs *regs) +static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) { - mega_host_config *megaCfg; - u_char byte, idx, sIdx; - u_long dword; - mega_mailbox *mbox; - mega_scb *pScb; - long flags; - int qCnt, qStatus; + mega_host_config *megaCfg; + u_char byte, idx, sIdx; + u_long dword; + mega_mailbox *mbox; + mega_scb *pScb; + long flags; + int qCnt, qStatus; - megaCfg = (mega_host_config *)devp; - mbox = (mega_mailbox *)megaCfg->mbox; + megaCfg = (mega_host_config *) devp; + mbox = (mega_mailbox *) megaCfg->mbox; if (megaCfg->host->irq == irq) { - spin_lock_irqsave(&mega_lock,flags); + +#if LINUX_VERSION_CODE >= 0x20100 + spin_lock_irqsave (&io_request_lock, flags); +#endif + + spin_lock_irqsave (&mega_lock, flags); if (megaCfg->flag & IN_ISR) { - TRACE(("ISR called reentrantly!!\n")); + TRACE (("ISR called reentrantly!!\n")); } megaCfg->flag |= IN_ISR; /* Check if a valid interrupt is pending */ if (megaCfg->flag & BOARD_QUARTZ) { - dword = RDOUTDOOR(megaCfg); - if (dword != 0x10001234) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - spin_unlock_irqrestore(&mega_lock,flags); - return; - } - WROUTDOOR(megaCfg,dword); - } else { - byte = READ_PORT(megaCfg->host->io_port, INTR_PORT); - if ((byte & VALID_INTR_BYTE) == 0) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - spin_unlock_irqrestore(&mega_lock,flags); - return; - } - WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); + dword = RDOUTDOOR (megaCfg); + if (dword != 0x10001234) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); +#if LINUX_VERSION_CODE >= 0x20100 + spin_unlock_irqrestore (&io_request_lock, flags); +#endif + return; + } + WROUTDOOR (megaCfg, dword); + } + else { + byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); + if ((byte & VALID_INTR_BYTE) == 0) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); +#if LINUX_VERSION_CODE >= 0x20100 + spin_unlock_irqrestore (&io_request_lock, flags); +#endif + return; + } + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); } - - qCnt = mbox->numstatus; + + qCnt = mbox->numstatus; qStatus = mbox->status; - if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt)) - printk(KERN_DEBUG "Got numstatus = %d\n",qCnt); + if (qCnt > 1) { + TRACE (("ISR: Received %d status\n", qCnt)) + printk (KERN_DEBUG "Got numstatus = %d\n", qCnt); } - - for(idx=0; idxcompleted[idx]; if (sIdx > 0) { - pScb = &megaCfg->scbList[sIdx-1]; - spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */ - mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus); - spin_lock_irqsave(&mega_lock,flags); + pScb = &megaCfg->scbList[sIdx - 1]; + /* FVF: let's try to avoid un/locking for no good reason */ + pScb->SCpnt->result = qStatus; + ENQUEUE_NL (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + freeSCB (pScb); } } if (megaCfg->flag & BOARD_QUARTZ) { - WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2); - while (RDINDOOR(megaCfg) & 0x02); - } else { - CLEAR_INTR(megaCfg->host->io_port); + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + while (RDINDOOR (megaCfg) & 0x02); + } + else { + CLEAR_INTR (megaCfg->host->io_port); } megaCfg->flag &= ~IN_ISR; megaCfg->flag &= ~PENDING; - spin_unlock_irqrestore(&mega_lock,flags); + spin_unlock_irqrestore (&mega_lock, flags); + mega_runque (NULL); - spin_lock_irqsave(&io_request_lock, flags); - mega_runque(NULL); - spin_unlock_irqrestore(&io_request_lock,flags); +#if LINUX_VERSION_CODE >= 0x20100 + spin_unlock_irqrestore (&io_request_lock, flags); +#endif #if 0 /* Queue as a delayed ISR routine */ - queue_task_irq_off(&runq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - spin_unlock_irqrestore(&mega_lock,flags); + queue_task_irq_off (&runq, &tq_immediate); + mark_bh (IMMEDIATE_BH); #endif } @@ -709,15 +842,17 @@ /*==================================================*/ /* Wait until the controller's mailbox is available */ /*==================================================*/ -static int busyWaitMbox(mega_host_config *megaCfg) +static int busyWaitMbox (mega_host_config * megaCfg) { - mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; - long counter; + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + long counter; - for(counter=0; counter<0xFFFFFF; counter++) { - if (!mbox->busy) return 0; + for (counter = 0; counter < 10000; counter++) { + udelay (100); + if (!mbox->busy) + return 0; } - return -1; + return -1; /* give up after 1 second */ } /*===================================================== @@ -728,92 +863,105 @@ * u_char *mboxData - Mailbox area, 16 bytes * mega_scb *pScb - SCB posting (or NULL if N/A) * int intr - if 1, interrupt, 0 is blocking - *=====================================================*/ -static int MegaIssueCmd(mega_host_config *megaCfg, - u_char *mboxData, - mega_scb *pScb, - int intr) -{ - mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; - long flags; - u_char byte; - u_long cmdDone; - - mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00); /* Set cmdid */ - mboxData[0xF] = 1; /* Set busy */ - - /* one bad report of problem when issuing a command while pending. - * Wasn't able to duplicate, but it doesn't really affect performance - * anyway, so don't allow command while PENDING - */ + *===================================================== + */ +static int MegaIssueCmd (mega_host_config * megaCfg, + u_char * mboxData, + mega_scb * pScb, + int intr) +{ + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + long flags; + u_char byte; + u_long cmdDone; + + mboxData[0x1] = (pScb ? pScb->idx + 1 : 0x00); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ + + spin_lock_irqsave(&mega_lock,flags); + +#if !MULTI_IO if (megaCfg->flag & PENDING) { - return -1; + spin_unlock_irqrestore(&mega_lock,flags); + return -1; } +#endif /* Wait until mailbox is free */ - if (busyWaitMbox(megaCfg)) { + if (busyWaitMbox (megaCfg)) { if (pScb) { - TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number, - pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun)); + TRACE (("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number, + pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun)); + } else { + TRACE(("pScb NULL in MegaIssueCmd!\n")); } + spin_unlock_irqrestore(&mega_lock,flags); return -1; } /* Copy mailbox data into host structure */ - spin_lock_irqsave(&mega_lock,flags); - memset(mbox, 0, sizeof(mega_mailbox)); - memcpy(mbox, mboxData, 16); - spin_unlock_irqrestore(&mega_lock,flags); + memset (mbox, 0, 16); + memcpy (mbox, mboxData, 16); /* Kick IO */ megaCfg->flag |= PENDING; if (intr) { /* Issue interrupt (non-blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); - } else { - ENABLE_INTR(megaCfg->host->io_port); - ISSUE_COMMAND(megaCfg->host->io_port); + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); + } + else { + ENABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); } + spin_unlock_irqrestore(&mega_lock,flags); } - else { /* Issue non-ISR (blocking) command */ + else { /* Issue non-ISR (blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); - while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234); - WROUTDOOR(megaCfg, cmdDone); + while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); + WROUTDOOR (megaCfg, cmdDone); + spin_unlock_irqrestore(&mega_lock,flags); if (pScb) { - mega_cmd_done(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); } - WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2); - while(RDINDOOR(megaCfg) & 0x2); + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + while (RDINDOOR (megaCfg) & 0x2); megaCfg->flag &= ~PENDING; + } else { - DISABLE_INTR(megaCfg->host->io_port); - ISSUE_COMMAND(megaCfg->host->io_port); - - while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID)); - WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); - - ENABLE_INTR(megaCfg->host->io_port); - CLEAR_INTR(megaCfg->host->io_port); - + DISABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); + + while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID)); + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); + + + ENABLE_INTR (megaCfg->host->io_port); + CLEAR_INTR (megaCfg->host->io_port); + megaCfg->flag &= ~PENDING; + spin_unlock_irqrestore(&mega_lock,flags); + if (pScb) { - mega_cmd_done(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); } - megaCfg->flag &= ~PENDING; + else { + TRACE (("Error: NULL pScb!\n")); + } + } } @@ -823,42 +971,42 @@ /*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*/ -static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, - u_long *buffer, u_long *length) +static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u_long * buffer, u_long * length) { struct scatterlist *sgList; int idx; /* Scatter-gather not used */ if (scb->SCpnt->use_sg == 0) { - *buffer = virt_to_bus(scb->SCpnt->request_buffer); - *length = (u_long)scb->SCpnt->request_bufflen; + *buffer = virt_to_bus (scb->SCpnt->request_buffer); + *length = (u_long) scb->SCpnt->request_bufflen; return 0; } - sgList = (struct scatterlist *)scb->SCpnt->buffer; + sgList = (struct scatterlist *) scb->SCpnt->request_buffer; if (scb->SCpnt->use_sg == 1) { - *buffer = virt_to_bus(sgList[0].address); - *length = (u_long)sgList[0].length; + *buffer = virt_to_bus (sgList[0].address); + *length = (u_long) sgList[0].length; return 0; } /* Copy Scatter-Gather list info into controller structure */ - for(idx=0; idxSCpnt->use_sg; idx++) { - scb->sgList[idx].address = virt_to_bus(sgList[idx].address); - scb->sgList[idx].length = (u_long)sgList[idx].length; + for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { + scb->sgList[idx].address = virt_to_bus (sgList[idx].address); + scb->sgList[idx].length = (u_long) sgList[idx].length; } - + /* Reset pointer and length fields */ - *buffer = virt_to_bus(scb->sgList); + *buffer = virt_to_bus (scb->sgList); *length = 0; /* Return count of SG requests */ return scb->SCpnt->use_sg; } - + /*-------------------------------------------------------------------- - * Initializes the address of the controller's mailbox register + * Initializes the adress of the controller's mailbox register * The mailbox register is used to issue commands to the card. * Format of the mailbox area: * 00 01 command @@ -873,25 +1021,25 @@ * 10 01 numstatus byte * 11 01 status byte *--------------------------------------------------------------------*/ -static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr) +static int mega_register_mailbox (mega_host_config * megaCfg, u_long paddr) { /* align on 16-byte boundry */ megaCfg->mbox = &megaCfg->mailbox; - megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0); - paddr = (paddr+16)&0xfffffff0; + megaCfg->mbox = (mega_mailbox *) ((((ulong) megaCfg->mbox) + 16) & 0xfffffff0); + paddr = (paddr + 16) & 0xfffffff0; /* Register mailbox area with the firmware */ if (megaCfg->flag & BOARD_QUARTZ) { } else { - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); - - CLEAR_INTR(megaCfg->host->io_port); - ENABLE_INTR(megaCfg->host->io_port); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); + + CLEAR_INTR (megaCfg->host->io_port); + ENABLE_INTR (megaCfg->host->io_port); } return 0; } @@ -899,77 +1047,79 @@ /*------------------------------------------------------------------- * Issue an adapter info query to the controller *-------------------------------------------------------------------*/ -static int mega_i_query_adapter(mega_host_config *megaCfg) +static int mega_i_query_adapter (mega_host_config * megaCfg) { mega_RAIDINQ *adapterInfo; mega_mailbox *mbox; - u_char mboxData[16]; - u_long paddr; + u_char mboxData[16]; + u_long paddr; - spin_lock_init(&mega_lock); + spin_lock_init (&mega_lock); /* Initialize adapter inquiry */ - paddr = virt_to_bus(megaCfg->mega_buffer); - mbox = (mega_mailbox *)mboxData; + paddr = virt_to_bus (megaCfg->mega_buffer); + mbox = (mega_mailbox *) mboxData; - memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer)); - memset(mbox, 0, 16); + memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); + memset (mbox, 0, 16); /* Initialize mailbox registers */ - mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; mbox->xferaddr = paddr; /* Issue a blocking command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); - + MegaIssueCmd (megaCfg, mboxData, NULL, 0); + /* Initialize host/local structures with Adapter info */ - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent; - megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; - megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; +/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */ + megaCfg->host->max_id = 16; /* max targets/chan */ + megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; #if 0 - printk(KERN_DEBUG "---- Logical drive info ----\n"); - for(i=0; inumldrv; i++) { - printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i, - adapterInfo->LogdrvInfo.LDrvSize[i], - adapterInfo->LogdrvInfo.LDrvProp[i], - adapterInfo->LogdrvInfo.LDrvState[i]); - } - printk(KERN_DEBUG "---- Physical drive info ----\n"); - for(i=0; iPhysdrvInfo.PDrvState[i]); + printk ("KERN_DEBUG ---- Logical drive info ----\n"); + for (i = 0; i < megaCfg->numldrv; i++) { + printk ("%d: size: %ld prop: %x state: %x\n", i, + adapterInfo->LogdrvInfo.LDrvSize[i], + adapterInfo->LogdrvInfo.LDrvProp[i], + adapterInfo->LogdrvInfo.LDrvState[i]); + } + printk (KERN_DEBUG "---- Physical drive info ----\n"); + for (i = 0; i < MAX_PHYSICAL_DRIVES; i++) { + if (i && !(i % 8)) + printk ("\n"); + printk ("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]); } - printk("\n"); + printk ("\n"); #endif megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds; -#ifdef HP /* use HP firmware and bios version encoding */ - sprintf(megaCfg->fwVer,"%c%d%d.%d%d", - adapterInfo->AdpInfo.FwVer[2], - adapterInfo->AdpInfo.FwVer[1] >> 8, - adapterInfo->AdpInfo.FwVer[1] & 0x0f, - adapterInfo->AdpInfo.FwVer[2] >> 8, - adapterInfo->AdpInfo.FwVer[2] & 0x0f); - sprintf(megaCfg->biosVer,"%c%d%d.%d%d", - adapterInfo->AdpInfo.BiosVer[2], - adapterInfo->AdpInfo.BiosVer[1] >> 8, - adapterInfo->AdpInfo.BiosVer[1] & 0x0f, - adapterInfo->AdpInfo.BiosVer[2] >> 8, - adapterInfo->AdpInfo.BiosVer[2] & 0x0f); +#ifdef HP /* use HP firmware and bios version encoding */ + sprintf (megaCfg->fwVer, "%c%d%d.%d%d", + adapterInfo->AdpInfo.FwVer[2], + adapterInfo->AdpInfo.FwVer[1] >> 8, + adapterInfo->AdpInfo.FwVer[1] & 0x0f, + adapterInfo->AdpInfo.FwVer[2] >> 8, + adapterInfo->AdpInfo.FwVer[2] & 0x0f); + sprintf (megaCfg->biosVer, "%c%d%d.%d%d", + adapterInfo->AdpInfo.BiosVer[2], + adapterInfo->AdpInfo.BiosVer[1] >> 8, + adapterInfo->AdpInfo.BiosVer[1] & 0x0f, + adapterInfo->AdpInfo.BiosVer[2] >> 8, + adapterInfo->AdpInfo.BiosVer[2] & 0x0f); #else - memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); - megaCfg->fwVer[4] = 0; + memcpy (megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); + megaCfg->fwVer[4] = 0; - memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); - megaCfg->biosVer[4] = 0; + memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); + megaCfg->biosVer[4] = 0; #endif - printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, - megaCfg->fwVer, - megaCfg->biosVer, - megaCfg->numldrv); + printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, + megaCfg->fwVer, + megaCfg->biosVer, + megaCfg->numldrv); return 0; } @@ -982,47 +1132,65 @@ /*---------------------------------------------------------- * Returns data to be displayed in /proc/scsi/megaraid/X *----------------------------------------------------------*/ -int megaraid_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout) +int megaraid_proc_info (char *buffer, char **start, off_t offset, + int length, int inode, int inout) { *start = buffer; return 0; } -int findCard(Scsi_Host_Template *pHostTmpl, - u_short pciVendor, u_short pciDev, - long flag) +int findCard (Scsi_Host_Template * pHostTmpl, + u_short pciVendor, u_short pciDev, + long flag) { mega_host_config *megaCfg; struct Scsi_Host *host; - u_char pciBus, pciDevFun, megaIrq; - u_long megaBase; - u_short pciIdx = 0; + u_char pciBus, pciDevFun, megaIrq; + u_long megaBase; + u_short pciIdx = 0; + u_short numFound = 0; #if LINUX_VERSION_CODE < 0x20100 - while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) { + while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { +#if 0 + if (flag & BOARD_QUARTZ) { + u_int magic; + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_CONF_AMISIG, + &magic); + if (magic != AMI_SIGNATURE) { + pciIdx++; + continue; /* not an AMI board */ + } + } +#endif + +#if 0 + } /* keep auto-indenters happy */ +#endif + #else - struct pci_dev *pdev=pci_devices; + struct pci_dev *pdev = pci_devices; - while((pdev = pci_find_device(pciVendor, pciDev, pdev))) { + while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { pciBus = pdev->bus->number; pciDevFun = pdev->devfn; #endif - printk(KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", - pciVendor, - pciDev, - pciIdx, pciBus, - PCI_SLOT(pciDevFun), - PCI_FUNC(pciDevFun)); - + printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", + pciVendor, + pciDev, + pciIdx, pciBus, + PCI_SLOT (pciDevFun), + PCI_FUNC (pciDevFun)); + /* Read the base port and IRQ from PCI */ #if LINUX_VERSION_CODE < 0x20100 - pcibios_read_config_dword(pciBus, pciDevFun, - PCI_BASE_ADDRESS_0, - (u_int *)&megaBase); - pcibios_read_config_byte(pciBus, pciDevFun, - PCI_INTERRUPT_LINE, - &megaIrq); + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_BASE_ADDRESS_0, + (u_int *) & megaBase); + pcibios_read_config_byte (pciBus, pciDevFun, + PCI_INTERRUPT_LINE, + &megaIrq); #else megaBase = pdev->base_address[0]; megaIrq = pdev->irq; @@ -1031,7 +1199,7 @@ if (flag & BOARD_QUARTZ) { megaBase &= PCI_BASE_ADDRESS_MEM_MASK; - megaBase = (long) ioremap(megaBase,128); + megaBase = (long) ioremap (megaBase, 128); } else { megaBase &= PCI_BASE_ADDRESS_IO_MASK; @@ -1039,72 +1207,75 @@ } /* Initialize SCSI Host structure */ - host = scsi_register(pHostTmpl, sizeof(mega_host_config)); - megaCfg = (mega_host_config *)host->hostdata; - memset(megaCfg, 0, sizeof(mega_host_config)); - - printk(KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, - host->host_no, (u_int)megaBase, megaIrq); - + host = scsi_register (pHostTmpl, sizeof (mega_host_config)); + megaCfg = (mega_host_config *) host->hostdata; + memset (megaCfg, 0, sizeof (mega_host_config)); + + printk (KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, + host->host_no, (u_int) megaBase, megaIrq); + /* Copy resource info into structure */ - megaCfg->flag = flag; - megaCfg->host = host; - megaCfg->base = megaBase; - megaCfg->host->irq = megaIrq; - megaCfg->host->io_port = megaBase; + megaCfg->flag = flag; + megaCfg->host = host; + megaCfg->base = megaBase; + megaCfg->host->irq = megaIrq; + megaCfg->host->io_port = megaBase; megaCfg->host->n_io_port = 16; megaCfg->host->unique_id = (pciBus << 8) | pciDevFun; - megaCtlrs[numCtlrs++] = megaCfg; + megaCtlrs[numCtlrs++] = megaCfg; if (flag != BOARD_QUARTZ) { /* Request our IO Range */ - if (check_region(megaBase, 16)) { - printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); - scsi_unregister(host); + if (check_region (megaBase, 16)) { + printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); + scsi_unregister (host); continue; } - request_region(megaBase, 16, "megaraid"); + request_region (megaBase, 16, "megaraid"); } /* Request our IRQ */ - if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ, - "megaraid", megaCfg)) { - printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, - megaIrq); - scsi_unregister(host); + if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, + "megaraid", megaCfg)) { + printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, + megaIrq); + scsi_unregister (host); continue; } - mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox)); - mega_i_query_adapter(megaCfg); + mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox)); + mega_i_query_adapter (megaCfg); /* Initialize SCBs */ - initSCB(megaCfg); + if (initSCB (megaCfg)) { + scsi_unregister (host); + continue; + } + numFound++; } - return pciIdx; + return numFound; } /*--------------------------------------------------------- * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/ -int megaraid_detect(Scsi_Host_Template *pHostTmpl) +int megaraid_detect (Scsi_Host_Template * pHostTmpl) { int count = 0; pHostTmpl->proc_dir = &proc_scsi_megaraid; #if LINUX_VERSION_CODE < 0x20100 - if (!pcibios_present()) - { - printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); - return 0; - } + if (!pcibios_present ()) { + printk (KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); + return 0; + } #endif - count += findCard(pHostTmpl, 0x101E, 0x9010, 0); - count += findCard(pHostTmpl, 0x101E, 0x9060, 0); - count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + count += findCard (pHostTmpl, 0x101E, 0x9010, 0); + count += findCard (pHostTmpl, 0x101E, 0x9060, 0); + count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); return count; } @@ -1112,54 +1283,67 @@ /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -int megaraid_release(struct Scsi_Host *pSHost) +int megaraid_release (struct Scsi_Host *pSHost) { mega_host_config *megaCfg; - mega_mailbox *mbox; - u_char mboxData[16]; + mega_mailbox *mbox; + u_char mboxData[16]; - megaCfg = (mega_host_config*)pSHost->hostdata; - mbox = (mega_mailbox *)mboxData; + megaCfg = (mega_host_config *) pSHost->hostdata; + mbox = (mega_mailbox *) mboxData; /* Flush cache to disk */ - memset(mbox, 0, 16); + memset (mbox, 0, 16); mboxData[0] = 0xA; /* Issue a blocking (interrupts disabled) command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); + MegaIssueCmd (megaCfg, mboxData, NULL, 0); - schedule(); + schedule (); /* Free our resources */ if (megaCfg->flag & BOARD_QUARTZ) { - iounmap((void *)megaCfg->base); - } else { - release_region(megaCfg->host->io_port, 16); - } - free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise - extra interrupt is generated */ - scsi_unregister(pSHost); + iounmap ((void *) megaCfg->base); + } + else { + release_region (megaCfg->host->io_port, 16); + } + free_irq (megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise + + extra interrupt is generated */ + freeSgList(megaCfg); + scsi_unregister (pSHost); return 0; } +static inline void freeSgList(mega_host_config *megaCfg) +{ + int i; + + for (i = 0; i < megaCfg->max_cmds; i++) { + if (megaCfg->scbList[i].sgList) + kfree (megaCfg->scbList[i].sgList); /* free sgList */ + } +} + /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ -const char *megaraid_info(struct Scsi_Host *pSHost) +const char * megaraid_info (struct Scsi_Host *pSHost) { - static char buffer[512]; - mega_host_config *megaCfg; - mega_RAIDINQ *adapterInfo; + static char buffer[512]; + mega_host_config *megaCfg; + mega_RAIDINQ *adapterInfo; - megaCfg = (mega_host_config *)pSHost->hostdata; - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + megaCfg = (mega_host_config *) pSHost->hostdata; + adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; - sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans", - megaCfg->fwVer, - adapterInfo->AdpInfo.MaxConcCmds, - megaCfg->host->max_id, - megaCfg->host->max_channel); + sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans", + megaCfg->fwVer, + adapterInfo->AdpInfo.MaxConcCmds, + megaCfg->host->max_id, + megaCfg->host->max_channel); return buffer; } @@ -1178,29 +1362,29 @@ * 10 01 numstatus byte * 11 01 status byte *-----------------------------------------------------------------*/ -int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *)) +int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { mega_host_config *megaCfg; - mega_scb *pScb; + mega_scb *pScb; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; if (!(megaCfg->flag & (1L << SCpnt->channel))) { - printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n", - megaCfg->host->host_no, - SCpnt->channel + 'A'); + printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n", + megaCfg->host->host_no, + SCpnt->channel + 'A'); megaCfg->flag |= (1L << SCpnt->channel); } SCpnt->scsi_done = pktComp; /* Allocate and build a SCB request */ - if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) { + if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { /* Add SCB to the head of the pending queue */ - ENQUEUE(pScb, mega_scb, qPending, next); + ENQUEUE (pScb, mega_scb, qPending, next); /* Issue the command to the card */ - mega_runque(NULL); + mega_runque (NULL); } return 0; @@ -1208,37 +1392,44 @@ /*---------------------------------------------------------------------- * Issue a blocking command to the controller - * - * Note - this isnt 2.0.x SMP safe *----------------------------------------------------------------------*/ -volatile static int internal_done_flag = 0; +volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; -static void internal_done(Scsi_Cmnd *SCpnt) +static void internal_done (Scsi_Cmnd * SCpnt) { internal_done_errcode = SCpnt->result; internal_done_flag++; } /* - * This seems dangerous in an SMP environment because - * while spinning on internal_done_flag in 2.0.x SMP - * no IRQ's will be taken, including those that might - * be needed to clear this. - * - * I think this should be using a wait queue ? - * -- AC + * This seems dangerous in an SMP environment because + * while spinning on internal_done_flag in 2.0.x SMP + * no IRQ's will be taken, including those that might + * be needed to clear this. + * + * I think this should be using a wait queue ? + * -- AC + */ + +/* + * I'll probably fix this in the next version, but + * megaraid_command() will never get called since can_queue is set, + * except maybe in a *really* old kernel in which case it's very + * unlikely they'd be using SMP anyway. Really this function is + * just here for completeness. + * - JLJ */ - -int megaraid_command(Scsi_Cmnd *SCpnt) + +int megaraid_command (Scsi_Cmnd * SCpnt) { internal_done_flag = 0; /* Queue command, and wait until it has completed */ - megaraid_queue(SCpnt, internal_done); + megaraid_queue (SCpnt, internal_done); - while(!internal_done_flag) - barrier(); + while (!internal_done_flag) + barrier (); return internal_done_errcode; } @@ -1246,67 +1437,67 @@ /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_abort(Scsi_Cmnd *SCpnt) +int megaraid_abort (Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; - int idx; - long flags; + int idx; + long flags; - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); + TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); /* * Walk list of SCBs for any that are still outstanding */ - for(idx=0; idxmax_cmds; idx++) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { if (megaCfg->scbList[idx].idx >= 0) { if (megaCfg->scbList[idx].SCpnt == SCpnt) { - freeSCB(&megaCfg->scbList[idx]); + freeSCB (&megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); + callDone (SCpnt); } } } - spin_unlock_irqrestore(&mega_lock,flags); + spin_unlock_irqrestore (&mega_lock, flags); return SCSI_ABORT_SNOOZE; } /*--------------------------------------------------------------------- * Reset a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags) +int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) { mega_host_config *megaCfg; - int idx; - long flags; + int idx; + long flags; - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); + TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); /* * Walk list of SCBs for any that are still outstanding */ - for(idx=0; idxmax_cmds; idx++) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { if (megaCfg->scbList[idx].idx >= 0) { SCpnt = megaCfg->scbList[idx].SCpnt; - freeSCB(&megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + freeSCB (&megaCfg->scbList[idx]); + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); + callDone (SCpnt); } } - spin_unlock_irqrestore(&mega_lock,flags); + spin_unlock_irqrestore (&mega_lock, flags); return SCSI_RESET_PUNT; -} +} /*------------------------------------------------------------- * Return the disk geometry for a particular disk @@ -1318,23 +1509,23 @@ * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom) +int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) { - int heads, sectors, cylinders; + int heads, sectors, cylinders; mega_host_config *megaCfg; /* Get pointer to host config structure */ - megaCfg = (mega_host_config *)disk->device->host->hostdata; + megaCfg = (mega_host_config *) disk->device->host->hostdata; /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; + heads = 64; + sectors = 32; cylinders = disk->capacity / (heads * sectors); /* Handle extended translation size for logical drives > 1Gb */ if (disk->capacity >= 0x200000) { - heads = 255; - sectors = 63; + heads = 255; + sectors = 63; cylinders = disk->capacity / (heads * sectors); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.h linux.ac/drivers/scsi/megaraid.h --- linux.vanilla/drivers/scsi/megaraid.h Tue Jan 26 09:44:21 1999 +++ linux.ac/drivers/scsi/megaraid.h Tue Mar 2 02:03:44 1999 @@ -1,7 +1,12 @@ #ifndef __MEGARAID_H__ #define __MEGARAID_H__ +#ifndef LINUX_VERSION_CODE #include +#endif + +#define MULTI_IO 0 /* change to 1 for fully parallel I/O to adapter */ + /* works on some systems, not on others yet */ #define IN_ISR 0x80000000L #define NO_INTR 0x40000000L @@ -20,7 +25,7 @@ #define MEGA_CMD_TIMEOUT 10 -#define MAX_SGLIST 20 +#define MAX_SGLIST 17 #define MAX_COMMANDS 254 #define MAX_LOGICAL_DRIVES 8 @@ -56,7 +61,7 @@ #define I_TOGGLE_PORT 0x01 #define INTR_PORT 0x0a -#define MAILBOX_SIZE 70 +#define MAILBOX_SIZE (sizeof(mega_mailbox)-16) #define MBOX_BUSY_PORT 0x00 #define MBOX_PORT0 0x04 #define MBOX_PORT1 0x05 @@ -96,6 +101,8 @@ #define PCI_CONF_BASE_ADDR_OFFSET 0x10 #define PCI_CONF_IRQ_OFFSET 0x3c +#define PCI_CONF_AMISIG 0xa0 +#define AMI_SIGNATURE 0x11223344 #if LINUX_VERSION_CODE < 0x20100 #define MEGARAID \ @@ -113,14 +120,14 @@ megaraid_reset, /* Reset Command Function */\ NULL, /* Slave Attach Function */\ megaraid_biosparam, /* Disk BIOS Parameters */\ - 1, /* # of cmds that can be\ + 254, /* # of cmds that can be\ outstanding at any time */\ 7, /* HBA Target ID */\ MAX_SGLIST, /* Scatter/Gather Table Size */\ - 1, /* SCSI Commands per LUN */\ + 64, /* SCSI Commands per LUN */\ 0, /* Present */\ 0, /* Default Unchecked ISA DMA */\ - ENABLE_CLUSTERING } /* Enable Clustering */ + ENABLE_CLUSTERING } /* Enable Clustering */ #else #define MEGARAID \ {\ @@ -134,10 +141,10 @@ abort: megaraid_abort, /* Abort Command Function */\ reset: megaraid_reset, /* Reset Command Function */\ bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ - can_queue: 255, /* Can Queue */\ + can_queue: 1 /* MAX_COMMANDS */, /* Can Queue */\ this_id: 7, /* HBA Target ID */\ sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\ - cmd_per_lun: 1, /* SCSI Commands per LUN */\ + cmd_per_lun: 64, /* SCSI Commands per LUN */\ present: 0, /* Present */\ unchecked_isa_dma:0, /* Default Unchecked ISA DMA */\ use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\ @@ -145,140 +152,150 @@ #endif /* Structures */ -typedef struct _mega_ADP_INFO -{ - u_char MaxConcCmds; - u_char RbldRate; - u_char MaxTargPerChan; - u_char ChanPresent; - u_char FwVer[4]; - u_short AgeOfFlash; - u_char ChipSet; - u_char DRAMSize; - u_char CacheFlushInterval; - u_char BiosVer[4]; - u_char resvd[7]; +typedef struct _mega_ADP_INFO { + u_char MaxConcCmds; + u_char RbldRate; + u_char MaxTargPerChan; + u_char ChanPresent; + u_char FwVer[4]; + u_short AgeOfFlash; + u_char ChipSet; + u_char DRAMSize; + u_char CacheFlushInterval; + u_char BiosVer[4]; + u_char resvd[7]; } mega_ADP_INFO; -typedef struct _mega_LDRV_INFO -{ - u_char NumLDrv; - u_char resvd[3]; - u_long LDrvSize[MAX_LOGICAL_DRIVES]; - u_char LDrvProp[MAX_LOGICAL_DRIVES]; - u_char LDrvState[MAX_LOGICAL_DRIVES]; +typedef struct _mega_LDRV_INFO { + u_char NumLDrv; + u_char resvd[3]; + u_long LDrvSize[MAX_LOGICAL_DRIVES]; + u_char LDrvProp[MAX_LOGICAL_DRIVES]; + u_char LDrvState[MAX_LOGICAL_DRIVES]; } mega_LDRV_INFO; -typedef struct _mega_PDRV_INFO -{ - u_char PDrvState[MAX_PHYSICAL_DRIVES]; - u_char resvd; +typedef struct _mega_PDRV_INFO { + u_char PDrvState[MAX_PHYSICAL_DRIVES]; + u_char resvd; } mega_PDRV_INFO; // RAID inquiry: Mailbox command 0x5 -typedef struct _mega_RAIDINQ -{ - mega_ADP_INFO AdpInfo; - mega_LDRV_INFO LogdrvInfo; - mega_PDRV_INFO PhysdrvInfo; +typedef struct _mega_RAIDINQ { + mega_ADP_INFO AdpInfo; + mega_LDRV_INFO LogdrvInfo; + mega_PDRV_INFO PhysdrvInfo; } mega_RAIDINQ; // Passthrough command: Mailbox command 0x3 -typedef struct mega_passthru -{ - u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u_char ars:1; - u_char reserved:3; - u_char islogical:1; - u_char logdrv; /* if islogical == 1 */ - u_char channel; /* if islogical == 0 */ - u_char target; /* if islogical == 0 */ - u_char queuetag; /* unused */ - u_char queueaction; /* unused */ - u_char cdb[MAX_CDB_LEN]; - u_char cdblen; - u_char reqsenselen; - u_char reqsensearea[MAX_REQ_SENSE_LEN]; - u_char numsgelements; - u_char scsistatus; - u_long dataxferaddr; - u_long dataxferlen; +typedef struct mega_passthru { + u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ + u_char ars:1; + u_char reserved:3; + u_char islogical:1; + u_char logdrv; /* if islogical == 1 */ + u_char channel; /* if islogical == 0 */ + u_char target; /* if islogical == 0 */ + u_char queuetag; /* unused */ + u_char queueaction; /* unused */ + u_char cdb[MAX_CDB_LEN]; + u_char cdblen; + u_char reqsenselen; + u_char reqsensearea[MAX_REQ_SENSE_LEN]; + u_char numsgelements; + u_char scsistatus; + u_long dataxferaddr; + u_long dataxferlen; } mega_passthru; -typedef struct _mega_mailbox -{ - /* 0x0 */ u_char cmd; - /* 0x1 */ u_char cmdid; - /* 0x2 */ u_short numsectors; - /* 0x4 */ u_long lba; - /* 0x8 */ u_long xferaddr; - /* 0xC */ u_char logdrv; - /* 0xD */ u_char numsgelements; - /* 0xE */ u_char resvd; - /* 0xF */ u_char busy; - /* 0x10*/ u_char numstatus; - /* 0x11*/ u_char status; - /* 0x12*/ u_char completed[46]; - u_char mraid_poll; - u_char mraid_ack; - u_char pad[16]; +typedef struct _mega_mailbox { + /* 0x0 */ u_char cmd; + /* 0x1 */ u_char cmdid; + /* 0x2 */ u_short numsectors; + /* 0x4 */ u_long lba; + /* 0x8 */ u_long xferaddr; + /* 0xC */ u_char logdrv; + /* 0xD */ u_char numsgelements; + /* 0xE */ u_char resvd; + /* 0xF */ u_char busy; + /* 0x10 */ u_char numstatus; + /* 0x11 */ u_char status; + /* 0x12 */ u_char completed[46]; + u_char mraid_poll; + u_char mraid_ack; + u_char pad[16]; } mega_mailbox; -typedef struct _mega_sglist -{ - u_long address; - u_long length; +typedef struct _mega_ioctl_mbox { + /* 0x0 */ u_char cmd; + /* 0x1 */ u_char cmdid; + /* 0x2 */ u_char channel; + /* 0x3 */ u_char param; + /* 0x4 */ u_char pad[4]; + /* 0x8 */ u_long xferaddr; + /* 0xC */ u_char logdrv; + /* 0xD */ u_char numsgelements; + /* 0xE */ u_char resvd; + /* 0xF */ u_char busy; + /* 0x10 */ u_char numstatus; + /* 0x11 */ u_char status; + /* 0x12 */ u_char completed[46]; + u_char mraid_poll; + u_char mraid_ack; + u_char malign[16]; +} mega_ioctl_mbox; + +typedef struct _mega_sglist { + u_long address; + u_long length; } mega_sglist; /* Queued command data */ typedef struct _mega_scb mega_scb; -struct _mega_scb -{ - int idx; - u_long flag; - Scsi_Cmnd *SCpnt; - u_char mboxData[16]; - mega_passthru pthru; - mega_sglist *sgList; - mega_scb *next; +struct _mega_scb { + int idx; + u_long flag; + Scsi_Cmnd *SCpnt; + u_char mboxData[16]; + mega_passthru pthru; + mega_sglist *sgList; + mega_scb *next; }; /* Per-controller data */ -typedef struct _mega_host_config -{ - u_char numldrv; - u_long flag; - u_long base; - - struct tq_struct megaTq; - - /* Host adapter parameters */ - u_char fwVer[7]; - u_char biosVer[7]; - - struct Scsi_Host *host; - - /* The following must be DMA-able!! */ - volatile mega_mailbox *mbox; - volatile mega_mailbox mailbox; - volatile u_char mega_buffer[2*1024L]; +typedef struct _mega_host_config { + u_char numldrv; + u_long flag; + u_long base; + + struct tq_struct megaTq; + + /* Host adapter parameters */ + u_char fwVer[7]; + u_char biosVer[7]; + + struct Scsi_Host *host; + + /* The following must be DMA-able!! */ + volatile mega_mailbox *mbox; + volatile mega_mailbox mailbox; + volatile u_char mega_buffer[2 * 1024L]; - u_char max_cmds; - mega_scb scbList[MAX_COMMANDS]; + u_char max_cmds; + mega_scb scbList[MAX_COMMANDS]; } mega_host_config; extern struct proc_dir_entry proc_scsi_megaraid; -const char *megaraid_info( struct Scsi_Host * ); -int megaraid_detect( Scsi_Host_Template * ); -int megaraid_release(struct Scsi_Host *); -int megaraid_command( Scsi_Cmnd * ); -int megaraid_abort( Scsi_Cmnd * ); -int megaraid_reset( Scsi_Cmnd *, unsigned int); -int megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); -int megaraid_biosparam( Disk *, kdev_t, int * ); -int megaraid_proc_info( char *buffer, char **start, off_t offset, - int length, int hostno, int inout ); +const char *megaraid_info(struct Scsi_Host *); +int megaraid_detect(Scsi_Host_Template *); +int megaraid_release(struct Scsi_Host *); +int megaraid_command(Scsi_Cmnd *); +int megaraid_abort(Scsi_Cmnd *); +int megaraid_reset(Scsi_Cmnd *, unsigned int); +int megaraid_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +int megaraid_biosparam(Disk *, kdev_t, int *); +int megaraid_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout); #endif 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 Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/ncr53c8xx.c Tue Feb 16 16:58:49 1999 @@ -4996,7 +4996,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){ @@ -9798,7 +9798,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 Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/pci2000.c Mon Jan 4 16:04:59 1999 @@ -108,7 +108,7 @@ do { if ( !inb_p (padapter->cmd) ) return FALSE; - } while ( timer > jiffies ); // test for timeout + } while ( time_after(timer, jiffies) ); // test for timeout return TRUE; } /**************************************************************** @@ -205,7 +205,7 @@ int bus; int z; - DEB(printk ("\npci2000 recieved interrupt ")); + DEB(printk ("\npci2000 received interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process { if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) ) 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 Sun Nov 8 15:07:56 1998 +++ linux.ac/drivers/scsi/pci2220i.c Mon Jan 4 16:04:59 1999 @@ -152,7 +152,7 @@ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear 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; @@ -192,7 +192,7 @@ return (WriteData (padapter)); 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; @@ -288,7 +288,7 @@ UCHAR status; int z; -// DEB(printk ("\npci2220i recieved interrupt\n")); +// DEB(printk ("\npci2220i received interrupt\n")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process { 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 Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/qlogicfc.c Tue Feb 16 17:56:04 1999 @@ -0,0 +1,1937 @@ +/* + * QLogic ISP2100 SCSI-FCP + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +/* Renamed and updated to 1.3.x by Michael Griffith */ + +/* This is a version of the isp1020 driver which was modified by + * Chris Loveland to support the isp2100 + */ + +/* + * $Date: 1995/09/22 02:23:15 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.c,v $ + * Revision 0.5 1995/09/22 02:23:15 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:44:33 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:15:39 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:14:19 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:55:45 root + * Initial release. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd.h" +#include "hosts.h" +#include "qlogicfc.h" + +/* Configuration section **************************************************** */ + +/* Set the following macro to 1 to reload the ISP2100's firmware. This is + version 1.13 of the firmware. */ + +#define RELOAD_FIRMWARE 1 + +#define USE_NVRAM_DEFAULTS 1 + + +/* Set the following to 1 to include fabric support, fabric support is + * currently not as well tested as the other aspects of the driver */ + +#define ISP2100_FABRIC 0 + +/* Macros used for debugging */ +/* +#define DEBUG_ISP2100 1 +#define DEBUG_ISP2100_INT 1 +#define DEBUG_ISP2100_INTR 1 +#define DEBUG_ISP2100_SETUP 1 + +#define DEBUG_ISP2100_FABRIC 1 +*/ +/* #define TRACE_ISP 1 */ + + +#define DEFAULT_LOOP_COUNT 10000000 + +/* End Configuration section ************************************************ */ + +#include + +#if TRACE_ISP + +#define TRACE_BUF_LEN (32*1024) + +struct { + u_long next; + struct { + u_long time; + u_int index; + u_int addr; + u_char *name; + } buf[TRACE_BUF_LEN]; +} trace; + +#define TRACE(w, i, a) \ +{ \ + unsigned long flags; \ + \ + save_flags(flags); \ + cli(); \ + trace.buf[trace.next].name = (w); \ + trace.buf[trace.next].time = jiffies; \ + trace.buf[trace.next].index = (i); \ + trace.buf[trace.next].addr = (long) (a); \ + trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ + restore_flags(flags); \ +} + +#else +#define TRACE(w, i, a) +#endif + +#if DEBUG_ISP2100_FABRIC +#define DEBUG_FABRIC(x) x +#else +#define DEBUG_FABRIC(x) +#endif /* DEBUG_ISP2100_FABRIC */ + + +#if DEBUG_ISP2100 +#define ENTER(x) printk("isp2100 : entering %s()\n", x); +#define LEAVE(x) printk("isp2100 : leaving %s()\n", x); +#define DEBUG(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define DEBUG(x) +#endif /* DEBUG_ISP2100 */ + +#if DEBUG_ISP2100_INTR +#define ENTER_INTR(x) printk("isp2100 : entering %s()\n", x); +#define LEAVE_INTR(x) printk("isp2100 : leaving %s()\n", x); +#define DEBUG_INTR(x) x +#else +#define ENTER_INTR(x) +#define LEAVE_INTR(x) +#define DEBUG_INTR(x) +#endif /* DEBUG ISP2100_INTR */ + + +#if defined(__i386__) +#define virt_to_bus_low32(x) virt_to_bus(x) +#define virt_to_bus_high32(x) 0x0 +#define bus_to_virt_low32(x) bus_to_virt(x) +#define bus_to_virt_high32(x) 0x0 +#elif defined(__alpha__) +#define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) +#define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) +#define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) +#define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) +#endif + +#define ISP2100_REV_ID 1 +#define ISP2100_REV_ID3 3 + +#define MAX_TARGETS 16 +#define MAX_LUNS 8 + +/* host configuration and control registers */ +#define HOST_HCCR 0xc0 /* host command and control */ + +/* pci bus interface registers */ +#define FLASH_BIOS_ADDR 0x00 +#define FLASH_BIOS_DATA 0x02 +#define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ +#define PCI_INTER_CTL 0x08 /* pci interupt control */ +#define PCI_INTER_STS 0x0a /* pci interupt status */ +#define PCI_SEMAPHORE 0x0c /* pci semaphore */ +#define PCI_NVRAM 0x0e /* pci nvram interface */ + +/* mailbox registers */ +#define MBOX0 0x10 /* mailbox 0 */ +#define MBOX1 0x12 /* mailbox 1 */ +#define MBOX2 0x14 /* mailbox 2 */ +#define MBOX3 0x16 /* mailbox 3 */ +#define MBOX4 0x18 /* mailbox 4 */ +#define MBOX5 0x1a /* mailbox 5 */ +#define MBOX6 0x1c /* mailbox 6 */ +#define MBOX7 0x1e /* mailbox 7 */ + +/* mailbox command complete status codes */ +#define MBOX_COMMAND_COMPLETE 0x4000 +#define INVALID_COMMAND 0x4001 +#define HOST_INTERFACE_ERROR 0x4002 +#define TEST_FAILED 0x4003 +#define COMMAND_ERROR 0x4005 +#define COMMAND_PARAM_ERROR 0x4006 +#define PORT_ID_USED 0x4007 +#define LOOP_ID_USED 0x4008 +#define ALL_IDS_USED 0x4009 + +/* async event status codes */ +#define RESET_DETECTED 0x8001 +#define SYSTEM_ERROR 0x8002 +#define REQUEST_TRANSFER_ERROR 0x8003 +#define RESPONSE_TRANSFER_ERROR 0x8004 +#define REQUEST_QUEUE_WAKEUP 0x8005 +#define LIP_OCCURED 0x8010 +#define LOOP_UP 0x8011 +#define LOOP_DOWN 0x8012 +#define LIP_RECEIVED 0x8013 +#define PORT_DB_CHANGED 0x8014 +#define CHANGE_NOTIFICATION 0x8015 +#define SCSI_COMMAND_COMPLETE 0x8020 + +struct Entry_header { + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; +}; + +/* entry header type commands */ +#define ENTRY_COMMAND 0x19 +#define ENTRY_CONTINUATION 0x0a +#define ENTRY_STATUS 0x03 +#define ENTRY_MARKER 0x04 + +/* entry header flag definitions */ +#define EFLAG_BUSY 2 +#define EFLAG_BAD_HEADER 4 +#define EFLAG_BAD_PAYLOAD 8 + +struct dataseg { + u_int d_base_lo; + u_int d_base_high; + u_int d_count; +}; + +struct Command_Entry { + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short rsvd1; + u_short control_flags; + u_short rsvd2; + u_short time_out; + u_short segment_cnt; + u_char cdb[16]; + u_int total_byte_cnt; + struct dataseg dataseg[2]; +}; + +/* command entry control flag definitions */ +#define CFLAG_NODISC 0x01 +#define CFLAG_HEAD_TAG 0x02 +#define CFLAG_ORDERED_TAG 0x04 +#define CFLAG_SIMPLE_TAG 0x08 +#define CFLAG_TAR_RTN 0x10 +#define CFLAG_READ 0x20 +#define CFLAG_WRITE 0x40 + +struct Ext_Command_Entry { + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[44]; +}; + +struct Continuation_Entry { + struct Entry_header hdr; + struct dataseg dataseg[5]; +}; + +struct Marker_Entry { + struct Entry_header hdr; + u_int reserved; + u_char target_lun; + u_char target_id; + u_char modifier; + u_char rsvd; + u_char rsvds[52]; +}; + +/* marker entry modifier definitions */ +#define SYNC_DEVICE 0 +#define SYNC_TARGET 1 +#define SYNC_ALL 2 + +struct Status_Entry { + struct Entry_header hdr; + u_int handle; + u_short scsi_status; + u_short completion_status; + u_short state_flags; + u_short status_flags; + u_short res_info_len; + u_short req_sense_len; + u_int residual; + u_char res_info[8]; + u_char req_sense_data[32]; +}; + +/* status entry completion status definitions */ +#define CS_COMPLETE 0x0000 +#define CS_INCOMPLETE 0x0001 +#define CS_DMA_ERROR 0x0002 +#define CS_TRANSPORT_ERROR 0x0003 +#define CS_RESET_OCCURRED 0x0004 +#define CS_ABORTED 0x0005 +#define CS_TIMEOUT 0x0006 +#define CS_DATA_OVERRUN 0x0007 +#define CS_ABORT_MSG_FAILED 0x000e +#define CS_REJECT_MSG_FAILED 0x000f +#define CS_DATA_UNDERRUN 0x0015 +#define CS_PORT_UNAVAILABLE 0x0028 +#define CS_PORT_LOGGED_OUT 0x0029 +#define CS_PORT_CONFIG_CHANGED 0x002a + +/* status entry state flag definitions */ +#define SF_SENT_CDB 0x0400 +#define SF_TRANSFERRED_DATA 0x0800 +#define SF_GOT_STATUS 0x1000 + +/* status entry status flag definitions */ +#define STF_BUS_RESET 0x0008 +#define STF_DEVICE_RESET 0x0010 +#define STF_ABORTED 0x0020 +#define STF_TIMEOUT 0x0040 + +/* interupt control commands */ +#define ISP_EN_INT 0x8000 +#define ISP_EN_RISC 0x0008 + +/* host control commands */ +#define HCCR_NOP 0x0000 +#define HCCR_RESET 0x1000 +#define HCCR_PAUSE 0x2000 +#define HCCR_RELEASE 0x3000 +#define HCCR_SINGLE_STEP 0x4000 +#define HCCR_SET_HOST_INTR 0x5000 +#define HCCR_CLEAR_HOST_INTR 0x6000 +#define HCCR_CLEAR_RISC_INTR 0x7000 +#define HCCR_BP_ENABLE 0x8000 +#define HCCR_BIOS_DISABLE 0x9000 +#define HCCR_TEST_MODE 0xf000 + +#define RISC_BUSY 0x0004 + +/* mailbox commands */ +#define MBOX_NO_OP 0x0000 +#define MBOX_LOAD_RAM 0x0001 +#define MBOX_EXEC_FIRMWARE 0x0002 +#define MBOX_DUMP_RAM 0x0003 +#define MBOX_WRITE_RAM_WORD 0x0004 +#define MBOX_READ_RAM_WORD 0x0005 +#define MBOX_MAILBOX_REG_TEST 0x0006 +#define MBOX_VERIFY_CHECKSUM 0x0007 +#define MBOX_ABOUT_FIRMWARE 0x0008 +#define MBOX_LOAD_RISC_RAM 0x0009 +#define MBOX_DUMP_RISC_RAM 0x000a +#define MBOX_CHECK_FIRMWARE 0x000e +#define MBOX_INIT_REQ_QUEUE 0x0010 +#define MBOX_INIT_RES_QUEUE 0x0011 +#define MBOX_EXECUTE_IOCB 0x0012 +#define MBOX_WAKE_UP 0x0013 +#define MBOX_STOP_FIRMWARE 0x0014 +#define MBOX_ABORT_IOCB 0x0015 +#define MBOX_ABORT_DEVICE 0x0016 +#define MBOX_ABORT_TARGET 0x0017 +#define MBOX_BUS_RESET 0x0018 +#define MBOX_STOP_QUEUE 0x0019 +#define MBOX_START_QUEUE 0x001a +#define MBOX_SINGLE_STEP_QUEUE 0x001b +#define MBOX_ABORT_QUEUE 0x001c +#define MBOX_GET_DEV_QUEUE_STATUS 0x001d +#define MBOX_GET_FIRMWARE_STATUS 0x001f +#define MBOX_GET_INIT_SCSI_ID 0x0020 +#define MBOX_GET_RETRY_COUNT 0x0022 +#define MBOX_GET_TARGET_PARAMS 0x0028 +#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 +#define MBOX_SET_RETRY_COUNT 0x0032 +#define MBOX_SET_TARGET_PARAMS 0x0038 +#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 +#define MBOX_EXECUTE_IOCB64 0x0054 +#define MBOX_INIT_FIRMWARE 0x0060 +#define MBOX_GET_INIT_CB 0x0061 +#define MBOX_INIT_LIP 0x0062 +#define MBOX_GET_POS_MAP 0x0063 +#define MBOX_GET_PORT_DB 0x0064 +#define MBOX_CLEAR_ACA 0x0065 +#define MBOX_TARGET_RESET 0x0066 +#define MBOX_CLEAR_TASK_SET 0x0067 +#define MBOX_ABORT_TASK_SET 0x0068 +#define MBOX_GET_FIRMWARE_STATE 0x0069 +#define MBOX_GET_PORT_NAME 0x006a +#define MBOX_SEND_SNS 0x006e +#define MBOX_PORT_LOGIN 0x006f +#define MBOX_SEND_CHANGE_REQUEST 0x0070 +#define MBOX_PORT_LOGOUT 0x0071 + +#include "qlogicfc_asm.c" + +/* Each element in mbox_param is an 8 bit bitmap where each bit indicates + if that mbox should be copied as input. For example 0x2 would mean + only copy mbox1. */ + +const u_char mbox_param[] = +{ + 0x01, /* MBOX_NO_OP */ + 0x1f, /* MBOX_LOAD_RAM */ + 0x03, /* MBOX_EXEC_FIRMWARE */ + 0x1f, /* MBOX_DUMP_RAM */ + 0x07, /* MBOX_WRITE_RAM_WORD */ + 0x03, /* MBOX_READ_RAM_WORD */ + 0xff, /* MBOX_MAILBOX_REG_TEST */ + 0x03, /* MBOX_VERIFY_CHECKSUM */ + 0x01, /* MBOX_ABOUT_FIRMWARE */ + 0xff, /* MBOX_LOAD_RISC_RAM */ + 0xff, /* MBOX_DUMP_RISC_RAM */ + 0x00, /* 0x000b */ + 0x00, /* 0x000c */ + 0x00, /* 0x000d */ + 0x01, /* MBOX_CHECK_FIRMWARE */ + 0x00, /* 0x000f */ + 0x1f, /* MBOX_INIT_REQ_QUEUE */ + 0x2f, /* MBOX_INIT_RES_QUEUE */ + 0x0f, /* MBOX_EXECUTE_IOCB */ + 0x03, /* MBOX_WAKE_UP */ + 0x01, /* MBOX_STOP_FIRMWARE */ + 0x0f, /* MBOX_ABORT_IOCB */ + 0x03, /* MBOX_ABORT_DEVICE */ + 0x07, /* MBOX_ABORT_TARGET */ + 0x03, /* MBOX_BUS_RESET */ + 0x03, /* MBOX_STOP_QUEUE */ + 0x03, /* MBOX_START_QUEUE */ + 0x03, /* MBOX_SINGLE_STEP_QUEUE */ + 0x03, /* MBOX_ABORT_QUEUE */ + 0x03, /* MBOX_GET_DEV_QUEUE_STATUS */ + 0x00, /* 0x001e */ + 0x01, /* MBOX_GET_FIRMWARE_STATUS */ + 0x01, /* MBOX_GET_INIT_SCSI_ID */ + 0x00, /* 0x0021 */ + 0x01, /* MBOX_GET_RETRY_COUNT */ + 0x00, /* 0x0023 */ + 0x00, /* 0x0024 */ + 0x00, /* 0x0025 */ + 0x00, /* 0x0026 */ + 0x00, /* 0x0027 */ + 0x03, /* MBOX_GET_TARGET_PARAMS */ + 0x03, /* MBOX_GET_DEV_QUEUE_PARAMS */ + 0x00, /* 0x002a */ + 0x00, /* 0x002b */ + 0x00, /* 0x002c */ + 0x00, /* 0x002d */ + 0x00, /* 0x002e */ + 0x00, /* 0x002f */ + 0x00, /* 0x0030 */ + 0x00, /* 0x0031 */ + 0x07, /* MBOX_SET_RETRY_COUNT */ + 0x00, /* 0x0033 */ + 0x00, /* 0x0034 */ + 0x00, /* 0x0035 */ + 0x00, /* 0x0036 */ + 0x00, /* 0x0037 */ + 0x0f, /* MBOX_SET_TARGET_PARAMS */ + 0x0f, /* MBOX_SET_DEV_QUEUE_PARAMS */ + 0x00, /* 0x003a */ + 0x00, /* 0x003b */ + 0x00, /* 0x003c */ + 0x00, /* 0x003d */ + 0x00, /* 0x003e */ + 0x00, /* 0x003f */ + 0x00, /* 0x0040 */ + 0x00, /* 0x0041 */ + 0x00, /* 0x0042 */ + 0x00, /* 0x0043 */ + 0x00, /* 0x0044 */ + 0x00, /* 0x0045 */ + 0x00, /* 0x0046 */ + 0x00, /* 0x0047 */ + 0x00, /* 0x0048 */ + 0x00, /* 0x0049 */ + 0x00, /* 0x004a */ + 0x00, /* 0x004b */ + 0x00, /* 0x004c */ + 0x00, /* 0x004d */ + 0x00, /* 0x004e */ + 0x00, /* 0x004f */ + 0x00, /* 0x0050 */ + 0x00, /* 0x0051 */ + 0x00, /* 0x0052 */ + 0x00, /* 0x0053 */ + 0xcf, /* MBOX_EXECUTE_IOCB64 */ + 0x00, /* 0x0055 */ + 0x00, /* 0x0056 */ + 0x00, /* 0x0057 */ + 0x00, /* 0x0058 */ + 0x00, /* 0x0059 */ + 0x00, /* 0x005a */ + 0x00, /* 0x005b */ + 0x00, /* 0x005c */ + 0x00, /* 0x005d */ + 0x00, /* 0x005e */ + 0x00, /* 0x005f */ + 0xff, /* MBOX_INIT_FIRMWARE */ + 0xcd, /* MBOX_GET_INIT_CB */ + 0x01, /* MBOX_INIT_LIP */ + 0xcd, /* MBOX_GET_POS_MAP */ + 0xcf, /* MBOX_GET_PORT_DB */ + 0x03, /* MBOX_CLEAR_ACA */ + 0x03, /* MBOX_TARGET_RESET */ + 0x03, /* MBOX_CLEAR_TASK_SET */ + 0x03, /* MBOX_ABORT_TASK_SET */ + 0x01, /* MBOX_GET_FIRMWARE_STATE */ + 0x03, /* MBOX_GET_PORT_NAME */ + 0x00, /* 0x006b */ + 0x00, /* 0x006c */ + 0x00, /* 0x006d */ + 0xcf, /* MBOX_SEND_SNS */ + 0x0f, /* MBOX_PORT_LOGIN */ + 0x03, /* MBOX_SEND_CHANGE_REQUEST */ + 0x03, /* MBOX_PORT_LOGOUT */ +}; + +#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) + + +struct id_name_map { + u64 wwn; + u_char loop_id; +}; + +struct sns_cb { + u_short len; + u_short res1; + u_int response_low; + u_int response_high; + u_short sub_len; + u_short res2; + u_short data[22]; +}; + +/* address of instance of this struct is passed to adapter to initialize things + */ +struct init_cb { + u_char version; + u_char reseverd1[1]; + u_short firm_opts; + u_short max_frame_len; + u_short max_iocb; + u_short exec_throttle; + u_char retry_cnt; + u_char retry_delay; + u_short node_name[4]; + u_short hard_addr; + u_char reserved2[10]; + u_short req_queue_out; + u_short res_queue_in; + u_short req_queue_len; + u_short res_queue_len; + u_int req_queue_addr_lo; + u_int req_queue_addr_high; + u_int res_queue_addr_lo; + u_int res_queue_addr_high; +}; + +/* + * The result queue can be quite a bit smaller since continuation entries + * do not show up there: + */ +#define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) +#define QUEUE_ENTRY_LEN 64 + +#if ISP2100_FABRIC +#define QLOGICFC_MAX_ID 0xff +#else +#define QLOGICFC_MAX_ID 0x80 +#endif + +struct isp2100_hostdata { + u_char revision; + struct pci_dev *pci_dev; + /* result and request queues (shared with isp2100): */ + u_int req_in_ptr; /* index of next request slot */ + u_int res_out_ptr; /* index of next result slot */ + + /* this is here so the queues are nicely aligned */ + long send_marker; /* do we need to send a marker? */ + + char res[RES_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; + char req[QLOGICFC_REQ_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; + struct init_cb control_block; + int loop_up; + unsigned long int tag_ages[126]; + Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; + unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; + struct id_name_map port_db[QLOGICFC_MAX_ID + 1]; + u_char mbox_done; + u64 wwn; + u_int port_id; + u_char queued; +}; + + +/* queue length's _must_ be power of two: */ +#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) +#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ + QLOGICFC_REQ_QUEUE_LEN) +#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) + +static void isp2100_enable_irqs(struct Scsi_Host *); +static void isp2100_disable_irqs(struct Scsi_Host *); +static int isp2100_init(struct Scsi_Host *); +static int isp2100_reset_hardware(struct Scsi_Host *); +static int isp2100_mbox_command(struct Scsi_Host *, u_short[]); +static int isp2100_return_status(struct Status_Entry *); +static void isp2100_intr_handler(int, void *, struct pt_regs *); +static void do_isp2100_intr_handler(int, void *, struct pt_regs *); +static int isp2100_make_portdb(struct Scsi_Host *); + +#if ISP2100_FABRIC +static int isp2100_init_fabric(struct Scsi_Host *, struct id_name_map *, int); +#endif + +#if USE_NVRAM_DEFAULTS +static int isp2100_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); +static u_short isp2100_read_nvram_word(struct Scsi_Host *, u_short); +#endif + +#if DEBUG_ISP2100 +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 = +{ + PROC_SCSI_QLOGICFC, 7, "isp2100", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + + +static inline void isp2100_enable_irqs(struct Scsi_Host *host) +{ + outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); +} + + +static inline void isp2100_disable_irqs(struct Scsi_Host *host) +{ + outw(0x0, host->io_port + PCI_INTER_CTL); +} + + +int isp2100_detect(Scsi_Host_Template * tmpt) +{ + int hosts = 0; + int wait_time; + struct Scsi_Host *host = NULL; + struct isp2100_hostdata *hostdata; + struct pci_dev *pdev = NULL; + + ENTER("isp2100_detect"); + + tmpt->proc_dir = &proc_scsi_isp2100; + + if (pci_present() == 0) { + printk("qlogicfc : PCI not present\n"); + return 0; + } + while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, pdev))) { + + host = scsi_register(tmpt, sizeof(struct isp2100_hostdata)); + host->max_id = QLOGICFC_MAX_ID + 1; + host->hostt->use_new_eh_code = 1; + hostdata = (struct isp2100_hostdata *) host->hostdata; + + memset(hostdata, 0, sizeof(struct isp2100_hostdata)); + hostdata->pci_dev = pdev; + + hostdata->queued = 0; + /* set up the control block */ + hostdata->control_block.version = 0x0f; + hostdata->control_block.firm_opts = 0x010c; + hostdata->control_block.max_frame_len = 2048; + hostdata->control_block.max_iocb = 256; + hostdata->control_block.exec_throttle = 8; + hostdata->control_block.retry_delay = 5; + hostdata->control_block.retry_cnt = 0; + hostdata->control_block.node_name[0] = 0x0020; + hostdata->control_block.node_name[1] = 0xE000; + hostdata->control_block.node_name[2] = 0x008B; + hostdata->control_block.node_name[3] = 0x0000; + hostdata->control_block.hard_addr = 0x0003; + hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; + hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; + hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(&hostdata->res); + hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(&hostdata->res); + hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); + hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); + + hostdata->loop_up = 0; + + if (isp2100_init(host) || isp2100_reset_hardware(host)) { + scsi_unregister(host); + continue; + } + host->this_id = tmpt->this_id; + + if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { + printk("qlogicfc : interrupt %d already in use\n", + host->irq); + scsi_unregister(host); + continue; + } + if (check_region(host->io_port, 0xff)) { + printk("qlogicfc : i/o region 0x%lx-0x%lx already " + "in use\n", + host->io_port, host->io_port + 0xff); + free_irq(host->irq, host); + scsi_unregister(host); + continue; + } + request_region(host->io_port, 0xff, "qlogicfc"); + + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + isp2100_enable_irqs(host); + /* wait for the loop to come up */ + for (wait_time = jiffies + 20 * HZ; wait_time > jiffies && hostdata->loop_up == 0;) + barrier(); + + if (hostdata->loop_up == 0) { + printk("qlogicfc: loop is not up\n"); + release_region(host->io_port, 0xff); + free_irq(host->irq, host); + scsi_unregister(host); + continue; + } + hosts++; + } + + + /* this busy loop should not be needed but the isp2100 seems to need + some time before recognizing it is attached to a fabric */ + +#if ISP2100_FABRIC + for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) + barrier(); +#endif + + LEAVE("isp2100_detect"); + + return hosts; +} + + +static int isp2100_make_portdb(struct Scsi_Host *host) +{ + + short param[8]; + int i, j; + struct id_name_map temp[QLOGICFC_MAX_ID + 1]; + struct isp2100_hostdata *hostdata; + + isp2100_disable_irqs(host); + + memset(temp, 0, sizeof(temp)); + hostdata = (struct isp2100_hostdata *) host->hostdata; + +#if ISP2100_FABRIC + for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { + param[0] = MBOX_PORT_LOGOUT; + param[1] = i << 8; + param[2] = 0; + param[3] = 0; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("logout failed %x %x\n", i, param[0]); + } + } +#endif + + + param[0] = MBOX_GET_INIT_SCSI_ID; + + 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]; + } + + for (i = 0, j = 0; i <= QLOGICFC_MAX_ID; i++) { + temp[i].loop_id = host->this_id; + + param[0] = MBOX_GET_PORT_NAME; + param[1] = (i << 8) & 0xff00; + + isp2100_mbox_command(host, param); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + temp[j].loop_id = i; + temp[j].wwn = ((u64) (param[2] & 0xff)) << 56; + temp[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; + temp[j].wwn |= ((u64) (param[3] & 0xff)) << 40; + temp[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; + temp[j].wwn |= ((u64) (param[6] & 0xff)) << 24; + temp[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; + temp[j].wwn |= ((u64) (param[7] & 0xff)) << 8; + temp[j].wwn |= ((u64) ((param[7] >> 8) & 0xff)); + + j++; + + } + } + + +#if ISP2100_FABRIC + isp2100_init_fabric(host, temp, j); +#endif + + for (i = 0; i <= QLOGICFC_MAX_ID; i++) { + if (temp[i].wwn != hostdata->port_db[i].wwn) { + for (j = 0; j <= QLOGICFC_MAX_ID; j++) { + if (temp[j].wwn == hostdata->port_db[i].wwn) { + hostdata->port_db[i].loop_id = temp[j].loop_id; + break; + } + } + if (j == QLOGICFC_MAX_ID + 1) + hostdata->port_db[i].loop_id = host->this_id; + + for (j = 0; j <= QLOGICFC_MAX_ID; j++) { + if (hostdata->port_db[j].wwn == temp[i].wwn || !hostdata->port_db[j].wwn) { + break; + } + } + if (j == QLOGICFC_MAX_ID + 1) + printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n"); + if (!hostdata->port_db[j].wwn) { + hostdata->port_db[j].loop_id = temp[i].loop_id; + hostdata->port_db[j].wwn = temp[i].wwn; + } + } else + hostdata->port_db[i].loop_id = temp[i].loop_id; + + } + + isp2100_enable_irqs(host); + + return 0; +} + + +#if ISP2100_FABRIC + +int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j) +{ + + u_short param[8]; + u64 wwn; + int done = 0; + u_short loop_id = 0x81; + u_short scsi_id = j; + u_int port_id; + struct sns_cb req; + u_char sns_response[608]; + struct isp2100_hostdata *hostdata; + + hostdata = (struct isp2100_hostdata *) host->hostdata; + + DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n")); + param[0] = MBOX_GET_PORT_NAME; + param[1] = 0x7E00; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + DEBUG_FABRIC(printk("fabric check result %x\n", param[0])); + return 0; + } + printk("qlogicfc.c: Fabric found.\n"); + + + port_id = hostdata->port_id; + while (!done) { + memset(&req, 0, sizeof(req)); + + req.len = 304; + req.response_low = virt_to_bus_low32(sns_response); + req.response_high = virt_to_bus_high32(sns_response); + req.sub_len = 6; + req.data[0] = 0x0100; + req.data[4] = (u_short) (port_id & 0xffff); + req.data[5] = (u_short) (port_id >> 16 & 0xffff); + + param[0] = MBOX_SEND_SNS; + param[1] = 14; + param[2] = virt_to_bus_low32(&req) >> 16; + param[3] = virt_to_bus_low32(&req); + param[6] = virt_to_bus_high32(&req) >> 16; + param[7] = virt_to_bus_high32(&req); + + isp2100_mbox_command(host, param); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + DEBUG_FABRIC(printk("found node %02x%02x%02x%02x%02x%02x%02x%02x ", sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); + DEBUG_FABRIC(printk(" port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19])); + port_id = ((u_int) sns_response[17]) << 16; + port_id |= ((u_int) sns_response[18]) << 8; + port_id |= ((u_int) sns_response[19]); + wwn = ((u64) sns_response[20]) << 56; + wwn |= ((u64) sns_response[21]) << 48; + wwn |= ((u64) sns_response[22]) << 40; + wwn |= ((u64) sns_response[23]) << 32; + wwn |= ((u64) sns_response[24]) << 24; + wwn |= ((u64) sns_response[25]) << 16; + wwn |= ((u64) sns_response[26]) << 8; + wwn |= ((u64) sns_response[27]); + if (hostdata->port_id >> 8 != port_id >> 8) { + DEBUG_FABRIC(printk("adding a fabric port: %x\n", port_id)); + param[0] = MBOX_PORT_LOGIN; + param[1] = loop_id << 8; + param[2] = (u_short) (port_id >> 16); + param[3] = (u_short) (port_id); + + isp2100_mbox_command(host, param); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + port_db[scsi_id].wwn = wwn; + port_db[scsi_id].loop_id = loop_id; + loop_id++; + scsi_id++; + } else { + printk("qlogicfc.c: Error performing port login %x\n", param[0]); + DEBUG_FABRIC(printk("loop_id: %x\n", loop_id)); + } + + } + if (hostdata->port_id == port_id) + done = 1; + } else { + printk("qlogicfc.c: Get All Next failed %x.\n", param[0]); + return 0; + } + } + + return 1; +} + +#endif /* ISP2100_FABRIC */ + + +int isp2100_release(struct Scsi_Host *host) +{ + struct isp2100_hostdata *hostdata; + + ENTER("isp2100_release"); + + hostdata = (struct isp2100_hostdata *) host->hostdata; + + outw(0x0, host->io_port + PCI_INTER_CTL); + free_irq(host->irq, host); + + release_region(host->io_port, 0xff); + + LEAVE("isp2100_release"); + + return 0; +} + + +const char *isp2100_info(struct Scsi_Host *host) +{ + static char buf[80]; + struct isp2100_hostdata *hostdata; + ENTER("isp2100_info"); + + hostdata = (struct isp2100_hostdata *) host->hostdata; + sprintf(buf, + "QLogic ISP2100 SCSI on PCI bus %02x device %02x irq %d base 0x%lx", + hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, + host->io_port); + + + LEAVE("isp2100_info"); + + return buf; +} + + +/* + * The middle SCSI layer ensures that queuecommand never gets invoked + * concurrently with itself or the interrupt handler (though the + * interrupt handler may call this routine as part of + * request-completion handling). + */ +int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) +{ + int i, sg_count, n, num_free; + u_int in_ptr, out_ptr; + struct dataseg *ds; + struct scatterlist *sg; + struct Command_Entry *cmd; + struct Continuation_Entry *cont; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + + ENTER("isp2100_queuecommand"); + + host = Cmnd->host; + hostdata = (struct isp2100_hostdata *) host->hostdata; + Cmnd->scsi_done = done; + + DEBUG(isp2100_print_scsi_cmd(Cmnd)); + + if (hostdata->loop_up == 2) { + hostdata->loop_up = 1; + isp2100_make_portdb(host); + for (i = 0; hostdata->port_db[i].wwn != 0; i++) { + DEBUG(printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id)); + } + } + if (hostdata->loop_up == -1) { + printk("qlogicfc.c: The firmware is dead, just return.\n"); + host->max_id = 0; + return 0; + } + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + DEBUG(printk("qlogicfc : request queue depth %d\n", + REQ_QUEUE_DEPTH(in_ptr, out_ptr))); + + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + DEBUG(printk("qlogicfc : request queue overflow\n")); + return 1; + } + if (hostdata->send_marker) { + struct Marker_Entry *marker; + + TRACE("queue marker", in_ptr, 0); + + DEBUG(printk("qlogicfc : adding marker entry\n")); + marker = (struct Marker_Entry *) cmd; + memset(marker, 0, sizeof(struct Marker_Entry)); + + marker->hdr.entry_type = ENTRY_MARKER; + marker->hdr.entry_cnt = 1; + marker->modifier = SYNC_ALL; + + hostdata->send_marker = 0; + + if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) { + outw(in_ptr, host->io_port + MBOX4); + hostdata->req_in_ptr = in_ptr; + DEBUG(printk("qlogicfc : request queue overflow\n")); + return 1; + } + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; + } + TRACE("queue command", in_ptr, Cmnd); + + memset(cmd, 0, sizeof(struct Command_Entry)); + + /* find a free handle mapping slot */ + for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1))); + + if (!hostdata->handle_ptrs[i]) { + cmd->handle = i; + hostdata->handle_ptrs[i] = Cmnd; + hostdata->handle_serials[i] = Cmnd->serial_number; + } else + printk("qlogicfc: no handle slots, this should not happen.\n"); + + cmd->hdr.entry_type = ENTRY_COMMAND; + cmd->hdr.entry_cnt = 1; + cmd->target_lun = Cmnd->lun; + cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; + cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; + cmd->time_out = SCSI_TIMEOUT / HZ; + + memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); + + if (Cmnd->use_sg) { + cmd->segment_cnt = sg_count = Cmnd->use_sg; + sg = (struct scatterlist *) Cmnd->request_buffer; + ds = cmd->dataseg; + /* fill in first two sg entries: */ + n = sg_count; + if (n > 2) + n = 2; + for (i = 0; i < n; i++) { + ds[i].d_base_lo = virt_to_bus_low32(sg->address); + ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= 2; + + while (sg_count > 0) { + ++cmd->hdr.entry_cnt; + cont = (struct Continuation_Entry *) + &hostdata->req[in_ptr][0]; + memset(cont, 0, sizeof(struct Continuation_Entry)); + in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + DEBUG(printk("isp2100: unexpected request queue overflow\n")); + return 1; + } + TRACE("queue continuation", in_ptr, 0); + cont->hdr.entry_type = ENTRY_CONTINUATION; + ds = cont->dataseg; + n = sg_count; + if (n > 5) + n = 5; + for (i = 0; i < n; ++i) { + ds[i].d_base_lo = virt_to_bus_low32(sg->address); + ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= n; + } + } else { + cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->request_buffer); + cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->request_buffer); + cmd->dataseg[0].d_count = + (u_int) Cmnd->request_bufflen; + cmd->segment_cnt = 1; + } + + switch (Cmnd->cmnd[0]) { + case WRITE_10: + case WRITE_6: + case WRITE_BUFFER: + cmd->control_flags = CFLAG_WRITE; + break; + case REQUEST_SENSE: + /* scsi.c expects sense info in a different buffer */ + cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->sense_buffer); + cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->sense_buffer); + cmd->segment_cnt = 1; + cmd->control_flags = CFLAG_READ; + break; + default: + cmd->control_flags = CFLAG_READ; + break; + } + + + 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: + cmd->control_flags |= CFLAG_ORDERED_TAG; + break; + default: + if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (5 * HZ)) { + cmd->control_flags |= CFLAG_ORDERED_TAG; + hostdata->tag_ages[Cmnd->target] = jiffies; + } else + cmd->control_flags |= CFLAG_SIMPLE_TAG; + } + } + 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; + 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+2 < host->host_busy) + printk("qlogicfc.c crosses its fingers.\n"); + host->can_queue = host->host_busy; + } + + LEAVE("isp2100_queuecommand"); + + return 0; +} + + +#define ASYNC_EVENT_INTERRUPT 0x01 + + +void do_isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + isp2100_intr_handler(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + Scsi_Cmnd *Cmnd; + struct Status_Entry *sts; + struct Scsi_Host *host = dev_id; + struct isp2100_hostdata *hostdata; + u_int in_ptr, out_ptr, handle, num_free; + u_short status; + + ENTER_INTR("isp2100_intr_handler"); + + hostdata = (struct isp2100_hostdata *) host->hostdata; + + DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq)); + + if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { + /* spurious interrupts can happen legally */ + DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n")); + return; + } + in_ptr = inw(host->io_port + MBOX5); + out_ptr = hostdata->res_out_ptr; + + if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { + status = inw(host->io_port + MBOX0); + + DEBUG_INTR(printk("qlogicfc : mbox completion status: %x\n", + status)); + + switch (status) { + case LOOP_UP: + hostdata->loop_up = 2; + break; + case LOOP_DOWN: + hostdata->loop_up = 0; + break; + case LIP_OCCURED: + case CHANGE_NOTIFICATION: + case PORT_DB_CHANGED: + case LIP_RECEIVED: + if (hostdata->loop_up == 1) + hostdata->loop_up = 2; + break; + case SYSTEM_ERROR: + printk("The firmware just choked.\n"); + hostdata->loop_up = -1; + break; + case SCSI_COMMAND_COMPLETE: + handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); + Cmnd = hostdata->handle_ptrs[handle]; + hostdata->handle_ptrs[handle] = NULL; + hostdata->handle_serials[handle] = 0; + hostdata->queued--; + if (Cmnd != NULL) { + Cmnd->result = 0x0; + (*Cmnd->scsi_done) (Cmnd); + } else + printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n"); + break; + case MBOX_COMMAND_COMPLETE: + case INVALID_COMMAND: + case HOST_INTERFACE_ERROR: + case TEST_FAILED: + case COMMAND_ERROR: + case COMMAND_PARAM_ERROR: + case PORT_ID_USED: + case LOOP_ID_USED: + case ALL_IDS_USED: + hostdata->mbox_done = 1; + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + return; + default: + printk("qlogicfc: got an unknown status? %x\n", status); + } + outw(0x0, host->io_port + PCI_SEMAPHORE); + } else { + DEBUG_INTR(printk("qlogicfc : response queue update\n")); + DEBUG_INTR(printk("qlogicfc : response queue depth %d\n", RES_QUEUE_DEPTH(in_ptr, out_ptr))); + + 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->result = isp2100_return_status(sts); + } else { + outw(out_ptr, host->io_port + MBOX5); + continue; + } + + if (sts->completion_status == CS_RESET_OCCURRED + || sts->completion_status == CS_ABORTED + || (sts->status_flags & STF_BUS_RESET)) + hostdata->send_marker = 1; + + 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 + printk("Ouch, scsi done is NULL\n"); + } + hostdata->res_out_ptr = out_ptr; + } + + + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); + num_free = num_free-2; + 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+2 < host->host_busy) + DEBUG(printk("qlogicfc crosses its fingers.\n")); + host->can_queue = host->host_busy; + } + + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + LEAVE_INTR("isp2100_intr_handler"); +} + + +static int isp2100_return_status(struct Status_Entry *sts) +{ + int host_status = DID_ERROR; +#if DEBUG_ISP2100_INTR + static char *reason[] = + { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_ISP2100_INTR */ + + ENTER("isp2100_return_status"); + + DEBUG(printk("qlogicfc : completion status = 0x%04x\n", + sts->completion_status)); + + switch (sts->completion_status) { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_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: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: + case CS_ABORT_MSG_FAILED: + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + host_status = DID_OK; + break; + case CS_PORT_UNAVAILABLE: + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHANGED: + host_status = DID_BAD_TARGET; + break; + default: + printk("qlogicfc : unknown completion status 0x%04x\n", + sts->completion_status); + host_status = DID_ERROR; + break; + } + + DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", + reason[host_status], sts->scsi_status)); + + LEAVE("isp2100_return_status"); + + return (sts->scsi_status & STATUS_MASK) | (host_status << 16); +} + + +int isp2100_abort(Scsi_Cmnd * Cmnd) +{ + u_short param[8]; + int i; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + int return_status = SCSI_ABORT_SUCCESS; + + ENTER("isp2100_abort"); + + host = Cmnd->host; + hostdata = (struct isp2100_hostdata *) host->hostdata; + + for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++) + if (hostdata->handle_ptrs[i] == Cmnd) + break; + + if (i == QLOGICFC_REQ_QUEUE_LEN) + return SCSI_ABORT_ERROR; + + isp2100_disable_irqs(host); + + param[0] = MBOX_ABORT_IOCB; + param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; + param[2] = i >> 16; + param[3] = i & 0xffff; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : scsi abort failure: %x\n", param[0]); + if (param[0] == 0x4005) + Cmnd->result = DID_ERROR << 16; + if (param[0] == 0x4006) + Cmnd->result = DID_BAD_TARGET << 16; + (*Cmnd->scsi_done) (Cmnd); + return_status = SCSI_ABORT_ERROR; + } + isp2100_enable_irqs(host); + + LEAVE("isp2100_abort"); + + return return_status; +} + + +int isp2100_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) +{ + u_short param[8]; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + int return_status = SCSI_RESET_SUCCESS; + + ENTER("isp2100_reset"); + + host = Cmnd->host; + hostdata = (struct isp2100_hostdata *) host->hostdata; + param[0] = MBOX_BUS_RESET; + param[1] = 3; + + isp2100_disable_irqs(host); + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : scsi bus reset failure: %x\n", param[0]); + return_status = SCSI_RESET_ERROR; + } + isp2100_enable_irqs(host); + + LEAVE("isp2100_reset"); + + return return_status;; +} + + +int isp2100_biosparam(Disk * disk, kdev_t n, int ip[]) +{ + int size = disk->capacity; + + ENTER("isp2100_biosparam"); + + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + if (ip[2] > 1024) { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + LEAVE("isp2100_biosparam"); + + return 0; +} + + +static int isp2100_reset_hardware(struct Scsi_Host *host) +{ + u_short param[8]; + struct isp2100_hostdata *hostdata; + int loop_count; + + ENTER("isp2100_reset_hardware"); + + outw(0x01, host->io_port + ISP_CTRL_STATUS); + outw(HCCR_RESET, host->io_port + HOST_HCCR); + outw(HCCR_RELEASE, host->io_port + HOST_HCCR); + outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) + barrier(); + if (!loop_count) + printk("qlogicfc: reset_hardware loop timeout\n"); + + + +#if DEBUG_ISP2100 + printk("qlogicfc : mbox 0 0x%04x \n", inw(host->io_port + MBOX0)); + printk("qlogicfc : mbox 1 0x%04x \n", inw(host->io_port + MBOX1)); + printk("qlogicfc : mbox 2 0x%04x \n", inw(host->io_port + MBOX2)); + printk("qlogicfc : mbox 3 0x%04x \n", inw(host->io_port + MBOX3)); + printk("qlogicfc : mbox 4 0x%04x \n", inw(host->io_port + MBOX4)); + printk("qlogicfc : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); + printk("qlogicfc : mbox 6 0x%04x \n", inw(host->io_port + MBOX6)); + printk("qlogicfc : mbox 7 0x%04x \n", inw(host->io_port + MBOX7)); +#endif /* DEBUG_ISP2100 */ + + DEBUG(printk("qlogicfc : verifying checksum\n")); + +#if RELOAD_FIRMWARE + { + int i; + for (i = 0; i < risc_code_length01; i++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + i; + param[2] = risc_code01[i]; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : firmware load failure\n"); + return 1; + } + } + } +#endif /* RELOAD_FIRMWARE */ + + param[0] = MBOX_VERIFY_CHECKSUM; + param[1] = risc_code_addr01; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : ram checksum failure\n"); + return 1; + } + DEBUG(printk("qlogicfc : executing firmware\n")); + + param[0] = MBOX_EXEC_FIRMWARE; + param[1] = risc_code_addr01; + + isp2100_mbox_command(host, param); + + param[0] = MBOX_ABOUT_FIRMWARE; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : about firmware failure\n"); + return 1; + } + DEBUG(printk("qlogicfc : firmware major revision %d\n", param[1])); + DEBUG(printk("qlogicfc : firmware minor revision %d\n", param[2])); + + hostdata = (struct isp2100_hostdata *) host->hostdata; + +#ifdef USE_NVRAM_DEFAULTS + + if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) { + printk("qlogicfc: Could not read from NVRAM\n"); + } +#endif + + hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0x00ff) << 48; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0x00ff) << 24; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; + + param[0] = MBOX_INIT_FIRMWARE; + param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16); + param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff); + param[4] = 0; + param[5] = 0; + param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); + param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); + isp2100_mbox_command(host, param); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc.c: Ouch 0x%04x\n", param[0]); + return 1; + } + param[0] = MBOX_GET_FIRMWARE_STATE; + isp2100_mbox_command(host, param); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc.c: 0x%04x\n", param[0]); + return 1; + } + + LEAVE("isp2100_reset_hardware"); + + return 0; +} + +#ifdef USE_NVRAM_DEFAULTS + +static int isp2100_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) +{ + + u_short value; + 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); + control_block->node_name[2] = isp2100_read_nvram_word(host, 11); + control_block->node_name[3] = isp2100_read_nvram_word(host, 12); + control_block->hard_addr = isp2100_read_nvram_word(host, 13); + + return 0; + +} + +#endif + +static int isp2100_init(struct Scsi_Host *sh) +{ + u_int io_base; + struct isp2100_hostdata *hostdata; + u_char revision; + u_int irq; + u_short command; + struct pci_dev *pdev; + + + ENTER("isp2100_init"); + + hostdata = (struct isp2100_hostdata *) sh->hostdata; + pdev = hostdata->pci_dev; + + if (pci_read_config_word(pdev, PCI_COMMAND, &command) + || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) { + printk("qlogicfc : error reading PCI configuration\n"); + return 1; + } + io_base = pdev->base_address[0]; + irq = pdev->irq; + + + + if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { + printk("qlogicfc : 0x%04x is not QLogic vendor ID\n", + pdev->vendor); + return 1; + } + if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) { + printk("qlogicfc : 0x%04x does not match ISP2100 device id\n", + pdev->device); + return 1; + } + if (command & PCI_COMMAND_IO && (io_base & 3) == 1) + io_base &= PCI_BASE_ADDRESS_IO_MASK; + else { + printk("qlogicfc : i/o mapping is disabled\n"); + return 1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk("qlogicfc : bus mastering is disabled\n"); + return 1; + } + if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3) + printk("qlogicfc : new isp2100 revision ID (%d)\n", revision); + + + hostdata->revision = revision; + + sh->irq = irq; + sh->io_port = io_base; + + LEAVE("isp2100_init"); + + return 0; +} + +#if USE_NVRAM_DEFAULTS + +#define NVRAM_DELAY() udelay(10) /* 10 microsecond delay */ + + +u_short isp2100_read_nvram_word(struct Scsi_Host * host, u_short byte) +{ + int i; + u_short value, output, input; + + outw(0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + + byte &= 0xff; + byte |= 0x0600; + for (i = 10; i >= 0; i--) { + output = ((byte >> i) & 0x1) ? 0x4 : 0x0; + outw(output | 0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(output | 0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(output | 0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + } + + for (i = 0xf, value = 0; i >= 0; i--) { + value <<= 1; + outw(0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + input = inw(host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + if (input & 0x8) + value |= 1; + } + + outw(0x0, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + + return value; +} + + +#endif /* USE_NVRAM_DEFAULTS */ + + + +/* + * currently, this is only called during initialization or abort/reset, + * at which times interrupts are disabled, so polling is OK, I guess... + */ +static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[]) +{ + int loop_count; + struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata; + + if (mbox_param[param[0]] == 0) + return 1; + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) + barrier(); + if (!loop_count) { + printk("qlogicfc: mbox_command loop timeout #1\n"); + param[0] = 0x4006; + return 1; + } + hostdata->mbox_done = 0; + + if (mbox_param[param[0]] == 0) + printk("qlogicfc: invalid mbox command\n"); + + if (mbox_param[param[0]] & 0x80) + outw(param[7], host->io_port + MBOX7); + if (mbox_param[param[0]] & 0x40) + outw(param[6], host->io_port + MBOX6); + if (mbox_param[param[0]] & 0x20) + outw(param[5], host->io_port + MBOX5); + if (mbox_param[param[0]] & 0x10) + outw(param[4], host->io_port + MBOX4); + if (mbox_param[param[0]] & 0x08) + outw(param[3], host->io_port + MBOX3); + if (mbox_param[param[0]] & 0x04) + outw(param[2], host->io_port + MBOX2); + if (mbox_param[param[0]] & 0x02) + outw(param[1], host->io_port + MBOX1); + if (mbox_param[param[0]] & 0x01) + outw(param[0], host->io_port + MBOX0); + + + outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR); + + while (1) { + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && !(inw(host->io_port + PCI_INTER_STS) & 0x08)) { + barrier(); + } + + if (!loop_count) { + printk("qlogicfc: mbox_command loop timeout #2\n"); + break; + } + isp2100_intr_handler(host->irq, host, NULL); + + if (hostdata->mbox_done == 1) + break; + + } + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + MBOX0) == 0x04) { + barrier(); + } + if (!loop_count) + printk("qlogicfc: mbox_command loop timeout #3\n"); + + param[7] = inw(host->io_port + MBOX7); + param[6] = inw(host->io_port + MBOX6); + param[5] = inw(host->io_port + MBOX5); + param[4] = inw(host->io_port + MBOX4); + param[3] = inw(host->io_port + MBOX3); + param[2] = inw(host->io_port + MBOX2); + param[1] = inw(host->io_port + MBOX1); + param[0] = inw(host->io_port + MBOX0); + + + outw(0x0, host->io_port + PCI_SEMAPHORE); + + if (inw(host->io_port + HOST_HCCR) & 0x0080) { + printk("mbox op is still pending\n"); + } + return 0; +} + + +#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", + status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); + printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", + status->scsi_status, status->completion_status); + printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", + status->state_flags, status->status_flags); + printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", + status->res_info_len, status->req_sense_len); + printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]); + +} + +#endif /* DEBUG_ISP2100_INTR */ + + +#if DEBUG_ISP2100 + +void isp2100_print_scsi_cmd(Scsi_Cmnd * cmd) +{ + int i; + + printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + cmd->target, cmd->lun, cmd->cmd_len); + printk("qlogicfc : command = "); + for (i = 0; i < cmd->cmd_len; i++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); +} + +#endif /* DEBUG_ISP2100 */ + + +#ifdef MODULE + +Scsi_Host_Template driver_template = QLOGICFC; + +#include "scsi_module.c" + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc.h linux.ac/drivers/scsi/qlogicfc.h --- linux.vanilla/drivers/scsi/qlogicfc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/qlogicfc.h Wed Dec 23 19:37:14 1998 @@ -0,0 +1,102 @@ +/* + * QLogic ISP2100 SCSI-FCP + * + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +/* Renamed and updated to 1.3.x by Michael Griffith */ + +/* This is a version of the isp1020 driver which was modified by + * Chris Loveland to support the isp2100 + */ + + +/* + * $Date: 1995/09/22 02:32:56 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.h,v $ + * Revision 0.5 1995/09/22 02:32:56 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:48:28 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:17:16 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:19:43 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:56:13 root + * Initial release. + * + */ + +#ifndef _QLOGICFC_H +#define _QLOGICFC_H + +/* + * With the qlogic interface, every queue slot can hold a SCSI + * command with up to 2 scatter/gather entries. If we need more + * than 2 entries, continuation entries can be used that hold + * another 5 entries each. Unlike for other drivers, this means + * that the maximum number of scatter/gather entries we can + * support at any given time is a function of the number of queue + * slots available. That is, host->can_queue and host->sg_tablesize + * are dynamic and _not_ independent. This all works fine because + * requests are queued serially and the scatter/gather limit is + * determined for each queue request anew. + */ +#define QLOGICFC_REQ_QUEUE_LEN 63 /* must be power of two - 1 */ +#define QLOGICFC_MAX_SG(ql) (2 + (((ql) > 0) ? 5*((ql) - 1) : 0)) +#define QLOGICFC_CMD_PER_LUN 8 + +int isp2100_detect(Scsi_Host_Template *); +int isp2100_release(struct Scsi_Host *); +const char * isp2100_info(struct Scsi_Host *); +int isp2100_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int isp2100_abort(Scsi_Cmnd *); +int isp2100_reset(Scsi_Cmnd *, unsigned int); +int isp2100_biosparam(Disk *, kdev_t, int[]); + +#ifndef NULL +#define NULL (0) +#endif + +extern struct proc_dir_entry proc_scsi_isp2100; + +#define QLOGICFC { \ + detect: isp2100_detect, \ + release: isp2100_release, \ + info: isp2100_info, \ + queuecommand: isp2100_queuecommand, \ + abort: isp2100_abort, \ + reset: isp2100_reset, \ + bios_param: isp2100_biosparam, \ + can_queue: QLOGICFC_REQ_QUEUE_LEN, \ + this_id: -1, \ + sg_tablesize: QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN), \ + cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ +} + +#endif /* _QLOGICFC_H */ + + + 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 Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/qlogicfc_asm.c Tue Dec 22 17:09:51 1998 @@ -0,0 +1,2985 @@ +/************************************************************************ + * * + * --- ISP2100 Fabric Initiator/Target Firmware --- * + * * + * * + * * + ************************************************************************ + */ +/* + * Firmware Version 1.13.00 (18:06 May 04, 1998) + */ + +unsigned short risc_code_version = 1*1024+13; + +unsigned char firmware_version[] = {1,13,0}; + +unsigned short risc_code_addr01 = 0x1000 ; + +unsigned short risc_code01[] = { + 0x0078, 0x1029, 0x0000, 0x5c95, 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, + 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, + 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, + 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, + 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, + 0x0000, 0x749e, 0x74a2, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0x6d00, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x1302, 0xa06e, + 0x0078, 0x130c, 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, + 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x6d00, 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, + 0x70a0, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, 0x0e7e, 0x2071, + 0x6f31, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, + 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, 0x007c, 0x0e7e, + 0x2270, 0x700b, 0x0000, 0x2071, 0x6f31, 0x7018, 0xa088, 0x6f3a, + 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, + 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, + 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, + 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, + 0x0001, 0x3300, 0x7016, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x6dc5, 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, + 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, + 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, + 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x1388, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x6dc3, 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, + 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, + 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x0d7f, + 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x1078, 0x1a3f, + 0x007c, 0x1078, 0x12b7, 0x1078, 0x12b7, 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, + 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, 0x700c, 0xa100, + 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, 0x1a09, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, + 0x41a4, 0x1078, 0x321b, 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, + 0x2073, 0x0000, 0x7843, 0x0090, 0x7843, 0x0010, 0x127f, 0x0f7f, + 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0x6f1a, 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, + 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, + 0x31f0, 0x1078, 0x40c4, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0015, 0x2004, 0xa08a, + 0x199a, 0x0048, 0x47dd, 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, + 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, + 0x493d, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4943, 0x60c3, + 0x0074, 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4a83, + 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, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0022, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, + 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4afa, 0x20a3, 0x0200, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, + 0x1078, 0x4fd1, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4afa, 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, + 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, + 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, + 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, + 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, + 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, + 0x2071, 0x6f10, 0x7018, 0x2068, 0x8dff, 0x0040, 0x50af, 0x68a0, + 0xa406, 0x0040, 0x509f, 0x6854, 0x2068, 0x0078, 0x5094, 0x6010, + 0x2060, 0x643c, 0x6540, 0x6644, 0xa6b4, 0x000f, 0x2d60, 0x1078, + 0x3522, 0x0040, 0x50af, 0x1078, 0x5374, 0xa085, 0x0001, 0x127f, + 0x007f, 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4a83, 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, + 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, + 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x4fd1, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 +}; +unsigned short risc_code_length01 = 0x5c95; + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.c linux.ac/drivers/scsi/scsi.c --- linux.vanilla/drivers/scsi/scsi.c Tue Jan 19 02:57:31 1999 +++ linux.ac/drivers/scsi/scsi.c Tue Jan 19 03:09:56 1999 @@ -280,8 +280,6 @@ {"YAMAHA","CDR100","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN}, -{"IBM","DPES-","*", BLIST_NOTQ | BLIST_NOLUN}, -{"WDIGTL","WDE","*", BLIST_NOTQ | BLIST_NOLUN}, /* * Must be at end of list... */ 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 Thu Jan 14 01:25:26 1999 +++ linux.ac/drivers/scsi/scsi.h Mon Mar 1 15:29:17 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_error.c linux.ac/drivers/scsi/scsi_error.c --- linux.vanilla/drivers/scsi/scsi_error.c Sat Jan 9 21:50:44 1999 +++ linux.ac/drivers/scsi/scsi_error.c Sun Feb 21 17:03:08 1999 @@ -563,6 +563,7 @@ struct semaphore sem = MUTEX_LOCKED; struct timer_list timer; + init_timer(&timer); timer.data = (unsigned long) &sem; timer.expires = jiffies + timeout; timer.function = (void (*)(unsigned long))scsi_sleep_done; 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/sd_ioctl.c linux.ac/drivers/scsi/sd_ioctl.c --- linux.vanilla/drivers/scsi/sd_ioctl.c Sun Nov 8 15:07:48 1998 +++ linux.ac/drivers/scsi/sd_ioctl.c Mon Feb 1 00:42:14 1999 @@ -108,6 +108,11 @@ return -EACCES; return revalidate_scsidisk(dev, 1); + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F], + (int *)arg); + RO_IOCTLS(dev, arg); default: 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 Sun Feb 28 17:50:27 1999 @@ -4,7 +4,44 @@ * 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. + * + * Modifications for scatter gather + command queuing 2.1.6 (990220) + * 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 +65,756 @@ #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 modules). */ + +#define SG_SECTOR_SZ 512 +#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) + +#define SG_LOW_POOL_THRESHHOLD 20 +#define SG_MAX_POOL_SECTORS 74 /* Maximum number pool sectors to take */ + +static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; + +static int sg_num_kmal = 0; +static int sg_num_pool = 0; +static int sg_num_page = 0; + +#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 declaration */ +struct sg_fd; /* forward declaration */ -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 */ +} Sg_fd; /* around 1188 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->noise, ... 9->dump state+noise */ + 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_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) { + 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 = 0; /* set to default: 'per fd' mode */ + } + 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; -} + /* Now copy the result back to the user buffer. */ + 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; + 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 -EMSGSIZE; + + 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 -EMSGSIZE; /* implies msg "too long" really "too short" */ } - 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")); */ - if (count>=sizeof(struct sg_header)) + 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; +} + +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); + 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_GET_BUFF_SIZE: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + put_user((int)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: + 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_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. */ + 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 (sdp->sgdebug > 8) + sg_debug(sfp); + return 0; + default: + 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 (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; } - /* - * Now wake up the process that is waiting for the - * result. - */ - device->complete=1; + 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. */ + srp->header.target_status = status_byte(SCpnt->result); + if ((sdp->sgdebug > 0) && (0 != srp->header.target_status)) + print_sense("sg", 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); + } + } + /* 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(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"); -#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; + const Sg_device * sdp; + Sg_fd * fp; + Sg_request * srp; + int dev; + int k; + + if (! sfp) { + printk("sg_debug: sfp (file descriptor pointer) NULL\n"); + return; } - - /* - * 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; + else if (! (sdp = sfp->parentdp)) { + printk("sg_debug: sfp parent 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 + dev = MINOR(sdp->i_rdev); - /* - * 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); - -#ifdef DEBUG - printk("done cmd\n"); -#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; + printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev); + printk("scsi%d chan=%d id=%d lun=%d\n", sdp->device->host->host_no, + sdp->device->channel, sdp->device->id, sdp->device->lun); + printk(" sg_tablesize=%d, excl=%d, sgdebug=%d, merge_fd=%d\n", + sdp->sg_tablesize, sdp->exclude, sdp->sgdebug, sdp->merge_fd); + printk(" sg_big_buff=%d, scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", + sg_big_buff, scsi_dma_free_sectors, sg_pool_secs_avail); + printk(" malloc counts, kmallocs=%d, dma_pool=%d, pages=%d\n", + sg_num_kmal, sg_num_pool, sg_num_page); + + 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\n", + k, fp->timeout, fp->fb_size); + 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 >>"); + 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 +826,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 +863,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 +980,539 @@ 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 { + 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 = 0; + sfp->low_dma = sdp->device->host->unchecked_isa_dma; + 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 */ +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) +{ + char * resp = NULL; + int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC; + + if (rqSz <= 0) + return resp; + if (SG_HEAP_KMAL == mem_src) { + resp = kmalloc(rqSz, page_mask); + if (resp && retSzp) *retSzp = rqSz; + ++sg_num_kmal; + 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; + ++sg_num_pool; + 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; + if (resp) ++sg_num_page; + } + 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/scsi/sr_ioctl.c linux.ac/drivers/scsi/sr_ioctl.c --- linux.vanilla/drivers/scsi/sr_ioctl.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/sr_ioctl.c Mon Feb 1 10:07:06 1999 @@ -872,6 +872,11 @@ read_ahead[MAJOR(cdi->dev)] = arg; return 0; + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)], + (int *)arg); + RO_IOCTLS(cdi->dev,arg); case BLKFLSBUF: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c416.c linux.ac/drivers/scsi/sym53c416.c --- linux.vanilla/drivers/scsi/sym53c416.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/sym53c416.c Sat Jan 16 21:35:28 1999 @@ -0,0 +1,806 @@ +/* + * sym53c416.c + * Low-level SCSI driver for sym53c416 chip. + * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) + * + * LILO command line usage: sym53c416=[,] + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "sd.h" +#include "sym53c416.h" + +#define VERSION_STRING "Version 1.0.0" + +#define TC_LOW 0x00 /* Transfer counter low */ +#define TC_MID 0x01 /* Transfer counter mid */ +#define SCSI_FIFO 0x02 /* SCSI FIFO register */ +#define COMMAND_REG 0x03 /* Command Register */ +#define STATUS_REG 0x04 /* Status Register (READ) */ +#define DEST_BUS_ID 0x04 /* Destination Bus ID (WRITE) */ +#define INT_REG 0x05 /* Interrupt Register (READ) */ +#define TOM 0x05 /* Time out multiplier (WRITE) */ +#define STP 0x06 /* Synchronous Transfer period */ +#define SYNC_OFFSET 0x07 /* Synchronous Offset */ +#define CONF_REG_1 0x08 /* Configuration register 1 */ +#define CONF_REG_2 0x0B /* Configuration register 2 */ +#define CONF_REG_3 0x0C /* Configuration register 3 */ +#define CONF_REG_4 0x0D /* Configuration register 4 */ +#define TC_HIGH 0x0E /* Transfer counter high */ +#define PIO_FIFO_1 0x10 /* PIO FIFO register 1 */ +#define PIO_FIFO_2 0x11 /* PIO FIFO register 2 */ +#define PIO_FIFO_3 0x12 /* PIO FIFO register 3 */ +#define PIO_FIFO_4 0x13 /* PIO FIFO register 4 */ +#define PIO_FIFO_CNT 0x14 /* PIO FIFO count */ +#define PIO_INT_REG 0x15 /* PIO interrupt register */ +#define CONF_REG_5 0x16 /* Configuration register 5 */ +#define FEATURE_EN 0x1D /* Feature Enable register */ + +/* Configuration register 1 entries: */ +/* Bits 2-0: SCSI ID of host adapter */ +#define SCM 0x80 /* Slow Cable Mode */ +#define SRID 0x40 /* SCSI Reset Interrupt Disable */ +#define PTM 0x20 /* Parity Test Mode */ +#define EPC 0x10 /* Enable Parity Checking */ +#define CTME 0x08 /* Special Test Mode */ + +/* Configuration register 2 entries: */ +#define FE 0x40 /* Features Enable */ +#define SCSI2 0x08 /* SCSI 2 Enable */ +#define TBPA 0x04 /* Target Bad Parity Abort */ + +/* Configuration register 3 entries: */ +#define IDMRC 0x80 /* ID Message Reserved Check */ +#define QTE 0x40 /* Queue Tag Enable */ +#define CDB10 0x20 /* Command Descriptor Block 10 */ +#define FSCSI 0x10 /* FastSCSI */ +#define FCLK 0x08 /* FastClock */ + +/* Configuration register 4 entries: */ +#define RBS 0x08 /* Register bank select */ +#define EAN 0x04 /* Enable Active Negotiation */ + +/* Configuration register 5 entries: */ +#define LPSR 0x80 /* Lower Power SCSI Reset */ +#define IE 0x20 /* Interrupt Enable */ +#define LPM 0x02 /* Low Power Mode */ +#define WSE0 0x01 /* 0WS Enable */ + +/* Interrupt register entries: */ +#define SRST 0x80 /* SCSI Reset */ +#define ILCMD 0x40 /* Illegal Command */ +#define DIS 0x20 /* Disconnect */ +#define BS 0x10 /* Bus Service */ +#define FC 0x08 /* Function Complete */ +#define RESEL 0x04 /* Reselected */ +#define SI 0x03 /* Selection Interrupt */ + +/* Status Register Entries: */ +#define SCI 0x80 /* SCSI Core Int */ +#define GE 0x40 /* Gross Error */ +#define PE 0x20 /* Parity Error */ +#define TC 0x10 /* Terminal Count */ +#define VGC 0x08 /* Valid Group Code */ +#define PHBITS 0x07 /* Phase bits */ + +/* PIO Interrupt Register Entries: */ +#define SCI 0x80 /* SCSI Core Int */ +#define PFI 0x40 /* PIO FIFO Interrupt */ +#define FULL 0x20 /* PIO FIFO Full */ +#define EMPTY 0x10 /* PIO FIFO Empty */ +#define CE 0x08 /* Collision Error */ +#define OUE 0x04 /* Overflow / Underflow error */ +#define FIE 0x02 /* Full Interrupt Enable */ +#define EIE 0x01 /* Empty Interrupt Enable */ + +/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */ +#define PHASE_DATA_OUT 0x00 +#define PHASE_DATA_IN 0x01 +#define PHASE_COMMAND 0x02 +#define PHASE_STATUS 0x03 +#define PHASE_RESERVED_1 0x04 +#define PHASE_RESERVED_2 0x05 +#define PHASE_MESSAGE_OUT 0x06 +#define PHASE_MESSAGE_IN 0x07 + +/* SYM53C416 core commands */ +#define NOOP 0x00 +#define FLUSH_FIFO 0x01 +#define RESET_CHIP 0x02 +#define RESET_SCSI_BUS 0x03 +#define DISABLE_SEL_RESEL 0x45 +#define RESEL_SEQ 0x40 +#define SEL_WITHOUT_ATN_SEQ 0x41 +#define SEL_WITH_ATN_SEQ 0x42 +#define SEL_WITH_ATN_AND_STOP_SEQ 0x43 +#define ENABLE_SEL_RESEL 0x44 +#define SEL_WITH_ATN3_SEQ 0x46 +#define RESEL3_SEQ 0x47 +#define SND_MSG 0x20 +#define SND_STAT 0x21 +#define SND_DATA 0x22 +#define DISCONNECT_SEQ 0x23 +#define TERMINATE_SEQ 0x24 +#define TARGET_COMM_COMPLETE_SEQ 0x25 +#define DISCONN 0x27 +#define RECV_MSG_SEQ 0x28 +#define RECV_CMD 0x29 +#define RECV_DATA 0x2A +#define RECV_CMD_SEQ 0x2B +#define TARGET_ABORT_PIO 0x04 +#define TRANSFER_INFORMATION 0x10 +#define INIT_COMM_COMPLETE_SEQ 0x11 +#define MSG_ACCEPTED 0x12 +#define TRANSFER_PAD 0x18 +#define SET_ATN 0x1A +#define RESET_ATN 0x1B +#define ILLEGAL 0xFF + +#define PIO_MODE 0x80 + +#define IO_RANGE 0x20 /* 0x00 - 0x1F */ +#define ID "sym53c416" +#define PIO_SIZE 128 /* Size of PIO fifo is 128 bytes */ + +#define READ_TIMEOUT 150 +#define WRITE_TIMEOUT 150 + +#ifdef MODULE + +#define sym53c416_base sym53c416 +#define sym53c416_base_1 sym53c416_1 +#define sym53c416_base_2 sym53c416_2 +#define sym53c416_base_3 sym53c416_3 + +static unsigned short sym53c416_base = 0; +static unsigned int sym53c416_irq = 0; +static unsigned short sym53c416_base_1 = 0; +static unsigned int sym53c416_irq_1 = 0; +static unsigned short sym53c416_base_2 = 0; +static unsigned int sym53c416_irq_2 = 0; +static unsigned short sym53c416_base_3 = 0; +static unsigned int sym53c416_irq_3 = 0; + +#endif + +/* #define DEBUG */ + +/* Macro for debugging purposes */ + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#define MAXHOSTS 4 + +enum phases + { + idle, + data_out, + data_in, + command_ph, + status_ph, + message_out, + message_in + }; + +typedef struct + { + int base; + int irq; + int scsi_id; + } host; + +host hosts[MAXHOSTS] = { + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID} + }; + +static int host_index = 0; + +static char info[120]; + +static Scsi_Cmnd *current_command = NULL; + +struct proc_dir_entry proc_scsi_sym53c416 = {PROC_SCSI_SYM53C416, 7, ID, S_IFDIR | S_IRUGO | S_IXUGO, 2}; + +int fastpio = 1; + +int probeaddrs[] = {0x200, 0x220, 0x240, 0}; + +static void sym53c416_set_transfer_counter(int base, unsigned int len) + { + /* Program Transfer Counter */ + outb(len & 0x0000FF, base + TC_LOW); + outb((len & 0x00FF00) >> 8, base + TC_MID); + outb((len & 0xFF0000) >> 16, base + TC_HIGH); + } + +/* Returns the number of bytes read */ +static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len) + { + unsigned int orig_len = len; + unsigned long flags = 0; + unsigned int bytes_left; + int i; + int timeout = READ_TIMEOUT; + + /* Do transfer */ + save_flags(flags); + cli(); + while(len && timeout) + { + bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */ + if(fastpio && bytes_left > 3) + { + insl(base + PIO_FIFO_1, buffer, bytes_left >> 2); + buffer += bytes_left & 0xFC; + len -= bytes_left & 0xFC; + } + else if(bytes_left > 0) + { + len -= bytes_left; + for(; bytes_left > 0; bytes_left--) + *(buffer++) = inb(base + PIO_FIFO_1); + } + else + { + i = jiffies + timeout; + restore_flags(flags); + while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout) + if(inb(base + PIO_INT_REG) & SCI) + timeout = 0; + save_flags(flags); + cli(); + if(inb(base + PIO_INT_REG) & EMPTY) + timeout = 0; + } + } + restore_flags(flags); + return orig_len - len; + } + +/* Returns the number of bytes written */ +static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len) + { + unsigned int orig_len = len; + unsigned long flags = 0; + unsigned int bufferfree; + unsigned int i; + unsigned int timeout = WRITE_TIMEOUT; + + /* Do transfer */ + save_flags(flags); + cli(); + while(len && timeout) + { + bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT); + if(bufferfree > len) + bufferfree = len; + if(fastpio && bufferfree > 3) + { + outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2); + buffer += bufferfree & 0xFC; + len -= bufferfree & 0xFC; + } + else if(bufferfree > 0) + { + len -= bufferfree; + for(; bufferfree > 0; bufferfree--) + outb(*(buffer++), base + PIO_FIFO_1); + } + else + { + i = jiffies + timeout; + restore_flags(flags); + while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout) + ; + save_flags(flags); + cli(); + if(inb(base + PIO_INT_REG) & FULL) + timeout = 0; + } + } + restore_flags(flags); + return orig_len - len; + } + +static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs) + { + int base = 0; + int i; + unsigned long flags = 0; + unsigned char status_reg, pio_int_reg, int_reg; + struct scatterlist *sglist; + unsigned int sgcount; + unsigned int tot_trans = 0; + + /* We search the base address of the host adapter which caused the interrupt */ + for(i = 0; i < host_index && !base; i++) + if(irq == hosts[i].irq) + base = hosts[i].base; + /* If no adapter found, we cannot handle the interrupt. Leave a message */ + /* and continue. This should never happen... */ + if(!base) + { + printk("sym53c416: No host adapter defined for interrupt %d\n", irq); + return; + } + /* Now we have the base address and we can start handling the interrupt */ + save_flags(flags); + cli(); + status_reg = inb(base + STATUS_REG); + pio_int_reg = inb(base + PIO_INT_REG); + int_reg = inb(base + INT_REG); + restore_flags(flags); + + /* First, we handle error conditions */ + if(int_reg & SCI) /* SCSI Reset */ + { + printk("sym53c416: Warning: Reset received\n"); + current_command->SCp.phase = idle; + current_command->result = DID_RESET << 16; + current_command->scsi_done(current_command); + return; + } + if(int_reg & ILCMD) /* Illegal Command */ + { + printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG)); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(status_reg & GE) /* Gross Error */ + { + printk("sym53c416: Warning: Gross Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(status_reg & PE) /* Parity Error */ + { + printk("sym53c416: Warning: Parity Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_PARITY << 16; + current_command->scsi_done(current_command); + return; + } + if(pio_int_reg & (CE | OUE)) + { + printk("sym53c416: Warning: PIO Interrupt Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(int_reg & DIS) /* Disconnect */ + { + if(current_command->SCp.phase != message_in) + current_command->result = DID_NO_CONNECT << 16; + else + current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); + current_command->SCp.phase = idle; + current_command->scsi_done(current_command); + return; + } + /* Now we handle SCSI phases */ + switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */ + { + case PHASE_DATA_OUT: + { + if(int_reg & BS) + { + current_command->SCp.phase = data_out; + outb(FLUSH_FIFO, base + COMMAND_REG); + sym53c416_set_transfer_counter(base, current_command->request_bufflen); + outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); + if(!current_command->use_sg) + tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen); + else + { + sgcount = current_command->use_sg; + sglist = current_command->request_buffer; + while(sgcount--) + { + tot_trans += sym53c416_write(base, sglist->address, sglist->length); + sglist++; + } + } + if(tot_trans < current_command->underflow) + printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow); + } + break; + } + case PHASE_DATA_IN: + { + if(int_reg & BS) + { + current_command->SCp.phase = data_in; + outb(FLUSH_FIFO, base + COMMAND_REG); + sym53c416_set_transfer_counter(base, current_command->request_bufflen); + outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); + if(!current_command->use_sg) + tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen); + else + { + sgcount = current_command->use_sg; + sglist = current_command->request_buffer; + while(sgcount--) + { + tot_trans += sym53c416_read(base, sglist->address, sglist->length); + sglist++; + } + } + if(tot_trans < current_command->underflow) + printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow); + } + break; + } + case PHASE_COMMAND: + { + current_command->SCp.phase = command_ph; + printk("sym53c416: Warning: Unknown interrupt in command phase\n"); + break; + } + case PHASE_STATUS: + { + current_command->SCp.phase = status_ph; + outb(FLUSH_FIFO, base + COMMAND_REG); + outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG); + break; + } + case PHASE_RESERVED_1: + case PHASE_RESERVED_2: + { + printk("sym53c416: Warning: Reserved phase\n"); + break; + } + case PHASE_MESSAGE_OUT: + { + current_command->SCp.phase = message_out; + outb(SET_ATN, base + COMMAND_REG); + outb(MSG_ACCEPTED, base + COMMAND_REG); + break; + } + case PHASE_MESSAGE_IN: + { + current_command->SCp.phase = message_in; + current_command->SCp.Status = inb(base + SCSI_FIFO); + current_command->SCp.Message = inb(base + SCSI_FIFO); + if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT) + outb(SET_ATN, base + COMMAND_REG); + outb(MSG_ACCEPTED, base + COMMAND_REG); + break; + } + } + } + +static void sym53c416_init(int base, int scsi_id) + { + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP, base + COMMAND_REG); + outb(0x99, base + TOM); /* Time out of 250 ms */ + outb(0x05, base + STP); + outb(0x00, base + SYNC_OFFSET); + outb(EPC | scsi_id, base + CONF_REG_1); + outb(FE | SCSI2 | TBPA, base + CONF_REG_2); + outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3); + outb(0x83 | EAN, base + CONF_REG_4); + outb(IE | WSE0, base + CONF_REG_5); + outb(0, base + FEATURE_EN); + } + +static int sym53c416_probeirq(int base, int scsi_id) + { + int irq, irqs, i; + + /* Clear interrupt register */ + inb(base + INT_REG); + /* Start probing for irq's */ + irqs = probe_irq_on(); + /* Reinit chip */ + sym53c416_init(base, scsi_id); + /* Cause interrupt */ + outb(NOOP, base + COMMAND_REG); + outb(ILLEGAL, base + COMMAND_REG); + outb(0x07, base + DEST_BUS_ID); + outb(0x00, base + DEST_BUS_ID); + /* Wait for interrupt to occur */ + i = jiffies + 20; + while(i > jiffies && !(inb(base + STATUS_REG) & SCI)) + barrier(); + if(i <= jiffies) /* timed out */ + return 0; + /* Get occurred irq */ + irq = probe_irq_off(irqs); + sym53c416_init(base, scsi_id); + return irq; + } + +/* Setup: sym53c416=base,irq */ +void sym53c416_setup(char *str, int *ints) + { + int i; + + if(host_index >= MAXHOSTS) + { + printk("sym53c416.c: Too many hosts defined\n"); + } + else + { + if(ints[0] < 1 || ints[0] > 2) + { + printk("sym53c416.c: Wrong number of parameters:\n"); + printk("sym53c416.c: usage: sym53c416=[,]\n"); + } + else + { + for(i = 0; i < host_index && i >= 0; i++) + if(hosts[i].base == ints[1]) + i = -2; + if(i >= 0) + { + hosts[host_index].base = ints[1]; + hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0; + host_index++; + } + } + } + } + +static int sym53c416_test(int base) + { + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP, base + COMMAND_REG); + if(inb(base + COMMAND_REG) != NOOP) + return 0; + if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF) + return 0; + if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY) + return 0; + return 1; + } + +void sym53c416_probe(void) + { + int *base = probeaddrs; + int ints[2]; + + ints[0] = 1; + for(; *base; base++) + if(!check_region(*base, IO_RANGE) && sym53c416_test(*base)) + { + ints[1] = *base; + sym53c416_setup(NULL, ints); + } + } + +int sym53c416_detect(Scsi_Host_Template *tpnt) + { + unsigned long flags; + struct Scsi_Host * shpnt = NULL; + int i; + int count; + +#ifdef MODULE + int ints[3]; + + ints[0] = 2; + if(sym53c416_base) + { + ints[1] = sym53c416_base; + ints[2] = sym53c416_irq; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_1) + { + ints[1] = sym53c416_base_1; + ints[2] = sym53c416_irq_1; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_2) + { + ints[1] = sym53c416_base_2; + ints[2] = sym53c416_irq_2; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_3) + { + ints[1] = sym53c416_base_3; + ints[2] = sym53c416_irq_3; + sym53c416_setup(NULL, ints); + } +#endif + + printk("sym53c416.c: %s\n", VERSION_STRING); + + sym53c416_probe(); + + /* Now we register and set up each host adapter found... */ + for(count = 0, i = 0; i < host_index; i++) + if(!sym53c416_test(hosts[i].base)) + printk("No sym53c416 found at address 0x%03x\n", hosts[i].base); + else + { + if(hosts[i].irq == 0) + /* We don't have an irq yet, so we should probe for one */ + if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0) + printk("irq autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base); + if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE)) + { + shpnt = scsi_register(tpnt, 0); + save_flags(flags); + cli(); + /* Request for specified IRQ */ + if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL)) + { + restore_flags(flags); + printk("Unable to assign IRQ %d\n", hosts[i].irq); + scsi_unregister(shpnt); + } + else + { + /* Inform the kernel of our IO range */ + request_region(hosts[i].base, IO_RANGE, ID); + shpnt->unique_id = hosts[i].base; + shpnt->io_port = hosts[i].base; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = hosts[i].irq; + shpnt->this_id = hosts[i].scsi_id; + sym53c416_init(hosts[i].base, hosts[i].scsi_id); + count++; + restore_flags(flags); + } + } + } + return count; + } + +const char *sym53c416_info(struct Scsi_Host *SChost) + { + int i; + int base = SChost->io_port; + int irq = SChost->irq; + int scsi_id = 0; + int rev = inb(base + TC_HIGH); + + for(i = 0; i < host_index; i++) + if(hosts[i].base == base) + scsi_id = hosts[i].scsi_id; + sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow"); + return info; + } + +int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + { + int base; + unsigned long flags = 0; + int i; + + /* Store base register as we can have more than one controller in the system */ + base = SCpnt->host->io_port; + current_command = SCpnt; /* set current command */ + current_command->scsi_done = done; /* set ptr to done function */ + current_command->SCp.phase = command_ph; /* currect phase is the command phase */ + current_command->SCp.Status = 0; + current_command->SCp.Message = 0; + + save_flags(flags); + cli(); + outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */ + outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */ + /* Write SCSI command into the SCSI fifo */ + for(i = 0; i < SCpnt->cmd_len; i++) + outb(SCpnt->cmnd[i], base + SCSI_FIFO); + /* Start selection sequence */ + outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG); + /* Now an interrupt will be generated which we will catch in out interrupt routine */ + restore_flags(flags); + return 0; + } + +static void internal_done(Scsi_Cmnd *SCpnt) + { + SCpnt->SCp.Status++; + } + +int sym53c416_command(Scsi_Cmnd *SCpnt) + { + sym53c416_queuecommand(SCpnt, internal_done); + SCpnt->SCp.Status = 0; + while(!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; + } + +int sym53c416_abort(Scsi_Cmnd *SCpnt) + { + printk("sym53c416_abort\n"); + + /* We don't know how to abort for the moment */ + return SCSI_ABORT_SNOOZE; + } + +int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) + { + int base; + int scsi_id = -1; + int i; + + printk("sym53c416_reset\n"); + base = SCpnt->host->io_port; + /* search scsi_id */ + for(i = 0; i < host_index && scsi_id != -1; i++) + if(hosts[i].base == base) + scsi_id = hosts[i].scsi_id; + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP | PIO_MODE, base + COMMAND_REG); + outb(RESET_SCSI_BUS, base + COMMAND_REG); + sym53c416_init(base, scsi_id); + return SCSI_RESET_PENDING; + } + +int sym53c416_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 + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26) +MODULE_AUTHOR("Lieven Willems"); +MODULE_PARM(sym53c416, "1-2i"); +MODULE_PARM(sym53c416_1, "1-2i"); +MODULE_PARM(sym53c416_2, "1-2i"); +MODULE_PARM(sym53c416_3, "1-2i"); +#endif + +Scsi_Host_Template driver_template = SYM53C416; + +#include "scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c416.h linux.ac/drivers/scsi/sym53c416.h --- linux.vanilla/drivers/scsi/sym53c416.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/sym53c416.h Tue Mar 2 02:03:44 1999 @@ -0,0 +1,91 @@ +/* + * sym53c416.h + * + * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) + * + * 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. + * + */ + +#ifndef _SYM53C416_H +#define _SYM53C416_H + +#if !defined(LINUX_VERSION_CODE) +#include +#endif + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include + +#define SYM53C416_SCSI_ID 7 + +extern struct proc_dir_entry proc_scsi_sym53c416; + +extern int sym53c416_detect(Scsi_Host_Template *); +extern const char *sym53c416_info(struct Scsi_Host *); +extern int sym53c416_command(Scsi_Cmnd *); +extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int sym53c416_abort(Scsi_Cmnd *); +extern int sym53c416_reset(Scsi_Cmnd *, unsigned int); +extern int sym53c416_bios_param(Disk *, kdev_t, int *); +extern void sym53c416_setup(char *str, int *ints); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) + +#define SYM53C416 { \ + proc_dir: &proc_scsi_sym53c416, \ + name: "Symbios Logic 53c416", \ + detect: sym53c416_detect, \ + info: sym53c416_info, \ + command: sym53c416_command, \ + queuecommand: sym53c416_queuecommand, \ + abort: sym53c416_abort, \ + reset: sym53c416_reset, \ + bios_param: sym53c416_bios_param, \ + can_queue: 1, \ + this_id: SYM53C416_SCSI_ID, \ + sg_tablesize: 32, \ + cmd_per_lun: 1, \ + unchecked_isa_dma: 1, \ + use_clustering: ENABLE_CLUSTERING \ + } + +#else + +#define SYM53C416 { \ + NULL, \ + NULL, \ + &proc_scsi_sym53c416, \ + NULL, \ + "Symbios Logic 53c416", \ + sym53c416_detect, \ + NULL, \ + sym53c416_info, \ + sym53c416_command, \ + sym53c416_queuecommand, \ + sym53c416_abort, \ + sym53c416_reset, \ + NULL, \ + sym53c416_bios_param, \ + 1, \ + SYM53C416_SCSI_ID, \ + 32, /* ???? */ \ + 1, \ + 0, \ + 1, \ + ENABLE_CLUSTERING \ + } + +#endif + +#endif 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 Tue Jan 19 02:57:32 1999 +++ linux.ac/drivers/sound/Config.in Tue Mar 2 01:32:35 1999 @@ -12,7 +12,7 @@ dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1370" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT -fi +fi dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1371" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1371_JOYPORT_BOOT @@ -75,6 +75,10 @@ dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then + if [ "$CONFIG_SOUND_OSS" = "y" ]; then + bool 'Persistent DMA buffers' CONFIG_SOUND_DMAP + fi + dep_tristate 'ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_PAS" = "y" ]; then int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 @@ -93,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 @@ -138,6 +145,7 @@ dep_tristate 'Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MSS" = "y" ]; then + bool 'Enable support for the SoundPro mixer' CONFIG_SOUND_SPRO hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530 int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11 int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3 @@ -267,6 +275,8 @@ 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 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/ad1848.c linux.ac/drivers/sound/ad1848.c --- linux.vanilla/drivers/sound/ad1848.c Sun Jan 24 19:55:36 1999 +++ linux.ac/drivers/sound/ad1848.c Tue Mar 2 01:32:12 1999 @@ -100,6 +100,11 @@ static int nr_ad1848_devs = 0; int deskpro_xl = 0; +#ifdef CONFIG_SOUND_SPRO +int soundpro = 1; +#else +int soundpro = 0; +#endif static volatile char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, @@ -312,22 +317,21 @@ if (mask & (1 << i)) n++; - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) /* Too many devices selected */ - { - mask &= ~devc->recmask; /* Filter out active settings */ + if (!soundpro) { + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) { /* Too many devices selected */ + mask &= ~devc->recmask; /* Filter out active settings */ - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; - if (n != 1) - mask = SOUND_MASK_MIC; - } - switch (mask) - { + if (n != 1) + mask = SOUND_MASK_MIC; + } + switch (mask) { case SOUND_MASK_MIC: recdev = 2; break; @@ -349,11 +353,38 @@ default: mask = SOUND_MASK_MIC; recdev = 2; - } + } + + recdev <<= 6; + ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); + ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + } else { /* soundpro */ + unsigned char val; + int set_rec_bit; + int j; + + for (i = 0; i < 32; i++) { /* For each bit */ + if ((devc->supported_rec_devices & (1 << i)) == 0) + continue; /* Device not supported */ + + for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { + if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ + continue; + + /* + * This is tricky: + * set_rec_bit becomes 1 if the corresponding bit in mask is set + * then it gets flipped if the polarity is inverse + */ + set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; - recdev <<= 6; - ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); - ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + val = ad_read(devc, devc->mix_devices[i][j].recreg); + val &= ~(1 << devc->mix_devices[i][j].recpos); + val |= (set_rec_bit << devc->mix_devices[i][j].recpos); + ad_write(devc, devc->mix_devices[i][j].recreg, val); + } + } + } /* Rename the mixer bits back if necessary */ for (i = 0; i < 32; i++) @@ -371,7 +402,8 @@ return mask; } -static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +static void change_bits(ad1848_info * devc, unsigned char *regval, + unsigned char *muteval, int dev, int chn, int newval) { unsigned char mask; int shift; @@ -379,7 +411,7 @@ int mutemask; int set_mute_bit; - set_mute_bit = (newval == 0); + set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ newval = 100 - newval; @@ -399,8 +431,11 @@ } newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ - *regval |= ((newval & mask) << shift) | mute; /* Set new value */ + *regval &= ~(mask << shift); /* Clear bits */ + *regval |= (newval & mask) << shift; /* Set new value */ + + *muteval &= mutemask; + *muteval |= mute; } static int ad1848_mixer_get(ad1848_info * devc, int dev) @@ -413,15 +448,36 @@ return devc->levels[dev]; } +static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel) +{ + int regoffs, muteregoffs; + unsigned char val, muteval; + + regoffs = devc->mix_devices[dev][channel].regno; + muteregoffs = devc->mix_devices[dev][channel].mutereg; + val = ad_read(devc, regoffs); + + if (muteregoffs != regoffs) { + muteval = ad_read(devc, muteregoffs); + change_bits(devc, &val, &muteval, dev, channel, value); + } + else + change_bits(devc, &val, &val, dev, channel, value); + + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; + if (muteregoffs != regoffs) { + ad_write(devc, muteregoffs, muteval); + devc->saved_regs[muteregoffs] = muteval; + } +} + static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; int retvol; - int regoffs; - unsigned char val; - if (dev > 31) return -EINVAL; @@ -430,6 +486,9 @@ dev = devc->mixer_reroute[dev]; + if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) + return -EINVAL; + if (left > 100) left = 100; if (right > 100) @@ -444,34 +503,21 @@ left = mix_cvt[left]; right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; - devc->levels[dev] = retvol; /* * Set the left channel */ - - regoffs = devc->mix_devices[dev][LEFT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, LEFT_CHN, left); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); /* * Set the right channel */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - return retvol; /* Was just a mono channel */ - - regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, RIGHT_CHN, right); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + goto out; + ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); + out: return retvol; } @@ -487,6 +533,8 @@ for (i = 0; i < 32; i++) devc->mixer_reroute[i] = i; + devc->supported_rec_devices = MODE1_REC_DEVICES; + switch (devc->model) { case MD_4231: @@ -509,11 +557,18 @@ devc->supported_devices = MODE3_MIXER_DEVICES; break; + case MD_1848: + if (soundpro) { + devc->supported_devices = SPRO_MIXER_DEVICES; + devc->supported_rec_devices = SPRO_REC_DEVICES; + devc->mix_devices = &(spro_mix_devices[0]); + break; + } + default: devc->supported_devices = MODE1_MIXER_DEVICES; } - devc->supported_rec_devices = MODE1_REC_DEVICES; devc->orig_devices = devc->supported_devices; devc->orig_rec_devices = devc->supported_rec_devices; @@ -528,10 +583,20 @@ ad1848_set_recmask(devc, SOUND_MASK_MIC); devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + + if (!soundpro) { + if (devc->mixer_output_port & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + } else { + /* + * From the "wouldn't it be nice if the mixer API had (better) + * support for custom stuff" category + */ + /* Enable surround mode and SB16 mixer */ + ad_write(devc, 16, 0x60); + } } static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) @@ -1706,7 +1771,27 @@ DDB(printk("ad1848_detect() - step K\n")); } + } else if (tmp1 == 0x0a) { + /* + * Is it perhaps a SoundPro CMI8330? + * If so, then we should be able to change indirect registers + * greater than I15 after activating MODE2, even though reading + * back I12 does not show it. + */ + + /* + * Let's try comparing register values + */ + for (i = 0; i < 16; i++) { + if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { + DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2)); + soundpro = 1; + devc->chip_name = "SoundPro CMI 8330"; + break; + } + } } + DDB(printk("ad1848_detect() - step L\n")); if (ad_flags) { @@ -2302,7 +2387,8 @@ (hw_config->irq != 7) && (hw_config->irq != 9) && (hw_config->irq != 10) && - (hw_config->irq != 11)) + (hw_config->irq != 11) && + (hw_config->irq != 12)) { printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); return 0; @@ -2555,6 +2641,7 @@ MODULE_PARM(dma2, "i"); /* Second DMA channel */ MODULE_PARM(type, "i"); /* Card type */ MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */ +MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro chips */ int io = -1; int irq = -1; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ad1848_mixer.h linux.ac/drivers/sound/ad1848_mixer.h --- linux.vanilla/drivers/sound/ad1848_mixer.h Sun Nov 8 15:08:02 1998 +++ linux.ac/drivers/sound/ad1848_mixer.h Tue Mar 2 01:32:12 1999 @@ -24,7 +24,10 @@ * solution). */ #define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE1|SOUND_MASK_IMIX) + SOUND_MASK_LINE1 | SOUND_MASK_IMIX) + +#define SPRO_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_LINE1) #define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ SOUND_MASK_LINE2 | \ @@ -47,16 +50,27 @@ SOUND_MASK_LINE3 | \ SOUND_MASK_IGAIN | SOUND_MASK_PCM) +#define SPRO_MIXER_DEVICES (SOUND_MASK_VOLUME | SOUND_MASK_PCM | \ + SOUND_MASK_LINE | SOUND_MASK_SYNTH | \ + SOUND_MASK_CD | SOUND_MASK_MIC | \ + SOUND_MASK_SPEAKER | SOUND_MASK_LINE1 | \ + SOUND_MASK_OGAIN) + struct mixer_def { - unsigned int regno: 5; - unsigned int polarity:1; /* 0=normal, 1=reversed */ - unsigned int bitpos:3; - unsigned int nbits:3; - unsigned int mutepos:4; + unsigned int regno:5; /* register number for volume */ + unsigned int polarity:1; /* volume polarity: 0=normal, 1=reversed */ + unsigned int bitpos:3; /* position of bits in register for volume */ + unsigned int nbits:3; /* number of bits in register for volume */ + unsigned int mutereg:5; /* register number for mute bit */ + unsigned int mutepol:1; /* mute polarity: 0=normal, 1=reversed */ + unsigned int mutepos:4; /* position of mute bit in register */ + unsigned int recreg:5; /* register number for recording bit */ + unsigned int recpol:1; /* recording polarity: 0=normal, 1=reversed */ + unsigned int recpos:4; /* position of recording bit in register */ }; static char mix_cvt[101] = { - 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, + 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, @@ -77,7 +91,17 @@ */ #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - {{reg_l, pola_l, pos_l, len_l, mute_bit}, {reg_r, pola_r, pos_r, len_r, mute_bit}} + [name] = {{reg_l, pola_l, pos_l, len_l, reg_l, 0, mute_bit, 0, 0, 8}, \ + {reg_r, pola_r, pos_r, len_r, reg_r, 0, mute_bit, 0, 0, 8}} + +#define MIX_ENT2(name, reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l, \ + reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r) \ + [name] = {{reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l}, \ + {reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r}} static mixer_ents ad1848_mix_devices[32] = { MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), @@ -142,6 +166,25 @@ MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) +}; + +static mixer_ents spro_mix_devices[32] = { +MIX_ENT (SOUND_MIXER_VOLUME, 19, 0, 4, 4, 19, 0, 0, 4, 8), +MIX_ENT (SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 23, 0, 3, 0, 0, 8, 5, 1, 1, 4, 23, 0, 3, 0, 0, 8), +MIX_ENT (SOUND_MIXER_PCM, 6, 1, 1, 4, 7, 1, 1, 4, 8), +MIX_ENT (SOUND_MIXER_SPEAKER, 18, 0, 3, 2, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_LINE, 20, 0, 4, 4, 17, 1, 4, 16, 0, 2, 20, 0, 0, 4, 17, 1, 3, 16, 0, 1), +MIX_ENT2(SOUND_MIXER_MIC, 18, 0, 0, 3, 17, 1, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT2(SOUND_MIXER_CD, 21, 0, 4, 4, 17, 1, 2, 16, 0, 4, 21, 0, 0, 4, 17, 1, 1, 16, 0, 3), +MIX_ENT (SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_OGAIN, 17, 1, 6, 1, 0, 0, 0, 0, 8), +/* This is external wavetable */ +MIX_ENT2(SOUND_MIXER_LINE1, 22, 0, 4, 4, 23, 1, 1, 23, 0, 4, 22, 0, 0, 4, 23, 1, 0, 23, 0, 5), }; static int default_mixer_levels[32] = 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 Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/es1370.c Sat Feb 27 20:09:15 1999 @@ -1597,6 +1597,7 @@ down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac2(s); + synchronize_irq(); dealloc_dmabuf(&s->dma_dac2); } if (file->f_mode & FMODE_READ) { 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 Sun Feb 28 02:35:09 1999 @@ -0,0 +1,888 @@ +#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; + } + + /* + * 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/lowlevel/awe_compat.h linux.ac/drivers/sound/lowlevel/awe_compat.h --- linux.vanilla/drivers/sound/lowlevel/awe_compat.h Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/lowlevel/awe_compat.h Tue Mar 2 02:16:49 1999 @@ -54,7 +54,7 @@ #include "../soundvers.h" #endif -#if SOUND_INTERNAL_VERSION >= 0x30803 +#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803 /* OSS/Free-3.8 */ #define AWE_NO_PATCHMGR #define AWE_OSS38 @@ -151,18 +151,9 @@ #define my_malloc_memptr() _mem_start #define my_free(ptr) /* do nothing */ -static void *my_malloc(int size) -{ - char *ptr; - PERMANENT_MALLOC(ptr, char*, size, _mem_start); - return (void*)ptr; -} -#define my_kmalloc(size) my_malloc(size) -#define kfree(ptr) /* do nothing */ - /* allocate buffer only once */ #define INIT_TABLE(buffer,index,nums,type) {\ -buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ +PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\ } #else @@ -173,8 +164,6 @@ #define my_malloc_memptr() 0 #define my_malloc(size) vmalloc(size) #define my_free(ptr) if (ptr) {vfree(ptr);} -#define my_kmalloc(size) kmalloc(size,GFP_KERNEL) -#define my_kfree(ptr) kfree(ptr) /* do not allocate buffer at beginning */ #define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} @@ -254,6 +243,14 @@ #define sound_unload_mididev(dev) /**/ #endif /* AWE_MODULE_SUPPORT */ + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout) +{ + current->timeout = jiffies + timeout; + interruptible_sleep_on(q); +} +#endif #endif /* CONFIG_AWE32_SYNTH */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/lowlevel/awe_wave.c linux.ac/drivers/sound/lowlevel/awe_wave.c --- linux.vanilla/drivers/sound/lowlevel/awe_wave.c Tue Dec 22 23:19:53 1998 +++ linux.ac/drivers/sound/lowlevel/awe_wave.c Sat Feb 27 02:02:29 1999 @@ -2,9 +2,9 @@ * sound/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. - * version 0.4.3; Nov. 1, 1998 + * version 0.4.3; Feb. 1, 1999 * - * Copyright (C) 1996-1998 Takashi Iwai + * Copyright (C) 1996-1999 Takashi Iwai * * 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 @@ -204,16 +204,20 @@ #if defined(AWE_MODULE_SUPPORT) && defined(MODULE) /* replace awe_port variable with exported variable */ #define awe_port io -#define BASEVAR_DECL /**/ +#define awe_mem_size memsize +int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ +int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ +#ifdef MODULE_PARM +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "base i/o port of Emu8000"); +MODULE_PARM(memsize, "i"); +MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); +#endif #else -#define BASEVAR_DECL static +static int awe_port = AWE_DEFAULT_BASE_ADDR; +static int awe_mem_size = AWE_DEFAULT_MEM_SIZE; #endif /* module */ -/* awe32 base address (overwritten at initialization) */ -BASEVAR_DECL int awe_port = AWE_DEFAULT_BASE_ADDR; -/* memory byte size */ -BASEVAR_DECL int memsize = AWE_DEFAULT_MEM_SIZE; /* for module option */ -static int awe_mem_size = -1; /* DRAM start offset */ static int awe_mem_start = AWE_DRAM_OFFSET; @@ -669,7 +673,7 @@ #include -BASEVAR_DECL int pnp = 1; /* use PnP as default */ +static int pnp = 1; /* use PnP as default */ #define AWE_NUM_CHIPS 3 static unsigned int pnp_ids[AWE_NUM_CHIPS] = { @@ -812,6 +816,7 @@ } #ifdef MODULE_PARM +EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); MODULE_SUPPORTED_DEVICE("sound"); @@ -975,23 +980,9 @@ #else static struct wait_queue *awe_sleeper = NULL; -static void awe_wakeup(unsigned long dummy) -{ - wake_up(&awe_sleeper); -} - -static struct timer_list awe_timer = -{NULL, NULL, 0, 0, awe_wakeup}; - static void awe_wait(unsigned short delay) { - unsigned long flags; - awe_timer.expires = jiffies + (HZ * (unsigned long)delay + 44099) / 44100; - add_timer(&awe_timer); - save_flags (flags); - cli(); - sleep_on(&awe_sleeper); - restore_flags(flags); + interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100); } #endif /* wait by loop */ @@ -1553,7 +1544,7 @@ vp->parm.moddcysus)); if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { - awe_poke(AWE_ENVVAL(voice), 0xBFFF); + awe_poke(AWE_ENVVOL(voice), 0xBFFF); vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); } else { awe_poke(AWE_ENVVOL(voice), @@ -3268,7 +3259,7 @@ sf_list *sf; /* search for all sharing lists */ - for (sf_id = rec->v.sf_id; sf_id > 0; sf_id = sf->shared) { + for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) { sf = &sflists[sf_id - 1]; for (j = sf->infos; j >= 0; j = infos[j].next) { awe_voice_list *p = &infos[j]; @@ -4201,7 +4192,7 @@ if (id1 < id2) { /* make sure id1 > id2 */ int tmp; tmp = id1; id1 = id2; id2 = tmp; } - for (i = sflists[id1-1].shared; i > 0; i = sflists[i-1].shared) { + for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) { if (i == id2) return TRUE; } @@ -4223,10 +4214,10 @@ return i; } #ifdef AWE_ALLOW_SAMPLE_SHARING - if (sflists[sf-1].shared) { /* search recursively */ + if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */ if (level > current_sf_id) return -1; /* strange sharing loop.. quit */ - return search_sample_index(sflists[sf-1].shared, sample, level + 1); + return search_sample_index(i, sample, level + 1); } #endif return -1; @@ -4272,10 +4263,12 @@ note <= infos[rec].v.high && velocity >= infos[rec].v.vellow && velocity <= infos[rec].v.velhigh) { - vlist[nvoices] = &infos[rec].v; - if (infos[rec].type == V_ST_MAPPED) /* mapper */ + if (infos[rec].type == V_ST_MAPPED) { + /* mapper */ + vlist[0] = &infos[rec].v; return -1; - nvoices++; + } + vlist[nvoices++] = &infos[rec].v; if (nvoices >= AWE_MAX_VOICES) break; } @@ -5009,8 +5002,6 @@ DEBUG(0,printk("AWE32 not found\n")); return 0; } - if (memsize >= 0) /* given by config file or module option */ - awe_mem_size = memsize * 1024; /* convert to Kbytes */ return 1; } @@ -5028,8 +5019,13 @@ static void awe_check_dram(void) { - if (awe_mem_size >= 0) /* already initialized */ + if (awe_present) /* already initialized */ return; + + if (awe_mem_size >= 0) { /* given by config file or module option */ + awe_mem_size *= 1024; /* convert to Kbytes */ + return; + } awe_open_dram_for_check(); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/mad16.c linux.ac/drivers/sound/mad16.c --- linux.vanilla/drivers/sound/mad16.c Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/mad16.c Fri Feb 26 18:32:51 1999 @@ -800,7 +800,7 @@ mad_write(MC3_PORT, tmp | 0x04); hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif 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;iio_base); return 0; } - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); } void unload_sb(struct address_info *hw_config) @@ -135,6 +135,7 @@ int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ int trix = 0; /* Set trix=1 to load this as support for trix */ int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int support = 0; /* Set support to load this as a support module */ int sm_games = 0; /* Mixer - see sb_mixer.c */ int acer = 0; /* Do acer notebook init */ @@ -145,6 +146,7 @@ MODULE_PARM(mpu_io, "i"); MODULE_PARM(type, "i"); MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); @@ -156,7 +158,7 @@ { printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (mad16 == 0 && trix == 0 && pas2 == 0) + if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0) { if (io == -1 || dma == -1 || irq == -1) { @@ -191,7 +193,7 @@ { if (smw_free) vfree(smw_free); - if (!mad16 && !trix && !pas2) + if (!mad16 && !trix && !pas2 && !support) unload_sb(&config); if (sbmpu) unload_sbmpu(&config_mpu); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_common.c linux.ac/drivers/sound/sb_common.c --- linux.vanilla/drivers/sound/sb_common.c Tue Jan 26 09:44:21 1999 +++ linux.ac/drivers/sound/sb_common.c Fri Feb 26 19:42:11 1999 @@ -179,13 +179,25 @@ status = inb(DSP_DATA_AVL16); } +static void pci_intr(sb_devc *devc) +{ + int src = inb(devc->pcibase+0x1A); + src&=3; + if(src) + sb_intr(devc); +} + static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - sb_devc *devc = dev_id; + sb_devc *devc = dev_id; devc->irq_ok = 1; switch (devc->model) { + case MDL_ESSPCI: + pci_intr (devc); + break; + case MDL_ESS: ess_intr (devc); break; @@ -478,7 +490,7 @@ #endif } -int sb_dsp_detect(struct address_info *hw_config) +int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio) { sb_devc sb_info; sb_devc *devc = &sb_info; @@ -508,7 +520,22 @@ devc->dma8 = hw_config->dma; devc->dma16 = -1; - + devc->pcibase = pciio; + + if(pci == SB_PCI_ESSMAESTRO) + { + devc->model = MDL_ESSPCI; + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + hw_config->card_subtype = MDL_ESSPCI; + } + + if(pci == SB_PCI_YAMAHA) + { + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + } + if (acer) { cli(); @@ -569,6 +596,10 @@ } } } + + if(devc->type == MDL_ESSPCI) + devc->model = MDL_ESSPCI; + /* * Save device information for sb_dsp_init() */ @@ -619,7 +650,15 @@ if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0) { /* IRQ setup */ - if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) + + /* + * ESS PCI cards do shared PCI IRQ stuff. Since they + * will get shared PCI irq lines we must cope. + */ + + int i=(devc->caps&SB_PCI_IRQ)?SA_SHIRQ:0; + + if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_mixer.c linux.ac/drivers/sound/sb_mixer.c --- linux.vanilla/drivers/sound/sb_mixer.c Tue Jan 26 09:44:22 1999 +++ linux.ac/drivers/sound/sb_mixer.c Fri Feb 19 14:00:09 1999 @@ -673,6 +673,7 @@ switch (devc->model) { + case MDL_ESSPCI: case MDL_SBPRO: case MDL_AZTECH: case MDL_JAZZ: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sequencer.c linux.ac/drivers/sound/sequencer.c --- linux.vanilla/drivers/sound/sequencer.c Tue Jan 19 02:57:34 1999 +++ linux.ac/drivers/sound/sequencer.c Sat Feb 27 02:02:29 1999 @@ -1105,7 +1105,7 @@ */ for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) + if (!midi_opened[i] && midi_devs[i]) { if ((retval = midi_devs[i]->open(i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) @@ -1411,7 +1411,7 @@ case SNDCTL_SEQ_TESTMIDI: if (__get_user(midi_dev, (int *)arg)) return -EFAULT; - if (midi_dev < 0 || midi_dev >= max_mididev) + if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) return -ENXIO; if (!midi_opened[midi_dev] && @@ -1529,7 +1529,7 @@ case SNDCTL_MIDI_INFO: if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device)))) return -EFAULT; - if (dev < 0 || dev >= max_mididev) + if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) return -ENXIO; midi_devs[dev]->info.device = dev; return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sound_core.c linux.ac/drivers/sound/sound_core.c --- linux.vanilla/drivers/sound/sound_core.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/sound/sound_core.c Mon Mar 1 14:24:09 1999 @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/soundcard.c linux.ac/drivers/sound/soundcard.c --- linux.vanilla/drivers/sound/soundcard.c Tue Jan 19 02:57:34 1999 +++ linux.ac/drivers/sound/soundcard.c Thu Feb 18 20:28:32 1999 @@ -67,7 +67,11 @@ int sound_nblocks = 0; /* Persistent DMA buffers */ -int sound_dmap_flag = 0; /* Off by default */ +#ifdef CONFIG_SOUND_DMAP +int sound_dmap_flag = 1; +#else +int sound_dmap_flag = 0; +#endif static int soundcard_configured = 0; @@ -802,13 +806,6 @@ return -1; } -static void destroy_special_devices(void) -{ - unregister_sound_special(6); - unregister_sound_special(1); - unregister_sound_special(8); -} - #ifdef MODULE static void #else @@ -849,11 +846,18 @@ #endif } +#ifdef MODULE + +static void destroy_special_devices(void) +{ + unregister_sound_special(6); + unregister_sound_special(1); + unregister_sound_special(8); +} + static int sound[20] = { 0 }; - -#ifdef MODULE int traceinit = 0; static int dmabuf = 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/trix.c linux.ac/drivers/sound/trix.c --- linux.vanilla/drivers/sound/trix.c Mon Dec 28 23:09:45 1998 +++ linux.ac/drivers/sound/trix.c Fri Feb 26 18:32:43 1999 @@ -323,7 +323,7 @@ hw_config->name = "AudioTrix SB"; #ifdef CONFIG_SBDSP - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Config.in linux.ac/drivers/video/Config.in --- linux.vanilla/drivers/video/Config.in Sun Jan 24 19:55:36 1999 +++ linux.ac/drivers/video/Config.in Sun Jan 24 20:28:50 1999 @@ -37,7 +37,7 @@ fi if [ "$CONFIG_ATARI" = "y" ]; then bool 'Atari native chipset support' CONFIG_FB_ATARI - bool 'ATI Mach64 display support' CONFIG_FB_ATY + bool 'ATI Mach64 display support' CONFIG_FB_ATARI_ATY fi if [ "$CONFIG_PPC" = "y" ]; then bool 'Open Firmware frame buffer device support' CONFIG_FB_OF @@ -45,7 +45,7 @@ bool 'Apple "control" display support' CONFIG_FB_CONTROL bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE - bool 'ATI Mach64 display support' CONFIG_FB_ATY + bool 'ATI Mach64 display support' CONFIG_FB_OF_ATY bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT bool 'Chips 65550 display support' CONFIG_FB_CT65550 bool 'S3 Trio display support' CONFIG_FB_S3TRIO @@ -73,7 +73,7 @@ bool ' G100/G200 support' CONFIG_FB_MATROX_G100 bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi - bool 'ATI Mach64 display support' CONFIG_FB_ATY + bool 'ATI Mach64 display support' CONFIG_FB_PCI_ATY fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then @@ -104,11 +104,27 @@ if [ "$CONFIG_PCI" != "n" ]; then bool 'PCI framebuffers' CONFIG_FB_PCI if [ "$CONFIG_FB_PCI" != "n" ]; then - bool ' ATI Mach64 display support' CONFIG_FB_ATY + bool ' ATI Mach64 display support' CONFIG_FB_SPARC64_PCI_ATY fi fi fi tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL + + if [ "$CONFIG_FB_ATARI_ATY" = "y" \ + -o "$CONFIG_FB_OF_ATY" = "y" \ + -o "$CONFIG_FB_PCI_ATY" = "y" \ + -o "$CONFIG_FB_SPARC64_PCI_ATY" = "y" ]; then + define_bool CONFIG_FB_ATY y + else + if [ "$CONFIG_FB_ATARI_ATY" = "m" \ + -o "$CONFIG_FB_OF_ATY" = "m" \ + -o "$CONFIG_FB_PCI_ATY" = "m" \ + -o "$CONFIG_FB_SPARC64_PCI_ATY" = "m" ]; then + define_bool CONFIG_FB_ATY m + else + define_bool CONFIG_FB_ATY n + fi + fi bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Sun Jan 24 19:55:36 1999 +++ linux.ac/drivers/video/Makefile Tue Jan 26 23:43:49 1999 @@ -128,6 +128,14 @@ endif endif +ifeq ($(CONFIG_FB_CYBER2000),y) +L_OBJS += cyber2000fb.o +else + ifeq ($(CONFIG_FB_CYBER2000),m) + M_OBJS += cyber2000fb.o + endif +endif + ifeq ($(CONFIG_FB_MAC),y) L_OBJS += macfb.o endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cgsixfb.c linux.ac/drivers/video/cgsixfb.c --- linux.vanilla/drivers/video/cgsixfb.c Tue Dec 22 23:19:55 1998 +++ linux.ac/drivers/video/cgsixfb.c Wed Jan 27 18:58:06 1999 @@ -352,8 +352,8 @@ do { i = fbc->s; } while (i & 0x10000000); - fbc->fg = attr_fgcol(p,*s); - fbc->bg = attr_bgcol(p,*s); + fbc->fg = attr_fgcol(p, scr_readw(s)); + fbc->bg = attr_bgcol(p, scr_readw(s)); fbc->mode = 0x140000; fbc->alu = 0xe880fc30; fbc->pixelm = ~(0); @@ -379,15 +379,15 @@ fbc->x1 = (x += 4 * fontwidth(p)) - 1; fbc->y0 = y; if (fontheightlog(p)) { - fd1 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd2 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd3 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd4 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); } else { - fd1 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd2 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd3 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd4 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); } if (fontwidth(p) == 8) { for (i = 0; i < fontheight(p); i++) @@ -408,11 +408,11 @@ fbc->x1 = (x += 2 * fontwidth(p)) - 1; fbc->y0 = y; if (fontheightlog(p)) { - fd1 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); - fd2 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); } else { - fd1 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); - fd2 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); + fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); } for (i = 0; i < fontheight(p); i++) { fbc->font = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p)); @@ -428,9 +428,9 @@ fbc->x1 = (x += fontwidth(p)) - 1; fbc->y0 = y; if (fontheightlog(p)) - i = ((*s++ & p->charmask) << fontheightlog(p)); + i = ((scr_readw(s++) & p->charmask) << fontheightlog(p)); else - i = ((*s++ & p->charmask) * fontheight(p)); + i = ((scr_readw(s++) & p->charmask) * fontheight(p)); if (fontwidth(p) <= 8) { fd1 = p->fontdata + i; for (i = 0; i < fontheight(p); i++) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/clgenfb.c linux.ac/drivers/video/clgenfb.c --- linux.vanilla/drivers/video/clgenfb.c Sun Jan 24 19:55:37 1999 +++ linux.ac/drivers/video/clgenfb.c Wed Jan 27 18:59:21 1999 @@ -204,8 +204,8 @@ struct fb_info_gen *info); static int clgen_blank(int blank_mode, struct fb_info_gen *info); -static void clgen_set_dispsw(const void *par, struct display *disp, - struct fb_info_gen *info); +static void clgen_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info); /* function table of the above functions */ static struct fbgen_hwswitch clgen_hwswitch = @@ -220,7 +220,7 @@ clgen_setcolreg, clgen_pan_display, clgen_blank, - clgen_set_dispsw + clgen_set_disp }; /* Text console acceleration */ @@ -1372,13 +1372,14 @@ } } -static void clgen_set_dispsw(const void *par, struct display *disp, - struct fb_info_gen *info) +static void clgen_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info) { struct clgenfb_par *_par = (struct clgenfb_par*) par; struct clgenfb_info *info2 = (struct clgenfb_info *)info; - printk("clgen_get_dispsw(): "); + printk("clgen_set_disp(): "); + disp->screen_base = info2->fbmem; switch (_par->var.bits_per_pixel) { #ifdef FBCON_HAS_MFB @@ -1670,7 +1671,7 @@ int init_module(void) { printk("init_module()\n"); - clgenfb_init(0); + clgenfb_init(); return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/creatorfb.c linux.ac/drivers/video/creatorfb.c --- linux.vanilla/drivers/video/creatorfb.c Sun Jan 24 19:55:38 1999 +++ linux.ac/drivers/video/creatorfb.c Wed Jan 27 18:58:06 1999 @@ -433,8 +433,8 @@ FFBWait(fbc); FFBFifo(fbc, 2); - fbc->fg = ((u32 *)p->dispsw_data)[attr_fgcol(p,*s)]; - fbc->bg = ((u32 *)p->dispsw_data)[attr_bgcol(p,*s)]; + fbc->fg = ((u32 *)p->dispsw_data)[attr_fgcol(p,scr_readw(s))]; + fbc->bg = ((u32 *)p->dispsw_data)[attr_bgcol(p,scr_readw(s))]; xy = fb->s.ffb.xy_margin; if (fontwidthlog(p)) xy += (xx << fontwidthlog(p)); @@ -452,15 +452,15 @@ fbc->fontinc = 0x10000; fbc->fontxy = xy; if (fontheightlog(p)) { - fd1 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd2 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd3 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); - fd4 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); + fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); } else { - fd1 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd2 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd3 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); - fd4 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); + fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); } FFBFifo(fbc, fontheight(p)); if (fontwidth(p) == 8) { @@ -483,11 +483,11 @@ fbc->fontinc = 0x10000; fbc->fontxy = xy; if (fontheightlog(p)) { - fd1 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); - fd2 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); + fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); } else { - fd1 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); - fd2 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); + fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); } FFBFifo(fbc, fontheight(p)); for (i = 0; i < fontheight(p); i++) { @@ -504,9 +504,9 @@ fbc->fontinc = 0x10000; fbc->fontxy = xy; if (fontheightlog(p)) - i = ((*s++ & p->charmask) << fontheightlog(p)); + i = ((scr_readw(s++) & p->charmask) << fontheightlog(p)); else - i = ((*s++ & p->charmask) * fontheight(p)); + i = ((scr_readw(s++) & p->charmask) * fontheight(p)); FFBFifo(fbc, fontheight(p)); if (fontwidth(p) <= 8) { fd1 = p->fontdata + i; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cyber2000fb.c linux.ac/drivers/video/cyber2000fb.c --- linux.vanilla/drivers/video/cyber2000fb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/cyber2000fb.c Tue Jan 26 23:43:49 1999 @@ -0,0 +1,1125 @@ +/* + * linux/drivers/video/cyber2000.c + * + * Integraphics Cyber2000 frame buffer device + * + * Based on cyberfb.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include